因为项目需求,最近在研究如何使用符号执行技术对恶意程序进行分析。查找资料的时候发现国内关于符号执行的技术贴还是非常少的,查找了很多关于符号执行的开源框架之后,最终还是选择使用angr探探路(也只有angr有一些入门教程了(lll¬ω¬)),作为一名第一次发帖的新手,也趁着30天写作挑战活动的势头,发帖记录一下自己初学angr的一些理解与使用吧。
由于论坛里已经有前4道题目题解,因此在这里分享一下使用angr对第五道题目的多种解法。首先运行一下
发现有四段输入,再使用file命令看一下架构
好的32位,直接用idaPro打开。
虽然首先看看汇编码来理解程序是个好习惯,但是为了行文方便,直接F5反编译:
可以看出scanf分别接收了4个8字节长的字符串,连一起正好32字节,字符串存在程序.bss节,也就是说scanf接受的32字节长的字符串将不会存于栈而是存于事先就声明的未初始化的全局变量之中。随后for循环迭代32次,对输入的字符串的每个字节进行complex_function函数的加密处理,最后将加密过后的字符串与'NJPURZPCDYEAXCSJZJMPSOMBFDDLHBVN'进行比较,字符串相等则算是拿到了flag。整个程序的结构逻辑还是非常简单清晰的,接下来启动angr,载入程序。
angr的安装非常非常非常简单无痛,在virtualenv 环境下pip install angr就ok了。首先启动Jupyter Notebook,启动angr载入要分析的二进制文件,
Project对象只代表程序的“初始化映像”。若要使用angr进行符号执行,需要一个特定的对象State表示模拟程序的状态,当前选用了state对象表示模拟从程序的入口点开始的状态。随后我们需要找到符号执行的终点站,也就是正确的flag的位置,使用idaPro看一下,
我们发现'Good Job.'的地址位于0x0804866D,'Try again.'的地址位于0x0804865B,接下来在jupyer中定义angr要达到的程序的地址,并申明state的模拟管理器sim来用于执行模拟的程序,使其从一个给定地址的状态到达下一个地址的状态。
接下来要模拟程序的执行,
从函数的参数名称就能够知道,需要达到的是good_addr的指令状态,需要剪枝的是bad_addr指令状态,这样是为了避免不必要的状态的搜索,从而极大减少了符号执行需要模拟执行的指令范围以及时间。
运行完成之后,我们得到了如下结果:
<SimulationManager with 1 active, 64 deadended, 1 found>
很好,程序找到了一个可以达到good_addr的情况,我们将angr在到达这个分支所输入的内容打印出来,
结果如下:
b'NAXTHGNR JVSFTPWE LMGAUHWC XMDCPALU',刚好四个字符串,每个8个字节长,程序真实运行并输入以上字符串,
说明angr的输入是正确的,我们拿到了真实的flag。
让angr寻找到达具体地址的方法是一个不错的符号执行寻找flag的方法,除了地址还有其他方法吗,答案是有的,angr的强大之处不仅仅是可以搜索达到地址条件的状态,还可以根据多种多样的约束条件进行执行。接下来是根据程序的标准输出进行判断搜索。
之前的载入二进制文件的代码不需要改变,我们定义两个根据程序的标准输出进行判断的程序,
一般情况下,标准输出文件描述符为1,我们对模拟的程序的状态的标准输出进行判断,当Good Job.字符串在标准输出中时候,说明模拟的状态已经到达flag程序分支,angr在该状态中输入的字符串是正确的,反之,当state输出Try again.,则说明这是要剪枝的分支,没有再进一步模拟执行的必要,从而节省分析时间。让我们模拟运行一下,
得到结果
<SimulationManager with 64 deadended, 1 found, 1 avoid>、
说明angr找到了能够输出Good Job.的分支,打印该状态的下的输入
b'NAXTHGNR JVSFTPWE LMGAUHWC XMDCPALU'
可见拿到了正确的flag。
之前我们都是直接从二进制程序的程序入口点开始进行模拟的,因为scanf的四个字符串是全局变量,都存与地址已知的内存当中,我们不妨跳过scanf,直接对这个这四个字符串所在的内存地址进行赋值,让angr直接从scanf之后的程序指令地址开始执行(这也正是angr的强大之处,可以在二进制文件任意的程序地址执行,参数可以任由分析人员修改)。
首先确定模拟程序的入口地址,
调用scanf再还原栈地址后,地址为0x08048601,那么让模拟程序从该地址开始,由于不再是从一般程序的入口点开始,所以需要使用blank_state,对载入地址进行自定义,
接下来确定scanf存入字符串的内存的地址,并申明4个8字节长的字符串向量
将四个字符串载入模拟的程序状态的内存之中,
开始模拟执行,
得到结果,
<SimulationManager with 1 found, 65 avoid>
查看在状态内存中输入的四个字符串向量的值,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-9-7 17:10
被xuada编辑
,原因: