Crackme019

Crackme019 的逆向分析 

1.程序观察

 

 

 

可以看到,程序要求用户名至少要5位。

2.简单查壳

无壳。

 

3.程序分析

OD 载入程序,搜索字符串。

 

 

 

 

可以看到,字符串上方不远处有一个跳转语句。
在 JNZ 语句处下断点,运行程序,中断在了断点处

 

 

 修改 ZF 标志位

 

 

 

 因为 eax 的值是 JNZ 语句上面的函数返回的

 

 所以我们进入这个函数里面看一看

 

 

 可以看到,004018C0 这个函数在 004018D1 处调用了一个函数,参数有两个,其中一个是我们输入的假码,另一个可能是真码,我们试一下

 

 

那 004018D1 处的这个函数有可能就是比较函数了,我们进入这个函数内部看一下

这个函数又调用了 cmp 函数进行比较

 看来,004018C0 函数就是用来比较注册码是否正确的,正确 eax 返回0,不正确返回非0。

 

下面分析程序的算法

 

 程序首先求得用户名和注册码的长度,如果用户名长度小于5就会报错。

然后程序建立循环,循环次数为用户名的长度

  1. 取用户名一个字符 name[n],n 为循环次数
  2. 让一个十六进制的默认值 0x81276345 加上 name[n]
  3. 取循环次数 n,将 n 左移 8 位
  4. 步骤2的结果与 步骤3的结果进行异或运算
  5. 取循环次数加一
  6. 让用户名长度乘以循环次数,然后按位取反
  7. 5和6的结果相乘
  8. 4的结果再和7的结果相乘

以上就是循环的内容,如下图

 

循环完成之后,程序将结果转化为 lu 类型的,也就是无符号长整形整数

 

 这就是最终的注册码啦!

 

4.久违的注册机环节

 

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

int Key()
{
    char szName[20]    = { 0 };
    int NameLen         = 0;
    int code             = 0x81276345;

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

    NameLen = strlen(szName);
    for (int i = 0; i < NameLen; i++)
    {
        code += szName[i];
        code = code ^ (i << 8);
        code = code * ((~(NameLen * i)) * (i + 1));
    }

    printf("%lu", code);
    return 0;
}

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

 

 

 

 

相关文件在我的 Github:https://github.com/UnreachableLove/160-Crackme/tree/master/Crackme019

2019-09-20 19:27:13

posted @ 2019-09-20 19:27  随风而逝的白色相簿  阅读(136)  评论(0编辑  收藏  举报