angr中文文档-高级话题-中间表示

有一些不太好理解,或者不太好翻译的地方,就会把英文原文也留下来,后续再慢慢理解。如果有一些见解或者错误欢迎提出和指正。

简介

除了经典的 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 ValueVEX 输出示例
ConstantA constant value. 常量值值0x4:I32
Read TempThe value stored in a VEX temporary variable. 存储在 VEX 临时变量的值RdTmp(t10)
Get RegisterThe value stored in a register. 存储在寄存器的值GET:I32(16)
Load MemoryThe value stored at a memory address, with the address specified by another IR Expression. 存储在内存地址的值,地址由另一个 IR 表达式指定LDle:I32 / LDbe:I64
OperationA result of a specified IR Operation, applied to specified IR Expression arguments. 指定 IR 操作的结果,应用于指定的 IR 表达式参数Add32
If-Then-ElseIf a given IR Expression evaluates to 0, return one IR Expression. Otherwise, return another. 如果给定的 IR 表达式计算结果为 0,则返回一个 IR 表达式。 否则,返回另一个ITE
Helper FunctionVEX 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 MemoryUpdate 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_dep1cc_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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏打呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值