• 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

  • 相关阅读:
    Leetcode 694. 不同岛屿的数量 中等 回溯 岛屿问题
    集成电路设计流程
    Leetcode 44. 通配符匹配 困难 动态规划 精选 TOP 面试题
    Leetcode 13. 罗马数字转整数 简单 字符串
    Leetcode 36. 有效的数独 中等 数组遍历 精选 TOP 面试题
    windows 不是真正的多用户OS,linux才是
    java AWT弹球游戏
    java AWT 图片查看器
    java AWT 简易绘图
    java Swing 进度条
  • 原文地址:https://www.cnblogs.com/white-album2/p/11559121.html
Copyright © 2020-2023  润新知