def test_stub_procedure_args(): # stub procedures should have the right number of arguments lib.set_prototype( "____a_random_stdcall_function__", SimTypeFunction( [ SimTypeInt(signed=True), SimTypeInt(signed=True), SimTypeInt(signed=False) ], SimTypePointer(SimTypeChar(), offset=0), arg_names=["_random_arg_0", "_random_arg_1", "_random_arg_2"])) stub = lib.get_stub('____a_random_stdcall_function__', archinfo.ArchX86()) stub.cc = SimCCStdcall(archinfo.ArchX86()) lib._apply_metadata(stub, archinfo.ArchX86()) assert len(stub.cc.args) == 3 assert all(isinstance(arg, SimStackArg) for arg in stub.cc.args) proj = angr.Project(os.path.join(binaries_base, "i386", "all"), auto_load_libs=False) state = proj.factory.blank_state() initial_sp = state.regs.sp stub.state = state stub.successors = SimSuccessors(0, state) stub.ret(0) succ = stub.successors.all_successors[0] assert state.solver.eval_one(succ.regs.sp - initial_sp) == 0x10
def _hook_all_aux(proj): sim_procs = [x for x in globals().values() if inspect.isclass(x) and issubclass(x, angr.SimProcedure)] for sp in sim_procs: if issubclass(sp, StdcallSimProcedure): proj.hook_symbol(sp.__name__, sp(cc=SimCCStdcall(proj.arch))) else: # use default cc for the arch (for x86 it's Cdecl) proj.hook_symbol(sp.__name__, sp())
def find_ioctls(filename, dispatch_device_control, address_size=8): """Symbolically explore the dispatch function to find supported IOCTLs. We want to symbolically explore the function until we enter a state where the IOCTL is constrained to a single value. Return a map of IOCTL codes to a list of addresses where the handling code starts. """ proj = angr.Project(filename, auto_load_libs=False) # Create a call state with a symbolic IRP sirp = SymbolicIrp(address_size * 8) siosl = SymbolicDeviceIoControlIoStackLocation(address_size * 8) sirp.current_stack_location = PointerWrapper(siosl.pack()) irp = sirp.pack() if address_size == 4: cc = SimCCStdcall(proj.arch) else: cc = SimCCMicrosoftAMD64(proj.arch) state = proj.factory.call_state(dispatch_device_control, claripy.BVS("DeviceObject", 64), irp, cc=cc, ret_addr=0xdeadbeef) def ioctl_constrained(st): """Return true if the IOCTL code is constrained to a single value.""" try: st.solver.eval_one(siosl.io_control_code) return True except angr.SimValueError: return False # Run until all states finish simgr = proj.factory.simgr(state) while len(simgr.active) > 0: simgr.explore(find=ioctl_constrained, avoid=0xdeadbeef) #print(simgr) # Return a map of IOCTL codes to a list of handler addresses ioctls = collections.defaultdict(list) for s in simgr.found: # For some reason, the memory_endness for x64 symbolic variables isn't getting # set correctly. Account for little-endian manually. if address_size == 4: code = s.solver.eval_one(siosl.io_control_code) start = s.solver.eval_one(s.regs.eip) else: code = swap32(s.solver.eval_one(siosl.io_control_code)) start = s.solver.eval_one(s.regs.rip) ioctls[code].append(start) return ioctls
def setup(proj, aux_hooks=False, unhook=[], cdecl_stub=[], stdcall_stub=[]): if aux_hooks: _hook_all_aux(proj) for sym in unhook: proj.unhook_symbol(sym) for sym in cdecl_stub: proj.hook_symbol(sym, ReturnUnconstrained(cc=SimCCCdecl(proj.arch), is_stub=True)) for sym in stdcall_stub: proj.hook_symbol(sym, ReturnUnconstrained(cc=SimCCStdcall(proj.arch), is_stub=True))
def hook_all(proj): sim_procs = [ x for x in win32_patches.__dict__.values() if inspect.isclass(x) and issubclass(x, angr.SimProcedure) ] for sp in sim_procs: if issubclass(sp, StdcallSimProcedure): proj.hook_symbol(sp.__name__, sp(cc=SimCCStdcall(proj.arch))) else: # use default cc for the arch (for x86 it's Cdecl) proj.hook_symbol(sp.__name__, sp()) rdtsc_monkey_patch()
def create_cc(self, arch: Arch) -> Optional[SimCC]: if not isinstance(arch, ArchX86): # Use default calling convention unless arch is x86 return None if self.cc_str in { "__stdcall", "__fastcall", "__thiscall", "__vectorcall", "X86StdCall", }: # Callee cleanup return SimCCStdcall(arch) return None
@pytest.mark.parametrize("type_str,expected", [("SOCKET", True), (None, False)]) def test_has_complete_typing(type_str, expected): s = Parameter("s", type_str, "in") name = Parameter("name", "const sockaddr *", "in") namelen = Parameter("namelen", "int", "in") func_model = FunctionModel("connect", [s, name, namelen], "__stdcall") assert func_model.has_complete_typing == expected @pytest.mark.parametrize( "arch,cc,cc_str", [ (archinfo.ArchAMD64, None, "__stdcall"), (archinfo.ArchAMD64, None, "__cdecl"), (archinfo.ArchX86, SimCCStdcall(archinfo.ArchX86()), "__stdcall"), (archinfo.ArchX86, None, "__cdecl"), (archinfo.ArchARM, None, "__stdcall"), (archinfo.ArchARMEL, None, "__stdcall"), (archinfo.ArchARMHF, None, "__stdcall"), (archinfo.ArchARMCortexM, None, "__stdcall"), (archinfo.ArchAArch64, None, "__stdcall"), (archinfo.ArchPPC32, None, "__stdcall"), (archinfo.ArchPPC64, None, "__stdcall"), (archinfo.ArchMIPS32, None, "__stdcall"), (archinfo.ArchMIPS64, None, "__stdcall"), (archinfo.ArchSoot, None, "__stdcall"), (archinfo.ArchS390X, None, "__stdcall"), ], ) def test_create_cc(arch, cc, cc_str):
def __init__(self, project: angr.Project): super().__init__( project=project, num_args=0, cc=SimCCStdcall(project.arch), )
def find_sim_procedure( name: str, proj: angr.Project, export_manager: ExportManager, return_unconstrained: bool = True, ) -> Optional[SimProcedure]: """ Find the appropriate SimProcedure for the given procedure name and project """ arch = proj.arch # Use custom dynamic procedures # TODO: Add linux dynamic loading functions if name in custom_dynamic_procedures: cc = None if isinstance(arch, ArchX86): cc = SimCCStdcall(arch) if name == "GetProcAddress": return custom_dynamic_procedures["GetProcAddress"](proj, export_manager, cc) return custom_dynamic_procedures[name](proj, cc=cc) blacklist = { "_error", } if name in blacklist: # Don't hook function return # Search in cyfi's SimProcedures for lib, procs in cyfi_procedures.items(): if name in procs: sim_proc = procs[name](proj) log.log(5, f"Found {sim_proc} in {lib} (cyfi)") return sim_proc # Search in angr's SimProcedures # TODO: Optionally search a single library for lib in angr.SIM_LIBRARIES: sim_lib = angr.SIM_LIBRARIES[lib] if type(sim_lib) == SimSyscallLibrary: if sim_lib.has_implementation(name, arch): sim_proc = sim_lib.get(name, arch) log.log(5, f"Found {sim_proc} in {lib} (angr)") return sim_proc else: if sim_lib.has_implementation(name): sim_proc = sim_lib.get(name, arch) log.log(5, f"Found {sim_proc} in {lib} (angr)") return sim_proc # Search for function model if export_manager.model_handler: try: sim_proc = export_manager.model_handler.create_procedure( name, proj) log.log(5, f"Found {sim_proc} in models") return sim_proc except ValueError: pass if return_unconstrained: # Not found anywhere. Return unconstrained value. sim_proc = ReturnUnconstrainedLog(proj, display_name=name) return sim_proc return