Decompilare i binari python compilati (exe, elf) - Recuperare da .pyc
Reading time: 7 minutes
tip
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos di github.
Da binario compilato a .pyc
Da un binario compilato ELF puoi ottenere il .pyc con:
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 un eseguibile binario python compilato puoi ottenere il .pyc eseguendo:
python pyinstxtractor.py executable.exe
Da .pyc a codice python
Per i dati .pyc ("compilato" python) dovresti iniziare a provare a estrarre il codice python originale:
uncompyle6 binary.pyc > decompiled.py
Assicurati che il file binario abbia l'estensione ".pyc" (in caso contrario, uncompyle6 non funzionerà)
Durante l'esecuzione di uncompyle6 potresti incontrare i seguenti errori:
Errore: Numero magico sconosciuto 227
/kali/.local/bin/uncompyle6 /tmp/binary.pyc
Unknown magic number 227 in /tmp/binary.pyc
Per risolvere questo problema è necessario aggiungere il numero magico corretto all'inizio del file generato.
I numeri magici variano con la versione di python, per ottenere il numero magico di python 3.8 è necessario aprire un terminale python 3.8 ed eseguire:
>> import imp
>> imp.get_magic().hex()
'550d0d0a'
Il numero magico in questo caso per python3.8 è 0x550d0d0a
, quindi, per risolvere questo errore dovrai aggiungere all'inizio del file .pyc i seguenti byte: 0x0d550a0d000000000000000000000000
Una volta che hai aggiunto quell'intestazione magica, l'errore dovrebbe essere risolto.
Ecco come apparirà un intestazione magica .pyc python3.8 correttamente aggiunta:
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
Errore: Decompilazione errori generici
Altri errori come: class 'AssertionError'>; co_code dovrebbe essere uno dei tipi (<class 'str'>, <class 'bytes'>, <class 'list'>, <class 'tuple'>); è di tipo <class 'NoneType'>
possono apparire.
Questo probabilmente significa che non hai aggiunto correttamente il numero magico o che non hai usato il numero magico corretto, quindi assicurati di usare quello corretto (o prova uno nuovo).
Controlla la documentazione degli errori precedenti.
Strumento Automatico
Il tool python-exe-unpacker funge da combinazione di diversi strumenti disponibili nella comunità progettati per assistere i ricercatori nello smontaggio e nella decompilazione di eseguibili scritti in Python, specificamente quelli creati con py2exe e pyinstaller. Include regole YARA per identificare se un eseguibile è basato su Python e conferma lo strumento di creazione.
ImportError: Nome file: 'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc' non esiste
Un problema comune riscontrato coinvolge un file di bytecode Python incompleto risultante dal processo di smontaggio con unpy2exe o pyinstxtractor, che poi non viene riconosciuto da uncompyle6 a causa di un numero di versione di bytecode Python mancante. Per affrontare questo, è stata aggiunta un'opzione di prepend, che aggiunge il numero di versione di bytecode Python necessario, facilitando il processo di decompilazione.
Esempio del problema:
# 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.
Analizzare l'assembly di python
Se non sei riuscito a estrarre il codice "originale" di python seguendo i passaggi precedenti, allora puoi provare a estrarre l'assembly (ma non è molto descrittivo, quindi prova a estrarre di nuovo il codice originale). In qui ho trovato un codice molto semplice per disassemblare il binario .pyc (buona fortuna a capire il flusso del codice). Se il .pyc è di python2, usa 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 in Eseguibile
Per iniziare, ti mostreremo come i payload possono essere compilati in py2exe e PyInstaller.
Per creare un payload utilizzando py2exe:
- Installa il pacchetto py2exe da http://www.py2exe.org/
- Per il payload (in questo caso, lo chiameremo hello.py), utilizza uno script come quello nella Figura 1. L'opzione “bundle_files” con il valore di 1 raggrupperà tutto, incluso l'interprete Python, in un unico exe.
- Una volta che lo script è pronto, emetteremo il comando “python setup.py py2exe”. Questo creerà l'eseguibile, proprio come nella Figura 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
Per creare un payload utilizzando PyInstaller:
- Installa PyInstaller usando pip (pip install pyinstaller).
- Dopo di che, emetteremo il comando “pyinstaller –onefile hello.py” (un promemoria che ‘hello.py’ è il nostro payload). Questo raggrupperà tutto in un unico eseguibile.
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.
Riferimenti
tip
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos di github.