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

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

Підтримка 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 exe binary, скомпільованому, ви можете отримати .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 повинен бути одним з типів (<class 'str'>, <class 'bytes'>, <class 'list'>, <class 'tuple'>); є тип <class 'NoneType'> можуть з'явитися.

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

Перевірте документацію попередніх помилок.

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

python-exe-unpacker tool служить комбінацією кількох доступних інструментів спільноти, призначених для допомоги дослідникам у розпаковуванні та декомпіляції виконуваних файлів, написаних на Python, зокрема тих, що створені за допомогою py2exe та pyinstaller. Він включає правила YARA для ідентифікації, чи є виконуваний файл на основі Python, і підтверджує інструмент створення.

ImportError: Ім'я файлу: 'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc' не існує

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

If you weren't able to extract the python "original" code following the previous steps, then you can try to extract the assembly (but it isn't very descriptive, so try to extract again the original code).In here I found a very simple code to disassemble the .pyc binary (good luck understanding the code flow). If the .pyc is from python2, use 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

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

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

  1. Встановіть пакет py2exe з http://www.py2exe.org/

  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:

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

Bug bounty tip: зареєструйтесь на Intigriti, преміум платформі для баг-баунті, створеній хакерами для хакерів! Приєднуйтесь до нас на https://go.intigriti.com/hacktricks сьогодні та почніть заробляти винагороди до $100,000!

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated