예제 #1
0
파일: solve.py 프로젝트: seth1002/angr-doc
def calc_one_byte(p, known_passwords, hook_func, start_addr, load_addr1,
                  load_addr2, cmp_flag_reg, cmp_addr):
    byte_pos = len(known_passwords)

    p.hook(load_addr1, UserHook(user_func=hook_func, length=14))
    p.hook(load_addr2, UserHook(user_func=hook_func, length=14))
    state = p.factory.blank_state(addr=start_addr)
    state, password = prepare_state(state, known_passwords)
    sm = p.factory.simgr(state, immutable=False)
    sm.step(4)
    sm.step(size=cmp_addr - load_addr2)

    s0 = sm.active[0].copy()
    s0.add_constraints(getattr(s0.regs, cmp_flag_reg) == 0x1)
    candidates = s0.se.any_n_int(password[byte_pos], 256)
    # assert len(candidates) == 1

    return chr(candidates[0])
예제 #2
0
def main():
    p = angr.Project('baby-re')

    win = 0x4028e9  # good
    fail = 0x402941  # fail
    main = 0x4025e7  # Address of main
    PASS_LEN = 13
    flag_addr = 0x7fffffffffeff98  # First rsi from scanf
    find = (win, )
    avoid = (fail, )

    def patch_scanf(state):
        print(state.regs.rsi)
        state.mem[state.regs.rsi:].char = state.se.BVS('c', 8)

    # IDA xrefs
    scanf_offsets = (0x4d, 0x85, 0xbd, 0xf5, 0x12d, 0x165, 0x19d, 0x1d5, 0x20d,
                     0x245, 0x27d, 0x2b5, 0x2ed)

    init = p.factory.blank_state(addr=main)

    # Patch scanfs (don't know how angr handles it)
    for offst in scanf_offsets:
        p.hook(main + offst, UserHook(user_func=patch_scanf, length=5))

    sm = p.factory.simgr(init)

    # Now stuff becomes interesting
    ex = sm.explore(find=find, avoid=avoid)

    print(ex)
    s = ex.found[0]
    flag = s.se.eval(s.memory.load(flag_addr, 50), cast_to=str)

    # The flag is 'Math is hard!'
    print("The flag is '{0}'".format(flag))
    return flag
예제 #3
0
def get_possible_flags():
    # load the binary
    print '[*] loading the binary'
    p = angr.Project("whitehat_crypto400")

    # this is a statically-linked binary, and it's easer for angr if we use Python
    # summaries for the libc functions
    p.hook(0x4018B0, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())
    p.hook(0x422690, angr.SIM_PROCEDURES['libc']['memcpy']())
    p.hook(0x408F10, angr.SIM_PROCEDURES['libc']['puts']())

    # this is some anti-debugging initialization. It doesn't do much against angr,
    # but wastes time
    p.hook(0x401438, angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained']())

    # from playing with the binary, we can easily see that it requires strings of
    # length 8, so we'll hook the strlen calls and make sure we pass an 8-byte
    # string
    def hook_length(state):
        state.regs.rax = 8

    p.hook(0x40168e, UserHook(user_func=hook_length, length=5))
    p.hook(0x4016BE, UserHook(user_func=hook_length, length=5))

    # here, we create the initial state to start execution. argv[1] is our 8-byte
    # string, and we add an angr option to gracefully handle unsupported syscalls
    arg1 = claripy.BVS('arg1', 8 * 8)
    initial_state = p.factory.entry_state(
        args=["crypto400", arg1], add_options={"BYPASS_UNSUPPORTED_SYSCALL"})

    # and let's add a constraint that none of the string's bytes can be null
    for b in arg1.chop(8):
        initial_state.add_constraints(b != 0)

    # PathGroups are a basic building block of the symbolic execution engine. They
    # track a group of paths as the binary is executed, and allows for easier
    # management, pruning, and so forth of those paths
    sm = p.factory.simgr(initial_state, immutable=False)

    # here, we get to stage 2 using the PathGroup's find() functionality. This
    # executes until at least one path reaches the specified address, and can
    # discard paths that hit certain other addresses.
    print '[*] executing'
    sm.explore(find=0x4016A3).unstash(from_stash='found', to_stash='active')
    sm.explore(find=0x4016B7, avoid=[0x4017D6, 0x401699,
                                     0x40167D]).unstash(from_stash='found',
                                                        to_stash='active')
    sm.explore(find=0x4017CF, avoid=[0x4017D6, 0x401699,
                                     0x40167D]).unstash(from_stash='found',
                                                        to_stash='active')
    sm.explore(find=0x401825, avoid=[0x401811])

    # now, we're at stage 2. stage 2 is too complex for a SAT solver to solve, but
    # stage1 has narrowed down the keyspace enough to brute-force the rest, so
    # let's get the possible values for the passphrase and brute-force the rest.
    s = sm.found[0]

    # to reduce the keyspace further, let's assume the bytes are printable
    for i in range(8):
        b = s.memory.load(0x6C4B20 + i, 1)
        s.add_constraints(b >= 0x21, b <= 0x7e)

    # now get the possible values. One caveat is that getting all possible values
    # for all 8 bytes pushes a lot of complexity to the SAT solver, and it chokes.
    # To avoid this, we're going to get the solutions to 2 bytes at a time, and
    # brute force the combinations.
    possible_values = [
        s.se.eval_upto(s.memory.load(0x6C4B20 + i, 2), 65536, cast_to=str)
        for i in range(0, 8, 2)
    ]
    possibilities = tuple(itertools.product(*possible_values))
    return possibilities