pyinstaller打包的exe解包

将pyinstaller打包的exe解包:

  • 解非加密的exe
  • 解加密后的exe(打包的python版本要≤3.8)

一、解包依赖

uncompyle6不支持3.9,所以解包的对应的exe工程需要在3.8以下

二、解包

2.1 从exe文件提取二进制pyc文件

2.1.1、下载pyinstxtractor获取到py文件,win11终端中执行

1
py .\pyinstxtractor.py .\exe_file.exe

LOG:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(py_pack_env) PS H:\TestRepo\py_pack\unpack_test> py .\pyinstxtractor.py .\notion_dump_client_no_key.exe
[+] Processing .\notion_dump_client_no_key.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 309
[+] Length of package: 11041731 bytes
[+] Found 994 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_subprocess.pyc
[+] Possible entry point: pyi_rth_pkgutil.pyc
[+] Possible entry point: pyi_rth_multiprocessing.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: pyi_rth__tkinter.pyc
[+] Possible entry point: notion_dump_client.pyc
[+] Found 395 files in PYZ archive
[+] Successfully extracted pyinstaller archive: .\notion_dump_client_no_key.exe

You can now use a python decompiler on the pyc files within the extracted directory
(py_pack_env) PS H:\TestRepo\py_pack\unpack_test>

2.1.2、如果是加密后的exe文件,输出会显示(类似的Extracting as is.)

1
2
3
4
5
6
7
8
9
[!] Error: Failed to decompress PYZ-00.pyz_extracted\xml\sax\expatreader.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\xml\sax\handler.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\xml\sax\saxutils.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\xml\sax\xmlreader.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\xmlrpc\__init__.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\xmlrpc\client.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\zipfile.pyc, probably encrypted. Extracting as is.
[!] Error: Failed to decompress PYZ-00.pyz_extracted\zipimport.pyc, probably encrypted. Extracting as is.
[+] Successfully extracted pyinstaller archive: .\notion_dump_client_key.exe
  • 先获取密码(密码文件时解密加密文件后其中的一个pyimod00_crypto_key.pyc文件(在主目录下))先对pyimod00_crypto_key.pyc进行反编译
1
2
3
4
5
6
7
8
9
(py_pack_env) PS H:\TestRepo\py_pack\unpack_test\notion_dump_client_key.exe_extracted> uncompyle6 pyimod00_crypto_key.pyc
# uncompyle6 version 3.8.0
# Python bytecode 3.7.0 (3394)
# Decompiled from: Python 3.7.8 (tags/v3.7.8:4b47a5b6ba, Jun 28 2020, 08:53:46) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: build\notion_dump_client\pyimod00_crypto_key.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 51 bytes
key = '0000000000123456'
# okay decompiling pyimod00_crypto_key.pyc

可以看出密码是0000000000123456

  • 用(三、解密文件)中的代码对pyinstxtractor解析出来的内容进行解密
    • 确认:代码中的pyc header(magic Number)部分
    • 确认:代码中的passwd(解密密码)
    • 确认:代码中的PYZ-00.pyz_extracted路径位置

假设解密代码文件,存为文件名为decode.py ,并且与exe同级目录,在改目录下执行

1
py .\decode.py

即可获取到所有的pyc文件

2.2 将pyc文件反编译成py文件

使用uncompyle6 将pyc文件反编译成py文件即可

1
uncompyle6 notion_dump_client.pyc > notion_dump_client.py

三、解密文件

解密文件所用代码:

  • 密码部分需要替换
  • pyc header的magic Number需要替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import glob
import zlib
import tinyaes
from pathlib import Path

CRYPT_BLOCK_SIZE = 16

# key obtained from pyimod00_crypto_key
key = bytes('passwd', 'utf-8')

for p in Path("PYZ-00.pyz_extracted").glob("**/*.pyc.encrypted"):
print(p.with_name(p.stem))
inf = open(p, 'rb') # encrypted file input
outf = open(p.with_name(p.stem), 'wb') # output file

# Initialization vector
iv = inf.read(CRYPT_BLOCK_SIZE)

cipher = tinyaes.AES(key, iv)

# Decrypt and decompress
plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read()))

# Write pyc header
# The header below is for Python 3.7
outf.write(b'\x42\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0')

# Write decrypted data
outf.write(plaintext)

inf.close()
outf.close()

# Delete .pyc.encrypted file
p.unlink()

魔数与python版本对照表

获取魔数:

1
2
import importlib
print(importlib.util.MAGIC_NUMBER.hex())

uncompyle6

版本 魔数
python 3.7 \x42\x0d\x0d\x0a