首页
论坛
课程
招聘
[原创]angr/pyvex模块学习
2020-3-31 22:45 4623

[原创]angr/pyvex模块学习

2020-3-31 22:45
4623

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官方文档



[2022夏季班]《安卓高级研修班(网课)》月薪两万班招生中~

收藏
点赞1
打赏
分享
最新回复 (2)
雪    币: 0
活跃值: 活跃值 (344)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Qira 活跃值 2020-4-29 11:16
2
0
感谢分享,希望还有后续的分享
雪    币: 5
活跃值: 活跃值 (325)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
北美老徐 活跃值 2022-6-18 04:13
3
0
请教一下大佬,请问什么叫做从内存空间地址16开始储存呀:AMD64的rax从该内存空间的地址16开始存储
游客
登录 | 注册 方可回帖
返回