• 标 题:有关VB程序P-CODE代码逆向工程入门浅说
  • 作 者:virtualspace
  • 时 间: 2003年10月13日 08:21
  • 链 接:http://bbs.pediy.com

有关VB程序P-CODE代码逆向工程入门浅说

对于破解初学者来说,可能在调试VB(P-CODE)编写的程序时感到难于分析和跟踪,特别是查找和定位“注册码比较”关键点,以及修补代码等。小弟对VB程序内部构造同样也是一塌糊涂,对破解更是一知半解,和各位初学者一样,只是感兴趣而已。偶尔尝试调试,跟踪个VB程序玩玩,没什么目的。闲着没事,咱就随便扯点个人浅显的经验,仅供和我一样的菜鸟同道参考,让各位高手见笑了。

特别声明:本文仅仅服务于对VB P-CODE程序破解感兴趣的初学者,绝非专业学术研究,不提供任何有关研究分析的科学方法和步骤。

注:如果您仅仅对OLLYDBG调试VB P-CODE感兴趣,请直接参考第4部分。


1.缘起

有天,您正在网上溜达,忽然发现一个感兴趣的共享小程序,想拿来用用,可还没怎么试,它就跟您较劲儿,老是让您注册,烦不烦?咱能受这个限制吗?… 既然玩保护,那咱们就帮作者测试测试保护的强度,呵呵,考验咱们的时候又到了。。。3下5/2, 经过您的火眼金睛一看,原来是个VB(P-CODE)捏把的东东。怎么看出是P-CODE? 方法很多,比如拿WKTVBDE要是能LOAD,我想它就是了,什么?不知道WKTVBDE是什么?那用Exdec反一下,什么,这个也没听说过?那咱们先别往下继续了,您最好先了解一下有关的预备知识,也可以在本论坛搜索相关vb p-code破解案例分析。擅自推荐您参考“FLY”大侠的破解实例。

对手出现了,怎么办?要是我,可能准备如下工具:

VBExplorer (静态分析P-CODE的好东西,又免费,建议作者继续完善,坚持不收费政策50年不变 ^&^ )

WKTVBDE (VB P-CODE动态跟踪调试器,在下一般用它来动态修改代码,判断分析的效果。要想用它真正搞清楚程序的细节,小弟还没有发现好办法,但作为粗略的分析工具,查看程序分支判断,循环次数,它还是蛮好用的。对于分析VB P-CODE,它有如一个大砂轮,先用它磨一磨,精细加工,那是下一个将介绍的工具)

Ollydbg(很不错的调试器,我用1.09D。好在它的兼容性和便捷性,在我的WIN2003 sever上表现很稳定,跟踪,调试VB P-CODE再合适不过了,只可惜不是咱们中国人的产品。在本短文稍后,咱们主要就讨论如何用它跟踪分析VB P-CODE,因为这个步骤也算蛮重要嘛)

还有其它一些可以选择的工具,就看您的个人爱好了,比如:

Exdec vb p-code代码反编译器,不错的工具
Vbparser 1.2 同样是 vb p-code反编译器,不过我用的版本不能反VB 5, 有些vb 6的也不行,不知道是怎么回事。

还有什么好工具希望您告诉我。

2.鬼穷三技

聊斋上说,小鬼儿也没什么可怕的,也就有3招,你知道了,对付它就心里有了底,有了战胜它的信心。话说VB P-CODE程序,咱们这些新手外行如何搞定它呢?咱们也来个3招克敌:

a.静态分析:粗略搞清楚目标程序的大致流程,分支,凭分析结果和编程,破解的经验,判断和假设目标程序的设计思路
b.代码还原:根据p-code伪代码,大致可以还原出VB源程序代码(针对关键和重要的部分,对于破解,就是还原判断有关的和比较注册码前后部分的VB代码)
c.动态跟踪:应用源码级调试器(例如olldbg)跟踪程序的运行细节,发现重要数据,甚至注册码等信息

空口无凭,咱们还是通过一个简单案例来演示一下整个的VB P-CODE逆向过程,如何?

3.循序渐进

为了演示方便,咱们先写一个简单的VB注册小程序,源代码如下(程序未经任何优化,仅用于演示):

Private Sub Text1_Change()
 
  Dim i As Byte
 
  For i = 1 To Len(Text1.Text)
  
  If Mid(Text1.Text, i, 1) > "9" Or Mid(Text1.Text, i, 1) < "0" Then
   
   Text2.Text = "Please enter 0-9, try again"
   GoTo final_end
  End If
  
  Next
 
 If Len(Text1.Text) >= 3 Then
 
  get_1 = CInt(Mid(Text1.Text, 1, 1))
  get_2 = CInt(Mid(Text1.Text, 2, 1))
  get_3 = CInt(Mid(Text1.Text, 3, 1))
  
  get_4 = get_2 + get_3
  
  If get_1 = get_4 Then
  Text2.Text = "good"
  Else
  Text2.Text = "bad"
  End If
 
 End If
 
final_end:
 
End Sub

程序仅仅根据用户输入的数字判断是否符合内定的规则,如果是,显示:good,错误,则提示:bad。程序很简单,您自己看一下就明白了,咱们就不再详细解释了,不耽误您的时间了。

这段小程序对应的P-CODE代码如下(使用VBExplorer获得,相关程序可以从本论坛得到,或联系作者):

[Text1.Change]
:00401B9C  F401                LitI2_Byte           ;Push 01
:00401B9E  FC0D                CUI1I2               ;
:00401BA0  047AFF              FLdRfVar             ;Push LOCAL_0086
:00401BA3  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401BA6  21                  FLdPrThis            ;[SR]=[stack2]
:00401BA7  0F0003              VCallAd              ;Return the control index 02
:00401BAA  1974FF              FStAdFunc            ;

For i = 1 To Len(Text1.Text)

:00401BAD  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401BB0  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401BB5  6C70FF              ILdRf                ;Push DWORD [LOCAL_0090]
:00401BB8  4A                  FnLenStr    ;取得输入串的长度,作为循环的参数
:00401BB9  FC0E                CUI1I4               ;
:00401BBB  2F70FF              FFree1Str            ;SysFreeString [LOCAL_0090];
:00401BBE  1A74FF              FFree1Ad             ;Push [LOCAL_008C];  
:00401BC1  FE626CFFD900        ForUI1      ; 循环开始
:00401BC7  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401BCA  21                  FLdPrThis            ;[SR]=[stack2]
:00401BCB  0F0003              VCallAd              ;Return the control index 02
:00401BCE  1974FF              FStAdFunc            ;
:00401BD1  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text  ;出现这个提示,说明程序中参照了输入框内容
:00401BD4  0DA0000000          VCallHresult         ;Call ptr_004016B8

If Mid(Text1.Text, i, 1) > "9" Or Mid(Text1.Text, i, 1) < "0" Then

:00401BD9  0404FF              FLdRfVar             ;Push LOCAL_00FC
:00401BDC  21                  FLdPrThis            ;[SR]=[stack2]
:00401BDD  0F0003              VCallAd              ;Return the control index 02
:00401BE0  1908FF              FStAdFunc            ;
:00401BE3  0808FF              FLdPr                ;[SR]=[LOCAL_00F8]
***********Reference To:[propget]TextBox.Text
:00401BE6  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401BEB  283CFF0100          LitVarI2    ;Push 数字 1
:00401BF0  FCE07AFF            FLdUI1               ;
:00401BF4  E7                  CI4UI1      ;Push 变量 i
:00401BF5  3E70FF              FLdZeroAd            ; 
:00401BF8  465CFF              CVarStr              ;
:00401BFB  042CFF              FLdRfVar             ;
**********Reference To->msvbvm60.rtcMidCharVar       ;调用了Mid 函数,一般相关的参数在调用前已经入栈,注意上边两个PUSH指令,参数入栈顺序是从右到左,对于MID,既是压入1,i。意思是取从第i个开始的字符,总共取1个。

:00401BFE  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020; 
:00401C03  042CFF              FLdRfVar             ;Push LOCAL_00D4
******Possible String Ref To->"9"    ;表示”9”这个文本字符被引用   
:00401C06  3A1CFF0200          LitVarStr            ;PushVarString ptr_004016CC
:00401C0B  5D                  HardType             ;
:00401C0C  FB700CFF            GtVar                ;
:00401C10  28D4FE0100          LitVarI2 ;Push 数字 1
:00401C15  FCE07AFF            FLdUI1               ;
:00401C19  E7                  CI4UI1   ;Push 变量 i
:00401C1A  3E04FF              FLdZeroAd            ;
:00401C1D  46F4FE              CVarStr              ;
:00401C20  04C4FE              FLdRfVar             ;
**********Reference To->msvbvm60.rtcMidCharVar
:00401C23  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020;
:00401C28  04C4FE              FLdRfVar             ;Push LOCAL_013C
******Possible String Ref To->"0"
:00401C2B  3AB4FE0300          LitVarStr ; 表示”0”文本字符串被引用
:00401C30  5D                  HardType             ;
:00401C31  FB63A4FE            LtVar                ;
:00401C35  FB1F94FE            OrVar     ; or 另一个条件
:00401C39  FF1B                CBoolVarNull         ;vbaBoolVarNull
:00401C3B  29040074FF08FF      FFreeAd              ;
:00401C42  360C005CFF3CFF2C    FFreeVar             ;Free 000C/2 variants
:00401C51  1CD000              BranchF   ;比较指令,
******Possible String Ref To->"Please enter 0-9, try again"

Text2.Text = "Please enter 0-9, try again"        ;如果输入字符无效,提示重新输入

:00401C54  1B0400              LitStr               ;Push ptr_004016DC
:00401C57  21                  FLdPrThis            ;[SR]=[stack2]
:00401C58  0F0803              VCallAd              ;Return the control index 04
:00401C5B  1974FF              FStAdFunc            ;
:00401C5E  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propput]TextBox.Text
:00401C61  0DA4000000          VCallHresult         ;Call ptr_004016B8
:00401C66  1A74FF              FFree1Ad             ;

GoTo final_end

:00401C69  1E1002              Branch               ;ESI=00401DAC
:00401C6C  047AFF              FLdRfVar             ;Push LOCAL_0086

Next

:00401C6F  FE786CFF2B00        NextUI1       ; 循环部分中止
:00401C75  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401C78  21                  FLdPrThis            ;[SR]=[stack2]
:00401C79  0F0003              VCallAd              ;Return the control index 02
:00401C7C  1974FF              FStAdFunc            ;

If Len(Text1.Text) >= 3 Then

:00401C7F  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text      
:00401C82  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401C87  6C70FF              ILdRf                ;Push DWORD [LOCAL_0090]
:00401C8A  4A                  FnLenStr     ; 输入字符串长度
:00401C8B  F503000000          LitI4        ;常数3用于比较
:00401C90  E0                  GeI4                 ;
:00401C91  2F70FF              FFree1Str            ;SysFreeString [LOCAL_0090]; 
:00401C94  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; 
:00401C97  1C1002              BranchF      ;比较判断

get_1 = CInt(Mid(Text1.Text, 1, 1))

:00401C9A  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401C9D  21                  FLdPrThis            ;[SR]=[stack2]
:00401C9E  0F0003              VCallAd              ;Return the control index 02
:00401CA1  1974FF              FStAdFunc            ;
:00401CA4  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401CA7  0DA0000000          VCallHresult         ;
:00401CAC  283CFF0100          LitVarI2        ; Push 1 参数,用于MID函数 取几个字符
:00401CB1  F501000000          LitI4           ;Push 1 参数,用于MID函数
                                                        ;表示 从哪个字符位置开始取
:00401CB6  3E70FF              FLdZeroAd            ;Push DWORD [LOCAL_0090]; 
:00401CB9  465CFF              CVarStr              ;
:00401CBC  042CFF              FLdRfVar             ;Push LOCAL_00D4
**********Reference To->msvbvm60.rtcMidCharVar          ;mid函数调用
                               |
:00401CBF  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020; check stack 0010; Push EAX
:00401CC4  042CFF              FLdRfVar             ;Push LOCAL_00D4
:00401CC7  FC45                FnCIntVar            ;vbaI2ErrVar
:00401CC9  441CFF              CVarI2               ;
:00401CCC  FCF684FE            FStVar               ;
:00401CD0  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call  
:00401CD3  3608005CFF3CFF2C    FFreeVar             ;Free 0008/2 variants

get_2 = CInt(Mid(Text1.Text, 2, 1))

:00401CDE  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401CE1  21                  FLdPrThis            ;[SR]=[stack2]
:00401CE2  0F0003              VCallAd              ;Return the control index 02
:00401CE5  1974FF              FStAdFunc            ;
:00401CE8  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401CEB  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401CF0  283CFF0100          LitVarI2             ;PushVarInteger 0001
:00401CF5  F502000000          LitI4                ;Push 00000002
:00401CFA  3E70FF              FLdZeroAd            ;Push DWORD [LOCAL_0090]; 
:00401CFD  465CFF              CVarStr              ;
:00401D00  042CFF              FLdRfVar             ;Push LOCAL_00D4
**********Reference To->msvbvm60.rtcMidCharVar
:00401D03  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020;
:00401D08  042CFF              FLdRfVar             ;Push LOCAL_00D4
:00401D0B  FC45                FnCIntVar            ;vbaI2ErrVar
:00401D0D  441CFF              CVarI2               ;
:00401D10  FCF674FE            FStVar               ;
:00401D14  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 
:00401D17  3608005CFF3CFF2C    FFreeVar             ;Free 0008/2 variants

get_3 = CInt(Mid(Text1.Text, 3, 1))

:00401D22  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401D25  21                  FLdPrThis            ;[SR]=[stack2]
:00401D26  0F0003              VCallAd              ;Return the control index 02
:00401D29  1974FF              FStAdFunc            ;
:00401D2C  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401D2F  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401D34  283CFF0100          LitVarI2             ;PushVarInteger 0001
:00401D39  F503000000          LitI4                ;Push 00000003
:00401D3E  3E70FF              FLdZeroAd            ;Push DWORD [LOCAL_0090]; 
:00401D41  465CFF              CVarStr              ;
:00401D44  042CFF              FLdRfVar             ;Push LOCAL_00D4
**********Reference To->msvbvm60.rtcMidCharVar
:00401D47  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020; check stack 0010; Push EAX
:00401D4C  042CFF              FLdRfVar             ;Push LOCAL_00D4
:00401D4F  FC45                FnCIntVar            ;vbaI2ErrVar
:00401D51  441CFF              CVarI2               ;
:00401D54  FCF664FE            FStVar               ;
:00401D58  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 
:00401D5B  3608005CFF3CFF2C    FFreeVar             ;Free 0008/2 variants

get_4 = get_2 + get_3

:00401D66  0474FE              FLdRfVar      ;Push 变量1 用于相加
:00401D69  0464FE              FLdRfVar      ;Push 变量2 用于相加
:00401D6C  FB945CFF            AddVar               ;
:00401D70  FCF654FE            FStVar               ;

If get_1 = get_4 Then

:00401D74  0484FE              FLdRfVar      ;Push 变量1 用于比较
:00401D77  0454FE              FLdRfVar      ;Push 变量2 用于比较
:00401D7A  FB33                EqVarBool            ;
:00401D7C  1CFB01              BranchF       ;比较判断结果
******Possible String Ref To->"good"

Text2.Text = "good"                                   ;正确

:00401D7F  1B0500              LitStr               ;Push ptr_00401718
:00401D82  21                  FLdPrThis            ;[SR]=[stack2]
:00401D83  0F0803              VCallAd              ;Return the control index 04
:00401D86  1974FF              FStAdFunc            ;
:00401D89  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propput]TextBox.Text
:00401D8C  0DA4000000          VCallHresult         ;Call ptr_004016B8
:00401D91  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 

Else
  Text2.Text = "bad"

:00401D94  1E1002              Branch               ;ESI=00401DAC
******Possible String Ref To->"bad"
:00401D97  1B0600              LitStr               ;Push ptr_00401728
:00401D9A  21                  FLdPrThis            ;[SR]=[stack2]
:00401D9B  0F0803              VCallAd              ;Return the control index 04
:00401D9E  1974FF              FStAdFunc            ;
:00401DA1  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propput]TextBox.Text
:00401DA4  0DA4000000          VCallHresult         ;Call ptr_004016B8
:00401DA9  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 
:00401DAC  13                  ExitProcHresult      ;
:00401DAD  0000                LargeBos             ;IDE beginning of line 

注意:以上伪码中提示的VB源代码行,可能并不是精确的定位,仅是小弟凭经验加入的,仅供参考。由于在下对P-CODE以及VBExplorer都不甚了解,许多伪代码的含义,以及其在VBExplorer中给出的注释,都不能明了个中的含义,还望了解者指点,多谢。

不论如何,根据P-CODE代码,我们可以大致分析出粗略的程序流程,变量的使用和定位并不一定精确,许多还要凭您的破解经验和编程经验。但是,这个粗略的分析可以帮助我们模拟出大致的VB源代码。

在反向出粗略的VB源代码的过程中,您要不断将您写出的VB代码编译后P-CODE代码与源程序反编译后的P-code代码进行比对,尽量使其一致,至少看上去相似。这个过程需要您花些时间了,您要假设,如果你就是作者,你会如何写,特别是变量的运用,类型的定义,编程的习惯以及经验等。这个过程在不断的进行中,会使你逐渐积累更多有益的经验,不知不觉中,你就会有一种“感觉”,以前,那个台湾写破解教程的老兄说这个叫“触机”,大概对应的英文词是“sense”。总之,您就是知道了,似乎一下就明白了,原来做这个程序的老兄是这样的,是这个意思。好了,下一步就是验证我们的思路是否真的就是对的了。


4.着法宝

通常,我们可以用WKTVBDE跟踪程序P-CODE,看看它在关键部分的循环,分支走向,在某些关节点(P-CODE伪代码,或者是某个VB函数调用上)设断点,这样,基本上可以将我们模拟出来的VB源代码中大的框架构造搞清楚,设定好基本的分支条件。那么,到底在程序的细节实现上,哪里使用了哪些变量,关键的比较点,比较的变量值是怎样计算得到的,还有什么隐藏的花招,以及一些细节的东西?为了快速获得有益的信息,我们还是应该通过OLLDBG这样的实时调试器去观察分析。

在应用OLLDBG调试VB P-CODE代码时,我们应该注意几点:

一般VB中的使用的局部变量位置在内存中是不确定的,这次调试和上次调试的同一变量位置基本是不同的,是动态产生的,所以,不要象调试其他C编译或汇编程序那样,下一个固定的内存断点去发现某些变量的变化(仅仅是个人意见,不一定对)。

VB P-CODE编译的程序运行时,在主要流程中,通常ESI寄存器指向相应的VB p-code伪代码。 所以,调试时,最好同时打开相应程序的P-CODE伪代码(例如运行VBExplorer,并打开相应的程序。为了便于分析,可以是同样程序的拷贝副本),以供参考,查看程序的实际流程。

通常,vb 程序运行在虚拟机(MSVBVM60.DLL)中 ,因此,当您使用OLLDBG打开一个vb p-code程序后,应该在菜单中选择“view”选项,然后再进入选择“Executable modules”, 并在其中的“MSVBVM60”行上,点击鼠标右键,然后选“view name”。如此,可以直接查看VB运行库中的函数名,查找有关的函数名,在常用的函数名上点击,并设置断点。

例如:在rtcMidCharVar上设置断点:
在我得机器上是:7352B403 > 55    PUSH EBP

例如:设置条件断点 esi = = 401BEF ;ESI指向的P-CODE代码,应该是你在分析目标程序后,认为重要的调用了MID函数的位置。参考上面的演示程序,我们假定要查看两个MID函数被调用的位置,这两个位置可能是:
语句If Mid(Text1.Text, i, 1) > "9" Or Mid(Text1.Text, i, 1) < "0" 中的两个调用了MID的地方(p-code代码的相对位置):00401BFE 和 00401C23(VBExplorer 中看到的)

当程序中断在您设置的断点后,你可以逐步跟踪程序了,为了把握住程序的流向,您要时刻关注ESI值的变化,它通常在40xxxx范围内,它明确地指向VB P-CODE伪代码的流向,你不用担心不知道自己所在的位置。你可以随时切换到VBExplorer中,看看程序到底跑到哪里去了。

在您调试的过程中,您会发CALL AX,应该单步跟进去,它通常会带你返回那个正被调试的VB程序主域(或叫“领空”,学台湾人的说法),一般附近是一些JMP长跳转,这些是程序中需要调用函数,应该给予重视,可以尝试在相关函数上下断点。

当您看到call bx时,通常程序要调用真正的函数执行功能,你应该跟进去,一般在执行P-CODE比较伪指令的过程中,你会发现一个call bx,一定要跟进去,通常会它引导你看到真正的注册码以及你输入的假注册码进行比较。通过观察堆栈的显示,你就可以看到他们,两个可爱的字符串(通常出现在OLLYDBG的调试窗口的右下方)。

跟踪VB程序时,通常会看到如下的代码:

7353F7B7   3BFC             CMP EDI,ESP
7353F7B9   0F85 D67D0000    JNZ MSVBVM60.73547595
7353F7BF   33C0             XOR EAX,EAX
7353F7C1   8A06             MOV AL,BYTE PTR DS:[ESI]
7353F7C3   46               INC ESI
7353F7C4   FF2485 58FA5373  JMP DWORD PTR DS:[EAX*4+7353FA58]

7353F7CB   0FB70E           MOVZX ECX,WORD PTR DS:[ESI]
7353F7CE   0FB77E 02        MOVZX EDI,WORD PTR DS:[ESI+2]
7353F7D2   83C6 04          ADD ESI,4
7353F7D5   03FC             ADD EDI,ESP
7353F7D7   8B55 AC          MOV EDX,DWORD PTR SS:[EBP-54]
7353F7DA   8B048A           MOV EAX,DWORD PTR DS:[EDX+ECX*4]
7353F7DD   0BC0             OR EAX,EAX
7353F7DF   90               NOP
7353F7E0   0F84 027F0000    JE MSVBVM60.735476E8
7353F7E6   803D B4115573 00 CMP BYTE PTR DS:[735511B4],0
7353F7ED   0F85 037F0000    JNZ MSVBVM60.735476F6
7353F7F3   FFD0             CALL EAX
7353F7F5   3BFC             CMP EDI,ESP
7353F7F7   0F85 987D0000    JNZ MSVBVM60.73547595
7353F7FD   50               PUSH EAX
7353F7FE   33C0             XOR EAX,EAX
7353F800   8A06             MOV AL,BYTE PTR DS:[ESI]
7353F802   46               INC ESI
7353F803   FF2485 58FA5373  JMP DWORD PTR DS:[EAX*4+7353FA58]

7353F80A   0FB706           MOVZX EAX,WORD PTR DS:[ESI]

其中:
7353F7BF   33C0             XOR EAX,EAX
7353F7C1   8A06             MOV AL,BYTE PTR DS:[ESI]
7353F7C3   46               INC ESI
7353F7C4   FF2485 58FA5373  JMP DWORD PTR DS:[EAX*4+7353FA58]
既是伪代码的执行模板。JMP指令转入伪指令的执行,不断按下“F8”,盯着esi寄存器的变化,参照vbexplorer中提示的p-code,你就不会迷失方向(通常是这样。当然,如果你按错了键,那就是你自己的事了,别怪我没提醒你)


大结局

关于最后的修改VB P-CODE代码,暴力破解法,据我所知一般只要能将重要的转移指令改变就可以了。无非是在您选好的比较指令的位置将BranchF(伪代码1c)BranchT(1d) 或者Branch(1e)改来改去。别的好招我还不会呢,等着咱们继续切磋。

有空的朋友,还可以分析程序中的算法,只要花功夫,没什么看不懂的。除非编程序的那位憋着劲和咱们作对,不怕,咱不用他的软件了还不行?我是菜鸟,我怕谁?

够了,说了一堆有用没用的废话,您自己看着办8,您也听累了,我手也酸了。总之,vb p-code毕竟是由高级语言转换来的,应该不难分析和跟踪,只是特点不同,掌握了基本的要点,用OLLDBG跟踪没什么难的。现在又有WKTVBDE 和vbexplorer助阵,一边捏着P-CODE,一边瞄着ESI, 祭起OLLYDBG,一手按着F8,您说,咱还怕谁呀?

什么逆向工程,什么VB,  V JQK,谁是破解高手?不就是花时间嘛。
唉,所以高手都不来发言了,所以,您和我,还是菜鸟。苦恼中。。。。

要是那位高手作个OLLDBG的VB P-CODE插件,一遇到VB p-code中JMP DWORD PTR DS:[EAX*4+&*%$@$^] 就显示相关的P-CODE指令就更方便了,尤其期待中。。。。