PyInstallerでコンパイルされたファイルを解析する際のメモ。
以下はコマンドのメモ。
ファイルがPyInstallerでコンパイルされたかの確認。
strings sample.bin | grep -i pyinstaller
strings sample.bin | grep "\.pyd"
PyInstaller Extractorでpycファイルを抽出。
python pyinstxtractor.py sample.bin
Uncompyle6でpycファイルをデコンパイル。
uncompyle6 code.pyc
デコンパイル結果をファイルにリダイレクトしたい場合は
uncompyle6 code.pyc > code.py
テスト・プログラムを用いて上記を実践してみた。
テスト・プログラムの作成
以下のPythonスクリプトを用意した。
def print_num():
for i in range(1, 10):
print(i)
print_num()
上記のPythonスクリプトをPyInstallerを用いてEXEファイルに変換した。
pyinstaller test.py --onefile
dist
ディレクトリ以下にEXEファイル化されたtest.exe
が作成された。
ちゃんと実行された。
C:\Users\REM\Desktop\test\dist>test.exe
1
2
3
4
5
6
7
8
9
ちなみに作成されたEXEファイルをCFF ExplorerやDetect It Easyでサクッと眺めても、PyInstallerでコンパイルされたことはわからない。
fileコマンドでも単にEXEファイルとしか認識されない。
$ file test.exe
test.exe: PE32+ executable (console) x86-64, for MS Windows
PyInstallerの使用の痕跡を確認
stringsコマンドでPyInstallerが使用された痕跡を確認。
$ strings test.exe | grep -i pyinstaller
PyInstaller: FormatMessageW failed.
PyInstaller: pyi_win32_utils_to_utf8 failed.
$ strings test.exe | grep "\.pyd"
b_bz2.pyd
b_ctypes.pyd
b_hashlib.pyd
b_lzma.pyd
b_socket.pyd
b_ssl.pyd
bpyexpat.pyd
bselect.pyd
bunicodedata.pyd
pycファイルの抽出
PyInstaller Extractorでtest.exe
からpycファイルを抽出。
$ python /opt/remnux-scripts/pyinstxtractor.py test.exe
[+] Processing test.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.5
[+] Length of package: 5165992 bytes
[+] Found 60 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: test.pyc
[!] Warning: This script is running in a different Python version than the one used to build the executable.
[!] Please run this script in Python 3.5 to prevent extraction errors during unmarshalling
[!] Skipping pyz extraction
[+] Successfully extracted pyinstaller archive: test.exe
You can now use a python decompiler on the pyc files within the extracted directory
test.exe_extracted
ディレクトリにtest.pyc
が作成された。
$ ls
test.exe test.exe_extracted
$ cd test.exe_extracted/
$ ls | grep pyc
pyiboot01_bootstrap.pyc
pyimod01_os_path.pyc
pyimod02_archive.pyc
pyimod03_importers.pyc
struct.pyc
test.pyc
pycファイルをデコンパイル
pycファイルはバイナリファイルなので、この状態では解析には不向き。
$ file test.pyc
test.pyc: data
$ xxd test.pyc
0000000: 160d 0d0a 0000 0000 0000 0000 e300 0000 ................
0000010: 0000 0000 0000 0000 0002 0000 0040 0000 .............@..
0000020: 0073 1700 0000 6400 0064 0100 8400 005a .s....d..d.....Z
0000030: 0000 6500 0083 0000 0164 0200 5329 0363 ..e......d..S).c
0000040: 0000 0000 0000 0000 0100 0000 0300 0000 ................
0000050: 4300 0000 7328 0000 0078 2100 7400 0064 C...s(...x!.t..d
0000060: 0100 6402 0083 0200 445d 1000 7d00 0074 ..d.....D]..}..t
0000070: 0100 7c00 0083 0100 0171 1000 5764 0000 ..|......q..Wd..
0000080: 5329 034e e901 0000 00e9 0a00 0000 2902 S).N..........).
0000090: da05 7261 6e67 65da 0570 7269 6e74 2901 ..range..print).
00000a0: da01 69a9 0072 0600 0000 fa07 7465 7374 ..i..r......test
00000b0: 2e70 79da 0970 7269 6e74 5f6e 756d 0100 .py..print_num..
00000c0: 0000 7304 0000 0000 0116 0172 0800 0000 ..s........r....
00000d0: 4e29 0172 0800 0000 7206 0000 0072 0600 N).r....r....r..
00000e0: 0000 7206 0000 0072 0700 0000 da08 3c6d ..r....r......<m
00000f0: 6f64 756c 653e 0100 0000 7302 0000 000c odule>....s.....
0000100: 04
ので、Uncompyle6でpycファイルをデコンパイルする。
$ uncompyle6 test.pyc
# uncompyle6 version 3.9.0
# Python bytecode version base 3.5 (3350)
# Decompiled from: Python 2.7.6 (default, Jun 22 2015, 17:58:13)
# [GCC 4.8.2]
# Embedded file name: test.py
def print_num():
for i in range(1, 10):
print(i)
print_num()
# okay decompiling test.pyc
ちゃんとPythonスクリプトのソースコードが現れた。