• 标 题:p-code 执行(译)
  • 作 者:virtualspace
  • 时 间:2003年11月17日 08:33
  • 链 接:http://bbs.pediy.com

小弟在上一篇短文“有关VB程序P-CODE代码逆向工程入门浅说”中介绍了调试p-code代码的一点简单方法,今天,再来和各位初学者一起回顾一下p-code的有关资料。

John Chamberlain 在他的文章“Microsoft's P-Code Implementation”中是这样介绍的:

最初的Pascal编译器涉及特定的计算机,它的复杂性基于编译器自身。为了解决生成代码的跨平台问题,编译器产生一种伪代码(伪执行代码,与特定计算机的指令无关)“pseudo-opcode”,它被称为"Pascal-P",编译器能够输出伪指令“p-pcode”。大约10年后,Microsoft为它自己相关产品采用了这个惯用的术语"p-code" 和 "p-code 引擎"。对于“VB p-code”,可移植性“portable”不是被优先考虑的,这个前缀“p”的含义被转义为压缩“packed”,可执行程序被压缩成字节占用很小的文件。1995年sun公司的java席卷了web世界,Microsoft 作为回应,将它的 p-code 引擎转换成更性感的新名称 vb虚拟机"VB Virtual Machine",其实这并不十分恰当。无论如何,Java's 操作码opcode 对应的是抽象的cpu指令,Microsoft的p-codes 是一种抽象的编程语言和环境,它更适当的称呼应该是vb虚拟语言 "VB Virtual Language".

VB 虚拟机基础 
如是我闻,John Chamberlain 接着说,VB6 有1351 条伪指令opcodes,它维护一个寄存器指针和一个跳转表,指向那些待处理的后续伪代码,并且,vb不通过p-code进行循环操作。

举例:执行伪指令f5,将一个Long(长整型,32 位,4 个字节)变量存储. ESI 寄存器总是指向有关的伪指令,EAX 包含跳转地址的索引。



Address………..(p-code bytes)
001a56d1………3c 00 0a f5  ;f5 当前执行的伪指令
001a56d5………08 00 00 00 
001a56d9………71 78 ff 00 

当前伪指令指令结束后,将跳到下一条伪指令(71)处
Eax=000000f5 (begin)  ; 伪指令
Eax=00000071 (end)

Esi=001a56d5 (begin)  ; 伪指令序列指针
Esi=001a56da (enbd)

0FC01377 mov eax,dword ptr [esi] (1) 引出伪指令参量
0FC01379 push eax (2) 进行伪指令相应的工作
0FC0137A xor eax,eax (3) 转入下一个伪指令
0FC0137C mov al,byte ptr [esi+4] 
0FC0137F add esi,5 ; 下一个待处理的伪指令位置
0FC01382 jmp dword ptr [eax*4+0FC027CCh] 执行相关伪指令的处理控制进程

注:0FC01382 语句中的0FC027CCh 指向一个向量表

处理引擎的工作:在字节代码流中,放入一个long数据类型的常量8(好像这样的形式"F5 08 00 00 00"等待被vb处理机执行. 所有的伪代码都是基于类似的形式。

如是我闻,John Chamberlain 又继续解释上面的这个实例:
以上实例中,向量表指向0FC027CC,因此,一个伪指令(71)将跳到这个向量表的第71个入口地址71*4+0FC027CC. 在这里,第二步只是进行了一个简单的压栈操作,但是其他的伪代码可能有很复杂的执行过程。不管那些处理过程有多复杂,你不必介入具体的执行过程,只要你清楚每个伪指令对应的向量表中执行入口即可。
例如:在debugger中设置一个断点在0FC01377(参照以上实例),你就会中断在执行伪指令f5之前. 
Vb6虚拟机仅仅指定寄存器ESI,EAX作为专用寄存器,EAX总是在被调用之前清除(xor eax, eax),并且装入有关的跳转参量,在相应的伪指令处理过程中,ESI 寄存器是被保护的. 在上例中,(add esi, 5) 使得esi指向下一条伪指令,并忽略当前执行的伪指令的参数。vb应用程序的执行控制流是基于对ESI寄存器的设置. Vb6中有775 伪指令处理子程序,大概是因为1351 伪指令中有一些对应着同一个伪指令处理程序。 
John Chamberlain 提供的The opcode database(见附件)格式:
|Opcode|__|VB6虚拟机的rva|__|VBA的rva|__|参数尺寸|__|注释|
1F___________09AD_____________0A32__________2_1_2____vbaRecUniToAnsi                                                                                                                                                   
参数尺寸:
1. 参数总尺寸(bytes)
2. 参数总个数
3. 第1,2,3个参数的尺寸(bytes)
更多的信息请参照:
http://www.programmersheaven.com/articles/userarticles/john/vbvm.htm.