如何将 angr 限制为可打印字符

逆向工程 C 愤怒
2021-07-09 19:48:11

我有一个二进制文件,它 scanfs 然后做一些检查并返回 FAIL 或 SUCCESS,其中有多个输入的 SUCCESS。虽然只有一个输入只有可打印的字符。如何限制 angr 仅使用输入到 scanf 中的可打印字符?

import angr

def main():
    proj = angr.Project('a.out')
    init_state = proj.factory.entry_state()
    simulation = proj.factory.simgr(init_state)
    simulation.explore(find=lambda s: b"SUCCESS\n" in s.posix.dumps(1))
    
    for solution in simulation.found:
        print(solution.posix.dumps(0), solution.posix.dumps(1))

if __name__ == '__main__':
    main()

这给了我一个包含很多不可打印的 \xDD 的输出,其中 DD 是一个十六进制数。我可以限制 angr 在探索时只使用可打印的字符吗?或者如何防止 angr 在找到一种解决方案以获取 SUCCESS 消息后停止。目前虽然有多种解决方案,但它只能找到一种。

1个回答

如果您知道标志的长度(例如从 RE 获取),您可以通过以下方式修改代码:

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

这将创建一个具有 15 个(在本例中)大小为 8 位的位向量的数组。在下一行,我们将连接它们(+ 新行值)以获得一个我们可以操作的值。

接下来,我们通过标志来创建我们的状态。

 init_state = proj.factory.entry_state(stdin=flag)

有了 init 状态,我们可以限制标志:

 for k in flag_chars:
     init_state.solver.add(k <= 0x7f)
     init_state.solver.add(k >= 0x20)

其余保持不变。

完整程序:

import angr
import claripy

def main():
    proj = angr.Project('a.out')
    flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(15)]
    flag = claripy.Concat(*flag_chars+[claripy.BVV(b'\n')])

    init_state = proj.factory.entry_state(stdin=flag)

    for k in flag_chars:
        init_state.solver.add(k <= 0x7f)
        init_state.solver.add(k >= 0x20)

    simulation = proj.factory.simgr(init_state)
    simulation.explore(find=lambda s: b"SUCCESS\n" in s.posix.dumps(1))

    for solution in simulation.found:
        print(solution.posix.dumps(0), solution.posix.dumps(1))


if __name__ == '__main__':
    main()