python EXE打包二进制逆向分析 2021-01-03 11:37:02 Steven Xeldax ## 工具 https://github.com/countercept/python-exe-unpacker https://github.com/extremecoders-re/pyinstxtractor https://github.com/rocky/python-decompile3 uncompyle ## pyinstaller逆向 对打包的exe进行进行还原 使用pyinstxtractor工具 ``` python pyinstxtractor.py target.exe ```  得到目录如下:  对pyc进行还原用户代码发现如下报错: ``` root@kali:~/Tools/Others/pyinstxtractor/1.exe_extracted# uncompyle6 1.pyc Traceback (most recent call last): File "/usr/local/lib/python3.8/dist-packages/xdis/load.py", line 297, in load_module_from_file_object co = xdis.unmarshal.load_code(fp, magic_int, code_objects) File "/usr/local/lib/python3.8/dist-packages/xdis/unmarshal.py", line 106, in load_code raise TypeError( TypeError: File 1.pyc doesn't smell like Python bytecode: expecting code indicator 'c'; got ' ' Traceback (most recent call last): File "/usr/local/lib/python3.8/dist-packages/xdis/load.py", line 297, in load_module_from_file_object co = xdis.unmarshal.load_code(fp, magic_int, code_objects) File "/usr/local/lib/python3.8/dist-packages/xdis/unmarshal.py", line 106, in load_code raise TypeError( TypeError: File 1.pyc doesn't smell like Python bytecode: expecting code indicator 'c'; got ' ' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/local/bin/uncompyle6", line 8, in <module> sys.exit(main_bin()) File "/usr/local/lib/python3.8/dist-packages/uncompyle6/bin/uncompile.py", line 193, in main_bin result = main(src_base, out_base, pyc_paths, source_paths, outfile, File "/usr/local/lib/python3.8/dist-packages/uncompyle6/main.py", line 316, in main deparsed = decompile_file( File "/usr/local/lib/python3.8/dist-packages/uncompyle6/main.py", line 183, in decompile_file (version, timestamp, magic_int, co, is_pypy, source_size, sip_hash) = load_module( File "/usr/local/lib/python3.8/dist-packages/xdis/load.py", line 163, in load_module return load_module_from_file_object( File "/usr/local/lib/python3.8/dist-packages/xdis/load.py", line 306, in load_module_from_file_object raise ImportError( ImportError: Ill-formed bytecode file 1.pyc <class 'TypeError'>; File 1.pyc doesn't smell like Python bytecode: expecting code indicator 'c'; got ' ' ``` 发现只有用户代码会出现问题,struct其他pyc不会  推测和magic魔术头有关 参考资料 https://blog.chembiosim.com/pyinstaller-reverse-engineer/ https://zhuanlan.zhihu.com/p/109266820 根据dll文件知道exe为py 3.7版本  hexdump struct发现3.7 为0d42  我们将1.pyc的头f303改成0d42   成功反编译  ## pyarmor混淆还原 项目 https://github.com/nlscc/unpyarmor 安装后报错  修改代码 ``` import sys import marshal import click from unpack import * from pyarmor import * def do_unpack(enc_data, key_data): pubkey = parse_key(key_data) armor = parse_armored(enc_data) # Make sure the python version matches python_ver = (sys.version_info.major, sys.version_info.minor) if armor.py_ver != python_ver: print("You are using python {}, but this script was packed with {}, expect errors!".format(python_ver, armor.py_ver)) co = restore_codeobj(armor.code, pubkey) co = deobfusc_codeobj(co, pubkey) pyc_data = armor.import_magic.ljust(16, b"\x00") + marshal.dumps(co) return pyc_data @click.group() def main(): pass ''' @main.command() @click.argument("enc") @click.argument("key") @click.argument("pyc_out") ''' def unpack(enc, key, pyc_out): with open(enc, "rb") as fd: enc = fd.read() with open(key, "rb") as fd: key = fd.read() dec = do_unpack(enc, key) with open(pyc_out, "wb") as fd: fd.write(dec) import sys print(sys.argv[1]) print(sys.argv[2]) print(sys.argv[3]) unpack(sys.argv[1],sys.argv[2],sys.argv[3]) ``` 注意使用unpyarmor的py版本需要和exe使用的py版本一致 还原 提取pyarmor为raw bin   然后使用修改后的unpyarmor还原 ``` python main.py enc.bin pytransformer.key out.pyc ```