3. P-Code操作码详解(上):LOAD、STORE、COPY、INT_EQUAL、INT_NOTEQUAL等基础操作码
好,咱们今天来啃P-Code操作码这块硬骨头。说实话,我刚接触Ghidra那会儿,看到P-Code也是一脸懵——这玩意儿到底在干嘛?后来做多了逆向分析才明白,P-Code就是Ghidra的「通用语言」,它把x86、ARM、MIPS这些五花八门的指令集,全部翻译成一套统一的操作码。你想想看,这多方便?
今天我们先讲最基础的一批操作码。它们就像盖房子的砖头,虽然简单,但所有复杂的分析都建立在它们之上。
3.1 LOAD:从内存里把数据「请」出来
LOAD操作码,说白了就是读内存。它的格式长这样:
LOAD dest, src, size
其中dest是目标寄存器,src是内存地址,size是读取的字节数。举个例子:
LOAD R0, [R1+4], 4
这条P-Code的意思是:从R1+4这个地址开始,读4个字节,存到R0里。
嗯,这里要注意一点——Ghidra的P-Code里,内存地址都是用方括号括起来的。这是它的语法习惯,你得适应。
3.2 STORE:把数据「塞」回内存
STORE和LOAD正好相反,它是写内存。格式:
STORE dest, src, size
比如:
STORE [R2], R3, 2
意思就是把R3里的2个字节,写到R2指向的内存地址。
我曾经在分析一个恶意软件样本时,发现它频繁使用STORE操作码往栈上写数据。一开始以为是正常操作,后来仔细一看——它是在构造ROP链!每个STORE对应一个gadget地址的写入。这个发现让我对STORE操作码格外敏感。
3.3 COPY:数据搬运工
COPY操作码,就是寄存器到寄存器的数据移动。格式:
COPY dest, src
例如:
COPY R4, R5
把R5的值复制到R4。
你可能会问:「这不就是MOV指令吗?」对,但P-Code里没有MOV,只有COPY。Ghidra的设计者觉得「复制」比「移动」更准确——因为源寄存器的值并没有消失,只是被复制了一份。
我个人习惯在分析函数调用时,特别关注COPY操作码。因为参数传递经常通过COPY来完成。比如:
COPY R0, R1 ; 把R1的值传给R0,作为第一个参数
CALL func
看到这种模式,基本就能确定参数传递关系了。
3.4 INT_EQUAL 和 INT_NOTEQUAL:比较的真相
这两个操作码是条件判断的基础。INT_EQUAL判断相等,INT_NOTEQUAL判断不等。
格式:
INT_EQUAL dest, src1, src2
INT_NOTEQUAL dest, src1, src2
比如:
INT_EQUAL R6, R7, R8
如果R7等于R8,R6就被设为1(真),否则设为0(假)。
INT_NOTEQUAL同理,不等则为1。
为什么我要单独讲这两个?因为在逆向分析中,条件跳转的识别全靠它们。你看下面这个例子:
INT_EQUAL R6, R7, R8
CBRANCH R6, label
这对应高级语言里的 if (R7 == R8) goto label;。CBRANCH是条件跳转操作码,我们后面会细讲。
3.5 知识体系总览
说了这么多,咱们用一张图来梳理一下今天的内容。这张SVG图展示了基础操作码的分类和关系:
3.6 实战中的组合使用
光讲单个操作码没意思,咱们来看一个实际场景。假设你在分析一个字符串比较函数,P-Code可能是这样的:
LOAD R0, [R1], 1 ; 从R1地址读1个字节到R0
LOAD R2, [R3], 1 ; 从R3地址读1个字节到R2
INT_EQUAL R4, R0, R2 ; 比较两个字节是否相等
CBRANCH R4, equal_label ; 相等则跳转
...
你看,LOAD负责从内存取字符,INT_EQUAL负责比较,CBRANCH负责跳转。三个操作码配合,就实现了字符串的逐字节比较。
我当初在分析一个加密算法时,就是通过这种模式定位到了密钥比较的逻辑。当时找了半天没找到关键判断点,后来直接搜P-Code里的INT_EQUAL,一下子就锁定了位置。
3.7 小结
今天咱们讲了四个基础操作码:LOAD、STORE、COPY、INT_EQUAL和INT_NOTEQUAL。它们虽然简单,但却是P-Code世界的基石。你想想看,没有LOAD和STORE,程序怎么访问内存?没有COPY,数据怎么在寄存器间流动?没有比较操作码,条件判断怎么实现?
嗯,这些基础操作码就像字母表里的字母。单个看没什么,但组合起来就能写出千变万化的程序逻辑。下一批操作码会更复杂一些,比如算术运算、位操作、还有那个让人头疼的CBRANCH。不过别担心,咱们一步一步来。
记住我今天说的:在P-Code的世界里,没有秘密。所有的高级语义,最终都会落在这几十个操作码上。你只要掌握了它们,任何二进制在你面前都是透明的。