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

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

In a python exe binary로 컴파일된 경우, 다음을 실행하여 .pyc를 얻을 수 있습니다:

python pyinstxtractor.py executable.exe

From .pyc to python code

For the .pyc data ("compiled" python) you should start trying to extract the original python code:

uncompyle6 binary.pyc  > decompiled.py

확실히 이 바이너리가 ".pyc" 확장자를 가지고 있는지 확인하세요 (그렇지 않으면, uncompyle6가 작동하지 않습니다)

uncompyle6를 실행하는 동안 다음 오류를 발견할 수 있습니다:

오류: 알 수 없는 매직 넘버 227

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

이 문제를 해결하려면 생성된 파일의 시작 부분에 올바른 매직 넘버추가해야 합니다.

매직 넘버는 파이썬 버전에 따라 다릅니다, 파이썬 3.8의 매직 넘버를 얻으려면 파이썬 3.8 터미널을 열고 다음을 실행해야 합니다:

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

The magic number in this case for python3.8 is 0x550d0d0a, then, to fix this error you will need to add at the beginning of the .pyc file the following bytes: 0x0d550a0d000000000000000000000000

한 번 당신이 추가한 그 매직 헤더는, 오류가 수정되어야 합니다.

This is how a correctly added .pyc python3.8 magic header will look like:

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

Error: Decompiling generic errors

다른 오류: class 'AssertionError'>; co_code는 (<class 'str'>, <class 'bytes'>, <class 'list'>, <class 'tuple'>) 중 하나여야 합니다; 타입은 <class 'NoneType'>입니다가 나타날 수 있습니다.

이는 아마도 매직 넘버를 올바르게 추가하지 않았거나 올바른 매직 넘버를 사용하지 않았기 때문일 수 있으므로 올바른 것을 사용하고 있는지 확인하세요 (또는 새로운 것을 시도해 보세요).

이전 오류 문서를 확인하세요.

Automatic Tool

python-exe-unpacker tool는 Python으로 작성된 실행 파일을 언팩하고 디컴파일하는 데 도움을 주기 위해 설계된 여러 커뮤니티에서 제공하는 도구의 조합으로 작동합니다. 특히 py2exe 및 pyinstaller로 생성된 파일에 해당합니다. 이 도구는 실행 파일이 Python 기반인지 식별하고 생성 도구를 확인하기 위한 YARA 규칙을 포함하고 있습니다.

ImportError: File name: 'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc' doesn't exist

일반적으로 발생하는 문제는 unpy2exe 또는 pyinstxtractor로 언팩하는 과정에서 발생한 불완전한 Python 바이트코드 파일로, 이로 인해 누락된 Python 바이트코드 버전 번호로 인해 uncompyle6에서 인식되지 않는 경우입니다. 이를 해결하기 위해 필요한 Python 바이트코드 버전 번호를 추가하는 prepend 옵션이 추가되어 디컴파일 과정을 용이하게 합니다.

문제의 예:

# 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.

Analyzing python assembly

이전 단계에 따라 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 to Executable

시작하기 위해, 우리는 payload가 py2exe와 PyInstaller에서 어떻게 컴파일될 수 있는지 보여줄 것입니다.

py2exe를 사용하여 payload 생성하기:

  1. http://www.py2exe.org/에서 py2exe 패키지를 설치합니다.

  2. payload를 위해 (이 경우, 우리는 hello.py라고 이름을 지을 것입니다), 그림 1에 있는 것과 같은 스크립트를 사용합니다. 값이 1인 “bundle_files” 옵션은 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

To create a payload using PyInstaller:

  1. pip을 사용하여 PyInstaller를 설치합니다 (pip install pyinstaller).

  2. 그 후, “pyinstaller –onefile hello.py” 명령을 실행합니다 (여기서 ‘hello.py’는 우리의 페이로드입니다). 이렇게 하면 모든 것이 하나의 실행 파일로 묶입니다.

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.

References

버그 바운티 팁: 해커를 위해 해커가 만든 프리미엄 버그 바운티 플랫폼인 Intigriti가입하세요! 오늘 https://go.intigriti.com/hacktricks에서 저희와 함께하고 최대 $100,000의 보상을 받기 시작하세요!

HackTricks 지원하기

Last updated