CTF中常见的四种python逆向

说在前面:

什么是pyc文件?

pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件变成pyc文件后,加载的速度有所提高,

pyc 文件是 Python 编译过的字节码文件。它是 Python 程序在运行过程中由源代码(通常是 .py 文件)自动或手动编译产生的二进制文件。

而且pyc是一种跨平台的字节码,是由[Python]的虚拟机来执行的,这个是类似于[Java]或者.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.py

pyc文件也是可以运行的

我们在对应的文件夹的搜索框下输入powershell

然后输入

python .\test.pyc

image

可以看到即使是运行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.py

image test

这里我们就得到了源码

接下来的操作就跟windows逆向别无二致了

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 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()
f

dis和marshal库 一个是装载库 一个是反编译字节码的库

image test

我们可以将我们的test.pyc导入010Editor中配合着一起看

python2的前八个字节是python2的魔术字

python3的前十六个字节是python3的魔术字

所以我们可以不用读前十六位 我们只需要读后十六位的东西

code=marshal.loads(f[16:])
code

现在我们读进来的是二进制数据,我们可以用dis来进行反编译 就会得到python的字节码 可以理解成python的汇编读出来了

dis.dis(code)

image test

这就是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 (<code object keyinit at 0x0000028C1CC11D20, file "crackPYC.py", line 1>)
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
1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值