跳转至

angr_explore

从这一节开始我们通过一些典型的CTF例题来学习angr的用法,这些例子都来自GitHub上的angr_ctf仓库,建议读者跟着教程一起练习,并尝试自己解决。

第一节我们首先学习explore函数的简单用法,这是angr中最简单粗暴的一个函数,也是非常常用的一个函数。

00_angr_find

一个非常简单的题目,这点计算量直接手动分析也很简单:

image-20211003114049432

image-20211003114100866

因为程序流程非常简单,运算量也比较小,可以直接用最简单粗暴的explore:

image-20211003114935901

import angr

proj = angr.Project('dist/00_angr_find')
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)
simgr.explore(find=0x8048678)
print(simgr.found[0].posix.dumps(0))

输出:

b'JXWVXRKX'

01_angr_avoid

这题的main函数非常庞大导致无法反编译,也无法手动分析程序流程:

image-20211003121247604

但我们仍然可以通过分析关键代码来了解部分程序逻辑,显然只有should_succeed为true时才能输出"Good Job.",所以avoid_me这个函数肯定是不能被执行的:

image-20211003211539074

image-20211003211549993

所以我们可以在给explore函数传递find参数的同时再传递一个avoid参数,让符号执行引擎避开avoid_me这个函数,代码如下:

import angr

proj = angr.Project('dist/01_angr_avoid')
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)
simgr.explore(find=0x80485E0, avoid=0x80485A8)
print(simgr.found[0].posix.dumps(0))

输出:

b'HUJOZMYS'

不加avoid参数也能跑出结果,不过速度会慢很多,这就是explore函数的第二个用法。

02_angr_find_condition

这题的控制流图(CFG)非常复杂,但是查看伪代码却很简单,推测是有大量功能相同的重复代码块,在IDA生成伪代码的时候被优化了:

image-20211003213024938

image-20211003213039809

因为有很多重复代码块,所以这题也有很多可能会输出"Good Job."的地址,这时候我们像00_angr_find那样设定一个单一的目标地址就不太可能了。不过幸好,explore函数的find参数除了地址外,也可以是一个携带SimState参数的函数,代码如下:

import angr

def is_successful(state):
    return b'Good Job.' in state.posix.dumps(1)

def should_avoid(state):
    return b'Try again.' in state.posix.dumps(1)

proj = angr.Project('dist/02_angr_find_condition')
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)
simgr.explore(find=is_successful, avoid=should_avoid)
print(simgr.found[0].posix.dumps(0))

输出:

b'HETOBRCU'

这里通过is_successful函数判断当前状态的输出流中是否包含b'Good Job.',如果包含则表示到达目的地址,ok,此时可以打印对应的输入了。should_avoid函数同理,这里不再赘述。

除了传入一个函数以外,我们也可以使用lambda表达式来简化代码:

import angr

proj = angr.Project('dist/02_angr_find_condition')
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)
# simgr.explore(find=is_successful, avoid=should_avoid)
simgr.explore(
    find=lambda state : b'Good Job.' in state.posix.dumps(1),
    avoid=lambda state: b'Try again.' in state.posix.dumps(1)
)
print(simgr.found[0].posix.dumps(0))

什么是lambda表达式,大家可以自行学习,这里就不多说了。

评论