比赛昨天下午开始,结果三个人昨天浪了一天,只能拖到今天看了看题目
FLOW
拿到题目,看了看题目The time is precious。时间是宝贵的… 可能是出题人觉得题目太简单了???使用IDA反编译看了一下,发现是一堆的函数,但是反编译中有很多是和Python相关的,通过strings 工具查看文件。发现py2exe,考虑可能是Python开发的exe,通过pyinstaller打包后的exe程序。
exe转换为pyc
我们可以通过unpy2exe.py将文件转换为.pyc然后进一步通过rePy2exe.py将.pyc文件转换为py文件,经过处理后如下:
1 | # 2018.12.01 18:18:26 PST |
算法逆向分析
在给出FLAG的字符串后,先经过finallu_chng()函数处理后,然后经过encode()得到最后的输出结果。连接到NC后得到字符串0036dbd8313ed055NJD5H1Ufzl75UfLf1JgrfxKNwNca3fcyERbivXzTt4x/hEPt+P7s3BiGfihF0N8Sm5woY4Jqjsn7qqiwU+y1/uN/,从源代码可知,我们得到的是st的值。我们需要的是FLAG的值。因此我们要从encode()函数依次向后推得到FLAG。
0x01 encode()函数分析
encode函数中,我们最后得到是base64加密的结果,self.car_c的长度是固定的,所以通过字符串st的值我们可以得到经过b64加密的字符串。
1 | def encode(self, string): |
将st的b64加密部分解密。
1 | import base64 |
解密后我们可以得到的是self.result,在encode()函数中,当我们得到self.resul后,接下来分析Decrypt()函数。
0x02 decrypt函数
在decrypt函数中,char_set = list(range(256))生成了256个字符的一个列表,之后经过一系列操作,列表中的顺序有所改变。但是最后的顺序是固定的。然后在函数的最后通过异或操作与string输入字符串进行异或。再异或依次便可以解密得到真正的string,再去掉一部分头部即可得到经过finallu_chng()加密后的字符串。
1 | char_set = [202, 158, 160, 206, 1, 205, 163, 166, 215, 164, 64, 169, 114, 62, 67, 12, 118, 73, 115, 225, 177, 226, 180, 72, 181, 228, 82, 231, 233, 25, 185, 236, 186, 28, 85, 134, 89, 239, 246, 194, 244, 195, 97, 95, 43, 245, 252, 0, 203, 148, 207, 210, 104, 9, 3, 5, 8, 4, 105, 156, 60, 159, 221, 13, 10, 222, 121, 19, 167, 165, 227, 230, 31, 18, 128, 22, 178, 29, 131, 76, 125, 137, 123, 35, 241, 240, 81, 38, 39, 86, 34, 248, 251, 44, 41, 190, 139, 96, 48, 198, 2, 52, 50, 47, 46, 6, 14, 61, 107, 152, 106, 111, 11, 212, 59, 122, 168, 173, 66, 174, 63, 23, 26, 70, 119, 68, 71, 77, 74, 79, 136, 133, 84, 229, 33, 32, 36, 45, 145, 142, 242, 90, 40, 140, 189, 199, 243, 99, 197, 93, 201, 102, 154, 254, 98, 103, 110, 108, 155, 153, 57, 211, 213, 54, 217, 170, 56, 116, 214, 220, 78, 223, 124, 216, 171, 175, 75, 16, 30, 234, 232, 237, 132, 238, 127, 87, 130, 83, 183, 27, 53, 94, 191, 143, 249, 146, 193, 147, 49, 200, 208, 250, 101, 149, 100, 157, 51, 204, 253, 109, 58, 113, 161, 117, 21, 65, 218, 209, 162, 15, 224, 172, 219, 7, 112, 69, 176, 20, 126, 129, 120, 184, 17, 187, 179, 24, 188, 80, 235, 192, 88, 182, 91, 150, 138, 144, 135, 37, 141, 151, 92, 42, 247, 196, 55, 255] |
0x03 finallu_chng函数
函数中首先生成一个列表[0,1,2,3]然后通过random.shuffle()函数打乱列表的顺序。while循环使得finallu的长度是8的倍数,不足的情况下补充 ‘.’,然后将如下操作循环100次。
- 首字母后移到字符串末尾
- 取字符串偶数部分的字符,字符串奇数部分的字符,构成新的字符串
- 首字母移动到字符串末尾
- 将新的字符串按照四个一组,按照新生成的列表perm里的顺序重新排列四个字符
1 | def finallu_chng(finallu): |
得到算法流程后,逆向写出解题脚本,由于我们不知道正确的顺序,由于random.shuffle()每次生成的顺序不固定,所以我们可以通过多次random.shuffle来生成列表,爆破得到最后的flag
1 | import random |
flag{9789e2e95ec53daea99d54b3ca9c357d}
总结
exe 到python的逆向,可以使用工具rePy2exe.py,github链接https://github.com/4w4k3/rePy2exe,也可以参考http://blog.nsfocus.net/wp-content/uploads/2015/09/reverse_400.pdf,使用工具 PyInstaller Extractor 通过 python pyinstxtractor.py Revesre03.exe来解题,也可以通过uncompyle https://github.com/wibiti/uncompyle2 uncompyle,pycdc 来解题。