Jche
qwqqqqqq

angr-理解符号执行

2022-02-16 angr

理解符号执行-angr

符号类似于我们在计算未知数x的值,我们可以通过路径来求解未知数。通过判断条件来选择路径,当符号满足设定条件时即走了正确的路径。

我们需要通过符号执行来达到一个目标,假设这个目标是走到success这一步。

那么我们符号执行的步骤就相当明了了。

第一步:找到符号。一般这里我们的未知数,即符号就是我们的input。

第二步:找到路径(分支)。

第三步:评估每条路径。

由于路径和二进制文件的复杂度提升,我们给出了更好的选择来通过电脑来评估路径,于是就有了angr

Angr是一个符号执行引擎。

它可以:

遍历二进制文件(并遵循任何分支)

搜索符合给定条件的程序状态

解给定路径(和其他)约束的符号变量

在这里分为符号执行路径两个板块

首先讨论执行路径

1.执行路径

Angr在一个模拟管理器对象中存储和处理一组给定程序的可能路径。

模拟管理器提供了逐步执行程序以生成可能路径/状态的功能。

构建一系列路径

1.Angr在你指定的地方启动程序(这是第一个激活状态)

2.在每个活动(非终止)状态下执行指令,直到到达分支点或状态终止

3.在每个分支点上,将状态拆分为多个状态,并将它们添加到活动状态集

4.重复步骤2 . .4,直到我们找到我们想要的,否则所有的州都会被终止

我们可以对活动状态进行标记,以排除错误的路径。

1.加载二进制

2.指定起点并创建模拟管理器

3.当我们还没有找到我们想要的……

1)步进所有激活状态

2)在每个活动状态上运行’ should_accept_state ‘谓词

3)如果有人接受,我们就找到了我们想要的!退出循环

4)在每个活动状态上运行’ should_avoid_state ‘谓词

5)对于每个被接受的状态,将其标记为终止

6)从活动状态集中移除所有标记为终止的状态

这个算法angr写了一个单独的explore函数

simulation.explore(find=should_accept_path, avoid=should_avoid_path)

将添加任何被接受的路径到列表’ simulation.found ‘

simulation.explore(find= 0 x80430a,avoid= 0x9aa442)

将搜索地址0x80430a并终止任何到达0x9aa442的内容。

2.符号和约束的引入

在某些情况下,当从stdin文件中查询用户输入时,Angr会自动注入符号。*它使用的是SimProcedures,我们将在后面介绍。

当Angr没有自动注入我们想要的符号时,我们可以手动这样做。

Angr的符号是用位向量来表示的

位向量有一个大小,即它们所代表的位数。

与编程中的所有数据一样,位向量可以表示任何适合的类型。通常,它们表示n位整数或字符串。

位向量和典型变量之间的区别是,典型变量存储单个值,而位向量存储满足一定约束条件的所有值。

在简单的例子中,angr会自动将您的input作为符号注入,但在一些复杂的情况下需要手动输入

下面是一些例子:

注入符号示例

1.寄存器

对于简单的情况,Angr会代替它,这样用户输入函数就会将符号值注入寄存器。

对于更复杂的情况,我们需要自己注入符号。在用户输入后启动程序,用符号值初始化寄存器。

情形:get_user_input函数通过将值写入寄存器来返回值(把输入存在内存中,并把地址写到rax寄存器并返回)。(angr不支持写入多个参数于不同地址。)

解决方案:不调用get_user_input,而是将符号值写入寄存器。

在Angr中,你可以用一个具体的或符号的值写入寄存器:

state.regs.eax = my_bitvector

将my_bitvector的值写入eax。

2.全局内存

情形:get_user_input函数通过将值写入编译时确定的地址来返回值。

解决方案:不调用get_user_input,而是将符号值写入地址。

3.栈

在Angr中,你可以用一个具体的或符号的值来推入堆栈:

state.stack_push (my_bitvector)

将my_bitvector的值推到堆栈的顶部。

你可能需要考虑你不关心的任何东西在堆栈的开始通过添加填充:

state.regs.esp - = 4

增加4个字节的填充。

4.动态内存

分配在堆上的内存

可以直接写入到指针覆盖原有指针

如果你不能确定scanf写入的地址,因为它存储在一个指针中,你可以覆盖指针的值,指向你选择的一个未使用的位置(在这个例子中,0x4444444):

state.memory.store(0xaf84dd8, 0x4444444) state.memory.store(0x4444444, my_bitvector)

此时,0xaf84dd8的指针将指向0x4444444,它将存储您的位向量。

5.文件系统

可以当作内存处理,但地址和内存的地址不同,要注意

特殊情况

1.hooks

如果想要跳一些地址,可以使用hook

您可以使用hooks来完成此操作。你可以指定一个‘hook’的地址,你想要跳过的指令的字节数,以及一个将运行的Python函数来替换跳过的指令。

注意:跳过的指令数可以为零。

Call: binary.hook(0x8048776, length=16, replacement_check_all_Z)

第一个是我们想要hook的地址,第二个是代表这些指令在内存中用16个字节表示(跳过的),第三个是代替运行这些指令的函数。

Hook可以用于:

在执行过程中注入符号值。

取代复杂的功能。

替换不支持的指令(例如,大多数系统调用)。

函数回顾

  1. 将参数推入堆栈
  2. 将返回地址推到堆栈
  3. 跳转到功能地址
  4. 处理参数*
  5. 执行函数
  6. 将返回值写入适当的位置
  7. 弹出返回地址并跳转到它
  8. 弹出参数

simprocedures

SimProcedures被用来替换任何你完全理解并且不想测试bug的东西,或者Angr不支持的东西。

因为问题的复杂性随着程序的长度呈指数级增长,任何满足上述条件的函数都应该用SimProcedure代替,以节省时间。

目前,在Angr中包含了libc子集(快速扩展)的重新实现。

Author: John Doe

Link: http://example.com/2022/02/16/angr-%E7%90%86%E8%A7%A3%E7%AC%A6%E5%8F%B7%E6%89%A7%E8%A1%8C/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
csapp-8
NextPost >
C++ Reserve 阅读
CATALOG
  1. 1. 理解符号执行-angr
    1. 1.1. 1.执行路径
    2. 1.2. 2.符号和约束的引入