发新话题
打印

[转载]Visual Basic 6 逆向工程与反逆向工程 第一部分

[转载]Visual Basic 6 逆向工程与反逆向工程 第一部分

信息来源:www.jyyy.com.cn

简介

自从微软公司推出VISUAL BASIC 5/6版本以来,摆脱了前版程序只是单纯调用vbrun*.dll的方式;在继续保留P-code编译同时也引入了native编译方式,使得生成本地二进制代码成为可能。
以下将介绍目前对VB6的反编译研究情况;也将演示如何保护你的VB6程序。(因为VB6逆向工程资料的缺乏,我仅将在目前能得到的资料基础上结合个人研究所得进行演述)。关于vb.net,也就是所谓的“VB7”,其生成的exe程序完全可用.net反编译工具完成,此处不再介绍。


P-code传奇

编译器的编译技术可以分为native-compile(自然编译)与pcode-compile(伪编译)两种。
自然编译是编译器将高级语言转换为汇编代码,并经链接生成EXE程序的过程。
伪编译是编译器将高级语言转换为某种编码后,将能解释、执行此编码的一段程序一同链接,生成EXE程序。
伪代码p-code,最早应该叫做Pascal-Code,其名称起源于一个pascal编译器使用的“中间代码”编译技术。现在一般作为pseudo-code(伪代码),或packed-code(压缩代码)简称。
此项编译技术的出现,最终导致了“虚拟机”的出现。而微软在其编程工具basic、c、vb中都使用了类似的编译技术。
所谓伪代码,其基本工作原理是编译器先把执行程序编译为比80X86机器码紧凑得多的中间代码形式,然后在链接时把一个小工作引擎嵌入执行程序中,最后在运行时由此工作引擎把P-Code解释为本地机器码实际执行,所以叫做packed-code;同时又由于此代码并不是最终的机器码形式,实际上是“变形的源代码”,所以也被称为pseudo-code。依靠P-code编译技术,使得编程语言不依赖于机器或照作平台称为可能。
目前实现伪代码编码方式的最流行方法是在特定硬件系统(比如x86,Mac)上,用基于“堆栈stack”的字节码编码实现。

虽然目前伪代码编译形式大多见于vb,但java,powerbuilder的编译实质也是一样;最新的microsoft visual studio.net中,只是将名称换成“中间语言(Microsoft Intermediate Language)”。(不管怎么解释我还是不能理解IL与p-code的不同。(参考http://windows.oreilly.com/news/hejlsberg_0800.html《Deep Inside C#: An Interview with Microsoft Chief Architect Anders Hejlsberg》))。

因为vb3、4都是使用伪代码编译形式;也因为伪代码编译的代码实际只是“变形的源代码”,所以只要我们能理解其对应机制,就能做出反编译器来,所以Dodi's vb3/4 disassembler来了。同样,java反编译器来了,对付最新microsoft .net的反编译程序也可以被得到。
为什么见不到vb5/6 伪代码反编译器,现在已经有了几个“半个”,就是exdec及建立在其基础上的wkt vb p-code debugger,还有VBDE;2001年有人写出一个vb6 add-in来实现vb6源代码-> P-code转换。第2部分:理解mid()函数

Private Sub Command1_Click()
Dim a, b As String

a = Text1.Text
b = Mid(a, 2, 3)

End Sub


将上述代码用vb6分别编译为native code和P-code

函数原型Mid(string, start[, length])

(1)wdasm反汇编native code

:00401D62 C745A403000000 mov [ebp-5C], 00000003
:00401D69 C7459C02000000 mov [ebp-64], 00000002

* Reference To: MSVBVM60.rtcMidCharVar, Ord:0278h
|
:00401D70 FF153C104000 Call dword ptr [0040103C]


(2) exdec反编译P-code
401A63: 28 LitVarI2: ( local_00E4 ) 0x3 (3)
401A68: f5 LitI4: 0x2 2 (....)
401A6D: 04 FLdRfVar local_0094
401A70: 04 FLdRfVar local_00F4
401A73: 0a ImpAdCallFPR4: rtcMidCharVar



trw2000 vb符号调试初步

我们都知道softice支持符号调试。而很少了解TRW2000也具有自动载入sym符号文件供调试的作用。
为了对Visual Basic 6进行符号调试,首先需要得到msvbvm60.dll及相对应的msvbvm60.dbg调试文件,这些可以从microsoft网站的VB6 SP5升级包中得到。
在你安装softice的目录\Util16下,有2个程序:Dbg2map及msym.exe
dos窗口下命令
c:\..\softice\util16> dbg2map.exe msvbvm60.dbg 生成msvbvm60.map文件
c:\..\softice\util16> msym.exe msvbvm60.map 生成msvbvm60.sym文件

将msvbvm60.sym文件放在trw2000.exe所在目录下,运行trw时会自动载入sym文件。
由此我们可以得到msvbvm50.sym、oleaut32.sym文件并一并载入。当多个sym被载入后可以在trw2000中下命令
sym
来选择当前使用的sym文件。

所以,我们将可以直接用exdec反编译得到的vb pcode助记符设断拦截。也可以在用trw进行跟踪时获得更多的程序信息。

注意:
1. 个人使用后体会,trw2000 1.23版本中,利用vb pcode助记符设断经常会出错,表现在trw不能将助记符正确转换为中断地址。

2. 如此也解决一个问题:exdec反编译后生成的pcode助记符名称是谁定义的?
答案是:微软公司


原有信息:
序 号:239688
标 题:送给SunBird的生日礼物----《如何定位简单的Visual Basic 6.0程序事件代码》。大家比老鸟晚看了3天。 (4千字)
发信人:小楼
时 间:2002-9-23 21:58:22
阅读次数:491
详细信息:

程序下载:http://xixiaolou.myetang.com/vb/vb01.zip


如何定位简单的Visual Basic 6.0程序事件代码

作者:小楼/[CCG]

下文是为看雪新书写作的一部分。本文作者保留对此文章的一切权利。非得到本作者书面授权,任何人不得修改、翻译、转载。

用过DEDE破解delphi程序的人,都很喜欢DEDE可以直接定位、显示具体某个事件,比如Command1.Click事件的起始至结束的反汇编代码。
VBDE对Visual Basic 6.0程序也能如此做到。但是仅仅限于VB6程序。

所以我将展示一种方法,来手工定位。此种方法对于VB5/6程序,不管是Native编译还是P-code编译全部适用,只有少数差异。

注:下文讲述时用到了COM的一些知识。
COM全称Components Object Model,通用组件模型。
想详细了解的可以访问以下链接:http://www.microsoft.com/china/m ... n_drguion020298.htm


我用Visual Basic 6.0编译了一个P-code程序keyup.exe,其中只添加了一个标准控件--Command1;实现一个事件

Private Sub Command1_KeyUp()
Msgbox("ddd")
End Sub


注意,实际上有2个标准控件:form及Command1。

编译为pcode程序keyup.exe后,用wdasm反汇编。
于import table中找到MSVBVM60.EVENT_SINK_AddRef
* Reference To: MSVBVM60.EVENT_SINK_AddRef, Ord:0000h
|
:00401032 FF2508104000 Jmp dword ptr [00401008]

上面就是跳转表一部分,vb事件总是从跳转表进入msvbvm60.dll

用search功能查找“00401032”。有2处

第一处
:004014CC 74144000 DWORD 00401474 // form
:004014D0 E8134000 DWORD 004013E8
:004014D4 2C104000 DWORD 0040102C // QueryInterface
:004014D8 32104000 DWORD 00401032 // addref, 控件出生
:004014DC 38104000 DWORD 00401038 // release, 控件死亡
//上述就是模拟的COM结构V-Table

:004014E0 00000000000000000000 BYTE 10 DUP(0)
:004014EA 00000000000000000000 BYTE 10 DUP(0)
:004014F4 00000000000000000000 BYTE 10 DUP(0)
:004014FE 00000000000000000000 BYTE 10 DUP(0)
:00401508 00000000000000000000 BYTE 10 DUP(0)
:00401512 00000000000000000000 BYTE 10 DUP(0)
:0040151C 00000000000000000000 BYTE 10 DUP(0)
:00401526 00000000000000000000 BYTE 10 DUP(0)
:00401530 00000000000000000000 BYTE 10 DUP(0)
:0040153A 00000000000000000000 BYTE 10 DUP(0)
:00401544 00000000000000000000 BYTE 10 DUP(0)
:0040154E 00000000000000000000 BYTE 10 DUP(0)
:00401558 0000000000000000 BYTE 8 DUP(0)


第二处
:00401560 9C144000 DWORD 0040149C //command1
:00401564 E8134000 DWORD 004013E8
:00401568 2C104000 DWORD 0040102C //QueryInterface
:0040156C 32104000 DWORD 00401032 //addref
:00401570 38104000 DWORD 00401038 //release


:00401574 00000000000000000000 BYTE 10 DUP(0)
:0040157E 00000000000000000000 BYTE 10 DUP(0)
:00401588 00000000 BYTE 4 DUP(0)

:0040158C B8154000 DB 004015B8 //定义keyup事件跳转地址

:00401590 00000000000000000000 BYTE 10 DUP(0)
:0040159A 00000000000000000000 BYTE 10 DUP(0)
:004015A4 00000000000000000000 BYTE 10 DUP(0)
:004015B0 00000000000000000000 BYTE 10 DUP(0)


:004015B8 B838000000 mov eax, 00000038 //跳到这里
:004015BD 663D33C0 cmp ax, C033
:004015C1 BABC184000 mov edx, 004018BC // call地址=004018BC
:004015C6 683E104000 push 0040103E //进入MethcallEngine
:004015CB C3 ret


然后ultraedit打开keyup.exe,定位到 0x004018BC - 0x00400000 = 0x18BC处
0x18BC - word (0x18BC+8) = 0x18BC - 0x002C = 0x1890

所以,call 004018BC后进入00401890开始运行,终止在004018BB附近。这就是pcode代码的事件代码手工定位方法。用exdec反编译后验证正确。(但是我们可以知道这是Command1_KeyUp事件,尽管exdec没有告诉我们。)

Proc: 4018bc
401890: 27 LitVar_Missing
401893: 27 LitVar_Missing
401896: 27 LitVar_Missing
401899: f5 LitI4: 0x0 0 (....)
40189E: 3a LitVarStr: ( local_0094 ) ddd
4018A3: 4e FStVarCopyObj local_00A4
4018A6: 04 FLdRfVar local_00A4
4018A9: 0a ImpAdCallFPR4: 
4018AE: 36 FFreeVar
4018B9: 13 ExitProcHresult

以上就是具体方法的实现。

至于如何明确二进制代码所代表的标准控件的属性、事件含义;弄明白msvbvm60.dll中各个函数(也是vb函数)的结构定义;WKT VB pcode Debugger工作原理等等我将在看雪新书中为大家描述。
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

发新话题