首页
社区
课程
招聘
VB程序分析方法及修改例 (“万能分析断点”、启动form修改,form隐藏)[原创]
发表于: 2006-6-30 19:42 18325

VB程序分析方法及修改例 (“万能分析断点”、启动form修改,form隐藏)[原创]

2006-6-30 19:42
18325

VB程序分析方法及修改例 (“万能分析断点”、启动form修改,form隐藏)

VB程序的分析一直较为麻烦。用OD打开VB程序后,光标停在程序入口点,如下所示:
00406BDC > $  68 20614600   push    00466120
00406BE1   .  E8 EEFFFFFF   call    <jmp.&MSVBVM60.#100>
按F8键也不能实现步进跟踪,程序直接进入程序界面。
进入程序界面后,对于按钮事件可设置按钮事件断点来确定按钮事件的入口点。但对于程序启动时的初始过程就难以跟踪,同时程序中除了一些按钮外,还有一些lable事件(即点一个label后,执行一段程序)很难用事件断点来断。
为了能跟踪程序启动时在formload中执行的一些初始化操作,以及对每一个动作(按钮动作、label点击动作)等全部进行跟踪,可以采用以下笨办法:

找到以下结构的跳转语句:注意,关键特征是在sub     dword ptr [esp+4],后有JMP,而且这种语句总是好多组在一起的。
00467600   .  816C24 04 37000000    sub     dword ptr [esp+4], 37
00467608   .  E9 03313B00           jmp     0081A710
0046760D   .  816C24 04 3B000000    sub     dword ptr [esp+4], 3B
00467615   .  E9 06323B00           jmp     0081A820
0046761A   .  816C24 04 4B000000    sub     dword ptr [esp+4], 4B
00467622   .  E9 E9323B00           jmp     0081A910
00467627   .  816C24 04 4F000000    sub     dword ptr [esp+4], 4F
0046762F   .  E9 2C413B00           jmp     0081B760
00467634   .  816C24 04 43000000    sub     dword ptr [esp+4], 43
0046763C   .  E9 DF413B00           jmp     0081B820
00467641   .  816C24 04 43000000    sub     dword ptr [esp+4], 43
00467649   .  E9 D25A3B00           jmp     0081D120
0046764E   .  816C24 04 47000000    sub     dword ptr [esp+4], 47
00467656   .  E9 755B3B00           jmp     0081D1D0

在程序开头部分,有不少这样的结构JMP,注意在不连续的地方可能都会找到这种结构的JMP(估计是一个FORM中的事件放在一起,不同的FORM就放在不同的地方了)。

接下来就是有点耐心,将这种结构跳转的JMP全部设置断点。

好了。接下F9吧。程序的每一步都在你的掌控中了。

实例1:改变程序启动时显示的FORM的顺序:

一个学习软件,启动时要先选择用户,然后才能进入学习。它设计的目的是这个软件在同一台电脑上可由不同的人用来学习,每人的学习记录分别保存。
但一般情况下,这台电脑也就是自己用这个软件来学习,因此,改造一下,让它启动后直接进入学习界面。

好,动手!

对每一个sub     dword ptr [esp+4], + JMP结构的JMP全部设置断点。
按下F9,一步一步跟踪,看那一步执行后显示用户选择界面,然后按下用户确定键后,程序停在那里:

.
46B2CD jmp 7A2156     在此按F9后,显示用户选择界面
.
.

46B2D8 jmp 7A2290     选择用户后,停在此处。在此按F9后,显示学习界面
.
.
就在这里下手:
将46B2CD jmp 7A2156     改为 jmp 7A2290

重新启动一下,哈哈,直接进入学习界面。

需要注意的是,这种修改启动form的方法不一定能全部成功,因为可能会跳过一些初始化过程,因而造成后面的程序不能正常运行。

实例2:让程序实现自己注册,你都不用输入什么,按注册键后,程序自己将正确的注册码写入注册文件

对上面说到的学习软件进行分析,发现它竟采用明码方式显示注册码的字符串。而且输入注册码后,不管注册码是否正确,都写入注册文件。

思路:在获得输入假码的地方,换为程序自己生成的真码。这样程序就自动将真码写入注册文件了。

动手:按“注册”后,程序停下,按F8跟踪:(注意这个“注册”按钮不是按钮,只是一个label,一般用按钮事件方法不能断下来)

00765F71   .  8B35 C4608900 mov     esi, [8960C4]
00765F77   .  8D4D CC       lea     ecx, [ebp-34]
00765F7A   .  51            push    ecx
00765F7B   .  56            push    esi
00765F7C   .  8B06          mov     eax, [esi]
00765F7E   .  FF90 04070000 call    [eax+704]       关键CALL,根据机器码生成注册码明码
00765F84   .  8B45 D4       mov     eax, [ebp-2C]   F8执行这一句后,EAX寄存器中显示出注册码了
00765F87   .  8945 E8       mov     [ebp-18], eax

好了,按F9,显示注册界面。
输入假码。
按“注册”按钮(这个是真的按钮了)。程序停下,按F8跟踪:

007E7919   .  FF15 6C104000 call    [<&MSVBVM60.__vbaHresultCheckObj>;  MSVBVM60.__vbaHresultCheckObj
007E791F   > \83EC 10       sub     esp, 10
007E7922   .  8B45 E8       mov     eax, [ebp-18]   F8执行这一句后,EAX寄存器中显示出办入的假码  这就是关键点了。
007E7925   .  8BD4          mov     edx, esp
007E7927   .  B9 08000000   mov     ecx, 8

哈哈,以上两段代码都是将注册码放入EAX!

动手:对007E791F处的代码修改如下:
007E7919   .  FF15 6C104000 call    [<&MSVBVM60.__vbaHresultCheckObj>;  MSVBVM60.__vbaHresultCheckObj
007E791F   >  E9 4CE60A00   jmp     00895F70    跳去新增的代码,生成真注册码
007E7924      90            nop
007E7925   >  8BD4          mov     edx, esp
007E7927   .  B9 08000000   mov     ecx, 8
.
.
.

在程序最后的空白处增加以下代码:
00895F70   > \56            push    esi
00895F71   .  8B35 C4608900 mov     esi, [8960C4]
00895F77   .  8D4D CC       lea     ecx, [ebp-34]
00895F7A   .  51            push    ecx
00895F7B   .  56            push    esi
00895F7C   .  8B06          mov     eax, [esi]
00895F7E   .  FF90 04070000 call    [eax+704]         调用注册码生成
00895F84   .  8B45 D4       mov     eax, [ebp-2C]     生成的真码放入EAX
00895F87   .  8945 E8       mov     [ebp-18], eax
00895F8A   .  5E            pop     esi
00895F8B   .  83EC 10       sub     esp, 10
00895F8E   .^ E9 9219F5FF   jmp     007E7925          返回原程序段,此时真码就已放入EAX了

嘿嘿!重新启动程序看看:是不是“未注册”已变为“已注册”,所有的限制已取消了。

注:这个软件的新版已不再采用生成明码注册码的方式了。这个老版留做记念。

实例3:改变程序启动form顺序,隐藏一些form(用VBExplorer配合)

还是前面的程序,增加自己注册功能后,想做成个专门的注册程序,不需要什么学习界面。
按实例1方法,在进入学习界面后,点“注册”,停在了下面:

46FF5D jmp 7F2BC2     在此按F9后,显示注册界面。

好了,按实例1中找到的启动画面显示处,进行修改:

将:46B2CD jmp 7A2156   修改为 jmp  7F2BC2

不好,怎么启动程序后,不仅显示了注册界面,还显示了用户选择界面,想了多种跳转修改,还是要显示用户选择。
郁闷!

先是自己用VB做了两个FORM,一个是可显示的,一个的显示属性设置为隐藏。然后分析两个form的数据结构,发现隐藏的form数据结构中的数据多了几个数据。看来想修改用户选择界面form的隐藏属性是不太可能了(因为要增加数据项)。

这下动用VBExplorer了。
用VBExplorer打开程序,找到用户选择的form,查看它的属性,将top 设置为-5,left设置为-5,height设置为1,width设置为1,将窗口显示方式设置为manual,存盘。

再启动程序,嘿!这个用户选择界面终于消失了(它只是1*1大小,而且是放在了左上角显示器之外了,当然看不见了 ^D^)

附实例4:利用VBExplorer改变程序对像放置位置

奇迹智能英语用来背单词还是很优秀的,但原版程序有个BUG:一启动就将系统音量调整到最大。真是很烦人的。

这个好办,找到启动时设置音量的代码,nop就行了。
但剩下的问题还有:程序音量调整按钮的音量指示还在音量最大处,想调音量时,一点指示器,音量又调到最大了。看来需要将这个指示器的初始位置调整一下了:

用VBExplorer打开程序,找到用于音量指示的image,将其left属性调整到一个适当值即可。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (32)
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢你的文章,我应好好学习!
2006-6-30 21:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
楼主好文章,谢谢分享
2006-6-30 21:38
0
雪    币: 417
活跃值: (475)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
4
收藏学习!
2006-6-30 21:38
0
雪    币: 202
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wdx
5
学习,谢谢
2006-6-30 21:40
0
雪    币: 191
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
第一种方法,我试过,有很多软件是拦不下的。
其他,学习!!!
2006-6-30 21:51
0
雪    币: 239
活跃值: (77)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
7
最初由 老头 发布
第一种方法,我试过,有很多软件是拦不下的。


不知道你指的具体是什么软件,具体是什么事件断不下来。有时间的话,我也可以看看分析分析,当学习提高的机会了。
这里提到的方法也是我分析新概念英语学习机和奇迹智能英语记忆这些VB程序时摸到的方法。
这个断法,是对VB中的的各种事件进行断下,如果是事件中调用的函数,可能这个就断不下来。这时可用其它方法辅助了。
还有,在JMP下断时,要将全部这种结构的JMP下断。我是用OD将全部内容输出为TXT文件,然后用ultraedit 以[esp+4]为关键词搜索,然后瑞在OD中进行下断。这样保证不会有漏掉的。
2006-6-30 22:31
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
8
提供了一个好思路哦,一直对 VB 头痛
2006-7-1 10:42
0
雪    币: 243
活跃值: (274)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
对用P-CODE处理的VB软件能不能用这种方法?
2006-7-1 11:01
0
雪    币: 191
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
我想请教楼主,如何用OD将全部内容输出为TXT文件?

我是这样做的将全部内容复制到 TXT 文件中,用 ultraedit 也无法找到 [esp+4]的。对吗?

下面的代码,楼主看看,可以中断吗(用[esp+4] 的方法)

工程1:

Private Sub Command1_Click()
Form2.Show
End Sub

工程2:

Private Sub Command1_Click()
MsgBox "11111"
End Sub

该如何找到 [esp+4] ,我怎么没有找到?

好象对用P-CODE处理的VB软件也不能用

2006-7-1 11:48
0
雪    币: 239
活跃值: (77)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
11
OD复制方法:

用OD载入程序后,点右键,选择“复制 / 全选”,然后再选择“复制 / 到文件” ,就将OD界面中的所有内容复制到一个文件了。

需要注意的是,这个文本文件比较大。奇迹智能英语复制出的这个文件有65M之大。

作了个测试:

一个form  load事件,一个text change事件,一个timer事件,一个command事件。
如下所示:
一般情况下,form load, text change, timer事件是很难跟踪的。

Private Sub Command1_Click()
MsgBox "exit"
End
End Sub

Private Sub Form_Load()
MsgBox "form load"
Timer1.Enabled = True
End Sub

Private Sub Text1_Change()
If Text1 = "123" Then
MsgBox "OK"
End If
End Sub

Private Sub Timer1_Timer()
Timer1.Enabled = False
MsgBox "timer off"
End Sub

用OD打开这个程序,查找相关特征码,可找到如下结构的JMP,设置断点后,跟踪,可以得到各个事件的入口:
00401BBC   .  816C24 04 3B0>sub     dword ptr [esp+4], 3B
00401BC4   .  E9 E7000000   jmp     00401CB0                         command1 click
00401BC9   .  816C24 04 330>sub     dword ptr [esp+4], 33
00401BD1   .  E9 EA010000   jmp     00401DC0                         form1 load
00401BD6   .  816C24 04 370>sub     dword ptr [esp+4], 37
00401BDE   .  E9 2D030000   jmp     00401F10                         text1 change
00401BE3   .  816C24 04 3F0>sub     dword ptr [esp+4], 3F
00401BEB   .  E9 B0040000   jmp     004020A0                         timer1

这个说明,这个JMP法基本可以跟到所有的VB事件.
同时,在进行测试时,自定义的function等入口也是在上述的JMP结构中。而且一个form中的所有事件和自定义的函数都是连续放在一起的。如果还有其它的form,则放在另一块地方。

附,测试程序。
上传的附件:
2006-7-3 08:49
0
雪    币: 1316
活跃值: (512)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
12
呵呵,不错,偶要将你的发现写成一段脚本.
2006-7-3 09:00
0
雪    币: 0
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
13
可否把你的目标程序也发上来?谢谢
2006-7-3 09:34
0
雪    币: 1316
活跃值: (512)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
14
按照楼主的文章与test.rar编写的OllyHTML脚本:
(0.5.0.5的OllyHTML插件有BUG,现已更新成0.5.0.6,下面是新的脚本,速度快一些)

<html>
        <head>
                <title>设置VB程序事件处理断点</title>
                <script src="res://OllyHTML.dll/const.js"></script>
        </head>
        <body>
                <table style="font-size:14px;width:100%;height:100%;border-collapse:collapse" cellspacing="0" cellpadding="0" align="center">
                        <tr>
                                <td>
                                        <textarea id="resultArea" style="width:100%;height:100%;" title="双击跳到相应地址的指令" rows="10" ondblclick="gotoAddr()" WRAP="off"></textarea>
                                </td>
                        </tr>
                        <tr style="height:24px">
                                <td align="center">
                                        <input type="button" value="设置断点" onclick="setEventBP()">
                                </td>
                        </tr>                       
                </table>
                <script>
                        function gotoAddr()
                        {
                                var txtRange=document.selection.createRange();
                                var val=parseInt(txtRange.text,16);
                                if(val>0x01000)
                                        app.Analyser.Cpu(val,val,0);
                        }
                        function setEventBP()
                        {
                                resultArea.value="";
                                var lines=new Array();
                                var t=app.Analyser.GetThreadInfo(app.MainThreadID);
                                if(!t)
                                {
                                        alert("请先装入被调试VB程序并让Ollydbg分析完代码!");
                                        return;
                                }
                                var m=app.Analyser.GetModuleInfo(t.Entry);
                                var st=m.CodeBase;
                                var ed=m.CodeBase+m.CodeSize;
                                var addr=st;
                                setOnce();
                                function setOnce()
                                {
                                        window.external.Title="addr:"+window.external.IntToHex(addr)+" found:"+lines.length;
                                        for(var ct=0;ct<100 && addr>0 && addr<m.CodeBase+m.CodeSize;ct++)
                                        {
                                                addr=app.Analyser.FindOP(addr,"816C2404");
                                                if(addr>0)
                                                {
                                                        addr=app.Analyser.GetNextOPAddr(addr,1);
                                                        var dasm=app.Analyser.Disasm(addr);
                                                        if(dasm.CmdType==C_JMP && dasm.JumpAddr>0)
                                                        {                                                                       
                                                                app.BreakPoint.On(addr);
                                                                lines.push(window.external.IntToHex(addr));
                                                        }
                                                }                                               
                                        }
                                        if(addr>0 && addr<m.CodeBase+m.CodeSize)
                                        {
                                                setTimeout(setOnce,100);
                                        }
                                        else
                                        {
                                                window.external.Title="finish! total found:"+lines.length;
                                                resultArea.value=lines.join("\r\n");
                                        }
                                }
                        }
                </script>
        </body>
</html>
2006-7-3 09:52
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
挺好的办法,但是对于一些窗体比较多的软件就头疼了,我遇到一个软件用VBexplor看了又十多个窗体,其中有两个跟注册有关的。
2006-7-3 11:02
0
雪    币: 239
活跃值: (77)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
16
这个是得需要点耐心。奇迹智能英语有21个form呢。
如果是要跟踪form load中的初始化情况,就需要一步一步跟踪。如果是只是跟踪程序中的几个事件,可以先设置断点,然后禁止断点,然后启动程序,在要跟踪前,将断点激活就可以了。

另,请教dreaman:我还不知道OllyHTML脚本怎么用呢。我已装好插件了。但不知道怎么才能用起来。这样用起来的话,设置断点就不用麻烦了。
2006-7-3 12:45
0
雪    币: 1316
活跃值: (512)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
17
1、首先装入被调试程序.

2、点插件菜单的OllyHTML=>Scripts,可以打开我放在网站上的脚本列表,点相应脚本条目后的"运行"就可以执行相应脚本了,这是在线脚本的用法.

3、如果脚本已经保存成本地HTML,则用菜单OllyHTML=>Load=>HTML,选择相应脚本文件,就可以运行脚本了.

4、脚本运行是使用弹出来的一个IE控件容器窗口,点“设置断点”就可以了。

另:
00401BBC   .  816C24 04 3B0>sub     dword ptr [esp+4], 3B
00401BC4   .  E9 E7000000   jmp     00401CB0         command1 click
前一句后面的3B是不是代表什么控件与事件类型之类的,要是能直接识别出是什么样的事件处理就更好了,呵呵。
2006-7-3 18:49
0
雪    币: 181
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
还是没懂  万能断点什么原理
2006-7-3 20:56
0
雪    币: 239
活跃值: (77)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
19
最初由 foretell 发布
还是没懂 万能断点什么原理


其实这个不是什么万能断点,是指的采用对[EBP+4] ~ JMP结构的下断,可能跟踪到所有的VB事件和各种自定义function入口点,便于对程序分析。所以称其为“万能”分析断点。主要是用于对程序分析用的。

另,dreaman:我调入HTM文件后,却显示如下内容?不知有什么问题。
2006-7-4 08:23
0
雪    币: 1316
活跃值: (512)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
20
看起来像是你的HTML文件内容不太正确.我已经将脚本放在网上了,你用OllyHTML=>Scripts,然后点"设置VB程序事件处理断点"条目后的"运行"试试.

或者保存这个附件.
上传的附件:
2006-7-4 09:02
0
雪    币: 239
活跃值: (77)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
21
谢谢 dreaman
我将你的HTML保存到文件后,不知怎么搞的 "<"和">"符号没有了。所以出错了。
2006-7-4 11:58
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
OD有VB万能断点的插件,不用这么麻烦的~~~
2006-7-4 12:57
0
雪    币: 239
活跃值: (77)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
23
dreaman:
用HTML插件设置断点后,有些是没有设置的,不知道是怎么回事。
2006-7-4 13:58
0
雪    币: 1316
活跃值: (512)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
24
能不能把你的这个程序发上来我试一下,我也不太清楚原因.
2006-7-4 15:23
0
雪    币: 191
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
用OllyHTML=>Scripts
为什么我的OD没有这一条,(找不到 OllyHTML)我该如何操作?
2006-7-4 16:25
0
游客
登录 | 注册 方可回帖
返回
//