动若脱兔(一):深入浅出angr--初步理解符号执行以及angr架构

一:概论 

 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有个直观的描述,后续具体的应用也需要对angr有个直观的认识。

猜你喜欢

转载自www.cnblogs.com/0xJDchen/p/9291335.html