def calc(key): key = key.replace('-', '') assert len(key) == 32 p = angr.Project('./libnative-lib.so') useless_func_addr = p.entry + 0x00050F00 p.hook(useless_func_addr, angr.Hook(simuvex.SimProcedures['stubs']['ReturnUnconstrained']), kwargs={'resolves': 'nothing'}) useless_func_addr = p.entry + 0x7F70 p.hook(useless_func_addr, angr.Hook(simuvex.SimProcedures['stubs']['ReturnUnconstrained']), kwargs={'resolves': 'nothing'}) useless_addr = p.entry + 0xA977 redirect_addr = p.entry + 0xAA10 # p.hook(useless_addr, angr.Hook(simuvex.SimProcedures['stubs']['Redirect'], redirect_to=redirect_addr), kwargs={'resolves': 'nothing'}) # def go(state): # state.regs.ip = redirect_addr # print 'f**k', state.regs.ip # p.hook(useless_addr, angr.Hook(simuvex.SimProcedures['stubs']['UserHook'], user_func=go, length=2)) start_addr = p.entry + 0xA41D aim_addr = p.entry + 0xAA50 state = p.factory.blank_state(addr=start_addr) x = [] for i in xrange(32): # x.append(state.se.BVS('x{}'.format(i), 8)) x.append(state.se.BVV(key[i], 8)) state.memory.store(state.regs.sp + 0x50, 0xAA000000, endness=state.arch.memory_endness) for i in xrange(8): str_addr = 0xBB000000 + i * 0x100 state.memory.store(0xAA000000 + i * 4, str_addr, endness=state.arch.memory_endness) state.memory.store(str_addr - 4, 4, endness=state.arch.memory_endness) for j in xrange(4): state.memory.store(str_addr + j, x[i * 4 + j], endness=state.arch.memory_endness) path = p.factory.path(state) pg = p.factory.path_group(path) ex = pg.explore(find=aim_addr) # pg.explore(find=p.entry + 0x00009BE0) s = ex.found[0].state seed = s.se.any_int(s.regs.eax) return seed
def calc(key): key = key.replace('-', '') assert len(key) == 32 p = angr.Project('./libnative-lib.so') useless_func_addr = p.entry + 0x00050F00 p.hook(useless_func_addr, angr.Hook(simuvex.SimProcedures['stubs']['ReturnUnconstrained']), kwargs={'resolves': 'nothing'}) start_addr = p.entry + 0x00009B93 aim_addr = p.entry + 0x0000A1AA state = p.factory.blank_state(addr=start_addr) x = [] for i in xrange(32): # x.append(state.se.BVS('x{}'.format(i), 8)) x.append(state.se.BVV(key[i], 8)) state.memory.store(state.regs.sp + 0x40, 0xAA000000, endness=state.arch.memory_endness) state.memory.store(state.regs.bp + 0x10, 0xCC000000, endness=state.arch.memory_endness) state.memory.store(state.regs.bp + 0x14, 0xDD000000, endness=state.arch.memory_endness) state.memory.store(state.regs.bp + 0x18, 0xEE000000, endness=state.arch.memory_endness) state.memory.store(state.regs.bp + 0x1c, 0xFF000000, endness=state.arch.memory_endness) for i in xrange(8): str_addr = 0xBB000000 + i * 0x100 state.memory.store(0xAA000000 + i * 4, str_addr, endness=state.arch.memory_endness) state.memory.store(str_addr - 4, 4, endness=state.arch.memory_endness) for j in xrange(4): state.memory.store(str_addr + j, x[i * 4 + j], endness=state.arch.memory_endness) path = p.factory.path(state) pg = p.factory.path_group(path) ex = pg.explore(find=aim_addr) # pg.explore(find=p.entry + 0x00009BE0) s = ex.found[0].state a1 = s.se.any_int( s.memory.load(0xCC000000, endness=state.arch.memory_endness)) a2 = s.se.any_int( s.memory.load(0xDD000000, endness=state.arch.memory_endness)) a3 = s.se.any_int( s.memory.load(0xEE000000, endness=state.arch.memory_endness)) a6 = s.se.any_int( s.memory.load(0xFF000000, endness=state.arch.memory_endness)) return a1, a2, a3, a6
def _hook_taint_procedures(self, project): self._hooks = { "scanf" : scanf_taint } for k, v in self._hooks.iteritems(): project.hook_symbol(k, angr.Hook(v)) v.taints = []
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, angr.Hook(UserHook, user_func=hook_func, length=14)) p.hook(load_addr2, angr.Hook(UserHook, user_func=hook_func, length=14)) state = p.factory.blank_state(addr=start_addr) state, password = prepare_state(state, known_passwords) pg = p.factory.path_group(state, immutable=False) pg.step(4) pg.step(max_size=cmp_addr - load_addr2) s0 = pg.active[0].state.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])
def _try_summarize(self, f): l.debug('Attempting to hook: %s', f.name) if self._has_cycle(f): l.debug('Failed to hook: %s has cycles, skipping', f.name) return False if self._has_side_effect(f): l.debug('Failed to hook: %s has side effects, skipping', f.name) return False FHook = self._generate_hook(f) if FHook is None: l.debug('Failed to generate hook: %s', f.name) return False l.debug('Hook generated for: %s', f.name) self._is_summarized[f.addr] = angr.Hook(FHook) self._p.hook(f.addr, self._is_summarized[f.addr]) return True
def main(): p = angr.Project('challenge-7.sys', load_options={'auto_load_libs': False}) # Set a zero-length hook, so our function got executed before calling the # function tea_decrypt(0x100f0), and then we can keep executing the original # code. Thanks to this awesome design by @rhelmot! p.hook(0xadc31, angr.Hook(UserHook, user_func=before_tea_decrypt, length=0)) # Declare the prototype of the target function prototype = SimTypeFunction((SimTypeInt(False), ), SimTypeInt(False)) # Initialize the function instance proc_big_68 = p.factory.callable(BIG_PROC, cc=p.factory.cc(func_ty=prototype), toc=None, concrete_only=True) # Call the function and get the final state proc_big_68.perform_call(0) state = proc_big_68.result_state # Load the string from memory return hex(state.se.any_int(state.memory.load( ARRAY_ADDRESS, 40)))[2:-1].decode('hex').strip('\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, angr.Hook(UserHook, user_func=patch_scanf, length=5)) pgp = p.factory.path_group(init) # Now stuff becomes interesting ex = pgp.explore(find=find, avoid=avoid) print(ex) s = ex.found[0].state flag = s.se.any_str(s.memory.load(flag_addr, 50)) # The flag is 'Math is hard!' print("The flag is '{0}'".format(flag)) return flag
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.Hook(simuvex.SimProcedures['libc.so.6']['__libc_start_main'])) p.hook(0x422690, angr.Hook(simuvex.SimProcedures['libc.so.6']['memcpy'])) p.hook(0x408F10, angr.Hook(simuvex.SimProcedures['libc.so.6']['puts'])) # this is some anti-debugging initialization. It doesn't do much against angr, # but wastes time p.hook(0x401438, angr.Hook(simuvex.SimProcedures['stubs']['ReturnUnconstrained']), kwargs={'resolves': 'nothing'}) # 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, angr.Hook(UserHook, user_func=hook_length, length=5)) p.hook(0x4016BE, angr.Hook(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 pg = p.factory.path_group(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' pg.explore(find=0x4016A3).unstash(from_stash='found', to_stash='active') pg.explore(find=0x4016B7, avoid=[0x4017D6, 0x401699, 0x40167D]).unstash(from_stash='found', to_stash='active') pg.explore(find=0x4017CF, avoid=[0x4017D6, 0x401699, 0x40167D]).unstash(from_stash='found', to_stash='active') pg.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 = pg.found[0].state # 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.any_n_str(s.memory.load(0x6C4B20 + i, 2), 65536) for i in range(0, 8, 2) ] possibilities = tuple(itertools.product(*possible_values)) return possibilities
def hook_simproc(proj, addr_fr, addr_to, proc_type, libname='libc.so.6'): """ Hook a given function using a predesignated SimProcedure. """ proj.hook(addr_fr, angr.Hook(simuvex.SimProcedures[libname][proc_type]), length=addr_to - addr_fr)
def setup_argv_atoi_constraints(self, state, atoi_added_constraints): # If we have string-array-atoi (argv-like) constraints, build the pointers # and the symbolic string atoi_special_addrs = dict( ) # looks like: {0xDEADBEEF: (operator.eq, 0)} need_to_hook_atoi = False if self.ida_func.startEA in self.plugin.extra_constraints: con_tuples = self.plugin.extra_constraints[self.ida_func.startEA] ctr = 0 for (opr1, op, opr2) in con_tuples: if opr1[0] == 5: # the string-array-atoi type need_to_hook_atoi = True (arr_addr, arr_idx) = opr1[1] # Get AST for right operand if opr2[0] == 0: ast2 = state.memory.load(opr2[1]).reversed elif opr2[0] == 2: ast2 = getattr(state.regs, opr2[1].lower()) elif opr2[0] == 3: ast2 = claripy.BVV(opr2[1], self.plugin.bitness) else: continue # TODO: invalid right operand, show error free_mem_addr = UNUSED_MEMORY_ADDR # TODO: unused memory location, declare somewhere else # Store (free_mem_addr - arr_idx * wordsize) at (arr_addr) would_be_arr_base_addr = free_mem_addr - arr_idx * ( self.plugin.bitness / 8) state.memory.store( arr_addr, claripy.BVV(would_be_arr_base_addr, self.plugin.bitness).reversed) # Create a magic constant for my_atoi to detect. str_addr = 0xDEADBEEF + ctr ctr += 1 # Store a pointer to (str_addr) at (free_mem_addr) state.memory.store( free_mem_addr, claripy.BVV(str_addr, self.plugin.bitness).reversed) # Add it to the dict for my_atoi to see atoi_special_addrs[str_addr] = (op, ast2) # Make the memory at (free_mem_addr + wordsize) symbolic: our actual string #st.memory.make_symbolic('user_constr_{}'.format(arr_idx), str_addr, 8 * len(opr1[1])) self.log_signal.emit("arr_addr = {:X}".format(arr_addr)) self.log_signal.emit( "would_be_arr_base_addr = {:X}".format( would_be_arr_base_addr)) self.log_signal.emit( "free_mem_addr = {:X}".format(free_mem_addr)) if need_to_hook_atoi: # Custom version of the default atoi SimProcedure class my_atoi(simuvex.SimProcedure): def run(self, s, special_addrs=None, added_constraints=None): self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(self.state.arch, True) res_symb_var = claripy.BVS('atoi_ret', self.state.arch.bits) # If the argument is a special constrained variable s_val = self.state.se.any_int(s) if s.concrete and s_val in special_addrs: print( "Got a special memory addr: {:X}\n".format(s_val)) # Grab the operator and right operand (op, r_opr) = special_addrs[s_val] # Add the constraint of: (return_val `op` r_opr) print("Adding claripy_op_mapping[{}]({}, {})\n".format( op, res_symb_var, r_opr)) added_constraints.append(claripy_op_mapping[op]( res_symb_var, r_opr)) return res_symb_var self.plugin.angr_proj.hook_symbol( 'atoi', angr.Hook(my_atoi, special_addrs=atoi_special_addrs, added_constraints=atoi_added_constraints))
def _linux_prepare_paths(self): ''' prepare the initial paths for Linux binaries ''' # Only requesting custom base if this is a PIE if self._p.loader.main_bin.pic: project = angr.Project( self.binary, load_options={ 'main_opts': { 'custom_base_addr': self.qemu_base_addr } }, exclude_sim_procedures_list=self.exclude_sim_procedures_list) else: project = angr.Project( self.binary, exclude_sim_procedures_list=self.exclude_sim_procedures_list) known_libc_functions = get_known_libc_functionaddr(self.binary) #known_libc_functions_new = {} #for key,val in known_libc_functions.items(): #known_libc_functions_new[val] = key simfuncs = simuvex.procedures.SimProcedures[ 'libc.so.6'] #changed for RHG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 #func_to_hook = {} #func_to_hook = {'memcpy':0x0805CA00,'scanf':0x0804F1F0,'printf':0x0804F190,'strlen':0x0805b800,'__libc_start_main':0x08048eb0} for addr, name in known_libc_functions.items(): if name in simfuncs: project.hook( int(addr, 16), angr.Hook(simuvex.SimProcedures['libc.so.6'][name])) if not self.crash_mode: self._set_linux_simprocedures(project) self._set_hooks(project) # fix stdin to the size of the input being traced fs = { '/dev/stdin': simuvex.storage.file.SimFile("/dev/stdin", "r", size=self.input_max_size) } options = set() options.add(so.CGC_ZERO_FILL_UNCONSTRAINED_MEMORY) options.add(so.BYPASS_UNSUPPORTED_SYSCALL) options.add(so.REPLACEMENT_SOLVER) options.add(so.UNICORN) options.add(so.UNICORN_HANDLE_TRANSMIT_SYSCALL) if self.crash_mode: options.add(so.TRACK_ACTION_HISTORY) self.remove_options |= so.simplification self.add_options |= options entry_state = project.factory.full_init_state( fs=fs, concrete_fs=True, chroot=self.chroot, add_options=self.add_options, remove_options=self.remove_options, args=self.argv) if self.preconstrain_input: self._preconstrain_state(entry_state) # increase size of libc limits entry_state.libc.buf_symbolic_bytes = 1024 entry_state.libc.max_str_len = 1024 pg = project.factory.path_group(entry_state, immutable=True, save_unsat=True, hierarchy=False, save_unconstrained=self.crash_mode) # Step forward until we catch up with QEMU if pg.active[0].addr != self.trace[0]: pg = pg.explore(find=project.entry) pg = pg.drop(stash="unsat") pg = pg.unstash(from_stash="found", to_stash="active") # don't step here, because unlike CGC we aren't going to be starting # anywhere but the entry point return pg
def run(self): print("Jumped into Hook :)") return 0x30 #Input 38 Chars long #input_size = 0x26 input_size = 38 find_addr = 0x400cae b = angr.Project("./antidebug") b.hook(0x4008cd, fixpid, length=5) b.hook(0x4006c0, angr.Hook(simuvex.SimProcedures['stubs']['ReturnUnconstrained']), kwargs={'resolves': 'nothing'}) argv1 = angr.claripy.BVS("argv1", input_size * 8) #initial_state = b.factory.full_init_state(args=["./antidebug", argv1], add_options={"BYPASS_UNSUPPORTED_SYSCALL"}, add_options=simuvex.o.unicorn, remove_options={simuvex.o.LAZY_SOLVES}) initial_state = b.factory.entry_state( args=["./antidebug", argv1], add_options={"BYPASS_UNSUPPORTED_SYSCALL"}) for byte in argv1.chop(8): initial_state.add_constraints(byte != '\x00') # null initial_state.add_constraints(byte >= ' ') # '\x20' initial_state.add_constraints(byte <= '~') # '\x7e' #initial_state.add_constraints(argv1.chop(8)[38] == '\x00')