2

I'm trying to create an angr script to solve this test program:

#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);
}

I'm trying to find out what value needs to be passed to the program in order for it to return True. This is turning out to be less trivial than anticipated.

The return value is set in the basic block:

last block

As you can see, al is set if the values used in the cmp are equal.

Most angr solutions I have seen are based on a path that is taken if a certain condition is met. Given the address of that path, it is possible to solve the constraints required to get to the address of that path. This will not work in my case.

I have been scouring the angr examples for a way to solve a symbolic variable for a function return value, but this doesn't seem to be possible.

I'm currently trying to use run or execute with the find or until args to say: execute until rip == <end of function> and eax == 1.

Currently I have this:

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()

Which is currently throwing:

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

Any help would be greatly appreciated.

2

Right from the documentation:

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

The “find” and “avoid” parameters may be any of:

An address to find A set or list of addresses to find A function that takes a state and returns whether or not it matches.

Basically, you will have to implement a function accepting a state to decide whether you are in the desired state. You can also just implement a function for the failed state if you'd like.

Maybe something easy can help you, such as

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

  • I have actually tried using explore, and run(until=<stuff>). I'll my current script to the question to illustrate. – ben_re Feb 7 at 13:39
1

Ok, I've figured it out.

First of all, the run command should be used. This will run for all paths.

After the run the value of eax will actually contain two possible values (one for eax == 0, and another for eax == 1. The solver needs to be told to solve arg where eax == 1.

This script will give the correct output:

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()

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.