本篇文章通过一到看雪签到CTF试题来进行pc逆向,通过练习规范化自己的解题步骤提炼出自己的解题流程。
涉及到知识点:
并且解题过程中需要对md5算法了解一哈,要不然只能用猜的了。
解题
分析赛题,找到赛题中隐藏的flag
运行程序找到输出的中文字符,也可以用通用的字符sucess等
接着搜索字符串,利用交叉引用找到关键函数
由于堆栈不平衡引起F5大法失败,网上有很多解决方法,参考【1】,先开启栈指针、然后将报错位置的上一条指令的栈指针设置为对应的值,依次往下直到让返回地址的栈指针值为000
根据命令行的输出内容可以判断sub_401410是输出函数,sub_401410应该是获取用户输入的函数。
但是从伪代码中并未看见sucess这样的返回字符。
查看当前函数的汇编代码,可以看见sucess字符出现在除0异常处理函数中,F5大法并未生成对应的伪代码。那么现在需要找到函数中哪里有除法运算(DIV)
继续在汇编代码中找DIV指令,伪代码中并未显示除法运算。
如果要满足除0异常也就是要esi寄存器的值为0,往上看可以看见只要eax的值等于esi的值就可以让esi的值为0
上面第一个红框内关于esi赋值的伪代码。输入的每一个字节经过运算后相加。
至于eax的值可以经过调试知道,即将把0x401353存入eax,也就是需要让esi的值也为0x401353才可以
接着在收集和计算esi值相关的其他已知条件。用户输入到lvInput指向的地址,对v7、v8、v9有判断,并且输入长度必须小于7,所以可以得出输入内容长度为6,并且后三位为353
from z3 import * v1 = Int('m1') v2 = Int('m2') v3 = Int('m3') v4 = 0x33 v5 = 0x35 v6 = 0x33 s = Solver() s.add(And(v1+v2+v3==0x95, v6 + 0x10*(v5 + 0x10*(v4 + 0x10*(v3 + 0x10*(v2 + 0x10*(v1 + 0x10*0 - 0x30 ) - 0x30) -0x30) -0x30) -0x30) -0x30 == 0x401353), v1 >= 33, v2 >= 33, v3 >= 33 ) while s.check() == sat: t = [] print("compute result: ") m = s.model() t.append(str(m[v1])) t.append(str(m[v2])) t.append(str(m[v3])) t.append(str(v4)) t.append(str(v5)) t.append(str(v6)) t = map(int, t) t = map(chr, t) print("".join(t)) s.add(Or(v1 != s.model()[v1], v2 != s.model()[v2], v3 != s.model()[v3]))
得到两个答案:
3A!353 401353
【1】解决IDA因为(Decompilation failure: positive sp value has been found)堆栈不平衡导致不可以F5的问题