• 标 题:关于VB P-CODE的一些总结 (10千字)
  • 作 者:RoBa
  • 时 间:2004-01-26 23:39:18
  • 链 接:http://bbs.pediy.com

关于VB P-CODE的一些总结

前言:到网上查PCODE的资料,到了一个讲Fight Against Crack的网站上,那个作者讲了许多阴毒的招数后,还特别说明,如果是VB程序,最好把它做成P-CODE,这会大大增加破解的难度。事实真的如此吗?WKT的一个大虾却说:We are going to show that protecting a VB application is a very difficult task.The last Microsoft's invention on VB, the 'p-code', it's a delicious bite for reverse engineers. I'll show that a 'p-compiled' application may be easier to crack that a conventional compiled one. 
    不知是不是我孤陋寡闻,总觉得现在关于VB P-CODE的资料少之又少,不管国内国外只能找到各位老大们为数不多的几篇教程(很多也是说“我猜想”之类拿不准的话),《加密与解密》上关于这个也是一笔带过(大概是为续集着想^_^),可能是大虾觉得这个太简单不屑于讲,或是哪里已经有非常系统全面的介绍。总之以前我是一见是VB就害怕,再见是PCODE就投降,这大概就是人家用P-CODE对付破解的原因。这几天终于下决心自己写了几个程序试验,再结合各位老大的文章,总结出一点东西,非常不全面,希望大家多多指教,多多补充。

“工欲善其事,必先利其器。”那句古话好像是这么说的。我们找的工具有:WKTVBDebug(动态破解用,相当于PCODE里的SOFTICE)EXDEC(静态分析,相当于W32DASM)SmartCheck(可以作辅助用)

要想破解PCODE程序,关键要理解里面的“助记符”(它又不同于汇编语言的“mnemonics”,我不知道该怎么表示了)的作用,PCODE的助记符乍看上去很乱,好像比汇编还难,其实它们都是由几部分组成的。比如CVarStr就是由三部分组成(详见下文)。VB PCODE中常见的“助记符”如下面所示:(只总结出了一点,恳请各位补充)

表示数据类型的:
 
I2 ---- Integer,占一个字节的整数(汇编里的BYTE)
I4 ---- Integer,占两个字节的整数(汇编里的WORD)
I8 ---- Integer,占四个字节的整数(汇编里的DWORD)
UI4---- Unsigned Integer,无符号整数
UI8---- Unsigned Integer,无符号整数
R4 ---- Real,单精度实数(Single)
R8 ---- Real,双精度实数(Double)
Str---- String,字符串类型
Var---- Variant,变量类型。这就是BASIC特殊的地方,它允许用户在使用变量前不进行声明,这种不声明的变量就用这种类型存储,它可以包括数字、字串等各种类型。我看M$的这个玩意儿没给用户带来方便,只能让一些初学编程的菜鸟思维混乱,让咱们破解时也非常郁闷:(。它的存储方式非常奇怪,比方说你看到一个VARIANT类型的数据被放到内存里了,你跟过去找,结果什么也找不到。看雪书上说应该D *(EAX+8),原来它真正的数据往后挪了8个字节,真不知在搞什么.....BTW:如果是一个数值类型的数据,它的地址向后移8个字节即为真正的数值,如果是一个字符串型的数据,它的地址向后移8个字节即为指向一个UNICODE字串的指针。

表示堆栈操作的:(PCODE没有寄存器,全部通过堆栈传送数据,因此非常重要)

St ---- Store,把当前栈顶的数据放在内存里
Ld ---- Load,把内存某处的数据压入堆栈
Lit---- Literal,把一个“立即数”压入堆栈

其它重要的:

C  ---- Convert,数据转换。如CI4I2即把BYTE扩充为WORD(I2->I4)
Eq ---- Equal,判断是否相等,并把结果(0或1)入栈
Lt ---- 判断是否小于
Gt ---- 判断是否大于
Len---- 得到字串长度

跳转指令:

Branch  ---- 无条件跳转
BranchT ---- 栈顶数据为真则跳
BranchF ---- 栈顶数据为假则跳

一些算术运算:

Add , Sub 等等应该都比较好认吧。

从一篇介绍PCODE的文章里抄来一些,不知有没有用:

Prefix                                                             Control
------------------------------------------------------------------------------------
cbo                                                                Combo box
chk                                                                Check box
cmd                                                                Command Button
dir                                                                Directory box
drv                                                                Drive list box
fil                                                                File list box
fra                                                                Frame
frm                                                                Form
grd                                                                Grid
hsb                                                                Horizontal scrollbar
img                                                                Image
lbl                                                                Label
lin                                                                Line
lst                                                                List box
mnu                                                                Menu
ole                                                                OLE client
opt                                                                Option button
pic                                                                Picture Box
shp                                                                Shape
tmr                                                                Timer
txt                                                                Text box
vsb                                                                Vertical scrollbar
-----------------------------------------------------------------------------------------

还有一些不太清楚的,都是我的猜想,希望大虾解释:

Call ---- 调用过程
Free ---- 释放内存空间
Rf   ---- 局部变量????
Pr   ---- ????
Ad   ---- 是不是Address??
HardType--是干什么的?

这些组合在一起就成了多种多样的指令,很有趣吧。

还有一个要特别强调的是PCODE的堆栈,PCODE几乎所有的指令都要对堆栈进行操作,有许多指令都是针对栈顶的一个或两个数据进行操作,因此在动态调试PCODE时要十分注意右边显示的堆栈区,并经常查看内存,这样才能理解指令的意义。

下面来实践一下,运行起尘封已久的VB,在FORM上放一个TEXT1,一个BUTTON1,双击Button1,在下面输入:

Private Sub Command1_Click()
    st1 = Text1.Text
    st2 = ""
    m = Len(Text1.Text)
    For i = 1 To m
        st2 = st2 + Mid$(Text1.Text, m - i + 1, 1)
    Next i
    MsgBox st2, vbOKOnly, "CRACK"
End Sub

呵呵,很简单是不是。按一下按钮就把TEXT里的文本反过来显示在消息框里。
下面来“生成工程”,注意一定要在“选项”里选择生成P-CODE文件。然后用Exdec分析一下:

Proc: 401a90
4019B0: 04 FLdRfVar                local_008C          好像是一个指向TEXT的指针
4019B3: 21 FLdPrThis                                   先给一个下马威,前几句全不太明白!
4019B4: 0f VCallAd                 text                用WKTVBDebug过这一句时能看到Form1.text1
4019B7: 19 FStAdFunc               local_0088          猜想应该是取得句柄之类的事情
4019BA: 08 FLdPr                   local_0088          
4019BD: 0d VCallHresult            get__ipropTEXTEDIT  调用,从字面上可以看出是GetText
4019C2: 3e FLdZeroAd               local_008C          好像压入一个指向上面文本的指针,不太清楚,反正上面这个过程很经典啦,几乎从文本框读数都是这样
4019C5: 46 CVarStr                 local_00AC          把上面得到的字串转为Var格式
4019C8: Lead1/f6 FStVar                                再把这个VAR数据入栈 st1
4019CC: 1a FFree1Ad                local_0088          释放前面的空间
4019CF: 3a LitVarStr:              ( local_00CC )      压入一个立即数:空字串st2=""
4019D4: Lead2/00 FStVarCopy       
4019D8: 04 FLdRfVar                local_008C
4019DB: 21 FLdPrThis              
4019DC: 0f VCallAd                 text
4019DF: 19 FStAdFunc               local_0088
4019E2: 08 FLdPr                   local_0088
4019E5: 0d VCallHresult            get__ipropTEXTEDIT  和上面相同,得到字串
4019EA: 6c ILdRf                   local_008C          压入字串
4019ED: 4a FnLenStr                                    得到字串的长度m              
4019EE: Lead2/69 CVarI4            local_00CC          转为VAR类型
4019F2: Lead1/f6 FStVar                                VAR类型的长度入栈
4019F6: 2f FFree1Str               local_008C          释放内存空间
4019F9: 1a FFree1Ad                local_0088
4019FC: 28 LitVarI2:               ( local_00FC ) 0x1  (1) 压入一个立即数0x1
401A01: 04 FLdRfVar                local_00EC          local_00EC是循环变量i
401A04: 04 FLdRfVar                local_00DC          这个是上面得到的长度m
401A07: Lead3/68 ForVar:           (when done) 401A67  FOR i=1 to m 开始循环
401A0D: 04 FLdRfVar                local_008C
401A10: 21 FLdPrThis              
401A11: 0f VCallAd                 text
401A14: 19 FStAdFunc               local_0088
401A17: 08 FLdPr                   local_0088
401A1A: 0d VCallHresult            get__ipropTEXTEDIT  和上面相同的过程,得到字串
401A1F: 04 FLdRfVar                local_00BC          把local_BC压入,这实际上是st2
401A22: 28 LitVarI2:               ( local_013C ) 0x1  (1) 压一个0x1,CALL的参数
401A27: 04 FLdRfVar                local_00DC          字串长度m
401A2A: 04 FLdRfVar                local_00EC          循环变量i
401A2D: Lead0/9c SubVar                                相减 m-i
401A31: 28 LitVarI2:               ( local_00CC ) 0x1  (1) 再压入一个0x1
401A36: Lead0/94 AddVar            local_012C          再加1, m-i+1,CALL的参数
401A3A: Lead1/22 CI4Var                                转成整数型
401A3C: 6c ILdRf                   local_008C          压入,作为下面CALL的参数
401A3F: 0b ImpAdCallI2                                 这是rtcMidCharBStr,源码中的Mid$()
401A44: 46 CVarStr                 local_014C          把取得的字符转成Var型
401A47: Lead0/94 AddVar            local_015C          把新取得的字符和上面的401A1F处的st2连起来
401A4B: Lead1/f6 FStVar           
401A4F: 2f FFree1Str               local_008C
401A52: 1a FFree1Ad                local_0088          释放
401A55: 36 FFreeVar
401A5E: 04 FLdRfVar                local_00EC          设好循环变量
401A61: Lead3/7e NextStepVar:      (continue) 401A0D   NEXT i,循环变量+1,直到结束
401A67: 27 LitVar_Missing                               VB里面那些带[]的可选参数,如果不加设定
401A6A: 27 LitVar_Missing                               就会变成这种Missing或NULL的形式
401A6D: 3a LitVarStr:              ( local_00CC ) CRACK 压入字串,MsgBox的标题
401A72: 4e FStVarCopyObj           local_00AC           把刚压入的字串复制到local_AC
401A75: 04 FLdRfVar                local_00AC           再压进去一次(???)
401A78: f5 LitI4:                  0x0  0  (....)       消息框的样式 vbOKOnly
401A7D: 04 FLdRfVar                local_00BC           这是上面计算得到的反转字串
401A80: 0a ImpAdCallFPR4:                               这个是rtcMsgBox,共有五个参数      
401A85: 36 FFreeVar
401A8E: 13 ExitProcHresult                              结束过程

我尽量想把分析写得明白一些,但还是有几句解释不清,希望精通PCODE的大侠解释一下,小弟代表广大菜鸟同胞感激不尽。