Crackme023

58次阅读

共计 1135 个字符,预计需要花费 3 分钟才能阅读完成。

Crackme023 的逆向分析

1. 程序观察


当输入的序列号正确的时候,下面的状态应该会变。

2. 简单查壳


使用汇编语言写的,没有壳。

3. 程序分析

使用 OD 载入程序,搜索字符串

可以看到状态栏的字符串出现在了里面,我们进入对应的代码空间

在地址 004012B3 处有一个比较语句,如果 eax 的值为 0x10,则程序跳转到正确提示处;如果 eax 的值不等于 0x10,程序则会跳转到错误提示处。

看来这里就是关键的比较了,那么 eax 的值是从哪里来的呢?
在地址 00401299 处可以看到,程序将内存 403166 处的值赋给了 eax。
那么问题又来了,内存 403166 处的值又是怎么来的呢?

我们在程序中查找常量 403166

和内存 403166 有关的语句共有 8 句,有 4 句命令是让内存 403166 的值加 4。
因为前面比较是让 403166 的值和 0x10 作比较,所以需要这四条命令全部执行才行。
这四处,分别是用来求得用户名,求得序列号,计算序列号,验证序列号。

求得用户名:

程序先得到输入的用户名,然后求得用户名长度。接着使用循环将用户名后面一定长度的值清零。最后进行判断,如果用户名长度为 0,则清零内存 403166 的值;如果不为 0,则将内存 403166 的值加 0x4。

求得序列号:

程序使用函数获取输入的序列号,如果函数返回值为 0,也就是序列号为空的话,就会直接返回;如果序列号不为空,将内存 403166 的值加 0x4。

计算序列号:

这是一个循环,循环次数要进行 0x10 次,内存 403166 处的值才会加 0x4。
在循环中:

  1. 程序得到用户名
  2. 用户名左移 i 位,i 为循环次数
  3. 求得输入的序列号
  4. 将序列号加 1
  5. 让序列号和移位后的用户名进行异或运算
  6. 将计算出来的值存入内存 403188 处

验证序列号:

将内存 401388 处序列号取出,加上 0x9112478,看结果是否为 0。如果为 0,就是正确的;如果非 0,就是错误的。所以计算出来的序列号一定是 0 – 0x9112478 = 0xF6EEDB88。

4. 注册机

#include <stdio.h>
#include <string.h>
#include <Windows.h>

int Key()
{
    unsigned long serial = 0xF6EEDB88;
    char szName[20] = {0};
    unsigned long* p;

    printf("请输入用户名:");
    scanf_s("%s", szName, 20);

    for (int i = 15; i >= 0; i--)
    {p = (unsigned long*)& szName[i];
        serial ^= *p;
        serial--;
    }

    printf("%u", serial);
    return 0;
}

int main(int argc, char* argv[])
{Key();
    return 0;
}

相关文件在我的 Github

正文完
 0