PyInstallerでコンパイルされたファイルを解析する際のメモ

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 Extractortest.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スクリプトのソースコードが現れた。

Leave a Reply

Your email address will not be published. Required fields are marked *