컴파일된 파이썬 바이너리(decompiled python binaries) (exe, elf) - .pyc에서 가져오기
Reading time: 7 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
컴파일된 바이너리에서 .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
파이썬 exe 바이너리로 컴파일된 경우, 다음을 실행하여 .pyc를 얻을 수 있습니다:
python pyinstxtractor.py executable.exe
.pyc에서 파이썬 코드로
.pyc 데이터("컴파일된" 파이썬)에 대해 원본 파이썬 코드를 추출하려고 시도해야 합니다:
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'
이 경우 python3.8의 magic number는 **0x550d0d0a
**입니다. 그러므로 이 오류를 수정하려면 .pyc 파일의 시작 부분에 다음 바이트를 추가해야 합니다: 0x0d550a0d000000000000000000000000
한 번 그 magic header를 추가하면 오류가 수정되어야 합니다.
올바르게 추가된 .pyc python3.8 magic header는 다음과 같이 보일 것입니다:
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는 (<class 'str'>, <class 'bytes'>, <class 'list'>, <class 'tuple'>) 중 하나여야 합니다; 유형은 <class 'NoneType'>입니다
가 나타날 수 있습니다.
이는 아마도 마법 숫자를 올바르게 추가하지 않았거나 올바른 마법 숫자를 사용하지 않았기 때문일 수 있으므로 올바른 숫자를 사용하고 있는지 확인하세요 (또는 새로운 숫자를 시도해 보세요).
이전 오류 문서를 확인하세요.
자동 도구
python-exe-unpacker 도구는 연구자들이 py2exe 및 pyinstaller로 작성된 실행 파일을 언팩하고 디컴파일하는 데 도움을 주기 위해 설계된 여러 커뮤니티에서 제공하는 도구의 조합으로 작동합니다. 이 도구는 실행 파일이 Python 기반인지 식별하고 생성 도구를 확인하기 위한 YARA 규칙을 포함합니다.
ImportError: 파일 이름: 'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc'가 존재하지 않습니다
일반적으로 발생하는 문제는 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.
파이썬 어셈블리 분석
이전 단계를 따라 파이썬 "원본" 코드를 추출할 수 없었다면, 어셈블리를 추출해 볼 수 있습니다(하지만 매우 설명적이지 않으므로, 다시 원본 코드를 추출해 보세요). 여기에서 .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 생성하기:
- http://www.py2exe.org/에서 py2exe 패키지를 설치합니다.
- payload를 위해 (이 경우, 우리는 hello.py라고 이름을 지을 것입니다), 그림 1에 있는 것과 같은 스크립트를 사용합니다. 값이 1인 “bundle_files” 옵션은 Python 인터프리터를 포함하여 모든 것을 하나의 exe로 묶습니다.
- 스크립트가 준비되면, “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를 사용하여 페이로드 생성하기:
- pip를 사용하여 PyInstaller를 설치합니다 (pip install pyinstaller).
- 그 후, “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.
참고문헌
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.