コンパイルされたPythonバイナリ(exe、elf)を逆コンパイルする - .pycから取得

Reading time: 11 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

コンパイルされたバイナリから.pycへ

ELFコンパイルバイナリから**.pycを取得**することができます:

bash
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 を取得できます:

bash
python pyinstxtractor.py executable.exe

.pycからPythonコードへ

.pycデータ("コンパイル済み" Python)については、元の Python コード抽出しようとすることから始めるべきです:

bash
uncompyle6 binary.pyc  > decompiled.py

必ずバイナリが拡張子".pyc"を持っていることを確認してください(そうでない場合、uncompyle6は機能しません)

uncompyle6を実行していると、以下のエラーが発生することがあります:

エラー: 不明なマジックナンバー 227

bash
/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マジックヘッダー**は次のようになります:

bash
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で作成されたものに対応しています。Pythonベースの実行可能ファイルを特定し、作成ツールを確認するためのYARAルールが含まれています。

ImportError: ファイル名: 'unpacked/malware_3.exe/pycache/archive.cpython-35.pyc' が存在しません

一般的な問題は、unpy2exeまたはpyinstxtractorを使用したアンパックプロセスの結果として不完全なPythonバイトコードファイルが発生し、その後Pythonバイトコードバージョン番号が欠落しているために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
python
# 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アセンブリの分析

前のステップに従ってpythonの「オリジナル」コードを抽出できなかった場合は、アセンブリ抽出してみてください(ただし、あまり説明的ではありませんので、再度オリジナルコードを抽出してみてください)。ここで、.pyc バイナリを逆アセンブルするための非常にシンプルなコードを見つけました(コードフローを理解するのは大変かもしれません)。.pyc がpython2の場合は、python2を使用してください:

bash
>>> 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を実行可能ファイルに変換する

まず、payloadがpy2exeとPyInstallerでどのようにコンパイルされるかを示します。

py2exeを使用してpayloadを作成するには:

  1. http://www.py2exe.org/ からpy2exeパッケージをインストールします。
  2. payload(この場合、hello.pyと名付けます)には、図1のようなスクリプトを使用します。オプション「bundle_files」の値を1に設定すると、Pythonインタプリタを含むすべてが1つのexeにバンドルされます。
  3. スクリプトが準備できたら、「python setup.py py2exe」というコマンドを発行します。これにより、図2のように実行可能ファイルが作成されます。
python
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,
)
bash
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. pipを使用してPyInstallerをインストールします(pip install pyinstaller)。
  2. その後、「pyinstaller –onefile hello.py」というコマンドを発行します(‘hello.py’は私たちのペイロードです)。これにより、すべてが1つの実行可能ファイルにバンドルされます。
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ハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする