Python字节码逆向分析
ctf题目
名称:misc-easypy
内容:
In [1]: import dis
In [2]: dis.dis(encrypt)
4 0 LOAD_CONST 1 ('')
2 STORE_FAST 1 (O0O)
5 4 LOAD_FAST 0 (oO0)
6 LOAD_ATTR 0 (upper)
8 CALL_FUNCTION 0
10 STORE_FAST 2 (o0O)
6 12 LOAD_FAST 2 (o0O)
14 LOAD_CONST 0 (None)
16 LOAD_CONST 0 (None)
18 LOAD_CONST 3 (-1)
20 BUILD_SLICE 3
22 BINARY_SUBSCR
24 STORE_FAST 2 (o0O)
7 26 SETUP_LOOP 60 (to 88)
28 LOAD_GLOBAL 1 (range)
30 LOAD_GLOBAL 2 (len)
32 LOAD_FAST 2 (o0O)
34 CALL_FUNCTION 1
36 CALL_FUNCTION 1
38 GET_ITER
>> 40 FOR_ITER 44 (to 86)
42 STORE_FAST 3 (O0)
8 44 LOAD_GLOBAL 3 (ord)
46 LOAD_FAST 2 (o0O)
48 LOAD_FAST 3 (O0)
50 BINARY_SUBSCR
52 CALL_FUNCTION 1
54 LOAD_FAST 3 (O0)
56 BINARY_ADD
58 LOAD_GLOBAL 2 (len)
60 LOAD_FAST 2 (o0O)
62 CALL_FUNCTION 1
64 LOAD_FAST 3 (O0)
66 BINARY_SUBTRACT
68 BINARY_XOR
70 STORE_FAST 4 (OO)
9 72 LOAD_FAST 1 (O0O)
74 LOAD_GLOBAL 4 (chr)
76 LOAD_FAST 4 (OO)
78 CALL_FUNCTION 1
80 INPLACE_ADD
82 STORE_FAST 1 (O0O)
84 JUMP_ABSOLUTE 40
>> 86 POP_BLOCK
10 >> 88 LOAD_FAST 1 (O0O)
90 RETURN_VALUE
#result:[cgjegl_&]!VW&KS_GVXHWI_EVCVDXGc^mgrj
上面的result显示异常,我截图放给大家。

解题:
分析题目发现与python有关,并且题目内容与python交互框架相似。使用网络搜索 dis.dis(encrypt)、import dis发现“dis库是python(默认的CPython)自带的一个库,可以用来分析字节码”。
找了几个例子查看下
import dis
def func2():
a = 0
a + 1
dis.dis(func2)
执行后内容如下
3 0 LOAD_CONST 1 (0) 2 STORE_FAST 0 (a) 4 4 LOAD_FAST 0 (a) 6 LOAD_CONST 2 (1) 8 BINARY_ADD 10 POP_TOP 12 LOAD_CONST 0 (None) 14 RETURN_VALUE
网上找到一张解释较清晰的图片

回到题目的开头代码,猜想意思是 第四行的代码是“O0O=''”
4 0 LOAD_CONST 1 ('') 2 STORE_FAST 1 (O0O)
第5行的代码是“o0O=oO0.upper()”
5 4 LOAD_FAST 0 (oO0) 6 LOAD_ATTR 0 (upper) 8 CALL_FUNCTION 0 10 STORE_FAST 2 (o0O)
第一次看看不懂,就使用python的dis库正向的编写代码生成字节码进行对比,中间列的内容当成英文理解。按照行数一行一行的翻译,每一行就是接下来python代码将要执行的操作,包括加、减、乘、除、调用函数等。完整翻译如下:
1 2 3 4 O0O='' 5 o0O=oO0.upper() 6 o0O=o0O[::-1] 7 for O0 in range(len(o0O)): 8 OO=ord(o0O[O0])+O0^len(o0O)-O0 9 O0O+=chr(OO) 10 return O0O
拼接函数其他部分可生成对应的字节码,执行以下内容即可生成
1 import dis 2 def func1(): 3 4 O0O='' 5 o0O=oO0.upper() 6 o0O=o0O[::-1] 7 for O0 in range(len(o0O)): 8 OO=ord(o0O[O0])+O0^len(o0O)-O0 9 O0O+=chr(OO) 10 return O0O 11 print(dis.dis(func1))
到这一步花的时间不多,而且算法也很简单,只有一个循环计算。根据算法逆向出反向代码
1 list1="[cgjegl_&]!VW&KS_GVXHWI_EVCVDXGc^mgrj" 2 flag="" 3 for x in range(len(list1)): 4 temp=int(ord(list1[x])^(len(list1)-x))-x 5 flag+=chr(temp) 6 print(flag[::-1].lower())
运行得到flag
flag{8e142b5b39c1f80a95e2ab3709facfae}
插曲:反向计算时错误理解了减号和异或的运算优先级,导致解密出现错误。虽然是一个减号的位置不对,但是花了好长时间排查问题。
减号优先级>异或优先级

浙公网安备 33010602011771号