WithSecureLabs / python-exe-unpacker

A helper script for unpacking and decompiling EXEs compiled from python code.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unpacked .pyc files are invalid (with dirty solution)

Gowee opened this issue · comments

When I try to decompile .pyc files generated by python-exe-unpacker, I got the following error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/xdis/load.py", line 209, in load_module_from_file_object
    co = marshal.loads(bytecode)
ValueError: bad marshal data (unknown type code)

And those .pyc are also treated invalid by Python interpreter:

RuntimeError: Bad code object in .pyc file

After spending two hours figuring out what's wrong, I think it is valuable to note them down here even if this project seemingly has ended:

I suppose the problem resides around
https://github.com/countercept/python-exe-unpacker/blob/6c88e9b28cb40615b680cefdb5f47ce4cab17833/pyinstxtractor.py#L322
where the appended header (incl. magic number, timestamp, size, etc) seems to mismatch with the .pyc format used by some newer Python versions (in my case 3.7).

To make uncompyle6 work well with malformed .pyc, dirty patch /usr/local/lib/python3.7/site-packages/xdis/load.py to make sure marshal.loads data starting from exactly 12th byte of original .pyc (e.g. utilizing BytesIO so that the fp can be read twice) helps.

I'm currently experiencing the same issue, and even though you gave the solution, I cannot figure out how to implement it myself. What do I need to change exactly in the load.py for it to work?

EDIT:
Some information, I'm using Python 3.8 and also trying to decompile a .pyc file made with Python 3.8
I've been trying to make your solution work, but so far no luck.

@appieGIT The dirty way aforementioned is a little tricky. Here is another way I did not try but expected to work:

Adding a new line pycFile.write(b'\0' * 4) just after the line https://github.com/countercept/python-exe-unpacker/blob/6c88e9b28cb40615b680cefdb5f47ce4cab17833/pyinstxtractor.py#L323

@Gowee I have tried this solution just now. It does start right now, which is something, but it keeps returning a parse error when decompyling the .pyc files with uncompyle6 or decompyle3.
I'm pretty sure this is still due to invalid .pyc files from the unpacker.

Is there any other solution you can think of?

@AlbertJanSch Would you mind sharing a sample .pyc?

@Gowee Of course. I uploaded a sample called calendar.pyc here: https://www.sendspace.com/file/id2d1f

@AlbertJanSch I see
Parse error at or near 'POP_BLOCK' instruction at offset 36. But I do not think it owes to python-exe-unpacker. And I have no idea how to fix it. Open a issue in the uncompyle6 project instead?

Gonna rephrase the solution in #14 (comment) for us, newbies. If you use rocky/python-decompile3 after extracting .pyc files and get "bad marshal data", do the following:

  1. Open the file /usr/local/lib/python3.7/site-packages/xdis/load.py
  2. Find lines:
if my_magic_int == magic_int:
    bytecode = fp.read()
    co = marshal.loads(bytecode)
  1. Replace with:
if my_magic_int == magic_int:
    fp.seek(12)
    bytecode = fp.read()
    co = marshal.loads(bytecode)

fp.seek(12) skips reading of the first 12 bytes and makes the decompiler work again.

Don't forget to revert the changes after you're done with decompilation.
Thanks to the original solution provider!

commented

It still doesn't works for me.. :( I tried all you have said until this message.

@CopyMist solution worked great for me. Tyty

I know this is a fairly old issue, but also try skipping 16 and 8 as well. 16 worked for me in python 3.10, I've heard 8 also works potentially.