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 key = 5854xxxx
xxxx – key>>0x10 = 26EB
第一个式子可以算出,key 的前 4 位为 580c。第二个式子可以算出 xxxx 为 7EF7。所以 00584554 xor 580cxxxx = 58547EF7,可以算出 key 一定为 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