Crackme024 的逆向分析
1.程序观察
程序界面和023一样。
2.简单查壳
使用汇编语言编写,无壳。
3.程序分析
使用 OD 载入程序,搜索字符串。
可以看到,程序的关键代码就在上方不远处
代码虽少,但是干的活却不少。总共分为以下四步:
1.得到输入
当输入事件发生的时候,首先程序得到输入的序列号,判断是否为空。然后得到输入的用户名,也判断是否为空。如果都不为空,继续验证;如果任意一个为空,就跳转走。
2.计算key值
接着程序有一个循环,循环次数为 0x10 次。程序使用我们输入的用户名计算得到一个 key。
3.修改代码
将计算得到的 key 和输入的 serial 相加,得到新的 key。然后使用内存 4012D9 处的值依次和key进行异或运算和减法运算。目的是修改内存 4012D9 处的代码。
4.验证
验证程序是一个长度为 0x3E 的循环。程序从地址 4011EC 开始,每次取四字节进行异或运算。最后计算出来的值和 0xAFFCCFFB 作比较。如果相等,跳转到地址4012D9处。
如果我们输入的序列号是正确的话,那么地址4012D9处的代码应该是跳转到地址401301。如果我们的输入不正确,那么无论如何也是跳转不到正确的提示处的。
接下里该我们可以倒推出地址4012D9处正确的代码:
因为我们知道输入:0,也知道输出:0xADDCCFFB,也知道计算过程:循环进行异或运算,那么应该可以计算得出地址4012D9处的值。
因为只有地址4012D8和地址4012DC这总共8个字节的值是不确定的,其余的值都是固定的。这两个地址处的值分别为 xxxxxx04 和 D833ADxx(xx表示未知的值)。
也就是说 23E989A7 xor xxxxxx04 xor D833ADxx = AFFCCFFB,所以 xxxxxx04 xor D833ADxx = 8C15465C。可以计算出这两个值分别为 5426EB04 和 D833AD58。
所以从4012D9处的四字节值为 585426EB。
然后可以倒推出 key 的值:
00584554 xor newkey = 5854xxxx
xxxx - newkey>>0x10 = 26EB
第一个式子可以算出,newkey 的前4位为 580c。第二个式子可以算出 xxxx 为 7EF7。所以 00584554 xor 580cxxxx = 58547EF7,可以算出 newkey一定为580C3BA3。
由于 newkey = oldkey + serial。
而 oldkey 是由用户名计算得到,所以我们可以很简单的写出注册机。
4.注册机
#include <stdio.h> #include <string.h> #include <Windows.h> int Keygen() { unsigned long key = 0x58455443; char szName[20] = { 0 }; unsigned long* p; printf("请输入用户名:"); scanf_s("%s", szName, 20); for (int i = 0; i <= 15; i++) { p = (unsigned long*)& szName[i]; key += *p; } unsigned long serial = 0x580C3BA3 - key; printf("%u", serial); return 0; } int main(int argc, char* argv[]) { Keygen(); return 0; }
相关文件在我的 Github:https://github.com/UnreachableLove/160-Crackme/upload/master/Crackme024