Декомпілювати скомпільовані python бінарники (exe, elf) - Retreive from .pyc

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

From Compiled Binary to .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 exe binary можна get the .pyc, запустивши:

python pyinstxtractor.py executable.exe

З .pyc до python code

Для даних .pyc (“скомпільований” python) слід почати з спроб витягти оригінальний python code:

uncompyle6 binary.pyc  > decompiled.py

Переконайтесь, що бінарний файл має розширення.pyc” (якщо ні, uncompyle6 не буде працювати)

Під час виконання uncompyle6 ви можете знайти наступні помилки:

Error: Unknown magic number 227

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

Щоб виправити це, потрібно додати правильний magic number на початку згенерованого файлу.

Magic numbers залежать від версії python, щоб отримати magic number для 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'> можуть з’явитися.

Це, ймовірно, означає, що ви неправильно додали магічний номер або що ви не використали правильний магічний номер, тож переконайтеся, що використовуєте правильний (або спробуйте інший).

Перегляньте попередню документацію щодо помилок.

Автоматичний інструмент

The python-exe-unpacker tool serves as a combination of several community-available tools designed to assist researchers in unpacking and decompiling executables written in Python, specifically those created with py2exe and pyinstaller. It includes YARA rules to identify if an executable is Python-based and confirms the creation tool.

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

Поширеною проблемою є неповний файл байткоду Python, який виникає внаслідок процесу розпаковки з unpy2exe або pyinstxtractor, через що він не розпізнається uncompyle6 через відсутній номер версії Python bytecode. Щоб вирішити це, додано опцію 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 assembly

Якщо вам не вдалося витягти python “original” код після виконання попередніх кроків, тоді ви можете спробувати extract assembly (але it isn’t very descriptive, тож try витягти again оригінальний код).In here я знайшов дуже простий код для disassemble .pyc бінарного файлу (удачі з розумінням потоку коду). Якщо .pyc з python2, використовуйте python2:

Disassemble a .pyc ```python >>> 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('>> timestamp = struct.unpack('>> code = marshal.loads(code) >>> magic, timestamp, code ((62211,), (1425911959,), at 0x7fd54f90d5b0, file "hello.py", line 1>) >>> >>> # Verify if the magic number corresponds with the current python version >>> struct.unpack('>> >>> # Disassemble the code object >>> dis.disassemble(code) 1 0 LOAD_CONST 0 () 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 ```

PyInstaller raw marshal і Pyarmor v9 — процес статичного розпакування

  • Extract embedded marshal blobs: pyi-archive_viewer sample.exe and export raw objects (e.g., a file named vvs). PyInstaller зберігає голі marshal-потоки, які починаються з 0xe3 (TYPE_CODE with FLAG_REF) замість повних .pyc файлів. Додайте на початок правильний 16-байтний заголовок .pyc (magic для вбудованої версії інтерпретатора + обнулений timestamp/size), щоб декомпілятори його прийняли. Для Python 3.11.5 можна отримати magic через imp.get_magic().hex() і запатчити його за допомогою dd/printf перед marshal-пейлоадом.
  • Decompile with version-aware tools: pycdc -c -v 3.11.5 vvs.pyc > vvs.py або PyLingual. Якщо потрібна лише частина коду, можна обходити AST (наприклад, ast.NodeVisitor) щоб витягти конкретні аргументи/константи.
  • Parse the Pyarmor v9 header щоб відновити криптографічні параметри: сигнатура PY<license> на 0x00, Python major/minor на 0x09/0x0a, тип захисту 0x09 коли увімкнений BCC (0x08 в іншому випадку), офсети початку/кінця ELF на 0x1c/0x38, і 12-байтовий AES-CTR nonce, розбитий по 0x24..0x27 та 0x2c..0x33. Така ж схема повторюється після вбудованого ELF.
  • Account for Pyarmor-modified code objects: у co_flags встановлений біт 0x20000000 і є додаткове поле з префіксною довжиною. Відключіть CPython deopt_code() під час парсингу, щоб уникнути збоїв дешифрування.
  • Identify encrypted code regions: байткод обгорнутий у LOAD_CONST __pyarmor_enter_*__LOAD_CONST __pyarmor_exit_*__. Розшифруйте вкладений бінарний блок за допомогою AES-128-CTR, використовуючи runtime-ключ (наприклад, 273b1b1373cf25e054a61e2cb8a947b8). Виведіть per-region nonce шляхом XOR між payload-специфічним 12-байтовим XOR-ключем (з Pyarmor runtime) і 12 байтами в маркері __pyarmor_exit_*__. Після дешифрування ви також можете побачити __pyarmor_assert_*__ (зашифровані рядки) та __pyarmor_bcc_*__ (скомпільовані dispatch-цілі).
  • Decrypt Pyarmor “mixed” strings: константи з префіксом 0x81 зашифровані AES-128-CTR (plaintext використовує 0x01). Використайте той самий ключ і runtime-обчислений string nonce (наприклад, 692e767673e95c45a1e6876d), щоб відновити довгі рядкові константи.
  • Handle BCC mode: Pyarmor --enable-bcc компілює багато функцій у супутній ELF і залишає Python-заглушки, які викликають __pyarmor_bcc_*__. Зіставте ці константи з ELF-символами за допомогою інструментів на кшталт bcc_info.py, потім декомпілюйте/аналізуйте ELF за вказаними офсетами (наприклад, __pyarmor_bcc_58580__bcc_180 на офсеті 0x4e70).

Python у виконуваний файл

Щоб почати, ми покажемо, як payloads можна скомпілювати в py2exe і PyInstaller.

Щоб створити payload за допомогою py2exe:

  1. Встановіть пакет py2exe з http://www.py2exe.org/
  2. Для payload (в цьому випадку ми назвемо його hello.py) використайте скрипт на кшталт того, що в Figure 1. Опція “bundle_files” зі значенням 1 упакує все, включно з Python interpreter, в один exe.
  3. Коли скрипт готовий, виконайте команду “python setup.py py2exe”. Це створить виконуваний файл, як показано в Figure 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

Щоб створити payload за допомогою PyInstaller:

  1. Встановіть PyInstaller за допомогою pip (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.

Посилання

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks