CTF中常见的四种python逆向
说在前面:什么是pyc文件?
pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件酿成pyc文件后,加载的速度有所进步,pyc 文件是 Python 编译过的字节码文件。它是 Python 程序在运行过程中由源代码(通常是 .py 文件)自动或手动编译产生的二进制文件。
而且pyc是一种跨平台的字节码,是由的虚拟机来执行的,这个是类似于或者.NET的虚拟机的概念。pyc的内容,是跟python的版本相关的,不同版本编译后的pyc文件是不同的,2.5编译的pyc文件,2.4版本的python是无法执行的。
为什么需要pyc文件?
因为py文件是可以直接看到源码的,假如你是开发商业软件的话,不可能把源码也泄漏出去吧?所以就需要编译为pyc后,再发布出去。当然,pyc文件也是可以反编译的,不同版本编译后的pyc文件是不同的,根据python源码中提供的opcode,可以根据pyc文件反编译出py文件源码,网上可以找到一个反编译python2.3版本的pyc文件的工具,不过该工具从python2.4开始就要收费了,假如需要反编译出新版本的pyc文件的话,就需要自己动手了,不过你可以自己修改python的源代码中的opcode文件,重新编译python,从而防止不法分子的破解。
pyc文件
解法:uncompyle6直接反编译
eg.
def check():
flag=1+1
if(flag==2):
return "right"
return "error"
print(check())这是我们所写的一个简单的python例子
现在我们来生成pyc文件 这里用的是python3
pyhton -m test.pyhttps://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550766.png
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550755.png
pyc文件也是可以运行的
我们在对应的文件夹的搜索框下输入powershell
然后输入
python .\test.pychttps://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550980.png
可以看到即使是运行py文件也是可以运行的
但区别的是我们没法看到pyc文件里面是什么东西,即使拖进IDA里面也无济于事
所以这里我们需要下载一个工具
uncompyle6.exe
在终端打开并输入
pip install uncompyle安装后包罗uncompyle6 但是版本为3.8.0 会导致一些软件的反编译失败发起利用下面命令回到3.7.4版本
pip install uncompyle6==3.7.4安装以后,我们回到我们的tmp目录并打开powershell输入
uncompyle6.exe .\test.pyhttps://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550109.png
这里我们就得到了源码
接下来的操纵就跟windows逆向别无二致了
【----帮助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
① 网安学习成长路径头脑导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技能电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战本领手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
txt里面是pyc字节码
解法:
[*]读py字节码
[*]根据opcode文件查询意思
我们先来得到我们test.py例子的字节码
在powershell下先输入python 然后输入
import dis,marshal
f=open("test.pyc", "rb").read()
fdis和marshal库 一个是装载库 一个是反编译字节码的库
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550579.png
我们可以将我们的test.pyc导入010Editor中共同着一起看
python2的前八个字节是python2的魔术字
python3的前十六个字节是python3的魔术字
所以我们可以不用读前十六位 我们只需要读后十六位的东西
code=marshal.loads(f)
code现在我们读进来的是二进制数据,我们可以用dis来进行反编译 就会得到python的字节码 可以明白成python的汇编读出来了
dis.dis(code)https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550873.png
这就是python的汇编
我们这里是直接将pyc文件uncompyle6回去的,但是在CTF中一般都是把python的汇编直接复制粘贴出来丢给我们...
所以我们只能硬看...或者共同点东西 比如python的opcode一起看
增补一点:python2是3个字节为1个指令 python3是2个字节为1个指令
比如test.pyc中LOAD_CONST 指令就占用了0,1两个字节
所以下条指令就从3开始了
1 0 LOAD_CONST 0 ()
2 LOAD_CONST 1 ('keyinit')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (keyinit)
8 8 LOAD_NAME 1 (__name__)
10 LOAD_CONST 2 ('__main__')
12 COMPARE_OP 2 (==)
14 POP_JUMP_IF_FALSE 250
9 16 LOAD_NAME 2 (print)
18 LOAD_CONST 3 ('Can you crack pyc?')
20 CALL_FUNCTION 1
22 POP_TOP
10 24 LOAD_NAME 3 (input)
26 LOAD_CONST 4 ('Plz give me your flag:')
28 CALL_FUNCTION 1
30 STORE_NAME 4 (str) #将输入的字符存入str内
11 32 LOAD_CONST 5 (108)
34 LOAD_CONST 6 (17)
36 LOAD_CONST 7 (42)
38 LOAD_CONST 8 (226)
40 LOAD_CONST 9 (158)
42 LOAD_CONST 10 (180)
44 LOAD_CONST 11 (96)
46 LOAD_CONST 12 (115)
48 LOAD_CONST 13 (64)
50 LOAD_CONST 14 (24)
52 LOAD_CONST 15 (38)
54 LOAD_CONST 16 (236)
56 LOAD_CONST 17 (179)
58 LOAD_CONST 18 (173)
60 LOAD_CONST 19 (34)
62 LOAD_CONST 20 (22)
64 LOAD_CONST 21 (81)
66 LOAD_CONST 22 (113)
68 LOAD_CONST 15 (38)
70 LOAD_CONST 23 (215)
72 LOAD_CONST 24 (165)
74 LOAD_CONST 25 (135)
76 LOAD_CONST 26 (68)
78 LOAD_CONST 27 (7)
12 80 LOAD_CONST 28 (119)
82 LOAD_CONST 29 (97)
84 LOAD_CONST 30 (45)
86 LOAD_CONST 31 (254)
88 LOAD_CONST 32 (250)
90 LOAD_CONST 33 (172)
92 LOAD_CONST 34 (43)
94 LOAD_CONST 35 (62)
96 BUILD_LIST 32 #建立容量为32的列表
98 STORE_NAME 5 (text) #以上32个数据为text数组的数值
13 100 LOAD_NAME 6 (len)
102 LOAD_NAME 4 (str)
104 CALL_FUNCTION 1
106 LOAD_CONST 36 (32)
108 COMPARE_OP 3 (!=)
110 POP_JUMP_IF_TRUE 140 #判断str即输入字符串的长度是否为32,不是则跳转到140
112 LOAD_NAME 4 (str)
114 LOAD_CONST 37 (0)
116 LOAD_CONST 27 (7)
118 BUILD_SLICE 2
120 BINARY_SUBSCR
122 LOAD_CONST 38 ('DASCTF{')
124 COMPARE_OP 3 (!=)
126 POP_JUMP_IF_TRUE 140 #判断str字符串的前七位是否为'DASCTF{',不是则跳转到140
128 LOAD_NAME 4 (str)
130 LOAD_CONST 39 (31)
132 BINARY_SUBSCR
134 LOAD_CONST 40 ('}')
136 COMPARE_OP 3 (!=)
138 POP_JUMP_IF_FALSE 154 #判断str字符串的最后一位也就是31位是否为'}',不是则跳转到154
#因为如果不跳转继续执行的话就会执行到输入字符串符合的一段代码使程序 #退出
14 >> 140 LOAD_NAME 2 (print)
142 LOAD_CONST 41 ('Bye bye~~')
144 CALL_FUNCTION 1
146 POP_TOP
15 148 LOAD_NAME 7 (exit)
150 CALL_FUNCTION 0
152 POP_TOP #退出程序
16 >> 154 LOAD_NAME 8 (list)
156 LOAD_NAME 4 (str)
158 CALL_FUNCTION 1
160 STORE_NAME 9 (st) #创建列表st
17 162 BUILD_LIST 0
164 STORE_NAME 10 (key)
18 166 LOAD_NAME 0 (keyinit)
168 LOAD_NAME 10 (key)
170 CALL_FUNCTION 1
172 POP_TOP
19 174 SETUP_LOOP 48 (to 224)
176 LOAD_NAME 11 (range)
178 LOAD_CONST 36 (32)
180 CALL_FUNCTION 1
182 GET_ITER
>> 184 FOR_ITER 36 (to 222)
186 STORE_NAME 12 (i) #相当于for i in range(0,32)
20 188 LOAD_NAME 13 (ord)
190 LOAD_NAME 4 (str)
192 LOAD_NAME 12 (i)
194 BINARY_SUBSCR
196 CALL_FUNCTION 1
198 LOAD_NAME 10 (key)
200 LOAD_NAME 12 (i)
202 LOAD_NAME 6 (len)
204 LOAD_NAME 10 (key)
206 CALL_FUNCTION 1
208 BINARY_MODULO #key元素少于str元素,所以要把i和key的长度取余避免越界
210 BINARY_SUBSCR
212 BINARY_XOR
214 LOAD_NAME 9 (st)
216 LOAD_NAME 12 (i)
218 STORE_SUBSCR #此处代码将str和key中的元素进行异或处理后存入st
220 JUMP_ABSOLUTE 184 #相当于st = ord(str) ^ key
>> 222 POP_BLOCK
21 >> 224 LOAD_NAME 9 (st)
226 LOAD_NAME 5 (text)
228 COMPARE_OP 2 (==)
230 POP_JUMP_IF_FALSE 242 #对比st数组和text数组,不相等则跳转到地址242处
22 232 LOAD_NAME 2 (print)
234 LOAD_CONST 42 ('Congratulations and you are good at PYC!')
236 CALL_FUNCTION 1
238 POP_TOP
240 JUMP_FORWARD 8 (to 250)
24 >> 242 LOAD_NAME 2 (print)
244 LOAD_CONST 43 ('Sorry,plz learn more about pyc.')
246 CALL_FUNCTION 1
248 POP_TOP
>> 250 LOAD_CONST 44 (None)
252 RETURN_VALUE
Disassembly of :
2 0 LOAD_CONST 1 (0)
2 STORE_FAST 1 (num)
3 4 SETUP_LOOP 42 (to 48)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 2 (8)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 30 (to 46)
16 STORE_FAST 2 (i) #相当于for i in range(0,8)
#从这里我们可以知道key的长度为8
4 18 LOAD_FAST 1 (num)
20 LOAD_CONST 3 (7508399208111569251)
22 BINARY_SUBTRACT
24 LOAD_CONST 4 (4294967295)
26 BINARY_MODULO
28 STORE_FAST 1 (num)
5 30 LOAD_FAST 0 (key)
32 LOAD_METHOD 1 (append)
34 LOAD_FAST 1 (num)
36 LOAD_CONST 5 (24)
38 BINARY_RSHIFT #不理解这一句的意思
40 CALL_METHOD 1 #但这一段代码就是给key赋值
42 POP_TOP
44 JUMP_ABSOLUTE 14
>> 46 POP_BLOCK
>> 48 LOAD_CONST 0 (None)
50 RETURN_VALUE这段代码的总体意思就是将输入的str字符串与key数组进行异或加密后存入st数组并于text数组进行对比我们可以从代码中得之text数组的元素值也可以知道str的前七位必为’DASCTF{’,末了一位必为’}’,而key数组只有8位,所以对str的加密是8位8位的进行的又因为异或具有自反性,所以可以据’DASCTF{‘字符串与text前7个元素做异或处理得出前7位,再将’}'与text末了一位进行异或 处理得出第8位,就可以得到key的整个数组
这段汇编最关键的部门如下
Disassembly of :
2 0 LOAD_CONST 1 (0)
2 STORE_FAST 1 (num)
3 4 SETUP_LOOP 42 (to 48)
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 2 (8)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 30 (to 46)
16 STORE_FAST 2 (i) #相当于for i in range(0,8)
#从这里我们可以知道key的长度为8
4 18 LOAD_FAST 1 (num)
20 LOAD_CONST 3 (7508399208111569251)
22 BINARY_SUBTRACT
24 LOAD_CONST 4 (4294967295)
26 BINARY_MODULO
28 STORE_FAST 1 (num)
5 30 LOAD_FAST 0 (key)
32 LOAD_METHOD 1 (append)
34 LOAD_FAST 1 (num)
36 LOAD_CONST 5 (24)
38 BINARY_RSHIFT #不理解这一句的意思
40 CALL_METHOD 1 #但这一段代码就是给key赋值
42 POP_TOP
44 JUMP_ABSOLUTE 14
>> 46 POP_BLOCK
>> 48 LOAD_CONST 0 (None)
50 RETURN_VALUE首先就是一个num的初始化 因为LOAD_CONST推送到堆栈
然后STORE_FAST将TOS(python的栈)存储到当地中
这两条结合起来 其实意思就是
num=0接下来 SETUP_LOOP(delta)
将一个循环的块推送到块堆栈。该块超过当前指令,巨细为delta字节。
LOAD_GLOBAL 定义一个全局变量 range LOAD_CONST定义一个常量 8
共同着utools里面程序员手册里面的Python库硬看
for i in range(8):然后关键的这一步
首先LOAD_FAST 将num压入栈堆,然后又把一个常量(7508399208111569251)推送到堆栈中
然后又执行BINARY_SUBTRACT 也就是减操纵 即栈的后一位减去栈顶,对应到代码中也就是num减去这个常量
然后又推了个值4294967295 然后进行BINARY_MODULO操纵 这是栈顶后一位取余栈顶的值
末了STORE_FAST 存储到num这个变量
所以这关键的一步python代码应该是
num=(num-7508399208111569251)%4294967295后面干的操纵大体就是 LOAD_FAST num 然后LOAD_CONST 24 然后BINARY_RSHIFT 主要是就是栈顶后一位右移栈顶数据的值 然后存储到key里面 大概就是这么个意思
print(num>>24)结合起来就是这样的
num=0
for i in range(8):
num=(num-7508399208111569251)%4294967295
print(num>>24)这样我们就得到这道题的密钥
40
80
121
161
202
242
27
67然后采用每八个字节都去异或一下这个密钥,flag就出来了
s=[108,17,42,226,158,180,96,115,64,24,38,236,179,173,34,22,81,113,38,215,165,135,68,7,119,97,
45,254,250,172,43,62]
key=[]
flag=''
num=0
for i in range(8):
num=(num-7508399208111569251)%4294967295
key.append(num>>24)
for i in range(32):
flag += chr(key ^ s)
print(flag)打包成exe的pyc文件
解法:
[*]通过脚本酿成布局体和一个文件
[*]重点:再把时间属性和版本的魔术字放回去保存
[*]uncompyle6即可
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550825.png
下载完题目发现这是个exe文件 但是图标又是很显着的pyc文件
所以这是个打包成exe的py文件
这里我们需要用到一个工具pyinstxtractor.py
把这个py文件复制到我们的题目文件夹里面
在搜索框中输入powershell 在打开的终端中输入
python .\pyinstxtractor.py .\attachment.exehttps://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550210.png
运行后生成attachment.exe_extracted文件夹,进入之后看到一些源文件,由于我电脑上的python是3.8版本,解包要3.6版本,所以生成了不正常的入口文件login而不是login.pyc,想要酿成正常的可反编译的pyc文件就要对生成文件进行修改。(假如不嫌麻烦可以换一下python3.6的情况)
现在开始修改login入口文件,这里用的是winhex。
修改之前需要了解一点,在将python文件打包成exe文件的过程中,会抹去pyc文件前面的部门信息,所以在反编译之前需要查抄并添加上这部门信息,这部门信息可以通过struct文件获取。
windex中打开struct文件后,把struct文件前几个字节插入login开头。(具体要插入几个字节还是要看解包后的文件,我的文件是E3字节码前面的丢失,那么就只需要看struct中E3之前的字节码有哪些,ctrl + c复制,然后在login开头ctrl + v 粘贴即可。)
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550850.png
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550281.png
修改后如下
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550790.png
保存后 将login后缀名修改为.pyc即可
将login.pyc复制粘贴到题目的文件夹后打开powershell终端
并且调用uncompyle6.exe
uncompyle6.exe .\login.pyc就可以看到源码了
https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202404181550072.png
import sysinput1 = input('input something:')if len(input1) != 14: print('Wrong length!') sys.exit()else: code = [] for i in range(13): code.append(ord(input1) ^ ord(input1[(i + 1)])) code.append(ord(input1)) a1 = code a2 = code a3 = code a4 = code a5 = code a6 = code a7 = code a8 = code a9 = code a10 = code a11 = code a12 = code a13 = code a14 = code if (a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748) & (a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25 + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66 + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39 + a14 * 17 == 7258) & (a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65 + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33 + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34 + a14 * 23 == 26190) & (a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59 + a5 * 49 + a6 * 81 + a7 * 25 + (a8 ></strong></p>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]