宇宙第一魔王 发表于 2022-4-6 02:17

CrackMe160学习记录3 AfKayAs.2

本帖最后由 宇宙第一魔王 于 2022-4-6 02:24 编辑

## **1.前期信息探查:**

### **1.EXEinfo:**

32位,无壳,VB编写的程序


### **2.运行一下:**

双击程序会发现弹出一个Neg窗口,过了很久才弹出主窗口:




随便输入一点东西:



主要关注一下出错后弹出的信息。

## 2.前置知识:

tips这里列一下分析这个程序会用到的一些知识点,但有些知识点不会在这里写得太详细,可以移步到百度或者我博客里关于一些知识点的整理。

### Timer:

在 Windows 应用程序中常常要用到时间控制的功能,如在程序界面上显示当前时间,或者每隔多长时间触发一个事件,等等。而 Visual Basic 中的 Timer(时间)控制器就是专门解决这方面问题的控件。Timer 控件可以使用 Name 属性与 Enabled 属性,但最重要的是 Interval 即时间间隔属性。Interval 属性决定了时钟事件之间的间隔,以毫秒为单位,取值范围为 0 ~ 65535 ,因此其最大时间间隔不能超过 65 秒,即一分钟多一点的时间。如果把 Interval 属性设置为 1000 ,则表示每秒钟触发一个 Timer 事件。 其语法格式:Timer.Interval = X ,其中,X 代表具体的时间间隔。

一个TImer对象需指定定义回叫方法的 TimerCallback 委托、传递到该回叫的可选状态对象、首次调用该回叫前的延迟时间以及两次回叫调用之间的时间间隔。

```c
timer = new Timer(
      callback: new TimerCallback(TimerTask),
      state: timerState,
      dueTime: 1000,
      period: 2000);
```

### Virtual Basic程序运行简介:
https://www.52pojie.cn/thread-1610514-1-1.html

### 汇编中关于浮点寄存器的知识点:

https://magnificent-syrup-61f.notion.site/e117ace2c3d949ec9c0d5f1671eee87e

## 3.去除Neg弹窗:

运行程序可以看到会停留在一个Neg弹窗很长时间,我们先把他给干掉。

tips:对于一个应用接口需要限制运行速度,需要在循环中加个延时函数,这个延时不需要多么精确,要求有个几秒延时就可以的话,一般使用Timer函数。这里首先尝试第一个方法

### 1.方法一:直接搜索Timer

首先可以直接在数据框中搜索字符串“Timer”:

OD打开程序,在右击数据窗口选择查找→二进制字串→输入Timer:





找到Timer后可以看到后面有有一串数值“0x1B58”(注意小端存储),这个数值就是调用Timer后的延迟时间,转换成10进制为7000,而Timer的单位为毫秒也就是说这个Neg窗口的停留时间为7秒,既然它存在了数据区里面那我们可以直接修改停留时间(修改为1毫秒):



同样还是要注意一个小端存储的问题,这里要输的值为“10 00”,这里在补充一个知识点就是当我们修改好一个程序后,如何保存为新的程序:

在指令窗口右击→选择复制到可执行文件→点击所有修改


然后会弹出一个选项卡:



选择复制,之后弹出一个文件窗格:


在窗口内右击然后选择保存文件就会弹出文件另存为窗口了。

保存为新的程序后双击运行就会发现Neg窗口一闪而过后就直接跳转到序列号窗口。

其实这里我有尝试过把时间改为0秒,但是运行后发现程序会一直停留在Neg窗口,我对Timer不是很熟悉,只能是猜测可能当数值为0时,就等于一直停留吧。

### 方法二:4C法

这个方法首先要明白的一个点就是啥是4C法,这里的4C指的其实就是对于VBHeader结构体中偏移为4C位置处的成员`GUITable`,这个成员也是一个指针其作用是指向Form GuI描述表。通俗的来说这个指针指向的就是窗体参数数据块,在这里面我们看到的窗口其出现的顺序,并且可以利用这个特征来根据按照我们的个人意愿来调整各窗口出现的顺序。

我们可以分析一下GUITable结构体的主要成员的定义:

```c
Signature DWORD //00H.必须是50000000
FomID TGUID //04,可能是以GUID方式命名的formID
Index BYTE //24H 窗体的序号
Flag1 BYTE //28H 第一个窗体的启动标志,可能是90 也可能是10
AGUIDescriptionTable DWORD //48H指针指向以“FFCC…“开始的FormGUI表
Flag3 Dword //4CH.意义不明
```

具体操作如下:

把程序丢入IDA分析,根据之前笔记的分析得知,EP的第一条指令push的是一个指针,指向的是VBHeader结构体。跟随到数据窗口:




找到`GUITable` 成员:



继续跳到0x406868处:



可以看到这里根据窗口分为了两个块每个块的大小就是一个GUITable的结构体的大小(0x50)


箭头所指的地方就是窗口出现的顺序,这里我修改了两个窗口的出场顺序,将序列号窗口放到了前面,而当执行完序列号窗口后就会直接退出程序,也就是Neg消息窗口根本就不会出现了。

将修改后的程序进行保存,我将修改后的程序命名为AfKayAs.banNeg,运行一下会发现已经不会弹出Neg窗口了。
## 4.动调分析算法:

### 1.定位关键跳转:

还是跟之前一样的老套路,采取的方式就是查找参考字符串:



双击跟踪字符串“You Get Wrong”根据跳转到错误字符串箭头定位到关键判断代码(当然也可以直接跟踪正确字符串,都可以)



### 2**.分析校验算法:**

在确认关键的判断点后下个断点,然后直接翻到构建栈帧的地方下断点,F9直接运行,用户名输入“hahaha”和序列号为“123456”。这些操作就不一一截图了,这些东西包括如何定位一些关于序列号生成算法的主要指令在之前的crack分析中都已经详细的走过了(主要是本人懒,可以看一下之前crackme的第二题学习笔记,那里面有讲)。这里直接贴关于序列号生成算法的主要流程:

首先是获取用户名长度



后面三条指令一个是将name长度放入edi,然后是将name存入ecx,第三条是将name的长度乘上0x15B38在存入edi



大概就是edi=name的长度*0x15B38+第一个字符的ASCII码



然后将算出来的值转换成十进制,我算出来的值为533432:



将算出来的值转换成浮点型之后加上2.0然后以浮点的形式表示:



之后还是将之前那个数放入ST0并乘上3,再减去2,等于1600300



最后将1600300减去负的15得出最后的序列号“”:



验证一下:



## 5.注册机编写:

### **1.确认整个算法逻辑:**

这个算法的验证过程虽然有用到浮点数但作用仅在于影响我们分析,基本的逻辑和上一个crack差不都,都是取name的第一个字符,验证过程如下:

- 取出name的长度将其乘上一个固定的值(0x15B38)
- 再加上name的第一个字符的ASCII码值,再加上2
- 之后再乘3减2
- 最后再加上15,得出来的值为序列号

### 2.注册机:

```c
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
int main()
{
      char str1 = "";
      int len,seriali;

      puts("Please Input Your Name:");
      scanf("%s", str1);
      len = strlen(str1);
      len = 0x15B38 * len;
      seriali = (len + str1 + 2) * 3 - 2 + 15;

      printf("%d",seriali);

      return 0;
}
```

编译成程序搞一搞:

tanghujili 发表于 2022-4-6 16:07

感谢分享

菠萝蜜 发表于 2022-4-6 19:30

来学习学习

112589 发表于 2022-4-7 08:46

学习到了

bj9ye666 发表于 2022-4-7 09:43

crack yyds一看这几个字母就兴奋

lishufeng 发表于 2022-4-7 11:53

skynet929 发表于 2022-4-7 14:11

谢谢分享!!
页: [1]
查看完整版本: CrackMe160学习记录3 AfKayAs.2