angr_stdin.ipynb

angr_stdin.ipynb

General definitions

I recommend using a pypy virtual environment to run angr.

# Imports
import angr
import claripy
import logging
logging.getLogger('angr').setLevel('INFO')

# Parameters
binary_path = './Exploit_Me(if_you_can)'

useVeritesting = False # Can speed up the analysis when there is a lot of branching, but causes instability
useUnicorn = True      # Unicorn engine is faster than the default engine, but can cause instability

# (OPTIONAL) address parameters
base_addr = 0x00
state_addr = 0x00

# (OPTIONAL) input parameters, when the input length is known
input_len = 0x00 

# (OPTIONAL) goal address parameters
success_addr = 0x00 
fail_addr = 0x00

# (OPTIONAL) goal strings in stdout
success_stdout = [b'Well']
fail_stdout = [b'Try again!']


def is_successful(state):
    stdout_output = state.posix.dumps(1)
    return any(s in stdout_output for s in success_stdout)

def is_failed(state):
    stdout_output = state.posix.dumps(1)
    return any(f in stdout_output for f in fail_stdout)


# Create the project
if base_addr:
    p = angr.Project(binary_path, main_opts={'base_addr': base_addr})
else:
    p = angr.Project(binary_path)

# (OPTIONAL) Hook ptrace to return 0. Avoid detection by anti-debugging techniques with ptrace.
#p.hook_symbol('ptrace', angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'](return_value=0))

Create the simulation manager and explore


# The input length is known
if input_len:
    # Define the input
    stdin_chars = [claripy.BVS('stdin_%d' % i, 8) for i in range(input_len)]
    stdin = claripy.Concat(*stdin_chars + [claripy.BVV(b'\n')])

    # Create the simulation manager
    state = p.factory.entry_state(args=[binary_path], stdin=stdin, add_options=({angr.options.UNICORN} if useUnicorn else {}))

    # (OPTIONAL) Conditions on the flag:
    # for c in stdin_chars:
    #     state.add_constraints(c >= ord(' '))
    #     state.add_constraints(c <= ord('~'))

    sm = p.factory.simulation_manager(state, veritesting=useVeritesting)

# The input length is unknown : let angr manage it
else:
    # Create the simulation manager
    state = p.factory.entry_state(args=[binary_path], add_options=({angr.options.UNICORN} if useUnicorn else {}))
    sm = p.factory.simulation_manager(state, veritesting=useVeritesting)
    
# Explore the binary
if success_addr and fail_addr:
    sm.explore(find=success_addr, avoid=fail_addr)
else:
    sm.explore(find=is_successful, avoid=is_failed)
print(sm)
# Parse the results
if sm.found:
    found = sm.found[0]
    print("FOUND")
    print("In:", found.posix.dumps(0))
    print("Out:", found.posix.dumps(1))
    print()

if sm.deadended:
    print("DEADENDED")
    for deadended in sm.deadended.state:
        print("In:", deadended.posix.dumps(0))
        print("Out:", deadended.posix.dumps(1))
        print()

if sm.errored:
    print("ERRORED")
    for errored in sm.errored.state:
        print(sm.errored)
        print("In:", errored.posix.dumps(0))
        print("Out:", errored.posix.dumps(1))
        print()