有一些不太好理解,或者不太好翻译的地方,就会把英文原文也留下来,后续再慢慢理解。如果有一些见解或者错误欢迎提出和指正。
简介
除了经典的 x86 外,angr 为了能够分析和执行来自不同 CPU 架构(MIPS,ARM 等)的机器代码,在中间表示上执行大部分分析。中间表示是对每条 CPU 指令的基本操作的结构化描述。通过了解 angr 的 IR,VEX(从 Valgrind 借鉴的),能够编写非常快速的静态分析并更好的了解 angr 的工作原理。
在处理不同架构时,VEX IR 抽象出几个架构的差异,允许单独的分析运行于所有架构之上:
- 寄存器名称:寄存器的数量和名称因架构而异,但现代 CPU 设计坚持一个共同的主题:每个 CPU 包含几个通用寄存器、一个用于保存堆栈指针的寄存器、一组用于存储条件标志的寄存器等等。 IR 为不同平台上的寄存器提供了一致的抽象接口。具体来说,VEX 将寄存器建模为一个单独的内存空间,具有整数偏移量(例如,AMD64 的 rax 存储在该内存空间中的偏移为 16 的位置)。
- 内存访问:不同的架构以不同的方式访问内存。例如,ARM 可以在 little-endian 和 big-endian 模式下访问内存。** IR 抽象了这些差异**。
- 内存分段:一些体系结构,例如 x86,通过使用特殊的段寄存器来支持内存分段。 IR 能够理解这类内存访问机制。
- 指令副作用(side-effects):大多数指令都有副作用。例如,ARM 上 Thumb 模式下的大多数操作会更新条件标志,入栈出栈指令会更新堆栈指针。在分析中以特殊的方式跟踪这些副作用会很 crazy,因此 IR 使这些影响变得明确。
VEX IR主要对象
IR 有很多选择。 我们使用 VEX,因为将二进制代码提升为 VEX 得到了很好的支持。VEX 是许多目标机器语言的架构无关、无副作用的表示。 它将机器代码抽象为一种旨在使程序分析更容易的表示。 这种表示有四个主要的对象类:
- 表达式:IR 表达式表示计算值或常数值。这包括内存加载、寄存器读取和算术运算的结果。
- 操作:IR 操作描述了 IR 表达式的修改。这包括整数运算、浮点运算、位运算等。应用于 IR 表达式的 IR 操作会产生一个 IR 表达式作为结果。
- 临时变量: VEX 使用临时变量作为内部寄存器:IR 表达式在使用之间存储在临时变量中。可以使用 IR 表达式检索临时变量的内容。这些临时文件从 t0 开始编号。这些临时变量是强类型的(例如,“64 位整数”或“32 位浮点数”)。
- 语句:IR 语句模型更改目标机器的状态,例如内存存储和寄存器写入的影响。 IR 语句将 IR 表达式用于它们可能需要的值。例如,内存存储 IR 语句使用一个 IR 表达式作为写入的目标地址,并使用另一个 IR 表达式作为内容。
- 块。IR 块是 IR 语句的集合,代表目标架构中的扩展基本块(称为“IR Super Block”或“IRSB”)。一个块可以有多个出口。对于从基本块中间的条件退出,使用特殊的 Exit IR 语句。 IR 表达式用于表示块末尾无条件退出的目标。
VEX IR 表达式
VEX IR 实际上在 VEX 存储库中的 libvex_ir.h 文件(https://github.com/angr/vex/blob/master/pub/libvex_ir.h)中有详细记录。 对于懒人,我们将详细介绍 VEX 的某些部分,您可能会经常与之交互。 首先,这里有一些 IR 表达式:
IR 表达式 | Evaluated Value | VEX 输出示例 |
---|---|---|
Constant | A constant value. 常量值值 | 0x4:I32 |
Read Temp | The value stored in a VEX temporary variable. 存储在 VEX 临时变量的值 | RdTmp(t10) |
Get Register | The value stored in a register. 存储在寄存器的值 | GET:I32(16) |
Load Memory | The value stored at a memory address, with the address specified by another IR Expression. 存储在内存地址的值,地址由另一个 IR 表达式指定 | LDle:I32 / LDbe:I64 |
Operation | A result of a specified IR Operation, applied to specified IR Expression arguments. 指定 IR 操作的结果,应用于指定的 IR 表达式参数 | Add32 |
If-Then-Else | If a given IR Expression evaluates to 0, return one IR Expression. Otherwise, return another. 如果给定的 IR 表达式计算结果为 0,则返回一个 IR 表达式。 否则,返回另一个 | ITE |
Helper Function | VEX uses C helper functions for certain operations, such as computing the conditional flags registers of certain architectures. These functions return IR Expressions. VEX 使用 C 辅助函数进行某些操作,例如计算某些架构标志寄存器。这些函数返回 IR 表达式 | function_name() |
VEX IR 语句
更进一步的,这些表达式会在IR 语句中使用,如下是一些常见的:
IR 语句 | 含义 | VEX 输出示例 |
---|---|---|
Write Temp | 设置 VEX 临时变量值为 IR 表达式的值 | WrTmp(t1) = (IR Expression) |
Put Register | 用 IR 表达式的值更新寄存器 | PUT(16) = (IR Expression) |
Store Memory | Update a location in memory, given as an IR Expression, with a value, also given as an IR Expression.使用给定的 IR 表达式更新一个内存位置,内存位置可以用一个值或者另一个 IR 表达式给出 | STle(0x1000) = (IR Expression) |
Exit | 从基本块有条件的退出,跳转目标由 IR 表达式执行,条件由 IR 表达式指定 | if (condition) goto (Boring) 0x4000A00:I32 |
一些例子
下面是一个在 ARM 上的 IR 转换示例。 在该示例中,减法运算被转换为包含 5 个 IR 语句的单个 IR 块,每个语句包含至少一个 IR 表达式(尽管在现实生活中,一个 IR 块通常包含多个指令)。 寄存器名称被转换为给 GET 表达式和 PUT 语句的数字索引。 精明的读者会观察到,实际的减法是由块的前 4 条 IR 语句建模的,程序计数器的递增指向下一条指令(在这种情况下,位于 0x59FC8)是由 最后声明。
ARM 指令:
subs R2, R2, #8
转换后的 VEX IR:
t0 = GET:I32(16) # 取偏移为16的位置(ARM架构下R0寄存器)的值赋值给t0
t1 = 0x8:I32 # 常量0x8赋值给t1
t3 = Sub32(t0,t1) # t0-t1的值赋值给t3
PUT(16) = t3 # t3的值存放到偏移为16的寄存器(R2)
PUT(68) = 0x59FC8:I32 # 更新PC的值为0x59FC8
现在您了解了 VEX,您实际上可以在 angr 中使用一些 VEX:我们使用名为 PyVEX 的库将 VEX 公开到 Python 中。 此外,PyVEX 实现了自己的漂亮输出,以便它可以在 PUT 和 GET 指令中显示寄存器名称而不是寄存器偏移量。
PyVEX 可以通过 angr 通过 Project.factory.block
接口访问。 您可以使用许多不同的表示来访问代码块的句法属性,但它们都有一个共同点,即分析特定的字节序列。 通过 factory.block
构造函数,您可以获得一个 Block
对象,可以轻松地将其转换为几种不同的表示形式。 转换为 PyVEX IRSB 使用 .vex
,或转换为 Capstone 块,使用 .capstone
。
PyVEX 的示例:
>>> import angr
# load the program binary
# 载入二进制程序
>>> proj = angr.Project("/bin/true")
# translate the starting basic block
# 翻译入口基本块为IRSB
>>> irsb = proj.factory.block(proj.entry).vex
# pretty-print 漂亮打印出来
>>> irsb.pp()
# 通过指定地址翻译成IRSB,并打印
>>> irsb = proj.factory.block(0x401340).vex
>>> irsb.pp()
# this is the IR Expression of the jump target of the unconditional exit at the end of the basic block
# 这是基本块末尾无条件退出的跳转目标的IR表达式
>>> print(irsb.next)
# this is the type of the unconditional exit (e.g., a call, ret, syscall, etc)
# 无条件退出的类型:调用、返回、系统调用等
>>> print(irsb.jumpkind)
# you can also pretty-print it
>>> irsb.next.pp()
# iterate through each statement and print all the statements
# 迭代输出每条语句
>>> for stmt in irsb.statements:
... stmt.pp()
# pretty-print the IR expression representing the data, and the *type* of that IR expression written by every store statement
# 打印每个store语句写入该IR表达式的type
>>> import pyvex
>>> for stmt in irsb.statements:
... if isinstance(stmt, pyvex.IRStmt.Store):
... print("Data:",)
... stmt.data.pp()
... print("")
... print("Type:",)
... print(stmt.data.result_type)
... print("")
# pretty-print the condition and jump target of every conditional exit from the basic block
# 打印每个条件退出的条件和跳转目标
>>> for stmt in irsb.statements:
... if isinstance(stmt, pyvex.IRStmt.Exit):
... print("Condition:",)
... stmt.guard.pp()
... print("")
... print("Target:",)
... stmt.dst.pp()
... print("")
# these are the types of every temp in the IRSB
>>> print(irsb.tyenv.types)
# here is one way to get the type of temp 0
>>> print(irsb.tyenv.types[0])
x86 和 ARM 下的条件标志计算(还没仔细看)
x86 和 ARM CPU 上最常见的指令副作用之一是更新条件标志,例如零标志、进位标志或溢出标志。计算机架构师通常将这些标志的串联(是的,标志的串联,因为每个条件标志是 1 bit 宽)放入一个特殊寄存器(即 x86 上的 EFLAGS/RFLAGS,ARM 上的 APSR/CPSR)。该特殊寄存器存储有关程序状态的重要信息,对于 CPU 的正确仿真至关重要。
VEX 使用 4 个寄存器作为其“Flag thunk descriptors”来记录最新的标志设置操作的详细信息。 VEX 有一个计算标志的惰性策略:当一个更新标志的操作发生时,VEX 不计算标志,而是将表示该操作的代码存储到 cc_op
伪寄存器中,并将该操作的参数存储在 cc_dep1
和 cc_dep2
中.然后,每当 VEX 需要获取实际的标志值时,它可以根据其标志 thunk 描述符找出与所讨论的标志对应的一位实际是什么。这是标志计算的优化,因为 VEX 现在可以直接在 IR 中执行相关操作,而无需费心计算和更新标志的值。
在 cc_op
中可以放置的不同操作中,有一个特殊值 0 对应于 OP_COPY
操作。此操作应该将 cc_dep1
中的值复制到标志。它只是意味着 cc_dep1
包含标志的值。 angr 使用这个事实让我们有效地检索标志的值:每当我们要求实际标志时,angr 计算它们的值,然后将它们转储回 cc_dep1
并设置 cc_op = OP_COPY
以缓存计算。我们还可以使用此操作来允许用户写入标志:我们只需设置 cc_op = OP_COPY
表示将新值设置为标志,然后将 cc_dep1
设置为该新值。
其他VEX IR的学习资料
angr/pyvex: Python bindings for Valgrind’s VEX IR.
angr中的中间语言表示VEX - 知乎
VEX IR学习 | Brubbish’s
原创 Valgrind VEX IR-软件逆向-看雪论坛-bbs.pediy.com