Декомпіляція скомпільованих python бінарників (exe, elf) - Отримання з .pyc
Reading time: 7 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Від скомпільованого бінарника до .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 бінарному файлі ви можете отримати .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'
Число magic number в цьому випадку для python3.8 - це 0x550d0d0a
, тоді, щоб виправити цю помилку, вам потрібно додати на початку .pyc файлу наступні байти: 0x0d550a0d000000000000000000000000
Якщо ви додали цей магічний заголовок, помилка повинна бути виправлена.
Ось як правильно доданий .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 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
Якщо вам не вдалося витягти "оригінальний" код python, дотримуючись попередніх кроків, ви можете спробувати витягти assembly (але це не дуже описово, тому спробуйте знову витягти оригінальний код). У цьому я знайшов дуже простий код для дизасемблювання двійкового файлу .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 в Executable
Для початку ми покажемо вам, як вантажі можуть бути скомпільовані в py2exe та PyInstaller.
Щоб створити вантаж за допомогою py2exe:
- Встановіть пакет py2exe з http://www.py2exe.org/
- Для вантажу (в цьому випадку ми назвемо його hello.py) використовуйте скрипт, подібний до того, що на Рисунку 1. Опція “bundle_files” зі значенням 1 об'єднає все, включаючи інтерпретатор 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
Щоб створити payload за допомогою PyInstaller:
- Встановіть PyInstaller за допомогою pip (pip install pyinstaller).
- Після цього ми виконаємо команду “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)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.