Angr - 求解函数返回值

逆向工程 愤怒
2021-06-14 02:16:36

我正在尝试创建一个 angr 脚本来解决这个测试程序:

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

int main(int argc, char *argv[])
{
    int value = atoi(argv[1]);
    char* foo = "foobar";
    int sum = 0;
    for (int i = 0; i < strlen(foo); ++i)
    {
        sum += foo[i];
    }
    return (sum == value);
}

我试图找出需要将什么值传递给程序才能使其返回 True。事实证明,这并不像预期的那么简单。

返回值在基本块中设置:

最后一块

如您所见,al如果 中使用的值cmp相等则设置

我见过的大多数 angr 解决方案都基于满足特定条件时采用的路径。给定该路径的地址,就可以解决获得该路径地址所需的约束。这在我的情况下不起作用。

我一直在搜索 angr 示例,以寻找一种解决函数返回值的符号变量的方法,但这似乎是不可能的。

我目前正在尝试使用runorexecutefindor untilargs 说: execute until rip == <end of function> and eax == 1

目前我有这个:

import angr
import claripy

def bv_to_int(bv):
    return claripy.backends.concrete.convert(bv).value

def main():
    p = angr.Project('angr_test')
    arg = claripy.BVS('arg', 4*8)

    st = p.factory.entry_state(args=[p.filename, arg])
    sm = p.factory.simulation_manager(st)

    sm.explore(find=lambda _s: bv_to_int(_s.regs.rip) >= 0x400708 and bv_to_int(_s.regs.al) == 1)

    print(sm.found[0].solver.eval(arg, cast_to=bytes))

if __name__ == "__main__":
    main()

目前正在抛出:

Traceback (most recent call last):
  File "angr_test.py", line 19, in <module>
    main()
  File "angr_test.py", line 14, in main
    sm.explore(find=lambda _s: bv_to_int(_s.regs.rip) >= 0x400708 and bv_to_int(_s.regs.al) == 1)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/sim_manager.py", line 237, in explore
    self.run(stash=stash, n=n, **kwargs)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/sim_manager.py", line 259, in run
    self.step(stash=stash, **kwargs)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/misc/hookset.py", line 75, in __call__
    result = current_hook(self.func.__self__, *args, **kwargs)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/exploration_techniques/explorer.py", line 96, in step
    return simgr.step(stash=stash, extra_stop_points=base_extra_stop_points | self._extra_stop_points, **kwargs)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/misc/hookset.py", line 80, in __call__
    return self.func(*args, **kwargs)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/sim_manager.py", line 330, in step
    goto = self.filter(state, filter_func=filter_func)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/misc/hookset.py", line 75, in __call__
    result = current_hook(self.func.__self__, *args, **kwargs)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/exploration_techniques/explorer.py", line 113, in filter
    stash = self._filter_inner(state)
  File "/home/ben/.local/lib/python3.6/site-packages/angr/exploration_techniques/explorer.py", line 124, in _filter_inner
    findable = self.find(state)
  File "angr_test.py", line 14, in <lambda>
    sm.explore(find=lambda _s: bv_to_int(_s.regs.rip) >= 0x400708 and bv_to_int(_s.regs.al) == 1)
  File "angr_test.py", line 5, in bv_to_int
    return claripy.backends.concrete.convert(bv).value
  File "/home/ben/.local/lib/python3.6/site-packages/claripy/backends/__init__.py", line 160, in convert
    "conversion on a child node" % (self, ast.op, ast.__class__.__name__))
claripy.errors.BackendError: <claripy.backends.backend_concrete.BackendConcrete object at 0x7f47a92c05f8> can't handle operation Extract (BV) due to a failed conversion on a child node

任何帮助将不胜感激。

2个回答

好的,我已经想通了。

首先,run应该使用命令。这将针对所有路径运行。

运行后, 的值eax实际上将包含两个可能的值(一个为eax == 0,另一个为eax == 1。需要告诉求解器求解argwhere eax == 1

此脚本将提供正确的输出:

import angr
import claripy

def main():
    p = angr.Project('angr_test')
    arg = claripy.BVS('arg', 3*8)

    st = p.factory.entry_state(args=[p.filename, arg])
    sm = p.factory.simulation_manager(st)

    sm.run()

    sm.deadended[0].solver.add(sm.deadended[0].regs.eax == 1)

    print(sm.deadended[0].solver.eval(arg, cast_to=bytes))

if __name__ == "__main__":
    main()

直接从文档

> explore(stash='active', n=None, find=None, avoid=None,
> find_stash='found', avoid_stash='avoid', cfg=None, num_find=1, **kwargs)

“find”和“avoid”参数可以是以下任何一个:

一个要查找的地址 一组或一组要查找的地址 一个函数,它接受一个状态并返回它是否匹配。

基本上,您必须实现一个接受状态的函数来决定您是否处于所需的状态。如果您愿意,您也可以为失败状态实现一个函数。

也许一些简单的事情可以帮助你,比如

find=lambda x: x.regs.eax == 1 && x.regs.rip >= 0x708