攻防世界 (xctf.org.cn)
前戏
下载文件,解压完成后是这个
一个pyc文件
这里要用到python的反编译
要用到的工具有两个
1.python自带的uncompyle6
2.pycdc文件——比uncompyle6强大一点
我们一个一个来尝试一下
uncompyle6:
我是直接在pycharm里面终端用的
把文件放在这个目录下
你需要先安装
然后输入这个命令(在cmd里面也行)
一般来说就OK了
但是这道题考点是进一步的
这是运行了,但是运行出错
最后得到的这个py文件是0kb的,什么都没有
至于后续,我先讲另一种方法,比较常用的
pycdc:
首先你要去下载一个pycdc文件(52上面有)
这样输入,你就会得到一个py文件,名字叫做1.py
但是是0kb
修改文件头
这个MAGIC是指pyc的文件头是坏的
pyc的文件头,我用010editor给大家打开看一下
蓝色标记这部分就是pyc文件的文件头
它包含的信息包括:
前四个字节——版本信息,比如python的3.6,3.8等
中间8个字节——不用管,修改时间而已,对我们来说没有
后面四个字节——包含大小信息和校验码(我也不确定,反正有用)
一般这种错误就是因为这个文件的文件头信息被修改了,我们需要去修复,也就是将文件头修复正确中间我们最重要的一步就是找到他是什么版本的pyc文件,不同版本的文件头不同
我们先给出答案,这道题的版本是3.6,我们可以从两个地方看出来
一:文件名字
还记得最开始文件名那么长的字符吗,你是不是就下意识忽略了,我们在回过头看一下(当时我也没看出来)
3.6版本
二:文件头
这个33 0D 就是3.6版本的文件名开头,他只是修改了后面的部分
然后下面就是我们找到正确的3.6版本的文件头是怎样的了
我是直接百度的,当然厉害的就是自己用3.6版本的python写一个pyc文件,放在010里面去看
橘黄色的就是改的
现在跑出来的py文件就有3KB了
后面就算正常的IDA静态分析了
IDA分析
因为这是个py文件,我们可以直接放入python中去看,他也只有3KB,代码不是很多,就不麻烦IDA了,你要放在IDA里面去看也行
# Source Generated with Decompyle++
# File: 1.pyc (Python 3.6)from ctypes import *
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytesdef encrypt(v, k):v0 = c_uint32(v[0])v1 = c_uint32(v[1])sum1 = c_uint32(0)delta = 195935983for i in range(32):v0.value += (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[sum1.value & 3]sum1.value += deltav1.value += (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[sum1.value >> 9 & 3]return (v0.value, v1.value)if __name__ == '__main__':flag = input('please input your flag:')k = [255,187,51,68]if len(flag) != 32:print('wrong!')exit(-1)a = []for i in range(0, 32, 8):v1 = bytes_to_long(bytes(flag[i:i + 4], 'ascii'))v2 = bytes_to_long(bytes(flag[i + 4:i + 8], 'ascii'))a += encrypt([v1,v2], k)enc = [0xEEC7D402L,0x99E9363FL,0x853BDE61L,558171287,0x908F94B0L,1715140098,986348143,1948615354]for i in range(8):if enc[i] != a[i]:print('wrong!')exit(-1)print('flag is flag{%s}' % flag)
就是这么个事
直接开干吧
这段代码可能新手比较懵逼
这个<<4,就是在二进制表示下,把整个数往左边移动4位,就也是变大了2的四次方大
这个>>7就是右移7次,就是表现2的七次方小,向下取整
然后这个&3就是在二进制层面按位与
3是11,8是11000
1000
0011
相同位置如果都是1,那么得到1,不同为0
得到的结果就是
0000
对应这段代码我很懵逼
然后我去实验了下
825307441
然后把1111又换成了aaaa,也是一串数字
得到了这个数字,然后感觉就是把4个字符串转换成为了一个数字,感觉和base64作用差不多
就是把每个字符的ASCII码提出来,然后通过一些算法组合在一起
这里我采用的就是暴力的方法的,硬跑
加上这个直接全部遍历一遍
(抄一个吧,不想写了)
我是废物
enc = [63912563639333235,63912563820295007,63912563319981409,63912564160552784,63912564260890672,63912564074962770,63912563086615890,63912564159242032]
flag = bytearray(32)
for i in range(8):flag[4 * i] = (enc[i] >> 24) & 0xFFFFFFFF & 0xFFflag[4 * i + 1] = (enc[i] >> 16) & 0xFFFFFFFF & 0xFFflag[4 * i + 2] = (enc[i] >> 8) & 0xFFFFFFFF & 0xFFflag[4 * i + 3] = (enc[i] & 0xFFFFFFFF & 0xFF)print(flag)
#bytearray(b'Th1s_1s_A_Easy_Pyth0n__R3veRse_0')
看不懂为啥这样就OK了,我是废物!~
但是废物也要下班拉~