Decompile compiled python binaries (exe, elf) - Retreive from .pyc

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert)

支持HackTricks的其他方式:

漏洞赏金提示注册Intigriti,一个由黑客创建的高级漏洞赏金平台!立即加入我们,访问https://go.intigriti.com/hacktricks,开始赚取高达**$100,000**的赏金!

从编译的二进制文件到 .pyc

从一个ELF编译的二进制文件中,您可以使用以下方法获取**.pyc**:

pyi-archive_viewer <binary>
# The list of python modules will be given here:
[(0, 230, 311, 1, 'm', 'struct'),
(230, 1061, 1792, 1, 'm', 'pyimod01_os_path'),
(1291, 4071, 8907, 1, 'm', 'pyimod02_archive'),
(5362, 5609, 13152, 1, 'm', 'pyimod03_importers'),
(10971, 1473, 3468, 1, 'm', 'pyimod04_ctypes'),
(12444, 816, 1372, 1, 's', 'pyiboot01_bootstrap'),
(13260, 696, 1053, 1, 's', 'pyi_rth_pkgutil'),
(13956, 1134, 2075, 1, 's', 'pyi_rth_multiprocessing'),
(15090, 445, 672, 1, 's', 'pyi_rth_inspect'),
(15535, 2514, 4421, 1, 's', 'binary_name'),
...

? X binary_name
to filename? /tmp/binary.pyc

在一个Python可执行二进制文件中编译,您可以通过运行以下命令获取 .pyc 文件

python pyinstxtractor.py executable.exe

从 .pyc 文件到 Python 代码

对于 .pyc 数据("已编译"的 Python),您应该开始尝试 提取 原始 Python 代码

uncompyle6 binary.pyc  > decompiled.py

确保二进制文件的扩展名为".pyc"(如果不是,则uncompyle6将无法工作)

在执行uncompyle6时,您可能会遇到以下错误:

错误:未知的魔术数字227

/kali/.local/bin/uncompyle6 /tmp/binary.pyc
Unknown magic number 227 in /tmp/binary.pyc

要修复这个问题,您需要在生成的文件开头添加正确的魔术数字

魔术数字随Python版本而变化,要获取Python 3.8的魔术数字,您需要打开Python 3.8终端并执行:

>> import imp
>> imp.get_magic().hex()
'550d0d0a'

在这种情况下,Python3.8 的魔术数字是**0x550d0d0a,为了修复这个错误,您需要在.pyc 文件开头**添加以下字节:0x0d550a0d000000000000000000000000

一旦您添加了这个魔术头部,错误应该就会被修复。

这是一个正确添加的**.pyc Python3.8 魔术头部**的样子:

hexdump 'binary.pyc' | head
0000000 0d55 0a0d 0000 0000 0000 0000 0000 0000
0000010 00e3 0000 0000 0000 0000 0000 0000 0000
0000020 0700 0000 4000 0000 7300 0132 0000 0064
0000030 0164 006c 005a 0064 0164 016c 015a 0064

错误:反编译通用错误

其他错误,如:class 'AssertionError'>; co_code should be one of the types (<class 'str'>, <class 'bytes'>, <class 'list'>, <class 'tuple'>); is type <class 'NoneType'> 可能会出现。

这可能意味着您没有正确添加魔术数字,或者您没有使用****正确的魔术数字,因此请确保您使用正确的魔术数字(或尝试一个新的)。

请查看先前的错误文档。

自动工具

python-exe-unpacker 工具 作为几个社区可用工具的组合,旨在帮助研究人员解压和反编译使用py2exe和pyinstaller创建的Python可执行文件。它包括YARA规则,用于识别可执行文件是否基于Python,并确认创建工具。

ImportError:文件名:'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc' 不存在

一个常见问题涉及到一个不完整的Python字节码文件,这是由于使用unpy2exe或pyinstxtractor进行解包过程而导致的,然后由于缺少Python字节码版本号而无法被uncompyle6识别。为了解决这个问题,添加了一个prepend选项,它附加了必要的Python字节码版本号,从而促进了反编译过程。

问题示例:

# Error when attempting to decompile without the prepend option
test@test: uncompyle6 unpacked/malware_3.exe/archive.py
Traceback (most recent call last):
...
ImportError: File name: 'unpacked/malware_3.exe/__pycache__/archive.cpython-35.pyc' doesn't exist
# Successful decompilation after using the prepend option
test@test:python python_exe_unpack.py -p unpacked/malware_3.exe/archive
[*] On Python 2.7
[+] Magic bytes are already appended.

# Successfully decompiled file
[+] Successfully decompiled.

分析Python汇编

如果您无法按照先前的步骤提取Python的“原始”代码,那么您可以尝试提取汇编代码(但它并不是非常描述性的,所以请尝试再次提取原始代码)。在这里我找到了一个非常简单的代码来反汇编_.pyc_二进制文件(祝您好运理解代码流程)。如果_.pyc_是来自Python2,请使用Python2:

>>> import dis
>>> import marshal
>>> import struct
>>> import imp
>>>
>>> with open('hello.pyc', 'r') as f:  # Read the binary file
...     magic = f.read(4)
...     timestamp = f.read(4)
...     code = f.read()
...
>>>
>>> # Unpack the structured content and un-marshal the code
>>> magic = struct.unpack('<H', magic[:2])
>>> timestamp = struct.unpack('<I', timestamp)
>>> code = marshal.loads(code)
>>> magic, timestamp, code
((62211,), (1425911959,), <code object <module> at 0x7fd54f90d5b0, file "hello.py", line 1>)
>>>
>>> # Verify if the magic number corresponds with the current python version
>>> struct.unpack('<H', imp.get_magic()[:2]) == magic
True
>>>
>>> # Disassemble the code object
>>> dis.disassemble(code)
1           0 LOAD_CONST               0 (<code object hello_world at 0x7f31b7240eb0, file "hello.py", line 1>)
3 MAKE_FUNCTION            0
6 STORE_NAME               0 (hello_world)
9 LOAD_CONST               1 (None)
12 RETURN_VALUE
>>>
>>> # Also disassemble that const being loaded (our function)
>>> dis.disassemble(code.co_consts[0])
2           0 LOAD_CONST               1 ('Hello  {0}')
3 LOAD_ATTR                0 (format)
6 LOAD_FAST                0 (name)
9 CALL_FUNCTION            1
12 PRINT_ITEM
13 PRINT_NEWLINE
14 LOAD_CONST               0 (None)
17 RETURN_VALUE

Python转可执行文件

首先,我们将向您展示如何在py2exe和PyInstaller中编译有效载荷。

使用py2exe创建有效载荷:

  1. http://www.py2exe.org/安装py2exe软件包。

  2. 对于有效载荷(在本例中,我们将其命名为hello.py),使用类似于图1中的脚本。选项“bundle_files”值为1将把所有内容,包括Python解释器,捆绑到一个exe文件中。

  3. 一旦脚本准备就绪,我们将发出命令“python setup.py py2exe”。这将创建可执行文件,就像图2中所示。

from distutils.core import setup
import py2exe, sys, os

sys.argv.append('py2exe')

setup(
options = {'py2exe': {'bundle_files': 1}},
#windows = [{'script': "hello.py"}],
console = [{'script': "hello.py"}],
zipfile = None,
)
C:\Users\test\Desktop\test>python setup.py py2exe
running py2exe
*** searching for required modules ***
*** parsing results ***
*** finding dlls needed ***
*** create binaries ***
*** byte compile python files ***
*** copy extensions ***
*** copy dlls ***
copying C:\Python27\lib\site-packages\py2exe\run.exe -> C:\Users\test\Desktop\test\dist\hello.exe
Adding python27.dll as resource to C:\Users\test\Desktop\test\dist\hello.exe

使用PyInstaller创建payload:

  1. 使用pip安装PyInstaller(pip install pyinstaller)。

  2. 然后,我们将发出命令“pyinstaller –onefile hello.py”(提醒一下,‘hello.py’是我们的payload)。这将把所有内容捆绑到一个可执行文件中。

C:\Users\test\Desktop\test>pyinstaller --onefile hello.py
108 INFO: PyInstaller: 3.3.1
108 INFO: Python: 2.7.14
108 INFO: Platform: Windows-10-10.0.16299
………………………………
5967 INFO: checking EXE
5967 INFO: Building EXE because out00-EXE.toc is non existent
5982 INFO: Building EXE from out00-EXE.toc
5982 INFO: Appending archive to EXE C:\Users\test\Desktop\test\dist\hello.exe
6325 INFO: Building EXE from out00-EXE.toc completed successfully.

参考资料

漏洞赏金提示注册Intigriti,这是一家由黑客创建的高级漏洞赏金平台!立即加入我们,访问https://go.intigriti.com/hacktricks,开始赚取高达**$100,000**的赏金!

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)

支持HackTricks的其他方式:

最后更新于