关于VB 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字串的指针。
网管论坛bbs_bitsCN_com
表示堆栈操作的:(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
网管u家u.bitscn@com
------------------------------------------------------------------------------------
cbo Combo box
chk Check box
cmd Command Button
dir Directory box
网管论坛bbs_bitsCN_com
drv Drive list box
fil File list box
fra Frame
frm Form
grd Grid
网管联盟bitsCN_com
hsb Horizontal scrollbar
img Image
lbl Label
lin Line
lst List box
网管论坛bbs_bitsCN_com mnu Menu
ole OLE client
opt Option button
pic Picture Box
shp Shape
中国网管联盟bitsCN.com
tmr Timer
txt Text box
vsb Vertical scrollbar
-----------------------------------------------------------------------------------------
还有一些不太清楚的,都是我的猜想,希望大虾解释:
Call ---- 调用过程
Free ---- 释放内存空间
Rf ---- 局部变量????
网管网www_bitscn_com 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里的文本反过来显示在消息框里。
网管下载dl.bitscn.com
下面来“生成工程”,注意一定要在“选项”里选择生成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
网管u家u.bitscn@com
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
网管联盟bitsCN_com 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类型的长度入栈
网管u家u.bitsCN.com 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
网管下载dl.bitscn.com
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
网管论坛bbs_bitsCN_com
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连起来
网管网www.bitscn.com
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的标题
网管联盟bitsCN@com 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的大侠解释一下,小弟代表广大菜鸟同胞感激不尽。
中国网管联盟bitsCN.com