In [1]:
import angr
import simuvex
import binascii
angr.path_group.l.setLevel('ERROR') # Can set to 'DEBUG' for more verbose output

stdin1 = None
In [2]:
def printf_hook(state):
    # print 'printf' # Uncomment this if you want to see if/when this gets called.
    state.regs.eax = 0 # 0 actually means 0 characters were printed, but the value isn't checked, so...
    
def scanf_hook(state):
    # print 'scanf' # Uncomment this if you want to see if/when this gets called.
    # print hex(state.se.any_int(state.regs.esp) + 0x4) # Printing the address of the arg on the stack...
    
    # Store a "pointer" to the symbolic string on the stack,
    # in the location of the 'target' variable for the real scanf.
    # i.e. if the code was `scanf("%s", &str)`, we're putting the `stdin`
    # symbolic string on the stack where &str would have been.
    state.memory.store(state.se.any_int(state.regs.esp) + 4, stdin1)

p = angr.Project('medium.exe', load_options={'auto_load_libs':False})

# Hooks for calls to printf and scanf.
# If you don't hook these, Angr gets
# unhappy -- so, better to avoid letting
# it branch into these symbolically by
# hooking.
p.hook(0x4010B7, scanf_hook, length=5)
p.hook(0x4010A6, printf_hook, length=5)
WARNING | 2016-10-18 12:04:27,625 | cle.pe | The PE module is not well-supported. Good luck!
In [3]:
#initial_state = p.factory.blank_state(addr=0x00401090, remove_options={simuvex.s_options.LAZY_SOLVES})
initial_state = p.factory.blank_state(addr=0x00401090) # Will still quickly solve without LAZY_SOLVES disabled.
#initial_state = p.factory.blank_state(addr=0x004010BF, remove_options={simuvex.s_options.LAZY_SOLVES})
#initial_state.regs.esp = 0xF0000000 # Don't actually need to set these, but can be useful for troubleshooting
#initial_state.regs.ebp = 0xE0000000


# Create a symbolic string. 8 bits & 50 to make a
# 50-char symbolic string.
stdin1 = initial_state.se.BVS("stdin1", 8 * 50)
In [4]:
initial_path = p.factory.path(initial_state)
path_group = p.factory.path_group(initial_state)

# `find` is the address of `printf("You got it!\n")`
# `avoid` is the address of the instructions immediately
# after the printf branch, which would indicate a wrong password.
path_group.explore(find=(0x401189,), avoid=(0x401196,))
Out[4]:
<PathGroup with 43 avoid, 42 unsat, 3 active, 1 found>
In [5]:
found = path_group.found[0]

#print found.state.regs.ip # Print EIP.
print found.state.se.any_str(stdin1)
milhous.30+the_Biggest_Goat_Ever@gmail.com
In [ ]:
 
In [ ]: