angr/pyvex模块学习
链接:https://github.com/angr/pyvex
VEX IR
为了处理广泛多样的体系结构,对中间表示进行分析是很有用的。在处理不同的体系结构时,一个IR抽象出几个体系结构差异,允许在所有这些差异上运行一个分析:
Register name:不同的架构有不同的寄存器,堆栈结构,IR为不同平台上的寄存器提供了一致的抽象接口。具体来说,VEX将寄存器建模为具有整数偏移量的单独内存空间(即,AMD64的rax从该内存空间的地址16开始存储)。
memory access.不同的体系结构以不同的方式访问内存。例如,ARM可以在小端和大端模式下访问内存。IR必须消除这些差异。
memory segentation.一些体系结构(如x86)通过使用特殊的段寄存器来支持内存分段。IR理解这种内存访问机制。
instruction side-effects.大多数指令都有副作用。例如,ARM上Thumb模式的大多数操作都会更新条件标志,堆栈推送/弹出指令会更新堆栈指针。在分析中以特别的方式跟踪这些副作用是很疯狂的,因此IR使这些副作用变得明确。
对于IR有很多选择。我们使用VEX,因为二进制代码提升到VEX是非常受支持的。VEX是许多目标机器语言的体系结构不可知、无副作用的表示。它将机器代码抽象成一个表示形式,以使程序分析更容易。此表示有四类主要对象:
expressions:IR表达式表示计算值或常量。这包括内存加载、寄存器读取和算术运算结果。
operations:IR operations 描述了对IR表达式的修改。这包括整数运算、浮点运算、位运算等。应用于IR表达式的IR操作将生成IR表达式。
Temporary
variables:VEX使用临时变量作为内部寄存器:IR表达式在使用之间存储在临时变量中。可以使用IR表达式检索临时变量的内容。从0开始,这些临时工被编号。这些临时变量是强类型的(即“64位整数”或“32位浮点”)。
Statements.:IR Statements modes改变目标机器的状态,例如内存存储和寄存器写入的影响。IR语句使用IR表达式表示它们可能需要的值。例如,内存存储IR语句使用一个IR表达式作为写入的目标地址,使用另一个IR表达式作为内容。
Blocks:IR块是IR语句的集合,表示目标体系结构中的扩展基本块(称为“IR Super Block”或“IRSB”)。一个Block可以有几个出口。对于基本块中间的条件退出,使用特殊的Exit IR语句。IR表达式用于表示块末尾无条件出口的目标。
VEX-IR实际上在VEX存储库的libvex-IR.h文件(https://github.com/angr/VEX/blob/dev/pub/libvex-IR.h)中有很好的文档记录。这里详细介绍VEX的一些部分,您可能会经常与之交互。首先,这里有一些IR表达式:IR expressiong(不会产生副作用)
constant0x4:I32 read Temp RdTmp(t10) GetRegister GET:I32(16) Load Memory LDle:I32/LDbe:I64 Operation Add32 If-Then-Else ITE Helper Function function_name
IR Statements(会产生副作用)
Write Temp WrTmp(t1)=(IR Expression) Put Register PUT(16)=(IR Expression) Store Memory Stle(0x1000)=(IR Expression) Exit if(condition) goto (Boring)0x400A00:I32
下面是一个在ARM上进行红外翻译的例子。在该示例中,减法运算被转换为包含5个IR语句的单个IR块,每个IR语句至少包含一个IR表达式(尽管在现实生活中,IR块通常由多个指令组成)。寄存器名被转换为给定给GET表达式和PUT语句的数字索引。精明的读者会注意到,实际的减法是由块的前4个IR语句建模的,而程序计数器指向下一条指令(在本例中,它位于0x59FC8)的递增是由最后一条语句建模的。
以下ARM指令:
subs R2, R2, #8
VEX IR
t0 = GET:I32(16)
t1 = 0x8:I32
t3 = Sub32(t0,t1)
PUT(16) = t3
PUT(68) = 0x59FC8:I32
pyvex下的测试代码(这里为了可视化对原来的代码进行了简单的修改)
1.test_ud2.py
import nose.tools
import archinfo
import pyvex
def test_ud2():
# On x86 and amd64, ud2 is a valid 2-byte instruction that means "undefined instruction". Upon decoding a basic
# block that ends with ud2, we should treat it as an explicit NoDecode, instead of skipping the instruction and
# resume lifting.
b = pyvex.block.IRSB(b'\x90\x90\x0f\x0b\x90\x90', 0x20, archinfo.ArchAMD64())
print("b.jumpkink: :",b.jumpkind)
print('b.next.con.value:',hex(b.next.con.value))
print('b.size :',hex(b.size))
if __name__ == "__main__":
test_ud2()
输出如下:
b.jumpkink: : Ijk_NoDecode
b.next.con.value: 0x22
b.size : 0x4
这里 Ijk_NoDecode 表示 current instruction cannot be decoded
这里举一个实际的例子:
环境:需要安装angr
proj=angr.Project('/bin/true')
block=proj.factory.block(proj.entry)
block.capstone.pp()
0x4017b0: xor ebp, ebp
0x4017b2: mov r9, rdx
0x4017b5: pop rsi
0x4017b6: mov rdx, rsp
0x4017b9: and rsp, 0xfffffffffffffff0
0x4017bd: push rax
0x4017be: push rsp
0x4017bf: lea r8, [rip + 0x322a]
0x4017c6: lea rcx, [rip + 0x31b3]
0x4017cd: lea rdi, [rip - 0xe4]
0x4017d4: call qword ptr [rip + 0x2057fe]
block.vex.pp()
IRSB {
t0:Ity_I32 t1:Ity_I32 t2:Ity_I32 t3:Ity_I64 t4:Ity_I64 t5:Ity_I64 t6:Ity_I64 t7:Ity_I64 t8:Ity_I64 t9:Ity_I64 t10:Ity_I64 t11:Ity_I64 t12:Ity_I64 t13:Ity_I64 t14:Ity_I64 t15:Ity_I32 t16:Ity_I64 t17:Ity_I64 t18:Ity_I64 t19:Ity_I64 t20:Ity_I32 t21:Ity_I64 t22:Ity_I32 t23:Ity_I64 t24:Ity_I64 t25:Ity_I64 t26:Ity_I64 t27:Ity_I64 t28:Ity_I64 t29:Ity_I64 t30:Ity_I64 t31:Ity_I64 t32:Ity_I64 t33:Ity_I64 t34:Ity_I64 t35:Ity_I64 t36:Ity_I64
00 | ------ IMark(0x4017b0, 2, 0) ------
01 | PUT(rbp) = 0x0000000000000000
02 | ------ IMark(0x4017b2, 3, 0) ------
03 | t26 = GET:I64(rdx)
04 | PUT(r9) = t26
05 | PUT(rip) = 0x00000000004017b5
06 | ------ IMark(0x4017b5, 1, 0) ------
07 | t4 = GET:I64(rsp)
08 | t3 = LDle:I64(t4)
09 | t27 = Add64(t4,0x0000000000000008)
10 | PUT(rsi) = t3
11 | ------ IMark(0x4017b6, 3, 0) ------
12 | PUT(rdx) = t27
13 | ------ IMark(0x4017b9, 4, 0) ------
14 | t5 = And64(t27,0xfffffffffffffff0)
15 | PUT(cc_op) = 0x0000000000000014
16 | PUT(cc_dep1) = t5
17 | PUT(cc_dep2) = 0x0000000000000000
18 | PUT(rip) = 0x00000000004017bd
19 | ------ IMark(0x4017bd, 1, 0) ------
20 | t8 = GET:I64(rax)
21 | t29 = Sub64(t5,0x0000000000000008)
22 | PUT(rsp) = t29
23 | STle(t29) = t8
24 | PUT(rip) = 0x00000000004017be
25 | ------ IMark(0x4017be, 1, 0) ------
26 | t31 = Sub64(t29,0x0000000000000008)
27 | PUT(rsp) = t31
28 | STle(t31) = t29
29 | ------ IMark(0x4017bf, 7, 0) ------
30 | PUT(r8) = 0x00000000004049f0
31 | ------ IMark(0x4017c6, 7, 0) ------
32 | PUT(rcx) = 0x0000000000404980
33 | ------ IMark(0x4017cd, 7, 0) ------
34 | PUT(rdi) = 0x00000000004016f0
35 | PUT(rip) = 0x00000000004017d4
36 | ------ IMark(0x4017d4, 6, 0) ------
37 | t17 = LDle:I64(0x0000000000606fd8)
38 | t33 = Sub64(t31,0x0000000000000008)
39 | PUT(rsp) = t33
40 | STle(t33) = 0x00000000004017da
41 | t35 = Sub64(t33,0x0000000000000080)
42 | ====== AbiHint(0xt35, 128, t17) ======
NEXT: PUT(rip) = t17; Ijk_Call
}
现在在对应对应的汇编看相应的vex ir就能大概知道每条语句的意思了,不会的以后再cha官方文档
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。