简单的 angr 示例不起作用

逆向工程 C 愤怒
2021-06-22 03:27:38

我正在尝试从头开始学习 angr。由于缺乏简单的教程,我编写了自己的小可执行文件,angr 应该可以解决这个问题。

C 代码如下所示:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    char buffer[20];
    printf("Password\n");
    fgets(buffer,20,stdin);
    if (strcmp(buffer,"super!\n")==0) {
        printf("SUCCESS!\n");
    } else {
        printf("FAIL!\n");
    }
    return 0;
}

在二进制 ninja 中编译和打开时,我在以下地址看到 printfs: 国阵 所以我创建了以下 angr python3 代码:

import angr
from angr.state_plugins import SimSystemPosix

p = angr.Project('./test')
state = p.factory.entry_state()



sm = p.factory.simulation_manager(state)
sm.explore(find=0x40118c, avoid=0x40119a)

print(sm.found)

运行 python 代码显示以下输出:

python3 solve_angr.py 警告 | 2020-06-08 10:02:29,497 | angr.state_plugins.symbolic_memory | 程序正在访问具有未指定值的内存或寄存器。这可能表示不需要的行为。
警告 | 2020-06-08 10:02:29,497 | angr.state_plugins.symbolic_memory | angr 将通过生成一个不受约束的符号变量并继续来解决这个问题。您可以通过以下方式解决此问题:
警告 | 2020-06-08 10:02:29,497 | angr.state_plugins.symbolic_memory | 1) 设置一个值到初始状态
WARNING | 2020-06-08 10:02:29,497 | angr.state_plugins.symbolic_memory | 2) 添加状态选项 ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS},使未知区域保持为空
警告 | 2020-06-08 10:02:29,497 | angr.state_plugins.symbolic_memory | 3) 添加状态选项 SYMBOL_FILL_UNCONSTRAINED_{MEMORY_REGISTERS},以抑制这些消息。
警告 | 2020-06-08 10:02:29,498 | angr.state_plugins.symbolic_memory | 在(在libc.so.6的(0x8d4e0)的strcmp +为0x0)从0x58d4e0引用0x7fffffffffefff8 72不受约束字节填充存储器
警告| 2020-06-08 10:02:29,499 | angr.state_plugins.symbolic_memory | 使用从 0x58d4e0 引用的 8 个无约束字节填充 0x7ffffffffffeff70 处的内存(libc.so.6 (0x8d4e0) 中的 strcmp+0x0)
[]

[] 表示它没有找到任何解决方案。

谁能告诉我我做错了什么?

2个回答

我认为这个问题与getsangr 中符号程序的实现方式有关您要求读取 20 个字节,据我所知,分配的实际符号内存的大小为 20(19 个字符串字符和一个 NULL 终止符)。稍后,当您调用 to 时strcmp,比较将始终失败,因为您将 20 个字节的字符串与super!\n较短的字符串进行比较所以比较结果永远不会是0,angr的符号执行引擎永远不会到达printf("SUCCESS!\n");子句。

如果您将代码修改为:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    char buffer[20];
    printf("Password\n");
    fgets(buffer,8,stdin); // <-------------- Adjust size to be same as "super!\n"
    if (strcmp(buffer,"super!\n")==0) {
        printf("SUCCESS!\n");
    } else {
        printf("FAIL!\n");
    }
    return 0;
}

这样它就可以正常工作并达到 printf("SUCCESS!\n");

如果您无法修改二进制文件,但通过静态分析,您可以获得需要作为标志提供的字节数,您可以构造位向量

flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(6)]
flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')])

并将其传递给 ,entry_state因为该标志作为输入提供stdin给此二进制文件。

p = angr.Project('test')
state = p.factory.entry_state(args=['./test'], stdin=flag)

通过这样的设置,angr将成功找到解决方案。

此外,如果您想提取标志

found = sm.found[0]
flag_str = found.solver.eval_upto(flag, 7, cast_to = bytes)
print(flag_str)