虎符ctf三道逆向中最简单的一道,比赛期间我只做出来这一道。题目对我来说挺新颖的,所以在这里也记录一下。刚写完vm的题解,有点累,所以这篇就简单点写。
只给出一个disasm.txt
,部分如下:
查了下,是python的字节码。
pyc可以还原成py源代码,但是这个类似汇编的东西没办法还原出来(如果大佬们知道怎么还原,劳请告诉我一下)
dis模块
同时查到这个文本是怎么来的,python的dis模块。
下面有个小例子:
1 | def f(): |
输出:
1 | 2 0 LOAD_CONST 1 (90) |
上面的输出的代码形式风格和题目给出的只有细微的差异(我用的是python3,而题目是python2,可能是这个原因)
然后可以去试着分析下题目给出的代码了,遇到不懂的点,可以自己写个函数,然后disasm,看看和题目中代码的差异。
分析字节码
首先是arr0,arr1,arr2这三个列表的赋值,很容易看出来。
然后有check0, check1,check2,check3四个检测函数。
check0
1 | # <genexpr> line 6 of game.py |
配合着我代码中的注释就应该能看懂了吧,我就不多解释了。
check1
1 | # check1 line 8 of game.py |
check1检测flag长度是否符合条件( if ((len(s) * len(s))%777) ^ 233 == 513
)
爆破可以求得长度为39
check2
1 | # check2 line 14 of game.py |
check2用于判断前6个字符是否满足(((((((ord(s[0])*128+ord(s[1]))*128)+ord(s[2]))*128)+ord(s[3]))*128) + ord(s[4])) * 128 + ord(s[5]) == 3533889469877
,同时判断最后一个字符是否是}
只要学过数学的小学生都知道6元一次等式根本不可能求出六个未知数,所以题目可能是假设了前五个字符是flag{
,由此我们可以求出flag的第6个字符,也就是flag主体部分的第一个字符。
注意,我和炜昊都被这里坑到了,看到了flag[5],以为只有5个字符,恰好是flag{
,忽略了第六个字符。
这个低级的下标错误平常不会错,但是每次到这个综合性题目中总会出错,还是要注意啊。
check3
1 | # check3 line 20 of game.py |
整理一下,check3的逻辑是这样的
1 | def check3(): |
逆向
倒着逆,脚本如下:
1 | arr0 = [249, 91, 149, 113, 16, 91, 53 ,41] |
注意flag[7, 27]的值需要依靠flag[34, 38]求出。