Skip to content

10 Angr SimProcedures

This is going to be a short one. The only thing new with this one is the introduction of SimProcedures which takes a lot of the manual work out of hooking a function. So instead of defining the start address and the skip length, then building the stack and registers back up, we simply define a SimProcedures to take care of it for us.

So, with that said, here is the solution.

import angr
import claripy
import sys
import pwn


def main():
    path_to_binary = "./10_angr_simprocedures"
    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,
        },
    )

    class ReplacementCheckEquals(angr.SimProcedure):
        def run(self, to_check, length):
            user_input_buffer_address = to_check
            user_input_buffer_length = length

            user_input_string = self.state.memory.load(
                user_input_buffer_address, user_input_buffer_length
            )

            check_against_string = "ORSDDWXHZURJRBDH".encode()

            return claripy.If(
                user_input_string == check_against_string,
                claripy.BVV(1, 32),
                claripy.BVV(0, 32),
            )

    check_equals_symbol = "check_equals_ORSDDWXHZURJRBDH"
    project.hook_symbol(check_equals_symbol, ReplacementCheckEquals())

    simulation = project.factory.simgr(initial_state)
    simulation.explore(find=is_successful, avoid=should_abort)

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


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 is_successful(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return b"Good Job." in stdout_output


def should_abort(state):
    stdout_output = state.posix.dumps(sys.stdout.fileno())
    return b"Try again." in stdout_output


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