前言
在攻防世界做题的时候遇到pseudorandom的一个题,需要一步步调试来确定我的输入,但是不知道为什么我的kali一直跑不起来这个程序,看大佬的解法大多都是我不认识的——Angr,所以开始学习一下
本文包括angr的一些基本操作和作用,以及angr_CTF的前三道题
angr_ctf——从0学习angr(一):angr简介与核心概念 – Uiharu – 博客园 (cnblogs.com)
上面的是大佬的博客学习一手
0x0.Angr有什么用
First of all , 得将二进制文件加载进来
import angr
p = angr.Project('./00_angr_find')
这个工具可以从函数入口开始,执行函数直至给定的结束地址,并将每一个state保存在SM(Simulation Manager,模拟管理器)中,state就是指在某一步时的状态,寄存器里的值啥的,下一条执行什么命令等,由此可见,他可以作为一个二进制的文件分析工具来用。
但他更厉害的作用是作为一个符号执行工具
符号执行就是将一个值以符号的形式来代替,碰到分支的时候均会进入,并且会保留所有的分支以及该分支以后的所有分支,还会记录该分支的判断条件,这些条件就是对符号的约束
E.g 输入一个数,如果0<x<=5是则进入Success

一般情况下从输入到Success的过程会经历大量的加解密,这时候Angr保存分支的作用就体现出来了
Angr会记录相应的约束,我们可以通过这些约束来求解出我们的输入,可以使用explorer方法去执行某个状态,直到找到目标指令或者active中没有状态为止,它有如下参数:
- find:传入目标指令的地址或地址列表,或者一个用于判断的函数,函数以state为形参,返回布尔值
- avoid:传入要避免的指令的地址或地址列表,或者一个用于判断的函数,用于减少路径
利用posix.dumps对结果进行约束或者将符号输出:
- state.posix.dumps(0):表示到达当前状态所对应的程序输入
- state.posix.dumps(1):表示到达当前状态所对应的程序输出
下面是angr_CTF的几道题目,练练手先 : )
0x1 angr_CTF 00_angr_find
该平台上的题目,目的是找到能够使程序输出”Good Job”的输入

很清晰的逻辑,将input进行一个加密后输出要为”ZLWLKQEO”即可

关键还是学一下Angr怎么个用法,下面是代码和每一步的详解
import angr
p = angr.Project('./00_angr_find' ,auto_load_libs = False)
#导入二进制文件,并将合适的库导入减少不必要的时间消耗
init_state = p.factory.entry_state() #保存主函数刚进入时候的state
simgr = p.factory.simgr(init_state) #simgr = p.factory.simgr()传入一个state用于创建一个SM
#factory 模块用于创建模拟管理器和基本块 .
target_address = 0x080492F8 #puts指令的地址
simgr.explore(find = target_address)
if simgr.found:
solution_state = simgr.found[0] #找到后打印出当前状态的输入
#0是当前状态,1是下一状态
print(solution_state.posix.dumps(0))
这个字符串好像是动态的,但是问题不大,运行结果如下:

PS: Angr的安装也有教程需要的可以移步观看
0x2 angr_CTF 01_angr_avoid
这个题一打开ida快卡死了,F5也是成功卡在反汇编
直接找字符串’Good Job’,交叉引用在maybe_good里面,但是主函数调用了一坨avoid_me和maybe_good所以主函数很大反汇编不了,这里要运用angr的avoid来避免不必要的分支

import angr
p = angr.Project('./01_angr_avoid',auto_load_libs = False)
init_state = p.factory.entry_state()
simgr = p.factory.simgr(init_state)
target_address = 0x80492FB
bad_address = 0x080492BB
simgr.explore(find = target_address,avoid = bad_address)
if simgr.found:
slotion_state = simgr.found[0]
print(slotion_state.posix.dumps(0))
这样就可以简化很多分支,提高效率
0x3 angr_CTF 02_angr_condition
扔进ida感觉和第一个没啥区别可以直接写

exp如下:
import angr
p = angr.Project('./02_angr_find_condition',auto_load_libs = False)
init_state = p.factory.entry_state()
simgr = p.factory.simgr(init_state)
target_address = 0x0804DA6E
simgr.explore(find=target_address)
if simgr.found:
solution_state = simgr.found[0]
print(solution_state.posix.dumps(0))
else :
print("Not Found")
直接出了,但是作者目的并不是这样,而是要在Good Job的地址不知道的情况下(很难找到打印的函数),根据回显来判断该路径是否满足条件,斯,给出预期的做法:
#target_address = 0x0804DA6E
#simgr.explore(find=target_address) #更改之前的
def is_sucessful(state):
stdout_output = state.posix.dumps(1)
if b'Good Job.' in stdout_output:
return True
else:
return False
def should_abort(state):
stdout_output = state.posix.dumps(1)
if b'Try again.' in stdout_output:
return True
else:
return False
simgr.explore(find = is_sucessful,avoid = should_abort)
通过判断输出中是否有目标字符串来返回布尔值确定是否是符合条件
因为有Plz input的提示所以不能是==