python反编译

出题

https://www.nssctf.cn/problem/2038

参考链接:https://www.nssctf.cn/note/set/1517

背景

pyc⽂件格式

magic number + 源代码⽂件信息 + PyCodeObject

4 个字节的 magic number

12 个字节的源代码⽂件信息(不同版本的 Python 包含的⻓度和信息都不⼀样)

序列化之后的 PyCodeObject

1715258388561-53814a84-a349-4923-ba8f-e226a50378d3.png

Python 是⼀种解释型语⾔,它不像编译型语⾔那样将源代码直接编译成机器码执⾏。Python 的解释器

会在运⾏代码之前先将源代码编译成字节码,然后将字节码解释执⾏。pyc ⽂件就是这个过程中⽣成的

字节码⽂件。

当 Python 解释器⾸次执⾏⼀个 .py ⽂件时,它会在同⼀⽬录下⽣成⼀个对应的 pyc ⽂件,以便于下次

加载该⽂件时可以更快地执⾏。如果源⽂件在修改之后被重新加载,解释器会重新⽣成pyc ⽂件以更新

缓存的字节码

⼀般需要反编译的附件查壳都会有如下红⾊标志

1715258505023-1668a2fb-5c28-42d4-8e8e-4471fb6c7079.png

工具

本地

uncompyle6 现仅适⽤于 Python 2.4 到 3.8 版本,3.8 及以上版本使⽤ pycdc ,3.8左右版本两者都可

以试试

uncompyle6安装要python版本对应(不能太⾼),我⽤anaconda创建虚拟环境

uncompyle: uncompyle6

⽂件名.pyc > ⽂件名.py

pycdc: ./pycdc.exe ⽂件名

https://github.com/extremecoders-re/decompyle-builds/releases/tag/build-14-Nov-2023-

5936412

下载地址如上

在线

贴两个⽐较好⽤的在线⽹站

https://www.toolkk.com/tools/pyc-decomplie#google_vignette

https://tool.lu/pyc

目标

1.exe⽂件变成pyc⽂件

⾸先,先将 pyinstxtractor.py ⼯具与我们要反编译的 .exe ⽂件放⼊同⼀个⼯作⽬录下:

在上述⽬录打开终端: python pyinstxtractor.py ⽂件名.exe

有些附件不清楚格式可以到kali下file命令查看或者⽤IDA打开发现如下字样,也暗示要反编译

1715258624795-2086050d-a431-413e-8f1c-1b97eab74e67.png

说明版本是python3.7的

1715258642956-9f079c6b-76d4-4507-a9fe-2a9e47eae62a.png

运⾏完成后,在此⽂件夹下我们会发现多了⼀个 ⽂件名.exe_extracted 的⽂件夹

1715258655829-7d5b192e-bef9-4686-8e66-0894531f5c4c.png

⽬录⾥有两个没有后缀的⽂件,这就是反编译的重点

总体上还是找那些没有后缀的⽂件

为src⽂件添加.pyc的后缀,并⽤winhex打开src和struct⽂件

1715258675431-342e6ef3-b699-4772-8655-1558dd19811e.png

注意,直接将src添加.pyc后缀后所编译的py⽂件是缺少Magic Number的,所以我们要⽤struct⽂件的

⽂件头来修复src⽂件的⽂件头

由于src⽂件直接是以E3开头的,所以我们这⾥直接将struct⽂件E3前⾯的11字节复制到src⽂件的⽂件头

就可以了;如果不是直接以E3开头,就⽐较两个⽂件E3前⾯的字节,将src⽂件E3前⾯的字节改为struct

⽂件E3前⾯的字节即可(这⾥只是针对这道题,其他题⽂件头通常都不⼀样)

2.pyc⽂件变成py⽂件

开启虚拟环境: uncompyle6 ⽂件名.pyc > ⽂件名.py

前提python版本要⼀样

magic修复

适合已知python版本的题⽬

放到winhex⾥可以发现E3前⾯全是0,正常的pyc⽂件E3前⾯包含Magic Number和时间戳

1.Python3.3以下的版本中,只有Magic Number和四位时间戳

2.Python3.3到Python3.7(不包含3.7)版本中,只有Magic Number和⼋位时间戳 + ⼤⼩信息

3.Python3.7及以上版本的编译后⼆进制⽂件中,头部除了四字节Magic Number,还有四个字节的空位

和⼋个字节的时间戳 + ⼤⼩信息,时间戳填充0即可

1715259152965-d1e2718e-9293-4e9f-ba36-c39dca615380.png

pyc版本号参考

补全的时候是⼩端序,记得颠倒过来,只改前四个字节就可以,⽐如3.7版本先42再0A

这⾥抄⼀下⽹上的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
enum PycMagic {
MAGIC_1_0 = 0x00999902,
MAGIC_1_1 = 0x00999903, /* Also covers 1.2 */
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_10 = 0x0A0D0D6F,
MAGIC_3_11 = 0x0A0D0DA7
}

可以看已有版本的magic number

1715259278773-3ff92c0e-1239-4d85-a7eb-098a2fd71a44.png

import importlib

importlib.util.MAGIC_NUMBER.hex()

出题

⽣成pyc: python -m ⽂件名

即使有报错也能⽣成

1715259329466-ce0288d1-ef6f-4566-9dca-5a8e01d332b3.png

如果是另外python版本可以⽤下⾯这种

1715259353666-2218578a-8ca7-40eb-86ee-452d8e5c359a.png

⽣成exe: pyinstaller -F tmp.py

1715259365833-f9bb93a6-7f58-40de-9858-4df0b40dc823.png

更新: 2024-05-09 20:56:20
原文: https://www.yuque.com/chaye-apqbl/vsc85q/svmmqlvdm0b8tzyu


http://example.com/2026/01/19/RE/各种语言/python反编译/index/
Author
chaye
Posted on
January 19, 2026
Licensed under