Angr - Examples

If the program is using scanf to get several values at once from stdin you need to generate a state that starts after the scanf.

Codes taken from https://github.com/jakespringer/angr_ctf

Input to reach address (indicating the address)

import angr
import sys

def main(argv):
  path_to_binary = argv[1]  # :string
  project = angr.Project(path_to_binary)

  # Start in main()
  initial_state = project.factory.entry_state()
  # Start simulation
  simulation = project.factory.simgr(initial_state)

  # Find the way yo reach the good address
  good_address = 0x804867d
  
  # Avoiding this address
  avoid_address = 0x080485A8
  simulation.explore(find=good_address, avoid=avoid_address)

  # If found a way to reach the address
  if simulation.found:
    solution_state = simulation.found[0]

    # Print the string that Angr wrote to stdin to follow solution_state
    print(solution_state.posix.dumps(sys.stdin.fileno()))
  else:
    raise Exception('Could not find the solution')

if __name__ == '__main__':
  main(sys.argv)

Input to reach address (indicating prints)

Registry values

Stack values

In this scenario, the input was taken with scanf("%u %u") and the value "1 1" was given, so the values 0x00000001 of the stack come from the user input. You can see how this values starts in $ebp - 8. Therefore, in the code we have subtracted 8 bytes to $esp (as in that moment $ebp and $esp had the same value) and then we have pushed the BVS.

Static Memory values (Global variables)

Dynamic Memory Values (Malloc)

File Simulation

Note that the symbolic file could also contain constant data merged with symbolic data:

Applying Constrains

Sometimes simple human operations like compare 2 words of length 16 char by char (loop), cost a lot to a angr because it needs to generate branches exponentially because it generates 1 branch per if: 2^16 Therefore, it's easier to ask angr get to a previous point (where the real difficult part was already done) and set those constrains manually.

Another thing you can do in these scenarios is to hook the function giving angr something it can understand more easily.

Simulation Managers

Some simulation managers can be more useful than others. In the previous example there was a problem as a lot of useful branches were created. Here, the veritesting technique will merge those and will find a solution. This simulation manager can also be activated with: simulation = project.factory.simgr(initial_state, veritesting=True)

Hooking/Bypassing one call to a function

Hooking a function / Simprocedure

Simulate scanf with several params

Static Binaries

Last updated