Angr应用

Angr符号执行

前言

之前已经把Angr下的所有方法进行了学习了解,但停留于表面等于没学,需要结合相关的题目进行应用才可以正确掌握。Angr在github的源码中以及提供有一个example的文件夹,里面包含了许多难易不一的比赛题目以及基于Angr的解题脚本。
链接在这里

参考:Angr状态选项列表:https://docs.angr.io/appendix/options

正文

这里以一道简单的题目作为例子进行学习:ais3_crackme,在linux下查看可以看到这个程序是一个64位程序

我们可以直接把程序脱到64位IDA下进行分析:

第一眼看来很简单,只要if中的条件能够达成就可以了,那么重点就在verify。

程序自带的数据:

就是程序自带的数据与指令行的输入进行处理后的结果进行比较,满足条件即可。

如果没有angr我们可以选择爆破,构造对应条件爆破对位字符即可。脚本如下:

import string
key=[ 0xCA, 0x70, 0x93, 0xC8, 0x06, 0x54, 0xD2, 0xD5, 0xDA, 0x6A,
  0xD1, 0x59, 0xDE, 0x45, 0xF9, 0xB5, 0xA6, 0x87, 0x19, 0xA5,
  0x56, 0x6E, 0x63]


flag=""
for i in range(len(key)):
    for a1 in string.printable:
            if (((((((ord(a1))&0xff) ^ i) << ((i ^ 9) & 3))&0xff) | ((((( ord(a1))&0xff) ^ i) >> ((8 - ((i ^ 9) & 3))&0xff))&0xff))+ 8)&0xff==key[i]:
                    flag+=a1
print flag

这里可以选择Angr进行解题。
想要使用Angr,基本的操作就是先要将程序进行加载:

project = angr.Project("./ais3_crackme")

上面已经提到,这里是通过命令行获取参数args,所以我们需要claripy库构造一个符号状态,从IDA中不难看出flag的长度为23,所以设置如下:

u = claripy.BVS("u",23*8)

此时我们需要获取程序的入口状态,并代入参数:

state = project.factory.entry_state(args=["./ais3_crackme",u])

下面要做的就是构造一个模拟器将程序载入进行等候运行,以找寻正确答案:
sm = project.factory.simulation_manager(state)

下面就是运行程序,但是这里我们可以进行一些小小的设置,这个题目的尽头有两种可能,成功提示,错误提示,或者就是没有思路。emmm,那么在尝试的过程中会触碰到多条路径,探索的过程中的限制我们先不讨论,我们可以设置尽头,我们只想要能够通向成功的路径。

所以我们可以在运行的时候加入如下限制,find后面跟的就是正确结果,avoid就是错误结果:

sm.explore(find=0x400602,avoid=0x40060E)

下面使用eval将找到值进行转换得到结果就是flag了(cast_to就是转换的类型,目前只能指出int和str两种):

solution = found.solver.eval(argv1, cast_to=str)

最终跑出结果:

脚本在题目所在目录下已经包含,这里就不贴了。

小结

Angr通俗而言就是爆破,但是在其中包含有许多其他的技术,约束求解、解析程序等。上述题目解答逻辑较为清晰,所以可以自主编写爆破脚本进行解答。但是有的题目设置了比较复杂的算法在其中,这时候编写解题脚本的过程就较为复杂,且不考虑出错的情况。所以Angr可以帮助更快的得到结果。大致的解题过程:

  1. 对题目进行分析找到正确路径地址,运行中的检验条件,flag长度等一系列信息。
  2. 加载程序,设置参数(根据分析得到的flag长度进行设置,也可设置一个大致数值,关乎效率),获得入口状态(根据需求,添加参数,添加状态选项等)
  3. 根据IDA下分析添加约束条件,提高效率。
  4. 使用模拟器进行符号执行求解。
  5. 获得运算结果。
Contents
  1. 1. 前言
  2. 2. 正文
  3. 3. 小结
|