(Raw/High) P-Code Ghidra使用的中间表示语言
简介
P-code是一种专为逆向工程而设计的寄存器传输语言。该语言通用性强,可以对不同处理器的行为进行建模,将对不同处理器的分析放入一个通用框架中,促进retargetable的分析算法和应用开发。
P-code的工作原理是将单个处理器指令转换为一组p-code操作,这些操作将处理器状态的一部分作为输入和输出变量(varnodes),这组唯一的p-code操作(和opcode区分)包含一组相当紧凑的由通用处理器执行的算术和逻辑操作。将指令直接转换为这些操作称为raw p-code。raw p-code可用于直接模拟指令执行,并且通常遵循相同的控制流,尽管它可能会添加一些自己的内部控制流。
P-code专门设计用于方便地构建数据流图,以便对反汇编后的指令进行后续分析。Varnodes和p-code操作符可以显式地视为这些图中的节点。生成raw p-code是图构造中必要的第一步,但还需要执行其他步骤,这会引入一些新的操作符。特别地其中两个新操作符MULTIEQUAL和INDIRECT用于图的构建过程,其他操作符可以在图的后续分析和转换过程中引入,并帮助保持恢复数据类型关系。最后,一些p-code操作CALL、CALLIND、RETURN可能会在分析期间更改其输入和输出varnode,导致它们不再和raw p-code形式匹配。
Ghidra的初始程序分析生成的p-code和varnode是原始(raw)的,因为仅用于表示指令的语义,很少或没有从高级语言中分析收集到的高级语义信息。Ghidra在反编译期间,p-code和varnodes被refined和关联到抽象的局部变量和源码级别的数据结构,称之为high p-code,因为它与 Ghidra中包含反编译信息的数据结构绑定,例如HighVariables和HighFunctions。
Ghidra默认情况下显示的p-code可读性较好:
然而在script中获取和处理的时候是未经翻译的原始形式,显示raw p-code的方法:Edit - Tool Options - Listing Fields - Pcode Field - Display Raw Pcode,例子:
high p-code举例(script时应该叫PcodeOpAST):
(register, 0x20, 4) CALL (ram, 0x13438, 8) , (unique, 0x10000051, 4) , (const, 0x0, 4)
(ram, 0x1d3330, 4) INDIRECT (ram, 0x1d3330, 4) , (const, 0x24, 4)
(stack, 0xffffffffffffffdc, 4) INDIRECT (stack, 0xffffffffffffffdc, 4) , (const, 0x24, 4)
(unique, 0x10000051, 4) COPY (const, 0xfa5da8, 4)
(register, 0x64, 1) INT_SLESS (register, 0x20, 4) , (const, 0x0, 4)--- CBRANCH (ram, 0x1d3318, 1) , (register, 0x64, 1)--- CALL (ram, 0x136c0, 8) , (register, 0x20, 4) , (const, 0x0, 4) , (const, 0x0, 4)
(ram, 0x1d3330, 4) INDIRECT (ram, 0x1d3330, 4) , (const, 0x3a, 4)
(stack, 0xffffffffffffffdc, 4) INDIRECT (stack, 0xffffffffffffffdc, 4) , (const, 0x3a, 4)
(unique, 0x10000059, 4) INT_ADD (register, 0x20, 4) , (const, 0xd0, 4)
(register, 0x24, 4) CAST (unique, 0x10000059, 4)
(register, 0x20, 4) CALL (ram, 0x13d54, 8) , (register, 0x20, 4) , (register, 0x24, 4) , (const, 0x400, 4)
(ram, 0x1d3330, 4) INDIRECT (ram, 0x1d3330, 4) , (const, 0x4c, 4)
(stack, 0xffffffffffffffdc, 4) INDIRECT (stack, 0xffffffffffffffdc, 4) , (const, 0x4c, 4)--- CALL (ram, 0x1216c, 8) , (register, 0x20, 4)
p-code的核心概念包括
地址空间(Address Space)
p-code的地址空间是RAM的泛化。简单的定义成可以被p-code操作读和写的可索引的字节序列。对于特定的字节,标记它的唯一索引是字节的地址。地址空间有一个名称用于识别它,一个大小表示空间中不同索引的数量,以及与之相关的endianess字节序表示整数或其他多字节的值如何编码到空间中。一个典型的处理器有一个RAM空间用于对可通过其主数据总线访问的内存进行建模,以及一个用于对处理器通用寄存器进行建模的寄存器空间(register space)。处理器操作的任何数据都必须在某个地址空间中。处理器的规范可以根据需要自由定义任意数量的地址空间。总是有一个特殊的地址空间,称为常量地址空间(const space),用于对p-code操作所需的任何常量值进行编码。生成p-code的系统通常也使用专用的临时空间(temporary space),可以将其视为临时寄存器的无尽bottomless的源,这些地址空间用于在对指令行为建模时保存中间值。
p-code的代码规范允许地址空间的可寻址单元大于一个字节。每个地址空间都有一个wordsize属性,可以设置该属性以指示一个单元中的字节数。大于1的wordsize对p-code的表示几乎没有影响。地址空间的所有偏移量仍在内部表示为字节偏移量。唯一的例外是 LOAD 和 STORE 操作,这些操作读取一个指针偏移量,当解引用指针时,该偏移量必须正确缩放以获得正确的字节偏移量。wordsize属性对任何其他 p-code操作都没有影响。
常见的地址空间包括CONST、RAM、UNIQUE、REGISTER、STACK
,其定义在ghidra/program/model/address/AddressSpace.java
Varnode
varnode是寄存器或内存位置的概括,由三元组表示**<地址空间、偏移量、大小>**,直观地说,varnode是某个地址空间中的连续字节序列,可以被视为单个值。p-code的所有操作都发生在varnode上。
Varnodes 本身只是一个连续的字节块,由地址和大小标识,没有类型。然而,p-code操作可以强制对 varnode 进行三种类型解释之一:整数、布尔值和浮点数。
- 操作整数的操作总是使用与包含 varnode 的地址空间相关的字节序将 varnode 解释为二进制补码编码。
- 用作布尔值的 varnode 被假定为单个字节,它只能取值 0,表示 false,1 表示 true。
- 浮点运算使用被建模的处理器所期望的编码,这取决于 varnode 的大小。对于大多数处理器,这些编码由 IEEE 754 标准描述,但原则上其他编码也是可能的。
如果将 varnode 指定为常量地址空间的偏移量,则在使用该 varnode 的任何 p 代码操作中,该偏移量将被解释为常量或立即值。在这种情况下,varnode 的大小可以被视为可用于常量编码的大小或精度。与其他 varnode 一样,常量只有一种类型,由使用它们的 p 代码操作强制。
P-code操作(P-code Operation)
p 码操作类似于机器指令。所有 p 码操作在内部具有相同的基本格式。它们都将一个或多个 varnode 作为输入,并可选择生成单个输出 varnode。操作的动作由其操作码决定。对于几乎所有 p 代码操作,只有输出 varnode 可以修改其值;操作没有间接影响。唯一可能的例外是伪操作,参见“伪 P-CODE 操作”一节,当对指令行为的了解不完整时,有时需要使用伪操作。
所有 p 代码操作都与它们被翻译的原始处理器指令的地址相关联。对于单个指令,使用从零开始的加一计数器来枚举其翻译中涉及的多个 p 码操作。地址和计数器作为一对被称为 p 码操作的唯一序列号。 p 码操作的控制流通常遵循序列号顺序。当一条指令的所有p-code执行完成时,如果该指令具有fall-through语义,则p-code控制流从fall-through地址处的指令对应的顺序的第一个p-code操作开始。类似地,如果 p 代码操作导致控制流分支,则顺序中的第一个 p 代码操作在目标地址处执行。
可能的操作码列表类似于许多基于 RISC 的指令集。每个操作码的作用在后面的章节中有详细的描述,在“语法参考”一节中给出了一个参考表。通常,特定 p 码操作的大小或精度取决于 varnode 输入或输出的大小,而不是操作码。
HighFunction
HighFunction是反编译器生成的函数的特定信息的集合。HighFunction由下列对象组成:
- 控制流表示基本块的基本功能
- 数据流表示varnodes和p-code操作
- 符号表函数访问的变量的符号表
HighSymbol
HighSymbol是反编译器恢复的显式符号之一,由名称和数据类型组成,可以描述为
- 函数的参数
- 函数的局部变量
- 函数访问的全局变量
Varnodes
反编译器中的Varnode和p-code操作中的varnode不是一个东西。Varnode是反编译器的核心变量概念。Varnode表示反编译器生成的函数数据流表示中的各个结点。在分析的初始阶段,varnode仅表示特定的存储位置,这些位置由各个p-code操作按顺序访问。反编译器立即将p-code转换为基于图的数据流表示,称为静态单赋值形式SSA。在SSA中,varnode具有一些附加属性。
关于SSA可以参考南大《软件分析》课程IR章节
SSA,每个变量都有自己的唯一定义(def-use),有phi结点。
优点:唯一的变量名可以间接体现程序流信息,简化分析过程;def和use都是显式的
缺点:拆解出太多的变量和phi结点;转换回字节码存在性能问题,引入很多拷贝操作。
在SSA形式中,对存储未知的每次写入操作都会定义一个新的varnode。将代码中不同位置的操作写入同一个存储位置,仍然会产生不同的varnode。在这种情况下,每个varnode在函数内部都有一个生命周期或范围,开始于:
- 定义了变量的(断句)p-code操作的(断句)输出varnode。
- 如果varnode是函数的输入,则开始于函数起始位置。
varnode的范围通过控制流扩展到读取了特定的varnode作为操作数的每个p-code操作。定义p-code操作和读取操作之间varnode的值不会改变。varnode的范围可以被认为是函数体中通过控制流连接的一组地址。定义了变量的p-code操作的地址称为varnode的first use point或first use offset。
在高级语言比如C和java的反编译器输出中,一个varnode也具有范围,并且仅在代码的这个连通区域中表示高级语言中的变量。一组不相交的范围的varnode提供了对可以在函数多个位置写入的高级变量的完整描述。
HighVariable
HighVariable是一组varnodes,合在一起表示在反编译器输出的高级语言中整个变量的存储。每个varnode都描述了变量值在某些代码段中的存储位置。
HighVariables 和 HighSymbols 之间一般是一一对应的。 HighVariables 可以被认为是高级变量的详细存储描述,而 HighSymbol 提供了它的名称和数据类型。
HighVariable 总是描述函数中的指令对数据的显式操作。在某些情况下,HighVariable 可能只描述 HighSymbol 的部分存储。特别是对于结构化或复合数据类型,函数可能在代码的不同点对变量的不同部分进行操作,因此 HighVariable 可能只包含结构的一个字段。
一个符号可以在一个函数中被引用,但是这个符号的值可能没有被显式地操作。常量指针可以引用堆栈或主存储器中的变量,但变量的值在函数内既不读取也不写入。在这种情况下,HighSymbol 存在,但没有对应的 HighVariable。
merging
合并(merging)是分析过程的一部分,反编译器决定将哪些varnode组合在一起以在输出中创建最终的HighVariable。每个 varnode 的作用域(参见反编译器中 Varnodes 中的讨论)提供了对此过程的基本限制。如果两个 varnode 的作用域相交,则不能合并它们。但这在哪些 varnode 可以合并方面留下了很大的余地。
某些 varnode 必须合并;例如,如果它们使用相同的存储但在不同的控制流路径中,或者如果明确知道 varnodes 必须表示相同的变量。这称为强制合并。
反编译器还可以合并可以作为单独变量轻松存在的 varnode。这称为投机合并。除了 varnode 作用域上的交集条件外,反编译器仅推测性地合并共享相同数据类型的变量。除此之外,反编译器会优先考虑在同一指令中读取和写入的变量对,然后是函数控制流中彼此靠近的对。在有限的范围内,用户能够控制这种合并(请参阅拆分为新变量)。
Prototype Model
略。
参考
文档目录$ghidra_home/docs/languages/html/pcoderef.html
opcodes的子集可以出现在raw p-code中的被描述在P-Code Operation Reference(docs/languages/html/pcodedescription.html
)和Pseudo P-CODE Operations(docs/languages/html/pseudo-ops.html)构成了本文档的大部分内容。
所有新的操作码都在Additional P-CODE Operations(docs/languages/html/additionalpcode.html
)一节中进行了描述,这些操作码都不能在原始原始 p 代码转换中发生。
(Raw/High) P-Code Ghidra使用的中间表示语言相关推荐
- 用Visual Studio Code Debug世界上最好的语言(Mac篇)
用Visual Studio Code Debug世界上最好的语言(Mac篇) 首先,你要有台Macbook Pro,接着才继续看这个教程. PS:Windows用户看这里用Visual Studio ...
- 如何在 VS Code 中编写、运行C语言程序 教程
本篇目录 前言 1.下载.安装VS Code 2.安装VS code中2个插件 3.下载minGW64 4.配置系统的环境变量 5.C语言配置 6.编写一个测试程序 7.可能存在的问题 总结 前言 折 ...
- qstudio c语言中文网,再整理:Visual Studio Code(vscode)下的通用C语言环境搭建
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 主要流程: 1.vscode的下载与简单配置 2.MinGw的下载与安装 3.配置系统环境变量 4 ...
- Visual Studio Code设置中文包/配置中文语言
打开vscode工具 使用快捷键组合[Ctrl+Shift+p],在搜索框中输入"configure display language",点击确定后: 修改locale.json文 ...
- exit code非0什么意思C语言,c++程序出现exit code -1073740940 (0xC0000374)
一道动态规划的算法题. dp是我用new关键字分配的一个整形数组用来记录转移量,在程序51行使用"delete []dp;"去释放内存 出现exit code -107374094 ...
- 解决fortify扫描出的Code Correctness: Double-Checked Locking问题(java语言)
现有java代码如下: ... if (fitz == null) { synchronized (this) { if (fitz == null) { fitz = new ...
- VS Code中如何关闭保存Go语言文件时自动去除未引用包的行为
在使用Visual Studio Code编写Go语言(Golang)程序代码的时候,有时候引用的包明明是正确引用了,但在保存的时候却会被自动删除掉,是被误认为未引用了.这时候,参照以下步骤就可以解决 ...
- 用Visual Studio Code Debug世界上最好的语言
前言 这阵子因缘巧合接手了一个辣鸡项目,是用世界上最好的拍黄片写的,项目基本是另一个小伙伴在撸码,我就兼职打杂和发布做点运维的工作. 然后昨天项目上了测试版之后,一用起来Error满天飞了.让小伙伴查 ...
- C语言读取raw格式图像,求指导,如何用c语言实现读取*.raw格式图像
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 /* ** 这个程序是读取jpg图像的 ** 后续加上jpg图像打开和存放 */ #include #include #include #include ...
最新文章
- java 流 复制文件_【Java】使用字节流复制文件
- 网站设计之Flash简单动画入门介绍(一)字体闪烁及渐显
- java 俄文,俄文字体在word里面是什么
- net start mysql 发生系统错误 5。 拒绝访问。的解决方法
- 悲观锁和乐观锁的区别和应用场景
- 阶段3 1.Mybatis_12.Mybatis注解开发_1 mybatis注解开发的环境搭建
- 【图像处理】基于matlab GUI图像分水岭分割+灰度几何校正+运动图像复原【含Matlab源码 024期】
- 自定义的string类
- 金蝶k3服务器的操作系统,金蝶k3服务器配置工具
- excel手机版_excel仓库管理手机版导出软件
- 触摸板不小心卸载,触摸板重装,触摸板没有开关选项
- 【单片机仿真】(四)寻址方式 — 寄存器寻址与直接寻址
- cmd查看自己的CPU参数
- 一款很哇塞的csdn开发助手,你确定不来看看嘛
- 关于Tacotron2看这一篇就够了
- JavaScript节点操作、删除节点
- PMP之敏捷图表之燃起图和燃尽图、累积流量图
- Android中Kotlin面试问题讲解
- 【干货篇】调用其他系统http接口超时了,如何处理,方案汇总
- 攻防世界web新手区合集