Skip to content

00 Angr Find

Analyzing the Binary

Opening up the binary in a decompiler we can see that the input is a 8 character string:

8 Character Input

It is going loop through each letter and then call complex_function with the letter and the index as arguments. It is then going to compare the output to the string JACEJGCS

Compare Output

Now, lets take a look at the complex_function. As you can see, it first tests if the input value is between 0x40 and 0x5a and then does some math operations and returns the result:

Complex Function

Building the Script

Now, lets try and build a script so that angr can solve it for us. The first thing we will want is to create a project and an initial state. For the state I am using the entry_state and adding a couple of options that if not included will print warning messages when run.

path_to_binary = "./00_angr_find"
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state(
    add_options={
        angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
        angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
    },
)

Next we create the simulation manager from the project and the initial_state created above.

simulation = project.factory.simgr(initial_state)

We want to give the simulation manager information so that it knows when it has found the solution. Then we want to tell the simulation manager to go forth and pillage. We can do both by running the explore method and giving it the address to find, which we get from the decompiler:

Find Address

print_good_address = 0x0804867D
simulation.explore(find=print_good_address)

The simulation manager will go and do its thing, once done we want to check for a solution and if it exists print it out.

if simulation.found:
    solution_state = simulation.found[0]

    solution = solution_state.posix.dumps(sys.stdin.fileno()).decode()
    print(f"[+] Solution found: {solution}")

Now we just run it.

That is it for the first one. I made a few changes to my final script (shown below).

Final Script

This is the final script. I include a python function to run the binary with the solution as input to verify it works.

import sys

import angr
import pwn


def run_binary(solution, path_to_binary):
    if type(solution) == str:
        solution = bytes(solution, "utf-8")
    print(f"[+] Solution found: {solution.decode()}")
    print("    [|] Running binary")
    elf = pwn.ELF(path_to_binary, checksec=False)
    pty = pwn.process.PTY
    io = elf.process(stdin=pty, stdout=pty, level="warn")
    io.recvuntil(b":")
    io.sendline(solution)
    output = io.recvline().decode().splitlines()[0].strip()
    print(f"    [+] Output: {output}")


def main():
    path_to_binary = "./00_angr_find"
    project = angr.Project(path_to_binary)
    initial_state = project.factory.entry_state(
        add_options={
            angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
            angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
        },
    )

    simulation = project.factory.simgr(initial_state)

    print_good_address = 0x0804867D
    simulation.explore(find=print_good_address)

    if simulation.found:
        solution_state = simulation.found[0]

        solution = solution_state.posix.dumps(sys.stdin.fileno()).decode()
        run_binary(solution, path_to_binary)
    else:
        raise Exception("Could not find the solution")


if __name__ == "__main__":
    main()
Back to top