vul函数分析
WORKING WITH GHIDRA'S P-CODE TO IDENTIFY VULNERABLE FUNCTION CALLS
ghidra-bridge
使用ghidra-bridge,可以调用别的package
图结构
ghidra自定义的图结构在以下文件中实现,常用API也可以从下边文件中寻找
常用成员
- VertexSet vertices
- EdgeSet edges
- AttributeManager<Vertex> vertexAttributes
- AttributeManager<Vertex> edgeAttributes
其中vertices和edges是记录节点和边的集合,vertexAttributes和edgeAttributes是管理节点和边属性的实例,具体的用法可以参考下边的实例代码:
from ghidra.util.graph import DirectedGraph
from ghidra.util.graph.attributes import *
self.graph = DirectedGraph()
self.graph.add(Vertex(1))
e = Edge(Vertex(1), Vertex(2))
self.graph.add(e)
edgeAttrm = self.graph.edgeAttributes()
att = edgeAttrm.createAttribute("type",AttributeManager.INTEGER_TYPE)
att.setValue(e, 123)
print(att.getValue(e))
构建程序依赖图
- 图中结点
- Varnode 和 pcodeAST (方便符号执行?)
- Varnode - 调用getDef - 返回 pcode - 添加边
- 获取pcodeAST的op类型,根据不同op类型进行处理
- Load 、 cast等
- 图中边的类型定义(看到这里我怎么觉得ghidra应该是有内置的图结构的?):
P-code
http://galaxylab.com.cn/使用ghidra-p-code进行辅助逆向分析/
基本概念:
https://blog.csdn.net/weixin_49393427/article/details/123201539
概述
- Ghidra P-Code是专为逆向工程设计的寄存器传输语言,能够对许多不同的处理器进行建模。
- P-Code会将单个处理器指令转化为一系列的P-Code操作, 这些操作将处理器状态的一部分作为输入和输出变量(VarNodes)。
- 通过getInput函数可以方便的获取P-Code的input参数
- 通过分析原始P-Code,可以了解代码中寄存器的控制流,从而帮助我们辅助分析代码。
- 具体说明可以参考P-Code相关文档: Ghidra安装目录下的docs/languages/html/pcoderef.html
- 也可以参考https://spinsel.dev/assets/2020-06-17-ghidra-brainfuck-processor-1/ghidra_docs/language_spec/html/additionalpcode.html
VarNode和Pcode
Varnode是pcode输入输出状态变量
- VarnodeAST 继承自 Varnode,是其抽象语法树中的节点,其中def和descend的是当前varnodeAST的入边和出边
private PcodeOp def; // Operation which defines this varnode (in-edge)
private LinkedList<PcodeOp> descend; // List of operations which use this varnode (out-edges)
@Override
public PcodeOp getDef() {
return def;
}
@Override
public Iterator<PcodeOp> getDescendants() {
return descend.iterator();
}
- PcodeOp和PcodeOpAST也是上述类似的关系
- PcodeOpBank是PcodeOpAST的容器
- varnode对象有很多类型,如unique、register、const等,其中unique类型的对象需要进一步分析
常用接口
遍历pcode
Iterator<PcodeOpAST> pcodeAst = hf.getPcodeOps();
while (pcodeAst.hasNext()) {
PcodeOpAST pcodeast = pcodeAst.next();
PrintAST(pcodeast);
}
获取变量名
HighVariable getNamedVariable(Varnode vnode) {
HighVariable hvar = vnode.getHigh();
if (hvar.getName() != null)
return hvar;
// Calling back getNamedVariable() on all of the pcode's input nodes
}
遍历所有的symbol
https://github.com/NationalSecurityAgency/ghidra/issues/1561
有时候会有想获取DAT变量的需求
while (addrIter.hasNext() && !monitor.isCancelled()) {
Address addr = addrIter.next();
Symbol sym = getSymbolAt(addr);
if (sym != null) {
printf("Symbol at 0x%x", addr.getOffset());
printf(" = %s\n", sym.getName());
}
}
PcodeOP
PTRADD

类似数组的表示 input0 + input1 * input2,其中
- 0 是数组基地址
- 1 是数组的index
- 2 是常量,每次的步长
PTRADD生成数组中指定索引处元素的指针值,并将其存储在输出中。
PTRSUB

PTRSUB执行简单的指针计算,即input0 + input1,但也显式地指示input0是对结构化数据类型的引用
- 0 是基址
- 1 是偏移
INDIRECT

INDIRECT操作符将input0复制到输出中,但是该值可以通过input1引用的操作以间接的方式改变, Output1不是机器状态的一部分,但实际上是对特定p-code操作符的内部引用,该操作符可能会影响输出varnode的值。和MULTIEQUAL一样,这个操作用于生成静态单赋值表。