参考链接:
https://www.bilibili.com/video/BV1JL4y1p7Tt/?spm_id_from=333.999.0.0
https://bbs.kanxue.com/thread-282542.htm
https://blog.youkuaiyun.com/weixin_35967330/article/details/114390031?spm=1001.2014.3001.5501
https://0xd13a.github.io/ctfs/0ctf2017/py/
前言:
可以关注一下个人博客:https://www.cnblogs.com/N1ng
python作为Reverse中的高级语言题目,占比逐渐上升,于是想着专门写一篇关于python逆向的文章。
这里分为四部分:直接反编译,pyc字节码,exe解包和加花的pyc
觉得看不懂的可以点击下方链接查看水番正文师傅的视频。d=====( ̄▽ ̄*)b
https://www.bilibili.com/video/BV1JL4y1p7Tt/?spm_id_from=333.999.0.0
不同版本的python魔数头
Python 版本 | 十六进制文件头 |
---|---|
Python 2.7 | 03f30d0a00000000 |
Python 3.0 | 3b0c0d0a00000000 |
Python 3.1 | 4f0c0d0a00000000 |
Python 3.2 | 6c0c0d0a00000000 |
Python 3.3 | 9e0c0d0a0000000000000000 |
Python 3.4 | ee0c0d0a0000000000000000 |
Python 3.5 | 170d0d0a0000000000000000 |
Python 3.6 | 330d0d0a0000000000000000 |
Python 3.7 | 420d0d0a000000000000000000000000 |
Python 3.8 | 550d0d0a000000000000000000000000 |
Python 3.9 | 610d0d0a000000000000000000000000 |
Python 3.10 | 6f0d0d0a000000000000000000000000 |
Python 3.11 | a70d0d0a000000000000000000000000 |
接下来我们需要先了解一下PyCodeObject(Python代码的编译结果,PyCodeObject对象可以由虚拟机加载后直接运行,而pyc文件就是PyCodeObject对象在硬盘上的保存形式)
名称 | 大小 | 作用 |
---|---|---|
Magic | long | 魔数,区分python不同版本的字节码 |
Mtime | long | 修改时间 |
Type_code | byte | 表示PyCodeObject对象 |
co_argcount/co_nlocals/co_stacksize/co_flags | long | PyCodeObject结构体各个域 |
Type_string | byte | 字符串 |
co_code size | long | PyCodeObject的co_code |
co_code value | bytes | |
Type_list | byte | 列表 |
co_consts size | long | 列表元素个数 |
Type_int | byte | co_consts[0]是一个整型 |
co_consts[0] | long | |
Type_string | byte | co_consts[1]是一个字符串 |
co_consts[1] size | long | |
co_consts[1] value | bytes | |
Type_code | byte | co_consts[2]是PyCodeObject |
co_consts[2] |
也可以去直接看这篇文章:https://www.bilibili.com/video/BV1JL4y1p7Tt/?spm_id_from=333.999.0.0
直接反编译
一般使用uncompyle6或者Pycdc将pyc文件反编译成py文件
uncompyle6
下载:https://github.com/rocky/python-uncompyle6
命令:pip install uncompyle6
检测:uncompyle6 --version
注意:下载的uncompyle6的版本最好别高于所使用的python版本
使用命令:uncompyle6 -o output_file.py your_file.pyc(-o目标生成python文件名原pyc文件名)
pycdc
下载:https://github.com/extremecoders-re/decompyle-builds
使用命令:pycdc -o output_file.py your_file.pyc
在线的反编译网站:
https://tool.lu/pyc/
https://toolkk.com/tools/pyc-decomplie
https://www.lddgo.net/string/pyc-compile-decompile
pyc字节码
前言
-
pyc字节码有点类似于汇编语言
-
dis库:用于反汇编Python字节码,将python函数或代码对象的字节码指令序列转换成可读形式,显示每个字节码指令的操作码和操作数,以及相应行号和位置信息
dis.dis函数作用:接受python函数对象或者代码作为参数; -
marshal:Python 标准库中的一个模块,提供了对 Python 对象进行序列化(转换为字节流)和反序列化(从字节流恢复为对象)功能
-
不同python版本的pyc文件头:
python2的pyc文件前4个字节是固定的魔数(03 F3 0D 0A),紧接着后4个字节表示编译这个.pyc的解释器版本号
python3的pyc文件前4个字节是固定的魔数(33 0D 0D 0A),紧接着两个字节时间戳表示.py文件最后修改时间,紧接着后4个字节源文件大小,最后是源文件名的字符串,以null字节结尾
注意:Python3的pyc文件头部并非固定的 16 个字节,而是一个不确定的长度,至少是 12 个字节,加上源文件名字符串的长度
pyc转字节码
如何获取pyc字节码:
import dis,marshal
f=open("文件.pyc","rb").read()
code=marshal.loads(f[8:])
dis.dis(code)
不理解的可以对照官方文档搜索去还原字节码的含义,这里列举几个常见的:
名称 | 含义 |
---|---|
LOAD_CONST | 加载const 变量,比如数值,字符串等等, 一般用于传递给函数作为参数 |
LOAD_FAST | 一般用于加载局部变量的值,也就是读取值,用于计算或者函数调用传传等 |
STORE_FAST | 一般用于保存值到局部变量 |
CALL_FUNCTION | CALL_FUNCTION n,其中 n 表示函数调用时传递的参数数量表示在此处调用了一个函数,并且传递了n个参数 |
例题
[羊城杯 2020]Bytecode 4 0 LOAD_CONST 0 (3)
3 LOAD_CONST 1 (37)
6 LOAD_CONST 2 (72)
9 LOAD_CONST 3 (9)
12 LOAD_CONST 4 (6)
15 LOAD_CONST 5 (132)
18 BUILD_LIST 6
21 STORE_NAME 0 (en)
5 24 LOAD_CONST 6 (101)
27 LOAD_CONST 7 (96)
30 LOAD_CONST 8 (23)
33 LOAD_CONST 9 (68)
36 LOAD_CONST 10 (112)
39 LOAD_CONST 11 (42)
42 LOAD_CONST 12 (107)
45 LOAD_CONST 13 (62)
48 LOAD_CONST 7 (96)
51 LOAD_CONST 14 (53)
54 LOAD_CONST 15 (176)
57 LOAD_CONST 16 (179)
60 LOAD_CONST 17 (98)
63 LOAD_CONST 14 (53)
66 LOAD_CONST 18 (67)
69 LOAD_CONST 19 (29)
72 LOAD_CONST 20 (41)
75 LOAD_CONST 21 (120)
78 LOAD_CONST 22 (60)
81 LOAD_CONST 23 (106)
84 LOAD_CONST 24 (51)
87 LOAD_CONST 6 (101)
90 LOAD_CONST 25 (178)
93 LOAD_CONST 26 (189)
96 LOAD_CONST 6 (101)
99 LOAD_CONST 27 (48)
102 BUILD_LIST 26
105 STORE_NAME 1 (output)
7 108 LOAD_CONST 28 ('welcome to GWHT2020')
111 PRINT_ITEM
112 PRINT_NEWLINE
9 113 LOAD_NAME 2 (raw_input)
116 LOAD_CONST 29 ('please input your flag:')
119 CALL_FUNCTION 1
122 STORE_NAME 3 (flag)
10 125 LOAD_NAME 3 (flag)
128 STORE_NAME 4 (str)
12 131 LOAD_NAME