xiaoyu2032 发表于 2022-5-3 20:49

练习笔记之160Crackme-009

本帖最后由 xiaoyu2032 于 2022-5-3 20:57 编辑

# 160CM-009

  008太简单了,固定明码字符串,直接一看就知道了,因此跳到009。

## 1.爆破

  先拖到PE中查一下,无壳,VB,请出VB Decompiler,很容易找到函数入口地址以及关键跳转地址(4022CB)。

  OD中将4022CB行的je改成jnz即可爆破成功。


## 2.算法

  根据VB Decompiler反编译出来的VB代码,其中有的VB函数不是很确定的话,百度一下也就搞定了,可以很方便的得出算法的C代码。

``` Cpp
char str1;
int i,m,code;
double f;
printf("请输入用户名:");
    scanf_s("%s",str1,30);
m=0;
for (i=0;i<=strlen(str1);i++)
{
m=m+str1;
}
printf("m为:%d \n",m);
code=m*1234567890;
printf("注册码为:%n \n",code);
```

  输入用户名abc,发现输出结果为-2109260500。呃。。。好像溢出了,把这个结果输入到程序中,发现失败。取出中间值m(294),用计算器算一下结果是362962959660,输入进去还是失败。
  在OD中F8跟踪了一下程序,发现算法中的中间值m计算是没有问题的,后面好像也是乘1234567890的计算,但是这个函数调用过程好像很奇怪,根据函数的参数变量地址,根本找不到对应的运算结果。
  在VB Decompiler中,去掉“程序分析器和优化器”选项,重新反编译一下,得到的反编译代码如下图所示。

  其中可以发现和前面的反汇编结果比较,代码可读性更差了,多出来很多看起来没有用处的变量赋值,而且还有两行代码40222F和402254是前面的反汇编代码里面没有的,好像是前一种反汇编方式有问题,漏掉了部分有用的代码。
  本来想用IDA来分析一下算法,结果IDA中没法直接识别到401FF0这个函数,手动创建函数后,按F5,结果显示“Call analysid failed”,百度了半天,也没找到解决办法,只能放弃。

  重新下载了一个最新的VB Decompiler Pro v11.5,同样反汇编一下,发现和第一次反汇编的结果相比,多出来402254这一行。按这个代码去算一个注册码,发现还是不对。看来还是要到OD里面看看汇编代码,看看到底是怎么回事。

  进入OD里面F8跟踪运行了一遍,发现有点懵圈(懵了整整一上午……)。以前调试跟踪的时候,汇编的函数调用之前,要么通过寄存器、要么通过指针传值,而这个程序里面,虽然套路也差不多,函数调用前push一堆地址进去,调用完成后有一堆数据更新了,但是查查对应地址的数据,前前后后没有一个对得上。
  比如vbaVarMul函数,百度得到的信息是:

__vbaVarMul ;变体变量相乘

``` asm
lea eax,var1
push eax ;被乘数
lea ecx,var2
push ecx ;乘数
lea edx,var3
push edx ;结果
call __vbaVarMul ;变量相乘,在eax中返回
```

  在OD中,对应的代码也类似,而且OD中的右侧的注释中已经自动将var1、var2和SaveTo识别出来了,该函数应该是将var1和var2相乘,结果放入SaveTo位置。但是F8跟踪的时候发现,函数调用前,var1为指针地址12F4AC,指向的变量数值为0x2,var2为指针地址12F434,指向的变量数值为0x3,SaveTo为指针地址12F474,指向的变量数值为0。函数调用后,var1的数值为仍0x2,var2的数值为仍0x3,SaveTo的数值变成了0x5。
  呃……,这哪哪都不对啊。。。

  在整整懵逼了一上午后,终于找到了一篇介绍VB变量体数据类型的文章,文章地址为<https://blog.csdn.net/vbsourcecode/article/details/18662089>。
  根据介绍,一个VB简单Variant(变量体数据)的表示至少需要12个字节。通常前2个字节是表示类型信息的。从第5个字节到第8个字节并不总是使用到,实际上很少被使用。我们不妨先叫它辅助类型信息。从第9个字节开始就是真正的变量的值了。这里有可能存储一个指针值,也可能是数据,具体是什么取决于变量类型。另一个值得注意的事实是VB的内存是以4个字节对齐的。即使你使用一个字节,那至少也要4个字节来表示。而且编译器只初始化它需要的那些字节,剩余的字节可能是随机数据。
==Variant变量的内部表示==

|符号常量    |函数值|数值类型|
|-          |-      |-|
|V_Empty    |0      |Empty(未初始化)|
|V_Null   |1      |Null(无有效数据)|
|V_Integer|2      |整数|
|V_Long   |3      |长整数|
|V_Single   |4      |单精度浮点数|
|V_Double   |5      |双精度浮点数|
|V_Currency |6      |货币值|
|V_Date   |7      |日期|
|V_String   |8      |字符串|
|V_Object   |9      |对象|
|V_Error    |10   |错误值|
|V_Boolean|11   |布尔值|
|V_Variant|12   |Variant(只与变体中的数组一起使用)|
|V_Object   |13   |数据访问对象|
|V_Byte   |17   |位值|
|V_Array    |8192   |数组|

  根据上述内容,实际抓了两个数据案例如下:

|地址|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|
|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
|0012F4AC|05| 00| 00| 00| E8| F4| 12| 00| 00| 40| 77| 92| 5A| 73| 65| 42|

  这表示一个双精度浮点数,1-2字节05表示类型的数值,9-16字节为4265735A92774000,表示浮点数737037030330。3-4和5-8意义不明。

|地址|1|2|3|4|5|6|7|8|9|10|11|12|
|-|-|-|-|-|-|-|-|-|-|-|-|-|
|0012F434|03 |00 |00 |00 |01 |00 |00 |00 |D2 |02 |96 |49|

  这表示一个长整型,1-2字节03表示类型的数值,9-12字节为499692D2,表示整型1234567890。3-4和5-8意义不明。
  回头再看一下VB Decompiler去掉“程序分析器和优化器”选项后反汇编的结果,终于明白那些看起来没有任何意义的赋值语句怎么来的了,OD调试也终于可以跟踪到正确的数据了。根据vbaVarMul后面的指令,可以看出是执行了两次vbaMidStmtVar函数,分别将字符串中第4个字符和第9个字符替换成“-”,这样就得到了最终的注册吗。

  最终得到注册码计算程序如下:

``` Cpp
#include "stdafx.h"
#include <Windows.h>
#include<stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
char str1,code;
int i,m;
double f;
printf("请输入用户名:");
scanf_s("%s",str1,30);
m=0;
for (i=0;i<=strlen(str1);i++)
{
m=m+str1;
}
printf("m为:%d \n",m);
f=double(m)*double(1234567890);
sprintf_s(code,"%.0f",f);
code= 45;       //ASCII "-"
code= 45;       //ASCII "-"
printf("注册码为:%s \n",code);
system("pause");
return 0;
}
```

  运行后,输入用户名abc,得到注册码

  将结果输入程序,注册成功!


## 3.总结

  这次破解碰到了一个未接触过的变量体数据类型,在没搞清楚这种数据类型的特点时,完全不知道如何下手。搞清楚以后问题迎刃而解,但是这种数据类型相对来说还是会增加一些跟踪难度(无法直接看到变量数据,需要自己去内存中查找)。

- 变量体数据类型可以表示各种数据类型,使用变量体函数进行处理时,不需要手动转换数据类型。比如vbaVarMul的运算结果是双精度浮点数,vbaMidStmtVar运算时就自动变成了字符串(整型转字符串)。
- 逆向时碰到的一些常用的VB函数如下:

|函数|功能|
|-|-|
|rtcMidCharVar| 从字符串中取相应字符,对应VB中的MID函数,用法为:MID("字符串","开始的位置","取几个字符")|
|rtcAnsiValueBstr|取字符的ASCII码数值,对应函数 Asc(string)|
|vbaLenVar|获得一个字符串的长度,与vbaLenBstr功能类似,只是对应的字符串为变量体数据类型|
|vbaVarForInit|for循环起始,参数为变量体数据类型|
|vbaVarForNext|循环结构的Next,每次执行时计数加步长,参数为变量体数据类型|
|vbaStrVarVal|从变量体字符串指定位置上获取字符串(非变量体类型),从str1中取arg开始的字符串,结果返回eax|
|vbaVarAdd|变量体类型的两数相加,var1+var2,结果返回var3|
|vbaVarMul|变量体类型的两数相乘,var1 * var2,结果返回var3|
|vbaVarTstEq|变量体类型的比较,结果返回ax|
|vbaMidStmtVar|从字符串中取相应字符,与rtcMidCharVar类似,不过操作对象为变量体|
|vbaVarMove|变量体类型的赋值,将var1赋值给var2|

- 第一次碰到IDA中F5无法生成伪代码的情况,没有找到解决办法。
- 发现VB Decompiler反编译有时会出现问题,有时候要把“程序分析器和优化器”选项去掉去排查。另外,不同版本的VB Decompiler结果也有不同,比如VB Decompiler V11.5去掉“程序分析器和优化器”选项后反编译的结果如下图,其中存在var_A4先使用再赋值“-”的情况。这个是编译器翻译的问题,就后续机器翻译一样,有时候翻出来的句子比较奇怪的时候,还是需要取查看一下原文(汇编代码)去确认一下准确含义。

92013 发表于 2022-5-3 22:28

谢谢分享~~

snakenba580 发表于 2022-5-4 07:21

谢谢分享,正在学习中,加油

5853687 发表于 2022-5-4 12:31

谢谢大佬的分享,正在学习中,加油

SB2500 发表于 2022-5-4 14:00

5853687 发表于 2022-5-4 12:31
谢谢大佬的分享,正在学习中,加油

谢,大佬分享

catprince 发表于 2022-5-4 21:43

学习一下,有时间研究一下

feiyang1 发表于 2022-5-5 02:45

学到了一些新的知识和思路,谢谢楼主

ljdog 发表于 2022-5-5 09:37

不会用,还是有空要学习才行

lmjxf 发表于 2022-5-6 22:11

谢谢分享
页: [1]
查看完整版本: 练习笔记之160Crackme-009