首页
社区
课程
招聘
从crackme程序中接触VB文件以及加密算法
2022-4-6 15:46 6698

从crackme程序中接触VB文件以及加密算法

2022-4-6 15:46
6698
目录
1、Visual Basic文件特征
2、查看serial值
3、分析生成serial的算法
4、整理加密方法以及脚本实现


一、Visual Basic文件特征

1.1、 VB专用引擎

VB文件使用名为MSVBVM60.dll的VB专用引擎。举个VB引擎的例子,显示消息框时,VB代码中要调用MsgBox()函数。其实,VB编辑器真正调用的是MSVBVM60.dll里的rtcMsgBox()函数,在函数内部通过调用user32.dll里的MessageBox()函数来工作。

1.2 、本地代码与伪代码

根据使用的编译选项不同,VB文件可以编译为本地代码与伪代码。本地代码使用方便调试器解析的IA-32指令;而伪代码是一个解释器语言,它使用由VB引擎实现虚拟机并可自解析的指令。

1.3 、事件处理程序

VB主要用于编写GUI程序。因为VB程序采用Windows操作系统的事件驱动,所以用户代码存在于各个事件处理程序之中。

1.4、未文档化的结构体

VB使用的各种信息以结构体形式存在于文件内部。

二、查看serial值

运行OD,打开abex'crackme #2.exe。执行程序后,首先调用的VB引擎的主函数ThunRTMain()。

EP的地址为00401238。00401238地址处的PSUH指令用来把RT_MainStruct结构体的地址(00401E14)压入栈。

然后40123D地址处的CALL 00401232指令来调用401232处的指令(跳转到主函数ThunRTMain())前面压入栈的值作为主函数的参数。

先运行abex'crackme #2.exe看看具体体现。可以看到输入错误的数据,会提示Nope,this serial is wrong!这就有捷径了啊。

这里本来想要查看字符串的方法需要定位到关键位置,但是我在使用OD下断点,然后运行之后就卡壳(不能进行任何操作,于是放弃这个方法,决定一步一步的调试到指定位置)。卡壳如下,有知道原因的师傅请指导一下:

重新调试。直接F8执行00401238 push abexcrac.00401E14 ,可以看到数据已经被压入右下角栈窗口,不要问为什么不F7,因为F7直接进入函数内部,太繁琐了。

再F8执行0040123D处的指令,熟悉的窗口再次出现

随便输入一串数字,点击check。如果不下断点就会弹出上面的错误提醒。这里在00403324处下了一个断点,目的是让程序停留在这里。

那么为什么是停留在这里呢,我们在这个地址后面可以看见一个Yep,this key is right!,再往下面看可以看见,

可以看见Nope,this serial is wrong!。那么可以推断这两个就是输入数据之后弹出的提醒。那么要想二选一,在它们的前面必然会有一个判断语句。向上面看,可以发现两个push指令,可以猜测这就是我们输入的数据。这也是在00403324下断点的原因。接下来执行这两条push指令,执行之前先记录一下右上角寄存器窗口的数据

然后依次执行两条push指令

push edx
push eax

执行之后,从栈窗口可以看见两个熟悉的值

执行完后,选中push edx右击选择follow in dump->Implicit stack address。可以看到下方的数据窗口有变化,但是为乱码。

在数据窗口右击选择Long->Address with ASCII dump转换数据窗口的查看形式

然后在数据窗口跳转到EDX的地址处,可以看到两个值,一个是我们前面输入,那另一个就是正确的序列值

输入D6C9DAC9验证,成功

但是当name的值发送改变后,验证就无法通过。说明serial是以name的值为基础进行变化的

三、分析生成serial的算法

既然输入正确的serial值会弹出Yep,this key is right!字符串提示,那么在字符串出现之前会有一个条件判断语句来决定如何进一下操作。那么可以在Yep,this key is right!字符串的上方代码区域里寻找条件转移的语句。

如图,在403332地址处发现转移语句。

那么可以推测上图中的条件转移代码属于某个函数。这个函数大概就是check按钮的事件处理程序。原因在于点击check按钮后,该函数就会被调用,并且在这个过程中会出现成功/失败的消息框。

接下来,在条件语句的上面继续查看,会发现图中所示的代码。在402ED0处的命令是一个典型的栈帧代码,在开始执行函数时就会形成栈帧。由此得出此处就是函数开始部分。

同时在402ED0上面有一段区域存在着nop指令(00402EC5-00402ECF)。这个区域为VB文件的特性——函数之间存在nop指令

生成序列码的方法有以下的特点:

1、读取Name字符串

2、启动循环,对字符串进行加密(xor,add,sub等)

在402ED0处下断点进行调试,当调试完00402F98处的call之后,可以看到存储在EBP-0X88(0012F488)处的reverse字符串。

注意:

在VB文件中,字符串使用字符串对象,在OD的默认查看模式下,很难认出实际字符串。要想实现下图的效果需要将OD的Dump窗口更改为Long-Address with ASCII dump模式。

加密循环(00403197-004032A0)


加密方法

输入的Name字符串为“reverse”

当执行到004031F6处,从name字符串中获取第一个字符r

从004031F0调试到0040323D之后,查看一下栈

再查看ECX的内存地址

查看EDX的内存地址,发现name字符串的首字符ASCII值R(十六进制值72转换成十进制值为114,对应的ascii值为r)。

执行如下函数,将加密后的值存储到ECX寄存器所指的缓冲区

00403243   .  FF15 AC104000 call dword ptr ds:[<&MSVBVM60.__vbaVarAd>;  msvbvm60.__vbaVarAdd

此时的栈内存地址如下。计算结果D6是原值72("r")加上密钥64生成的值。


下面的框中的代码将数字D6转换成字符串D6

下面代码将生成的字符串连接起来

循环,生成最终的序列号

四、整理加密方法以及脚本实现

加密方法整理如下:

1、从输入的name字符串中读取前四个字符
2、将读取的字符一一转换成数字
3、变换后的数字加64
4、再将与密钥64相加的数字转换成字符
5、连接变换的字符

java脚本如下:

public class Decrypt {
    public static void main(String[] args){
        String str = "orange";
        for(int i = 0;i<4;i++){

            int s = str.charAt(i)-0;
            s = s+100;
            String hex_str = Integer.toHexString(s);
            hex_str = hex_str.toUpperCase();
            System.out.println(hex_str);
        }
    }

结果为:

验证成功:



[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2022-4-10 13:49 被顾忧编辑 ,原因:
上传的附件:
收藏
点赞2
打赏
分享
最新回复 (5)
雪    币: 17850
活跃值: (59913)
能力值: (RANK:125 )
在线值:
发帖
回帖
粉丝
Editor 2022-4-7 20:58
2
0
将abex'crackme #2.exe也上传到论坛一份?
雪    币: 1473
活跃值: (1654)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
顾忧 2022-4-10 13:50
3
0

已上传至文章附件

最后于 2022-4-10 13:52 被顾忧编辑 ,原因:
雪    币: 1473
活跃值: (1654)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
顾忧 2022-4-10 13:57
4
0
Editor 将abex'crackme #2.exe也上传到论坛一份?
已上传至文章附件
雪    币: 209
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
晓宇 2023-12-22 01:01
5
0
www
雪    币: 31931
活跃值: (7105)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2023-12-22 07:22
6
0
还以为到ida微代码中去扣,结果是自己手写的
游客
登录 | 注册 方可回帖
返回