Quantcast
Viewing all articles
Browse latest Browse all 3

Python care and feeding, the Dropbox way

I've just revealed (by pure accident, actually), that Dropbox client binary (i.e. Dropbox.exe file) is in fact a zip file with compiled Python files inside (.pyc files, that is). Interesting, huh? A closer look at the executable file (as well as googling for some strings found in the binary) points to the tool used to pack the application into a single executable file - it's py2exe!

Needless to say, it's tempting to look closer at the .pyc files, or even try to decompile them. Here comes the surprise - the files seem encrypted. Typically, .pyc contains a lot of human-readable strings (at least the file name and variable/function names), but it's not the case with files from unzipped Dropbox.exe:

czajnik@czajnik:~/work/dropbox/exe$ strings distutils/__init__.pyc  
Oc {
z4E7ls
]yD~
:z<n

Also, every .pyc file starts with a 4-byte magic number - in case of extracted .pyc files, the magic number equals 0xb7f20d0a - no public Python release ever used this value.

It seems that Dropbox team decided to patch the Python interpreter with some decryption routines, in order to protect the application from reverse engineering. Note, that the Python interpreter (Python25.dll) itself is embedded inside Dropbox.exe as a resource, it can be easily extracted with any resource editor. I guess it's time to start IDA Pro and look deeper Image may be NSFW.
Clik here to view.
:)

Edit: For the curious - I've spent some time digging deeper. It turned out there are 2 protection levels - one is a decryption routine plugged into code demarshalling part of static PyObject *r_object(RFILE *p) function (see marshall.c). It's fairly easy to work it around, even without fully disassembling it - nothing stops one from building a small .exe which calls original code in the DLL to decrypt the file. However, there is another protection - the Python virtual machine opcodes are mixed. This required a bit of manual reverse engineering of PyObject *PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) (see ceval.c), but also turned out to be fairly easy. Now I'm able to uncompyle nearly all the files.


Viewing all articles
Browse latest Browse all 3

Trending Articles