xiaoyu2032 发表于 2022-8-18 21:42

练习笔记之160Crackme-033

本帖最后由 xiaoyu2032 于 2022-8-18 21:42 编辑

# 160CM-033

## 1. 爆破

  首先拖入PE看一下,应该是个汇编程序(ExeInfoPE检测为unknown,DetectItEasy检测为delphi(delhi反汇编工具无法反汇编),PEID检测为汇编)。直接拖进OD中,查找关键字符串也可以找到。这里我们用F12暂停法,打开注册界面,输入用户名和密码,然后确定,弹窗错误提示对话框后,在OD中按F12暂停,然后Alt+K进入堆栈调用列表中,再最后一个调用处双击,就找到了弹窗的调用程序,然后F8单步跟踪到返回,就可以到401245位置,该处调用就是错误弹窗函数。



  往上看,可以看到一个比较和一个判断跳转,这个跳转就是关键跳转,将`je`该为`jmp`,爆破就完成了。

## 2. 算法分析

  从图1中的代码可以看出,程序验证过程一目了然:先获取用户名字符串,然后调用校验算法1计算得到结果1;再获取密码字符串,然后调用校验算法2计算得到结果2,最后比较结果1和结果2是否相等,相等则提示成功,否则提示失败。

  先分析用户名校验算法,用IDA打开程序,找到算法子程序`40137E`,按F5得到伪代码,如下图:



  从伪代码中可以看出,算法先一次判断用户名字符串中的字符是否在A~Z之间,小于A,则弹窗报错,大于Z,将其ASCII值减32(即转换成大写字母),全部转换成大写字母后,再调用子程序`4013C2`,将所有字母的ASCII码值相加,最后在和`0x5678`进行异或运算(上述过程如果功力不够静态分析不大确定,在OD中跟踪一下程序执行过程也就很容易确定下来)。

  接着分析密码校验算法,同样用IDA打开程序,找到算法子程序`4013D8`,按F5得到伪代码,如下图:



  从伪代码中可以发现,IDA生成的伪代码有点问题,漏掉了与`0x1234`进行异或的计算过程。`*i-48`也就是字符的ASCII码减去数字0的ASCII码值,也即得到输入数字所代表的数值,`v2=(*i-48)+10*v2`,整个过程起始就是将数字字符串转化为其对应的数值。最后再与`0x1234`进行异或计算。

  将上述校验过程编写成校验算法如下,输入数据与程序本身的计算结果进行验证,可以证明算法无误。

```cpp
// 160CrackMe-033.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <math.h>

int _tmain(int argc, _TCHAR* argv[])
{
      char name;
      char code;
      int i,j;
      int k;
      printf("请输入用户名(长度≤20):");
      scanf_s("%s", name, 20);
      printf("请输入密码(长度≤20):");
      scanf_s("%s", code, 20);
      //未做用户名输入校验,只允许输入字母
      for (i = 0; i<strlen(name); i++)
      {
                name = toupper(name);
      }
      k = 0;
      for (i = 0; i<strlen(name); i++)
      {
                k = k + name;
      }
      printf("用户名字符和:%d \n",k);
      k = k ^ 0x5678;
      printf("用户名校验输出:%x \n", k);

      j = 0;
      for (i = 0; i<strlen(code); i++)
      {
                j = (code-48) + 10 * j;
      }
      printf("密码异或前的结果:%d \n", j);
      j = j ^ 0x1234;
      printf("密码校验输出:%x \n", j);
      system("pause");
      return 0;
}
```

  至于注册机的算法,由于密码的校验算法相当于输入数字字符串的数值与`0x1234`的异或结果,因此注册码的求解过程可以直接用用户名校验算法得到的结果,与`0x1234`进行异或,得到的数值就是注册码。具体算法程序如下:

```cpp
// 160CrackMe-033.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <math.h>

int _tmain(int argc, _TCHAR* argv[])
{
      char name;
      char code;
      int i,j;
      int k;
      printf("请输入用户名(长度≤20):");
      scanf_s("%s", name, 20);
      //未做用户名输入校验,只允许输入字母
      for (i = 0; i<strlen(name); i++)
      {
                name = toupper(name);
      }
      k = 0;
      for (i = 0; i<strlen(name); i++)
      {
                k = k + name;
      }
      k = k ^ 0x5678;
      k = k ^ 0x1234;
      printf("注册码为:%d \n", k);
      system("pause");
      return 0;
}
```

  输入用户名`abc`,可以计算得到注册码为`17546`,输入程序中,验证成功。



## 3. 总结

  这道题验证过程清晰简单,算法也不难,借助IDA、OD这两个软件,分析起来还是比较顺利的。

  其中关于注册码的计算,默认注册码为数字字符串的话,可以如上直接异或后得出,但由于程序没有限制只能输入数字字符串,因此将其中的数字用字母代替,也是可以算得注册码的,比如最后一个数字用字母`h`替代,则可以得到`1749h`这样一个注册码,有很多个解。

iawyxkdn8 发表于 2022-8-19 08:09


我大体看了一下,很想了解,仔细又看了一下,还不如大体看一下。总结,看不懂!

lxf100 发表于 2022-8-18 21:46

这是啥?看不到{:1_909:}

14762655378 发表于 2022-8-18 21:54

我大体看了一下,很想了解,仔细又看了一下,还不如大体看一下。总结,{:1_907:}看不懂!

gbk38866 发表于 2022-8-18 22:26

看不懂,先灌个水!

Pro111 发表于 2022-8-18 23:11

这个可以啊

戰龍在野 发表于 2022-8-18 23:13

谢谢分享谢谢你的坚持

tohyueyun 发表于 2022-8-18 23:27

写到好详细

dadaliya 发表于 2022-8-18 23:42

写的真好!!!

a12b19 发表于 2022-8-18 23:47

看了楼主的帖子。打算去自己练一下。
页: [1] 2 3
查看完整版本: 练习笔记之160Crackme-033