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

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (Ειδικός Ερευνητής Ερυθρής Ομάδας AWS του HackTricks)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Συμβουλή για bug bounty: Εγγραφείτε στο Intigriti, μια προηγμένη πλατφόρμα bug bounty δημιουργημένη από χάκερς, για χάκερς! Γίνετε μέλος στο 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, μπορείτε να λάβετε το αρχείο .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 τα ακόλουθα bytes: 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'> μπορεί να εμφανιστούν.

Αυτό πιθανότατα σημαίνει ότι δεν έχετε προσθέσει σωστά τον μαγικό αριθμό ή ότι δεν έχετε χρησιμοποιήσει τον σωστό μαγικό αριθμό, οπότε βεβαιωθείτε ότι χρησιμοποιείτε τον σωστό (ή δοκιμάστε έναν νέο).

Ελέγξτε την προηγούμενη τεκμηρίωση σφαλμάτων.

Αυτόματο Εργαλείο

Το εργαλείο python-exe-unpacker λειτουργεί ως συνδυασμός αρκετών εργαλείων που είναι διαθέσιμα στην κοινότητα και σχεδιάστηκαν για να βοηθήσουν τους ερευνητές στην αποσυμπίεση και αποσυναρμολόγηση εκτελέσιμων που έχουν γραφτεί σε Python, ειδικά αυτών που δημιουργήθηκαν με τα py2exe και pyinstaller. Περιλαμβάνει κανόνες YARA για την αναγνώριση εάν ένα εκτελέσιμο βασίζεται σε Python και επιβεβαιώνει το εργαλείο δημιουργίας.

ImportError: Όνομα αρχείου: 'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc' δεν υπάρχει

Ένα συνηθισμένο πρόβλημα που συναντάται εμπλέκει ένα ατελές αρχείο bytecode Python που προκύπτει από τη διαδικασία αποσυμπίεσης με το unpy2exe ή το pyinstxtractor, το οποίο στη συνέχεια αποτυγχάνει να αναγνωριστεί από το uncompyle6 λόγω απουσιάζουσας αριθμησης έκδοσης bytecode Python. Για να αντιμετωπιστεί αυτό, προστέθηκε μια επιλογή προσάρτησης, η οποία προσθέτει τον απαραίτητο αριθμό έκδοσης bytecode 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 είναι από Python 2, χρησιμοποιήστε την Python 2:

>>> 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 σε εκτελέσιμο

Για να ξεκινήσουμε, θα σας δείξουμε πώς μπορούν τα φορτία να μεταγλωττιστούν σε py2exe και PyInstaller.

Για να δημιουργήσετε ένα φορτίο χρησιμοποιώντας το py2exe:

  1. Εγκαταστήστε το πακέτο py2exe από http://www.py2exe.org/

  2. Για το φορτίο (σε αυτήν την περίπτωση, θα το ονομάσουμε hello.py), χρησιμοποιήστε ένα σενάριο όπως αυτό στο Σχήμα 1. Η επιλογή "bundle_files" με την τιμή 1 θα συγκεντρώσει τα πάντα, συμπεριλαμβανομένου του διερμηνέα Python, σε ένα εκτελέσιμο αρχείο.

  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

Για να δημιουργήσετε ένα 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.

Αναφορές

Συμβουλή για bug bounty: Εγγραφείτε στο Intigriti, μια προηγμένη πλατφόρμα bug bounty δημιουργημένη από χάκερς, για χάκερς! Γίνετε μέλος στο https://go.intigriti.com/hacktricks σήμερα και αρχίστε να κερδίζετε αμοιβές έως και $100,000!

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Last updated