6

There are several solutions available to extract Pyc files from Windows binaries and then decompile them using uncompyle2 or uncompyle6.

However, I have a Linux ELF 64-bit binary which was compiled using one of the Packagers used for Python (might be CX Freeze or PyInstaller). I am not sure of the exact package name.

Update:

File command output:

bin: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=212a49c7fff7342713aec6af6789abbaf3a8014, stripped

I also have a .so file called: libpython2.7.so.1.0 which I believe is the python interpreter.

The binary also has a .pydata section inside it as shown below:

 [27] pydata            PROGBITS         0000000000000000  00007a48
       00000000000a0c47  0000000000000000           0     0     1

The binary has strings inside it as shown below:

Py_SetPythonHome
Cannot dlsym for Py_SetPythonHome
Error loading Python lib '%s': dlopen: %s
Error detected starting Python VM.
libpython2.7.so.1.0

So, I'm quite sure that it is Python code compiled to a Linux binary.

Neither of these projects work for me.

  • unfrozen_binary - gives an error because in common.py it imports decompilers library which is not available.

  • pyThaw - it leverages radare2 however when I use it with my binary, it just hangs and does not extract the source code.

Are there any alternate solutions to decompile such elf binaries with python byte code for Linux?

  • 1
    Please clearly describe the file you are trying to reverse. Is it an ELF object file containing x86_64 object code in the .text section, or something else entirely? – julian Nov 17 '18 at 2:25
  • 1
    I'll add some more details. Yes, it is an ELF 64-bit binary. It has a pydata section inside it and I also have a .so file along with which corresponds to the python interpreter. – Neon Flash Nov 17 '18 at 3:35
  • You can set a breakpoint on PyEval_EvalFrameEx for starter and dump the bytecode as they are being executed. Not a complete solution though. – 0xec Nov 17 '18 at 5:44
  • can you provide the binary? – Evan Carroll Nov 17 '18 at 21:38
3

It can be said with certainty that your binary has been compiled with PyInstaller. Searching for the string "Error detected starting Python VM." leads to the PyInstaller repo.

Now that you know it's PyInstaller, you can have a look here which describes how PyInstaller works and how the binary is packaged. In short, here are the important parts

Two kinds of archives are used in PyInstaller. One is a ZlibArchive, which allows Python modules to be stored efficiently and, with some import hooks, imported directly. The other, a CArchive, is similar to a .zip file, a general way of packing up (and optionally compressing) arbitrary blobs of data. It gets its name from the fact that it can be manipulated easily from C as well as from Python. Both of these derive from a common base class, making it fairly easy to create new kinds of archives.

The docs recommend using the tool pyi-archive_viewer for inspecting PyInstaller binaries.

Use the pyi-archive_viewer command to inspect any type of archive:

pyi-archive_viewer archivefile

With this command you can examine the contents of any archive built with PyInstaller (a PYZ or PKG), or any executable (.exe file or an ELF or COFF binary)

This is what you can try for now. For Windows, there's the equivalent tool pyinstxtractor (I'm the author) but unfortunately there's no support for ELF's at the moment.

  • I was able to extract the python code however it's not plaintext yet and there's some binary data inside it. I used the "X" option of pyi-archive_viewer to extract the contents. It tells me the compressed and uncompressed size of the file. When I extract, the size matches the uncompressed size however the file is not proper python code. I checked the header of the file and ran binwalk on it as well to see if it's in a compressed form. But it is not. I have updated the answer. Could you please check? – Neon Flash Nov 17 '18 at 18:50
  • 1
    @NeonFlash You'd need to fix the header of the extracted pyc file before feeding it to the decompiler. I see that you have already figured that out :) – 0xec Nov 17 '18 at 21:06
2

One such alternative approach is, obviously, to extract the python code/byte code manually.

As integrating a python interpreter and/or bytecode compiler is takes some engineering, a lot of solutions tend to prefer the easy way. Although that may not be the case of a python code that was converted to an executable as an obfuscation measure, it is most definitely the case for most python to executable converters (such as py2exe, PyInstaller, etc).

The easy way I refer to is including a python interpreter as a whole, extracting raw py or pyc files to a temporary directory and executing the extracted code using the python interpreter.

Understanding whether that's the case with your sample should be quite easy to do either by process monitoring or debugging, and should also be possible by statically reverse engineering (which as we all know, is the hardcode way).


As a side note, that file you're looking at can have been generated using one of the available tools but then tweaked a bit to be unrecognizable or unparseable by common extractors. You can try handling that by trying to see the file structure resembles any of the python executable builders.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.