angr符号执行用例解析——cmu_binary_bomb

本文通过angr符号执行分析cmu_binary_bomb,涉及各阶段的解题策略,包括字符串比较、递归计算、switch case等。通过hook函数处理scanf等库函数,解决路径爆炸问题。
摘要由CSDN通过智能技术生成

解题源码以及二进制文件在:https://github.com/angr/angr-doc/tree/master/examples/cmu_binary_bomb

一道有趣的题目!

首先运行bomb文件,随便输入个字符串,bomb! 炸了!

总共有6关要闯,每次只要输入满足要求的数据才能进入下一关,否则就爆炸。

拖到IDA里面分析,发现第一关的字符串比较还蛮简单,下面几关就需要计算了。

int __fastcall phase_1(__int64 a1)
{
  int result; // eax@1

  result = strings_not_equal(a1, "Border relations with Canada have never been better.");
  if ( result )
    explode_bomb(a1, "Border relations with Canada have never been better.");
  return result;

还是直接angr符号执行进行分析算了。

当然angr符号执行分析肯定也不简单,还是需要分析的。

(在我十分高估angr的时候我写出过如下代码:

大意就是模拟执行,找到包含0x400E49的路径,求解约束

import angr
import claripy

b=angr.Project('bomb',load_options={'auto_load_libs':False})
sm=b.factory.simulation_manager(b.factory.entry_state())
sm.explore(find=0x400E49)
print len(sm.found)
found=sm.found[0]
solution1 = found.posix.dumps(0)
print "print"
print repr(solution1)

Error:    found=sm.found[0]

IndexError: list index out of range

呵,native!)

要想符号执行,首先要让angr能够模拟执行下去,如果都执行不下去,肯定是找不到包含目标地址的路径的啊。

那angr什么时候会执行不下去呢?我们需要提供哪些辅助呢?这个。。以后再说。先看这道题的用例都做了些什么。

首先是phase_1:

从IDA中,我们发现它的验证逻辑就是字符串比较,而且字符串以及明文在代码中了,所以逻辑非常简单。同时这个函数没有调用任何库函数以及系统调用,所以angr肯定能模拟执行的啦。

使用angr分析时,为了避免执行到angr无法模拟的函数或系统调用,用例代码只对phase_1函数进行了符号执行分析。

创建一个空状态,起始地址就是phase_1的起始地址;

创建一个符号变量,逆向发现phase_1是从reg.rdi寄存器读取输入数据的,因此将reg.rdi赋值为符号变量;

注意注意:reg.rdi存放的是地址,phase_1是先从reg.rdi取址,然后从这个地址读取字符串的。IDA里可以看到,read_line函数是从窗口读取数据放入到地址 0x603780中,然后将这个地址传递个reg.rdi的。(测试过,这个地址可以为任意值,只要不影响后面的执行就可以,毕竟只是提供了一个存放符号变量的媒介。)

初始化符号执行,找到phase_1的返回地址end = 0x400ef7,求解此时符号变量的值。

phase_2:

phase_2部分是输入6个数字进行判断,第一个数是否是1,然后后面一个数是否是前一个数的2倍。

phase_2函数调用了库 ___isoc99_sscanf,似乎angr不能处理呢,所以跳过了这个函数,符号执行的起始地址为:0x400f0a。

由于判断逻辑是从栈里面取数据,所以我们需要创建6个符号变量,并压入栈中。然后开始执行符号执行,结束地址就是phase_2函数的结束地址就可以。

phase_3:

phase_3部分是输入两个整数,switch case语句,根据第一个整数判断第二是否匹配。

与phase_2类型,不过这个函数有多个解,所以可以重点关注一下,如何求解多个解的方法。

对于explore发现的所有活跃(active)状态(or 路径)都加入队列里,分别求解它们的值。

同时对于found集合,不再只是取第一个found[0]而是对所有的found都进行遍历求解。

phase_4:

phase_4部分是输入两个整数,第二个整数不变,第一个整数递归计算,最后结果均为0。所以第二个数为0,第一个数利用angr求解为7。这里测试了一下栈数据的读取。有的时候通过found.regs.rsp - 0x18 + 0x8读取第一个参数,有的时候通过found.stack_pop()读取参数。其实它们是等价的。

rsp指向的是返回地址,所以会先found.stack_pop() 弹出返回地址 使rsp+0x8

rsp+0x8指向的是第一个参数 这时候found.stack_pop()弹出的才是第一个参数。

rsp+0xc指向的是第二个参数。

具体的内容可以学习一下:逆向基础 堆栈详解 —— https://mp.weixin.qq.com/s/PlLHRJ3XbJ6z6C5-rPXfEQ

phase_5:

phase_5需要接收长度6的字符串,遍历字符串的字符取byte值去一个字符数组中索引,拼接成一个新的字符串。新的字符串应该为"flyers"。

这次它利用了proj.kb.obj.get_symbol函数,通过函数名来获取想要分析的函数地址。

    start = proj.kb.obj.get_symbol('

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值