程序没有加壳,可以直接跟踪调试。
首先通过断Messagebox找到程序各个判断的地方,改掉验证字符长度,验证字符输入和验证CRC的分支后我们发现程序最后跳进了0x004044C8
继续跑,程序直接异常了
重新打开程序,对这个地址下断,根据看内存的值可以判断这里是一个16B的数组
而最后程序会跳到这个数组里执行代码
通过对程序的分析,可以知道里面有一个CRC48校验
要构造出能弹出Win的shellcode不难,但碰不上CRC校验。所以此路不通。
要构造出CRC校验,就只能用10B完成弹出Win的任务,然后用剩下的6B满足CRC校验。然而,当时的寄存器中也并没有存放”Win”的地址,光是call Messagebox 和push 字符串地址就占掉了10B了。所以,光靠这10B想完成任务也是行不通的。
因此可以肯定:这10B最终将跳转到其他的地方执行代码,而剩下的6B是根据这10B和CRC校验反推出来的。
那么我们就得找其他的地方是否可以执行出弹出带”Win”的Messagebox代码,作者是否留下了什么线索或漏洞。
线索一:这个exe的资源节是可执行的!!!
众所周知,正常编译出的exe的资源节没有执行权
然而,这个exe的4个节区都是可读可写可执行。这说明了数据区和资源区是可以在运行中修改数据并且可以执行代码的!
简单观察可以发现:资源节中4个字节为一组,第4个字节固定是FF,明显有规律。
但是,这里很明显有不符合规律的数据出现在了资源里面
这个地址是:0x1A390h + 2000h + 400000h = 41C390h
在Debug里面反汇编就能看出这里是一段弹出messagebox的代码。
显然,那10B应该跳到这里来!
如果觉得查看程序各节的权限,属于高难度技术手段,还有更简单的线索二:
线索二:用肉眼看一看这个程序的资源
这个程序没有什么其它资源,基本上就是图标了。用工具提取icon资源区图标,看看!
这里其他图片都没有彩色的点,这里却有彩色的点
有彩色点的图片是Icon的第6张
找到资源icon的第6个图标资源区,注意这个
根据上下格式这里有一段二进制和正常的icon数据不同(正常的格式4字节一组第4字节为FF),这也说明了为什么图片上有莫名的斑点
这里可以拿到文件地址 1A390h
程序没有开启随机基址 基址位置 0x00400000h
这个可疑的代码地址就有了 0x1A390h + 2000h + 400000h = 41C390h
以上两条线索,任意发现一条,都能找到这段代码的地址41C390h
接下来就能看到
这里是一段执行弹窗的程序。
但它只是弹窗,却没有‘Win’
我们在程序中搜索”Win”的ASCII(调用的A版),发现程序中找不到这个字符串
那么程序里是通过其他运算来算出这个字符串的
这里push了字符串而且push之前还有一个4字节异或寄存器eax的操作
[0x403FC] 的值是主窗口的窗口句柄,当参数传给MessageBoxA了
并且 弹框结束后jmp回 0x00401331
0x00401331 这个地址正好在校验完成并跳入数组执行代码之后,可以肯定图片里的函数是执行正确序列号用的
这里是序列号成功弹出”Win”的执行代码, ”Win”的字符串长度正好又是4个字节
那么41c38b地址的值异或eax 后为 Win的ascii码加个’\0’
57 69 6E 00 xor 2F 3F 5A 12 = 78 56 34 12
由于上面的 and al,0xFF 执行后 eax不可能是 78 56 34 12 所以锁定函数入口在0x0041c398
Eax 是人为写入的
所以得出数组里的执行10字节代码 mov eax, 0x12345678 jmp 0x0041C398
对应的机器码B8 78563412 E9 C67E0100
剩余6字节可从CRC结果中恢复,恢复算法是:
具体步骤和普通的CRC相同,已知被除数B878563412E9C67E0100????????????,可从crackme中得到除数0x180000030000 (对应恢复时0x80000c000001),余数0xb2a289cf038b0000,容易解出余下6字节。
下一步, 分析CrackMe可知,程序首先接收序列号,用于初始化数组,交给5个线程,经过300轮变换后,这个16字节的数组将被作为代码执行。
线程每轮修改数组需要知道两部分参数。
所有线程都共用一个相同的PRNG算法1和种子产生的随机数列,把每轮产生的随机数作为参数传给一个固定的洗牌算法,得到在[0,15]中的两个数x,y,决定修改数组中哪两个位置的值。
每个线程各自还有一个PRNG算法2和不同的种子,根据每轮产生的随机数得到L,R和q,由L,R决定线程如何修改这两处的值。5个线程的q合在一起改变PRNG内部的状态
线程对数组的变换具体是:
将数组x位上的数字取出,加上L,记为x0
将数组y位上的数字取出,加上R,记为y0
计算 x1=3*x0+y0
y1=x0-2*y0
然后将x1放到x位 ,将y1放到y位
显然只要知道<x,y,L,R>就可以从本轮数组还原出上一轮修改之前的数组的值
破解者可以自己实现5个线程,使用和CrackMe中相同的算法和初始种子,并在每轮计算完成后记录下本轮的<x,y,L,R>
用记录下来的<x,y,L,R>还原300轮后的正确的16个字节,得到300轮之前的16个字节,就可以得到正确的序列号。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界
最后于 2019-6-18 13:47
被leafpad编辑
,原因: 补充