一:概论 

 angr作为符号执行的工具,集成了过去的许多分析方式,它不仅能进行动态符号执行,而且还能进行很多静态分析,他在分析二进制程序中能发挥很大的作用,下面为一些应用:

  1:利用符号执行探究执行路径,自动解ctf逆向题

  2:利用angr获取程序控制流(CFG)

  3:利用angr生成rop链

  4:利用angr发现漏洞

  5:利用angr加密程序

  6:进行污点跟踪

  由上可以发现,angr的应用是非常多的,里面关于符号执行的应用和思路(特别是自动化相关的思路)是非常值得学习的,本篇不涉及angr的具体应用,主要讲一下angr整个设计的架构。

二:符号执行

  先初略了解一下符号执行,对angr有个大致的了解,后续利用angr再对符号执行的理解进行加深。最传统的符号执行是静态符号执行,首先将输入的变量符号化,如果通俗点的话就是设置输入变量为x,然后通过静态分析程序的cfg流,转化为中间语言,获得符号化的变量在程序流程中的改变,从而输出一个带符号化变量的值。举个例子:

a = raw_input()
b = 2*a
if( b == 10):
print "win"
else:
print "lose"

  在这个简单的代码段里,传统的运行是 先输入a的值,再运行下来的代码。在静态符号执行的过程中,首先将a进行符号化,就是转化为x,所以b就是 2*x,当b == 2*x时,则走入”win"路径,如果 b!=2*x时,则走入lose路径。路径合起来称之为执行树,(b==2*x)和(b!=2*x)即为路径约束式,当符号执行结束时(程序正常或者异常退出),约束求解器就会对路径约束式进行求解(可以简单理解为解方程),解出的答案就是走到这个路径需要的值。

  当然,这种方式看起来很美丽,但是在实际执行过程中会出现很多问题,其中一个就是约束式无法通过约束式求解的问题,这里的解决方案是将传统的静态符号执行和实际执行结合起来,称之为动态符号执行(concolic execution),concolic维持了两个状态。一种是实际变量的状态,另一种是符号化的状态。实际状态将随机生成值映射到变量中,而符号化状态将变量进行符号化。concolic首先将实际状态运行,并收集实际运行时该路径的变量符号化的约束式,i求解。并将约束式取反,获取另一条路径的约束式并求解。过程不断重复,知道路径被探索完,或者达到用户设置的限制。

  以上面的代码为示例,Concolic随机生成变量(a = 7),然后实际运行走了lose路径。在判断语句中,根据收集的约束式取反(b== 2*x),可以得到另一条路径。通过实际运行这种方式,可以很好的避免了约束式无法识别和求解的问题。

三:Angr架构

  angr架构非常清晰,主要分为下图这些模块,每个模块的功能以及彼此间的联系。

3.1 CLE模块

  二进制的装载组建是CLE(CLE Load Everything),它负责装载二进制对象以及它所依赖的库,将自身无法执行的操作转移给angr的其它组件,最后生成地址空间,表示该程序已加载并可以准备运行。

>>> import angr, monkeyhex
>>> proj = angr.Project('/bin/true')
>>> proj.loader
<Loaded true, maps [0x400000:0x5008000]>

  cle.loader代表着将整个程序映射到某个地址空间,而地址空间的每个对象都可以由一个加载器后端加载,例如cle.elf用于加载linux的32位程序。下面是地址空间的分类

>>> proj.loader.all_objects
[<ELF Object fauxware, maps [0x400000:0x60105f]>,
<ELF Object libc.so.6, maps [0x1000000:0x13c42bf]>,
<ELF Object ld-linux-x86-64.so.2, maps [0x2000000:0x22241c7]>,
<ELFTLSObject Object cle##tls, maps [0x3000000:0x300d010]>,
<KernelObject Object cle##kernel, maps [0x4000000:0x4008000]>,
<ExternObject Object cle##externs, maps [0x5000000:0x5008000]>

  其中,类型可以分为 proj.loader.main_object,proj.loader.share_object,proj.loader.kernel_object等等...获取特定object之后,可以与object进行交互获取更详细的信息

3.2 ArchInfo模块

  archinfo是包含特定于体系结构的信息的类的集合。太过于底层,在日后的分析中逐步解释

3.3 PyVex模块

  angr需要处理不同的架构,所以它选择一种中间语言来进行它的分析,angr使用Valgrind的中间语言——VEX来完成这方面的内容。VEX中间语言抽象了几种不同架构间的区别,允许在他们之上进行统一的分析。各种中间语言在设计理念上有很多的共通点,这里又会是一个很大的话题,所以暂且抛开,具体关于IR语言的语法规则请查阅 https://docs.angr.io/docs/ir.html。

3.4 SimuVEX模块

  这里是中间语言VEX执行的模拟器,它允许你控制符号执行。

3.5 Clarity

  这个模块主要专注于将变量符号化,生成约束式并求解约束式,这也是符号执行的核心所在,在angr中主要是利用微软提供的z3库去解约束式

3.6 angr以及以上

  这些则为上层封装好的接口,后续使用时在描述。

四:angr的输入输出

  一般来说,命令行程序主要有两种数据输入的方式,第一种是利用api(get,read),第二种是放在argc上,其它的方法有很多,最后也会提供一种通用的解法。

  当数据输入在argc上时,一般使用claripy库,将输入的数据符号化,具体代码如下:

import angr
import claripy
p = angr.Project("test")
args = claripy.BVS('args', 8*16)
initial_state = prog.factory.entry_state(args=["./vul", args])
for i in range(0,8):
  initial_state.add_constraints(argc.get_byte(0) >= argvc.get_byte(1))
pg = p.factory.path_group(initial_state)
pg.explore(find=(0x4005d1,))
print pg
# <PathGroup with 18 deadended, 4 active, 1 found>
print pg.found[0]
# <Path with 64 runs (at 0x4005d1)>
print pg.found[0].state.posix.dumps(0)

  claripy库是求解器引擎,绝大部分只是用来做z3的前端,而在这里起到的作用主要是将参数符号化,核心代码为第四行。

  当利用api时,主要通过对st.posix.files[0]进行符号化,具体代码如下:

 p = angr.Project('wyvern')
st = p.factory.full_init_state(args=['./wyvern'], add_options=angr.options.unicorn)
for _ in xrange(28):
k = st.posix.files[0].read_from(1)
st.solver.add(k != 0)
st.solver.add(k != 10)
k = st.posix.files[0].read_from(1)
st.solver.add(k == 10)
st.posix.files[0].seek(0)
st.posix.files[0].length = 29

  state.pix在angr中是  angr.state_plugins.posix.SimSystemPosix类,该类的主要作用是用于模拟符合posix环境的数据存储和输入输出。其中files[0]代表着数据的输入,read_from表示读取输入的数据。第3到第8行对输入的数据进行限制,

最后两行将指针重新指向开头并设置长度。

  第三种是最通用的方式,直接访问并修改内存,无论程序是通过何种方式进行输入,输入的数据总是在内存中,可以通过对内存进行符号化。具体代码示例如下:

import angr
p = angr.Project('./vul')
s = p.factory.blank_state(addr=0x80485c8)
bvs = s.se.BVS('to_memory', 8*4)
s.se.add(bvs > 1000)
s.memory.store(0x08049b80, bvs, endness='Iend_LE')
pg = p.factory.path_group(s, immutable=False)

  其中 endness有三个值,分别为

Variables:
LE – little endian, least significant byte is stored at lowest address
BE – big endian, most significant byte is stored at lowest address
ME – Middle-endian. Yep.

  关于内存操作还可以多说一下,s.memory.store可以用于存储数据,s.memory.load用于读取数据.。

五:angr解题步骤:

  这里本篇主要利用simulation_manager(老版本为factory_group)求解

#!/usr/bin/env python
# -*- coding: utf-8 -*- import angr
import claripy angr.l.setLevel('DEBUG')
p = angr.Project('./vul', load_options={"auto_load_libs": False}) args = claripy.BVS('args', 8*100)
initial_state = p.factory.entry_state(args=[p.filename, args], add_options={'BYPASS_UNSUPPORTED_SYSCALL'}) #pg = p.factory.path_group(initial_state, immutable=False),在新版本被代替,和simlation_manager等效
pg = p.factory.simulation_manager(initial_state)
find_addrs = (0x400546, )
avoid_addrs = ()
pg.explore(find=find_addrs, avoid=avoid_addrs)
print pg
print ans = pg.found[0].state.se._solver.result.model print pg.found[0].state.posix.dumps(0) //代表该状态程序的所有输入
print pg.found[0].state.posix.dumps(1) //代表该状态程序的所有输出

  simualtion_manager初始化运行之后,一般有以下几种状态   

  step()表示向下执行一个block(42bytes),step()函数产生active状态,表示该分支在执行中;

  run()表示运行到结束,run()函数产生deadended状态,表示分支结束;

  explore()可以对地址进行限制以减少符号执行遍历的路径。例如 sm.explore(find=0x400676,avoid=[0x40073d]) explore()产生found状态,表示探索的结果等等。也可以使用条件来进行find匹配

1
pg.explore(find=lambda s: "Congrats" in s.posix.dumps(1))

  simulation_manager式angr最重要的控制接口,模拟管理器的最基本功能是利用step()通过一个基本块将给定存储中的所有状态向前推进。当然,如果不对路径探究过程进行细致研究,只需要使用run()和explore()就好了,在简述run和explore之前,首先对路径的stashes进行描述。

  当explore()以find参数运行时,程序会一直运行,直到找到与查找条件相匹配的状态,该条件可以是要停止的指令的地址(地址列表),或者是一些运行时是否符合的状态。当条件存储的任何条件与find条件匹配时,他们将置于found存储中,同时也可以设置avoid,符合avoid条件时也会将其置于avoid中。和run()函数不同的是,run()函数会存储所有的路径状态,而expore()只会存储find的状态。

  在路径探索中,一般使用广度优先算法进行探究,当然我们也可以自由设置使用其它方法,例如深度优先...具体可以使用angr.exploration_techniques

动若脱兔:深入浅出angr--初步理解符号执行以及angr架构的更多相关文章

  1. javascript 原型及原型链的初步理解

    最近折腾了好久,终于是把js里面的原型和原型链做了个初步的理解: 在这里,我打个比喻: 我(child),我妈constructor(构造函数)生了我:别人问我老妈跟谁生的我,于是此时我妈会指向我爸爸 ...

  2. Spring学习笔记--环境搭建和初步理解IOC

    Spring框架是一个轻量级的框架,不依赖容器就能够运行,像重量级的框架EJB框架就必须运行在JBoss等支持EJB的容器中,核心思想是IOC,AOP,Spring能够协同Struts,hiberna ...

  3. Graph Cuts初步理解

    一些知识点的初步理解_8(Graph Cuts,ing...) Graph cuts是一种十分有用和流行的能量优化算法,在计算机视觉领域普遍应用于前背景分割(Image segmentation).立 ...

  4. 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感

    关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...

  5. 网络编程懒人入门(六):深入浅出,全面理解HTTP协议

    本文引用了自简书作者“涤生_Woo”的文章,内容有删减,感谢原作者的分享. 1.前言 HTTP(全称超文本传输协议,英文全称HyperText Transfer Protocol)是互联网上应用最为广 ...

  6. springBoot(1)---springboot初步理解

    springboot初步理解 在没有用SpringBoot之前,我们用spring和springMVC框架,但是你要做很多比如: (1)配置web.xml,加载spring和spring mvc 2) ...

  7. Mysql加锁过程详解(7)-初步理解MySQL的gap锁

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  8. 深入浅出:全面理解SQL Server权限体系

    转自IT168  好文转载存档! [IT168 技术]权限两个字,一个权力,一个限制.在软件领域通俗的解释就是哪些人可以对哪些资源做哪些操作.在SQL Server中,"哪些人", ...

  9. 关于THINKPHP5模型关联的初步理解

    初步理解的意思是,使用最常用的关联模型,然后可以正常运行 还是打个比方 文章表  和文章分类表 一个文章分类可以有多个文章  所以  文章分类模型和文章建立 hasMany的关联 而文章和文章分类表则 ...

随机推荐

  1. asp.net SimpleImpersonation使用身份模拟访问局域网共享目录

    mvc中默认账户的权限很低,缺省情况下,ASP.NET应用程序以本机的ASPNET帐号运行,该帐号属于普通用户组,权限受到一定的限制,以保障ASP.NET应用程序运行的安全.但是有时需要某个ASP.N ...

  2. 外观模式(Facde)【设计模式】

    定义:为子系统中的一组接口提供一个一致的界面,Fcade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. “外观模式(Facade pattern),是软件工程中常用的一种软件设计模式,它 ...

  3. onCreateView的一个细节--Fragment

    public View onCreateView(LayoutInflater inflater, ViewGroup contaiiner, Bundle savedInstanceState) 在 ...

  4. 【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】

    模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: ----------------------------------------- ...

  5. 五分钟学习Java8的流编程

    1.概述 Java8中在Collection中增加了一个stream()方法,该方法返回一个Stream类型.我们就是用该Stream来进行流编程的: 流与集合不同,流是只有在按需计算的,而集合是已经 ...

  6. 【洛谷 P3402】 【模板】可持久化并查集

    题目链接 可持久化并查集,就是用可持久化线段树维护每个版本每个节点的父亲,这样显然是不能路径压缩的,否则我们需要恢复太多状态. 但是这并不影响我们启发式合并,于是,每次把深度小的连通块向深度大的上并就 ...

  7. JavaWeb使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 1.什么是表单 ...

  8. Python第三方库wordcloud(词云)快速入门与进阶

    前言: 笔主开发环境:Python3+Windows 推荐初学者使用Anaconda来搭建Python环境,这样很方便而且能提高学习速度与效率. 简介: wordcloud是Python中的一个小巧的 ...

  9. hadoop入门学习

    hadoop入门学习:http://edu.csdn.net/course/detail/1397hadoop hadoop2视频:http://pan.baidu.com/s/1o6uy7Q6HDF ...

  10. Linux的SMP,UMA,NUMA

    SMP 是Symmetric Multi-Processing的意思,对称多处理器,一种多核结构,认为这些核是完全同构的,任务可以随便在任一个核上跑. UMA是Uniform Memory Acces ...