pyinstxtractor 解包 exe 文件

1
python pyinstxtractor.py pyexe.exe

pyc 文件反编译

pyc 文件格式

可以通过 010Editor 打开 pyc 文件查看,pyc 文件的格式为:

  • 4 个字节的 magic number (小端形式)
  • 12个字节的源代码文件信息(不同版本的 Python 包含的长度和信息都不一样)
  • 序列化之后的 PyCodeObject

Magic Number

pyc 文件头有一个 Magic Number,不同版本的 Python 生成的 pyc 文件的 magic number 都不相同,具体的可以见下表

pyc 文件的前两个字节以小端的形式写入,然后加上 \r\n(0D 0A) 形成了四个字节的 pyc 文件的 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
MAGIC_1_0 = 0x00999902
MAGIC_1_1 = 0x00999903
MAGIC_1_2 = 0x00999903
MAGIC_1_3 = 0x0A0D2E89
MAGIC_1_4 = 0x0A0D1704
MAGIC_1_5 = 0x0A0D4E99
MAGIC_1_6 = 0x0A0DC4FC

MAGIC_2_0 = 0x0A0DC687
MAGIC_2_1 = 0x0A0DEB2A
MAGIC_2_2 = 0x0A0DED2D
MAGIC_2_3 = 0x0A0DF23B
MAGIC_2_4 = 0x0A0DF26D
MAGIC_2_5 = 0x0A0DF2B3
MAGIC_2_6 = 0x0A0DF2D1
MAGIC_2_7 = 0x0A0DF303

MAGIC_3_0 = 0x0A0D0C3A
MAGIC_3_1 = 0x0A0D0C4E
MAGIC_3_2 = 0x0A0D0C6C
MAGIC_3_3 = 0x0A0D0C9E
MAGIC_3_4 = 0x0A0D0CEE
MAGIC_3_5 = 0x0A0D0D16
MAGIC_3_5_3 = 0x0A0D0D17
MAGIC_3_6 = 0x0A0D0D33
MAGIC_3_7 = 0x0A0D0D42
MAGIC_3_8 = 0x0A0D0D55
MAGIC_3_9 = 0x0A0D0D61
MAGIC_3_11 = 0x0A0D0DA7

在部分题目中,使用 pyinstaller 导出的 pyc 文件会将文件的 Magic Number 和时间戳信息抹去,反编译时工具会报错,于是需要手动添加 Magic Number 与时间戳,时间戳可以随便添加(全 0 也可以),但是每个版本 Python 编译的 pyc 文件 Magic Number 都不同,需要我们手动查找与填充

源代码文件信息

源代码文件信息在 Python 不同的版本之后差别较大

  • 在Python2的时候,这部分只有 4 个字节,为源代码文件的修改时间的 Unix timestamp(精确到秒)以小端法写入,如: (1586087865).to_bytes(4, 'little').hex() -> b9c7 895e

  • 在 Python 3.5 之前的版本已经找不到了

  • Python 3.5 和 3.6 相对于 Python 2,源代码文件信息这部分,在时间后面增加了4个字节的源代码文件的大小,单位字节,以小端法写入。如源码文件大小为 57 个字节,那么文件信息部分就写入 5700 0000。加上前面的修改时间,就是 b9c7 895e 5700 0000

  • 从 Python3.7 开始支持 hash-based pyc 文件,Python 不仅支持校验 timestrap 来判断文件是否修改过了,也支持校验 hash 值。Python 为了支持 hash 校验又使源代码文件信息这部分增加了4个字节,变为一共12个字节

    • hash 校验默认是不启用,不启用时前4个字节为 0000 0000,后 8 个字节为 3.6 和 3.7 版本一样的源码文件的修改时间和大小;当启用时前 4 个字节变为 0100 0000 或者 0300 0000,后 8 个字节为源码文件的 hash 值

反编译工具

  • uncompyle6
1
uncompyle6 input.pyc > output.py
  • pycdc

工具在编译好的 build 文件夹里

1
2
3
4
# 反编译为 py 文件
./pycdc xxx.pyc > output.py
# 反编译为 python 字节码
./pycdas xxx.pyc > output.txt

有时候,反编译失败的时候,需要得到 python 字节码,然后手动分析

  • 在线网站