angr学习
0、资料
几个主要的网站
angr的github:https://github.com/angr
angr的document:https://docs.angr.io/
angr的api:https://angr.io/api-doc/
1、angr安装
我的实验环境是Ubuntu14.04,显示安装依赖:
sudo apt-get install python-dev libffi-dev build-essential virtualenv
然后新建一个python虚拟环境,进入angr环境
virtualenv angr
source angr/bin/activate
安装angr
sudo pip install angr
2、angr中的基本概念
Project
Project是angr中的基本概念,通过下面的简单两行代码可以新建一个Project变量
import angr p = angr.Project('/bin/sh')
project中有一些基本属性,然后打印他们,包括arch中的很多属性
print(p.arch) print(p.arch.bits) print(p.arch.name) print(p.arch.bytes) print(p.arch.memory_endness) print(hex(p.entry)) print(p.filename)
结果
<Arch AMD64 (LE)> 64 AMD64 8 Iend_LE 0x404e32 /bin/sh
loader
loader是表示可执行文件加载到内存之中的变量,同样先来看一些基本的属性,打印他们
print(p.loader)#主程序对象,下面的打印结果显示程序的名字是dash print(p.loader.shared_objects)#动态库对象,结果包含了动态连接器、库以及主程序 print(p.loader.min_addr) print(p.loader.max_addr) print(p.loader.main_object)#主对象 print(p.loader.main_object.execstack)#是否有可执行栈,即是否开启了nx print(p.loader.main_object.pic)#是否是地址无关代码
结果如下:
<Loaded dash, maps [0x400000:0x5008000]> OrderedDict([('dash', <ELF Object dash, maps [0x400000:0x61fde7]>), (u'libc.so.6', <ELF Object libc-2.19.so, maps [0x1000000:0x13c82bf]>), (u'ld-linux-x86-64.so.2', <ELF Object ld-2.19.so, maps [0x2000000:0x22241c7]>)]) 4194304 83918848 <ELF Object dash, maps [0x400000:0x61fde7]> False True
factory
可以使用project构造一系列对象
Blocks
angr可以从基本块的角度来分析程序,block代表基本块,给project.factory.block()函数传递一个地址,则会返回一个block对象
看block中有哪些对象,将p.entry传递给block函数
block = p.factory.block(p.entry) print(block)#基本块信息 print(block.pp())#打印出汇编指令 print(block.instructions)#打印出指令数目 print(block.instruction_addrs)#打印出每条指令的地址
结果:
<Block for 0x404e32, 41 bytes> 0x404e32: xor ebp, ebp 0x404e34: mov r9, rdx 0x404e37: pop rsi 0x404e38: mov rdx, rsp 0x404e3b: and rsp, 0xfffffffffffffff0 0x404e3f: push rax 0x404e40: push rsp 0x404e41: lea r8, qword ptr [rip + 0x10c88] 0x404e48: lea rcx, qword ptr [rip + 0x10c11] 0x404e4f: lea rdi, qword ptr [rip - 0x1f6] 0x404e56: call 0x404900 None 11 [4214322L, 4214324L, 4214327L, 4214328L, 4214331L, 4214335L, 4214336L, 4214337L, 4214344L, 4214351L, 4214358L]
同时,可以使用block来获得其他的对象
print(block.capstone) print(block.vex)
States
在angr中,project代表一个可执行文件的映像,如果要模拟执行程序,则需要angr中的SimState的对象states来表示程序状态
state = p.factory.entry_state()
看里面的一些属性
print(state.regs.rip)#rip的值 print(state.regs.rax)#rax的值 print(state.mem[p.entry].int.resolved)#以int的格式打印出p.entry处的值
结果,因为是初始状态,所以初始的rip指向的是p.entry的值
<BV64 0x404e32> <BV64 0x1c> <BV32 0x8949ed31>
上面这些都是不python中int值的含义,BV指的Bitvector,位向量。
这样来进行位向量和int值的转换
>>> bv = state.solver.BVV(0x1234, 32) # create a 32-bit-wide bitvector with value 0x1234 <BV32 0x1234> # BVV stands for bitvector value >>> state.solver.eval(bv) # convert to python int 0x1234
>>> state.regs.rsi = state.solver.BVV(3, 64)
>>> state.regs.rsi
<BV64 0x3>
然后看mem接口
>>> state.regs.rsi = state.solver.BVV(3, 64) >>> state.regs.rsi <BV64 0x3> >>> state.mem[0x1000].long = 4 >>> state.mem[0x1000].long.resolved <BV64 0x4>
使用数组[索引]符号指定地址
使用.<type>指定内存应该解释为<type>(常见值:char、short、int、long、size_t、uint8_t、uint16_t…)
从那里,你可以:
为它存储一个值,可以是位向量,也可以是python int
使用.resolve获取作为位向量的值
使用.concrete获取作为python int的值
>>> state.regs.rdi
<BV64 reg_48_11_64{UNINITIALIZED}>
这仍然是一个64位位向量,但它不包含数值。相反,它有一个名字!这被称为符号变量,它是符号执行的基础。
Simulation Managers
模拟管理器,管理了程序在执行过程之中的各种接口,看看新建一个模拟管理器,使用statue
simgr = proj.factory.simulation_manager(state)
往下执行一个基本快
simgr.step()
我们可以看看simgr.active[0]来查看我们当前的statue,simgr.active[0].regs.rip则会打印寄存器的RIP,可以发现它和初始化simgr的statue已经不同了
Analyses
project中定义了许多的analyses
# Originally, when we loaded this binary it also loaded all its dependencies into the same virtual address space # This is undesirable for most analysis. >>> proj = angr.Project('/bin/true', auto_load_libs=False) >>> cfg = proj.analyses.CFGFast() <CFGFast Analysis Result at 0x2d85130> # cfg.graph is a networkx DiGraph full of CFGNode instances # You should go look up the networkx APIs to learn how to use this! >>> cfg.graph <networkx.classes.digraph.DiGraph at 0x2da43a0> >>> len(cfg.graph.nodes()) 951 # To get the CFGNode for a given address, use cfg.get_any_node >>> entry_node = cfg.get_any_node(proj.entry) >>> len(list(cfg.graph.successors(entry_node))) 2