Crackme007
Crackme007 的逆向分析
1.程序观察
根据作者的提示,该程序的目的还是隐藏下面的按钮,将图片显示出来。不能使用爆破,打补丁等。最好是找出注册算法。
2.简单查壳
无壳。
3.查看控件ID和事件
可以看出来,该程序其实还有一个叫做 Again 的按钮隐藏了起来。完全体的程序其实如下图所示:
根据 Crackme006 的经验,我们猜测这个程序的流程是:
- 输入用户名和正确的注册码。
- 点击注册按钮,程序验证注册码是否正确。如果正确,隐藏注册按钮,显示出来 Again 按钮。
- 再想办法隐藏 Again 按钮。
4.分析程序
使用 OD 载入程序。因为从上面的事件中我们可以发现,在输入用户名和注册码的时候是没有事件发生的。所以我们猜测正确注册码的计算以及验证都是在点击注册按钮之后发生的。
在点击注册按钮事件的代码头部下断点,输入用户名和注册码,点击注册按钮,程序就断了下来。
跟踪程序,发现程序首先会判断输入的验证码是否为纯数字,如果不为纯数字,就会报错。
在地址 00442FBE 处,会根据 al 的值,判断是否要跳转,如果不跳转,程序就会隐藏注册按钮,显示 Again 按钮。
在该条命令上面有一条 call 指令,调用的函数是无法识别的。所以大胆猜测这个函数是一个关键函数。按 F7 进入函数内部。
在函数内部,首先会判断用户名的长度,不符合就会跳转走。
然后有一个两层循环,循环会算出来一个值。
在这个循环中,edi 寄存器的值是一个关键点,因为在计算的时候要使用要 edi 寄存器的值。但我在调试的时候,edi 的值一直为 0,最后计算出来的值也为 0。为什么会这样呢?
- 追踪溯源,在地址 004429B7 处,程序使用 eax 给 edi 赋值。
- 函数外边,地址 00442FB4 处,程序使用 内存445830中的值给 eax 赋值。
- 在地址 00442F86 处,将 eax 的值保存到了内存 445830 中。而 eax 的值是上面一个函数调用的结果。
- 只有注册码不为纯数字,程序才会调用这个函数。关于这个函数稍后分析,先继续上面的内容。
在经过两层循环后,会计算出一个值。
- 将这个值除以 0xA2C2A,取余数。
- 将我们输入的注册码除以 0x59,取商。
- 再将输入的注册码除以 0x50,取余数。
- 将步骤 2 和步骤 3 的结果加在一起再加1。
- 比较步骤 1 和步骤 4 的结果。
如果两个值不相等,那么会返回 0;如果相同,返回值非 0。
下面分析计算另一个关键函数,也就是计算出 edi 值的那个函数。
这个函数首先会判断我们输入的注册码长度是否大于 5,如果不大于 5,就不会计算出 edi 所需要的值。所以我们必须输入一个不为纯数字的长度大于 5 的注册码。
然后程序会根据我们输入的注册码计算出一个值。由于是固定输入输出,就不仔细分析了。当我们输入 KAZUSA 时,程序计算出来的值是 0x13ED,我们就根据这个值来写注册机。
5.注册机算法
int cKey = 0x13ED; int cTemp = NULL; int cCode = NULL; char szName[10] = { 0 }; printf("请输入用户名: "); scanf_s("%s", szName, 10); for (int i = 1; i <= 5; i++) { for (int j = 5; j >= 1; j--) { cTemp += szName[i - 1] * szName[j - 1] * cKey; } } cTemp = cTemp % 0xA2C2A; cCode = (0x50 - ((cTemp - 1) * 0x59 % 0x50)) + (cTemp - 1) * 0x59; printf("%d\n", cCode); return 0;
Afain 按钮的算法和注册按钮的算法一样,就不再分析了。