def json_to_simval(d: Dict[str, Any]) -> SV.SimValue: id = d["i"] # SimValue (generic, covers all cases with jsonval implementation) if id == "x": return SSV.SimSymbolicValue(0, defined=False) # SimByteValue elif id == "b": if "d" in d: data = d["d"] v: int = data.get("v", 0) defined: bool = data.get("d", True) return SV.SimByteValue(v, defined) else: return SV.SimByteValue(0) # SimDoubleWordValue elif id == "d": if "d" in d: data = d["d"] v = data.get("v", 0) defined = data.get("d", True) b1defined: bool = data.get("db1", True) b2defined: bool = data.get("db2", True) b3defined: bool = data.get("db3", True) b4defined: bool = data.get("db4", True) return SV.SimDoubleWordValue(v, defined=defined, b1defined=b1defined, b2defined=b2defined, b3defined=b3defined, b4defined=b4defined) else: return SV.SimDoubleWordValue(0) # SimGlobalAddress elif id == "sga": data = d["d"] modulename: str = data.get("m", "?") offset = cast(SV.SimDoubleWordValue, json_to_simval(data["o"])) return SSV.SimGlobalAddress(modulename, offset) # SimReturnAddress elif id == "sra": data = d["d"] modulename = data.get("m", "?") functionaddr: str = data["f"] offset = cast(SV.SimDoubleWordValue, json_to_simval(data["o"])) return SSV.SimReturnAddress(modulename, functionaddr, offset) # SimMemoryByteLink elif id == "bl": data = d["d"] linkedto = cast(SSV.SimSymbolicValue, json_to_simval(data["l"])) position: int = cast(int, data["p"]) return SimMemoryByteLink(linkedto, position) else: raise UF.CHBError("No deserialization implemented yet for id = " + id)
def resolve_import_symbol(self, importsym: str) -> SSV.SimGlobalAddress: for dynlib in self.dynlibs: if dynlib.is_exported(importsym): faddr = dynlib.export_address(importsym) return SSV.mk_global_address(faddr, dynlib.name) else: return SSV.mk_undefined_global_address(self.modulename)
def do_initialization(self, simstate: "SimulationState") -> None: simstate.registers["sp"] = SSV.SimStackAddress(SV.simZero) simstate.registers["zero"] = SV.simZero for reg in [ "ra", "gp", "fp", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7" ]: simstate.registers[reg] = SSV.SimSymbol(reg + "_in") simstate.registers["t9"] = SSV.mk_global_address( int(simstate.startaddr, 16), modulename=simstate.modulename) if len(self.cmdlineargs) > 0: self.initialize_cmdline_arguments(simstate)
def mk_address(self, offset: int) -> SSV.SimAddress: addr = cast(SV.SimDoubleWordValue, SV.mk_simvalue(offset, size=4)) if self.name.startswith("global"): names = self.name.split(":") if len(names) == 2: image = names[1] else: image = "mainx" return SSV.SimGlobalAddress(image, addr) elif self.name == "stack": return SSV.SimStackAddress(addr) else: return SSV.SimBaseAddress(self.name, addr)
def get(self, iaddr: str, address: SSV.SimAddress, size: int) -> SV.SimValue: try: for base in self.baseoffsets: if ( address.offsetvalue >= base and address.offsetvalue < base + self.buffersize): address = address.add_offset(-base) try: memval = SimMemory.get(self, iaddr, address, size) except SU.CHBSimError: memval = SV.mk_simvalue(0, size=size) return memval else: raise SU.CHBSimError( self.simstate, iaddr, "invalid shared memory address: " + str(address)) except SU.CHBSimError as e: print("Error in shared memory: " + str(e)) name = (self.name + '[' + str(address.offsetvalue) + ']' + ' (value not retrieved: ' + str(e) + ')') return SSV.SimSymbol(name)
def simulate(self, iaddr: str, simstate: "SimulationState") -> str: dstop = self.dst_operand srcop = self.src_operand srcval = simstate.rhs(iaddr, srcop) result: SV.SimValue if srcval.is_undefined: result = SV.simUndefinedDW if srcval.is_global_address: val = cast(SV.SimDoubleWordValue, SV.mk_simvalue(srcval.literal_value)) srcval = cast(SSV.SimGlobalAddress, srcval) name = srcval.modulename resultval = val.swap_bytes_within_halfwords() result = SSV.mk_global_address(resultval.literal_value, name) elif srcval.is_literal: val = cast(SV.SimDoubleWordValue, srcval) result = val.swap_bytes_within_halfwords() else: raise SU.CHBSimError( simstate, iaddr, "wsbh: operand not recognized: " + str(srcop) + ": " + str(srcval)) lhs = simstate.set(iaddr, dstop, result) simstate.increment_programcounter() return SU.simassign(iaddr, simstate, lhs, result, intermediates=str(srcval))
def simulate(self, iaddr: str, simstate: "SimulationState") -> str: tgtaddr = self.target.absolute_address_value tgt = simstate.resolve_literal_address(iaddr, tgtaddr) simstate.increment_programcounter() simra = SSV.pc_to_return_address( simstate.programcounter.add_offset(4), simstate.function_address) simstate.registers["ra"] = simra simstate.simprogramcounter.set_delayed_programcounter(tgt) return SU.simcall(iaddr, simstate, tgt, simra)
def rhs_symbol(self, iaddr: str, sym: SSV.SimSymbol, offset: int, opsize: int) -> SV.SimValue: base = sym.name if base.startswith("/stderr"): return sym if base not in self.basemem: self.basemem[base] = SimBaseMemory(self, base) self.add_logmsg(iaddr, "Initialize base memory for " + base) addr: SSV.SimAddress = SSV.mk_base_address(base, offset=offset) return self.memval(iaddr, addr, opsize)
def get(self, iaddr: str, address: SSV.SimAddress, size: int) -> SV.SimValue: try: memval = SimMemory.get(self, iaddr, address, size) except SU.CHBSimError as e: print("Error in basemem: " + str(e)) name = (self.name + '[' + str(address.offsetvalue) + ']' + ' (value not retrieved: ' + str(e) + ')') return SSV.SimSymbol(name) else: return memval
def simulate_arm_function(xname: str, app: "ARMAccess", asm: "ARMAssembly", faddr: str) -> NoReturn: base = app.header.image_base mainparticipant = SimModule("app", app, base, app.max_address) simstate = SimulationState( faddr, mainparticipant, ARMSimProgramCounter(SSV.mk_global_address(int(faddr, 16), xname))) currentinstr = asm.instructions[faddr] print(str(currentinstr)) exit(0)
def sim_openfile(filename: str, mode: str) -> SSV.SimSymbolicFilePointer: print("Open file " + filename) if SSV.SimSymbolicFilePointer.has_openfile(filename): return SSV.SimSymbolicFilePointer.openfile(filename) if filename.startswith("/"): simfilename = os.path.join("simdisk", filename[1:]) simpathname = os.path.dirname(simfilename) if not os.path.exists(simpathname): print("make dir: " + simpathname + " (" + simfilename + ")") os.makedirs(simpathname) print("Open " + simfilename + " with mode " + mode) fp = open(simfilename, mode) symfp = SSV.mk_filepointer(filename, simfilename, fp) SSV.SimSymbolicFilePointer.add_openfile(filename, symfp) return symfp else: return SSV.mk_filepointer(filename, simfilename, filename, defined=False)
def __init__(self, startaddr: str, mainx: X86SimModule, simprogramcounter: SimProgramCounter, x86fn: "X86Function", simsupport: SimSupport = SimSupport(), dynlibs: Sequence[X86SimModule] = [], bigendian: bool = False) -> None: SimulationState.__init__(self, startaddr, mainx, simprogramcounter, simsupport=simsupport, dynlibs=dynlibs, bigendian=bigendian) self._x86fn = x86fn self.uninitializedregion: Optional[Tuple[SSV.SimGlobalAddress, SSV.SimGlobalAddress]] = None self.flags: Dict[str, SV.SimBoolValue] = {} # flagname -> SimBoolValue self.registers: Dict[str, SV.SimValue] = {} self._globalmem = SimGlobalMemory(self) self.stackmem = SimStackMemory(self) self.fnlog: Dict[str, List[str]] = {} # iaddr -> msg list self.registers['esp'] = SSV.mk_stack_address(0) self.registers['ebp'] = SSV.mk_symbol('ebp-in') self.registers['eax'] = SSV.mk_symbol('eax-in') self.registers['ecx'] = SSV.mk_symbol('ecx-in') self.stackmem.set("0", SSV.mk_stack_address(0), SSV.SimSymbolicReturnAddress()) self.flags['DF'] = SV.simflagclr # direction forward self.flags['CF'] = SV.simflagclr # no carry self.flags['PF'] = SV.simflagclr # even parity self.flags['ZF'] = SV.simflagclr # no zero result self.flags['SF'] = SV.simflagclr # unsigned result self.flags['OF'] = SV.simflagclr # no overflow occurred
def simulate(self, iaddr: str, simstate: "SimulationState") -> str: dstop = self.dst_operand srcop = self.src_operand srcval = simstate.rhs(iaddr, srcop) immval = self.imm_operand.to_signed_int() imm = SV.mk_simvalue(immval) def do_assign(result: SV.SimValue) -> str: lhs = simstate.set(iaddr, dstop, result) simstate.increment_programcounter() return SU.simassign(iaddr, simstate, lhs, result, "val(" + str(srcop) + ") = " + str(srcval)) if srcval.is_undefined: return do_assign(SV.simUndefinedDW) if srcval.is_symbol: expr = str(srcval) + ' + ' + str(immval) raise SU.CHBSymbolicExpression(simstate, iaddr, dstop, expr) elif srcval.is_address: srcval = cast(SSV.SimAddress, srcval) return do_assign(srcval.add_offset(immval)) elif srcval.is_literal: return do_assign(SV.mk_simvalue(srcval.literal_value + immval)) elif srcval.is_string_address: srcval = cast(SSV.SimStringAddress, srcval) if immval == len(srcval.stringval): result = SSV.mk_string_address('') else: result = SSV.mk_string_address(srcval.stringval[immval:]) return do_assign(result) else: return do_assign(SV.simUndefinedDW)
def simulate(self, iaddr: str, simstate: "SimulationState") -> str: tgtop = self.tgt_operand tgtval = simstate.rhs(iaddr, tgtop) simra = SSV.pc_to_return_address(simstate.programcounter.add_offset(8), simstate.function_address) simstate.increment_programcounter() simstate.registers['ra'] = simra if tgtval.is_undefined: raise SU.CHBSimError( simstate, iaddr, "jalr: target address is undefined: " + str(tgtop)) tgtaddr: Union[SSV.SimGlobalAddress, SSV.SimDynamicLinkSymbol] if tgtval.is_address: tgtval = cast(SSV.SimAddress, tgtval) if tgtval.is_global_address: tgtaddr = cast(SSV.SimGlobalAddress, tgtval) else: raise SU.CHBSimError( simstate, iaddr, "target address is not global: " + str(tgtval)) # check if literal could be an address elif tgtval.is_literal: tgtaddr = simstate.resolve_literal_address(iaddr, tgtval.literal_value) if tgtaddr.is_undefined: raise SU.CHBSimError( simstate, iaddr, "jalr: target address cannot be resolved: " + str(tgtval)) elif tgtval.is_dynamic_link_symbol: tgtaddr = cast(SSV.SimDynamicLinkSymbol, tgtval) elif tgtval.is_symbolic: raise SU.CHBSimError( simstate, iaddr, ("symbolic target address not recognized: " + str(tgtval))) else: raise SU.CHBSimCallTargetUnknownError(simstate, iaddr, tgtval, 'target = ' + str(tgtval)) simstate.simprogramcounter.set_delayed_programcounter(tgtaddr) return SU.simcall(iaddr, simstate, tgtaddr, simra)
def resolve_literal_address(self, iaddr: str, addrvalue: int) -> SSV.SimGlobalAddress: addr = self.modulestates[self.modulename].resolve_literal_address( iaddr, addrvalue) if addr.is_defined: return addr # elif addrvalue == 2: # return SFU.sim_openfile("sim_stderr", "w") else: for shmid in self.sharedmem: if self.sharedmem[shmid].has_address(addrvalue): addr = SSV.mk_global_address(addrvalue, "shared:" + str(shmid)) return addr else: raise SU.CHBSimError( self, iaddr, ("Unable to resolve address: " + hex(addrvalue) + " in " + self.modulename))
def initialize_cmdline_arguments(self, simstate: "SimulationState") -> None: simstate.registers["a0"] = SV.mk_simvalue(len(self.cmdlineargs)) simstate.registers["a1"] = SSV.mk_stack_address(16) aoffset = 100 # offset of information block on the initial process stack for (i, arg) in enumerate(self.cmdlineargs): argptr = SSV.mk_stack_address((i * 4) + 16) argvalptr = SSV.mk_stack_address(aoffset) simstate.set_memval(simstate.startaddr, argptr, argvalptr) for c in arg: addr = SSV.mk_stack_address(aoffset) cval = SV.mk_simcharvalue(c) simstate.set_memval(simstate.startaddr, addr, cval) aoffset += 1 addr = SSV.mk_stack_address(aoffset) simstate.set_memval(simstate.startaddr, addr, SV.simZerobyte) aoffset += 1 # null-terminate the list of arguments argptr = SSV.mk_stack_address((len(self.cmdlineargs) * 4) + 16) simstate.set_memval(simstate.startaddr, argptr, SV.simZero)
def set_uninitialized_region(self, low: str, high: str) -> None: self.uninitializedregion = (SSV.mk_global_address( int(low, 16), self.modulename), SSV.mk_global_address( int(high, 16), self.modulename))
def simulate_mips_function( xname: str, app: "MIPSAccess", asm: "MIPSAssembly", faddr: str, stepcount: int = 100, libs: Dict[str, Tuple["MIPSAccess", "MIPSAssembly"]] = {}, support: Optional[str] = None, stub_imports: List[str] = [], mainargs: List[str] = [], optargaddrstr: Optional[str] = None, optargstatestr: Optional[str] = None, patched_globals: Dict[str, str] = {}, envptr_addr: Optional[str] = None) -> NoReturn: bigendian = app.header.is_big_endian print("big endian " if bigendian else "little endian") stubs: Dict[str, "MIPSimStub"] = stubbed_libc_functions() for stubimport in stub_imports: importedstubs = importlib.import_module(stubimport) print("\nImported user stubs: " + importedstubs.__name__) for d in dir(importedstubs): if d.endswith("stubs"): userstubs: Dict[str, "MIPSimStub"] = getattr(importedstubs, d)() stubs.update(userstubs) print( "Main module " + xname + ": " + app.header.image_base + " - " + app.max_address) mainmodule = SimModule(xname, app, app.header.image_base, app.max_address) dynlibs: List[SimModule] = [] dynasms: Dict[str, "MIPSAssembly"] = {} for (libname, (libapp, libasm)) in libs.items(): print( "Lib module " + libname + ": " + libapp.header.image_base + " - " + app.max_address) dynlibs.append(SimModule( libname, libapp, libapp.header.image_base, libapp.max_address)) dynasms[libname] = libasm if envptr_addr is not None: environmentptr_address: Optional[SSV.SimGlobalAddress] = SSV.mk_global_address( int(envptr_addr, 16), modulename=mainmodule.name) else: environmentptr_address = None optargaddr: SV.SimValue = SV.simZero optargstate: SV.SimValue = SV.simZero if optargaddrstr: optargaddr = SSV.mk_global_address(int(optargaddrstr, 16), xname) if optargstatestr: optargstate = SSV.mk_global_address(int(optargstatestr, 16), xname) def default_simsupport() -> SimSupport: return SimSupport( stepcount=stepcount, optargaddr=optargaddr, optargstate=optargstate, patched_globals=patched_globals, environmentptr_address=environmentptr_address) if support: importedmodule = importlib.import_module(support) print('\nCustom Import: ' + importedmodule.__name__) for d in dir(importedmodule): print("Module: " + d) if importedmodule.__name__.endswith(d): print("found module: " + d) simsupport = getattr(importedmodule, d)( stepcount=stepcount, optargaddr=optargaddr, optargstate=optargstate, patched_globals=patched_globals, environmentptr_address=environmentptr_address) break else: simsupport = default_simsupport() else: simsupport = default_simsupport() programcounter = MIPSimProgramCounter( SSV.mk_global_address(int(faddr, 16), xname)) initializer = MIPSimInitializer(mainargs) simstate = SimulationState( faddr, mainmodule, programcounter, siminitializer=initializer, dynlibs=dynlibs, simsupport=simsupport, stubs=stubs, bigendian=bigendian) currentinstr = asm.instructions[faddr] blocktrace: List[Tuple[str, str]] = [] for i in range(0, simsupport.stepcount): try: action = currentinstr.simulate(simstate) simstate.trace.add( str(i).rjust(5) + " " + str(currentinstr).ljust(48) + str(action)) simstate.trace.include_delayed() if action == "return": print("=" * 80) print("Simulation ended normally: returning from starting function") print("=" * 80) print("\nSimulation trace:") print("-" * 80) print(str(simstate.trace)) print("\nSimulation state:") print("-" * 80) print(str(simstate)) exit(0) except SU.CHBSimCallTargetUnknownError as e: simstate.trace.add( str(i).rjust(5) + "**" + str(currentinstr).ljust(48) + str(e.calltgt)) pc = simstate.programcounter if pc.is_global_address: addr = pc.to_hex() if addr in asm.instructions: currentinstr = asm.instructions[addr] except SU.CHBSimSystemCallException as e: syscall = SC.get_mips_linux_syscall(e.syscallindex) if syscall in simstate.stubs: stub = cast(MIPSimStub, simstate.stubs[syscall]) # in MIPS register $a3 will be set to 0 or 1 to indicate success # ref: https://www.linux-mips.org/wiki/Syscall simstate.set_register(e.iaddr, "a3", SV.simZero) msg = stub.simulate(e.iaddr, simstate) simstate.trace.add( " ".ljust(15) + "syscall:" + syscall + ": " + msg) simstate.increment_programcounter() else: print(str(simstate.trace)) print(str(simstate)) print("No stub for syscall: " + syscall) exit(1) except SU.CHBSimBranchUnknownError as e: simstate.trace.add( str(i).rjust(5) + "**" + str(currentinstr).ljust(48) + str(e.truetgt) + " (" + e.msg + ")") if simstate.simsupport.branch_decision(e.iaddr, simstate): simstate.simprogramcounter.set_delayed_programcounter(e.truetgt) else: simstate.simprogramcounter.set_delayed_programcounter(e.falsetgt) except SU.CHBSymbolicExpression as e: print( "Symbolic expression: " + str(e) + "; " + str(currentinstr).ljust(48)) print("=" * 80) print("") print(str(simstate.trace)) print(str(simstate)) exit(1) except SU.CHBSimExitException as e: print("=" * 80) print( "System exit at address " + e.iaddr + " with exit value " + e.exitvalue) print("=" * 80) print("\n") print(str(simstate.trace)) print(str(simstate)) exit(1) except SU.CHBSimError as e: print("*" * 80) print("Error: " + str(e)) print("*" * 80) print("\nSimulation trace") print("-" * 80) print(str(simstate.trace)) print("\nSimulation state") print("-" * 80) print(str(simstate)) exit(1) except Exception as e: print("*" * 80) print("Exception: " + str(e)) print("Current instruction: " + str(currentinstr)) print("*" * 80) print("") print(str(simstate.trace)) print(str(simstate)) exit(1) pc = simstate.programcounter addr = pc.to_hex() try: if pc.modulename == xname: if addr in asm.instructions: currentinstr = asm.instructions[addr] else: raise UF.CHBError( "No instruction found at " + addr + " in " + xname) else: libasm = dynasms[pc.modulename] if addr in libasm.instructions: currentinstr = libasm.instructions[addr] else: raise UF.CHBError( "No instruction found at " + addr + " in " + pc.modulename) except UF.CHBError as e: print("*" * 80) print("Exception in fetching next instruction: " + str(e)) print("*" * 80) print("") print(str(simstate.trace)) print(str(simstate)) exit(1) print("\n\nSimulation trace") print(str(simstate.trace)) with open("simstackmemory.json", "w") as fp: json.dump(simstate.stackmem.jsonval(), fp, indent=3) print("\n\nSimulation state") print("=" * 80) print(str(simstate)) exit(0)
def sharedmem_shmat(self, iaddr: str, simstate: "SimulationState", shmid: int, shmaddr: SSV.SimGlobalAddress, shmflg: int) -> SSV.SimGlobalAddress: """void *shmat(int shmid, const void *shmaddr, int shmflg);""" return SSV.mk_undefined_global_address("shared:" + str(shmid))
def initialize(self, iaddr: str): addr = SSV.mk_global_address(0, "shared") for i in range(0, self.buffersize): SimMemory.set(self, iaddr, addr.add_offset(i), SV.simZerobyte)
def resolve_literal_address(self, iaddr: str, addrvalue: int) -> SSV.SimGlobalAddress: if self.module.has_address(addrvalue): return SSV.mk_global_address(addrvalue, modulename=self.modulename) else: return SSV.mk_undefined_global_address(self.modulename)
def simulate(self, iaddr: str, simstate: "SimulationState") -> str: tgt = SSV.mk_global_address(self.target.absolute_address_value, modulename=simstate.modulename) simstate.increment_programcounter() simstate.simprogramcounter.set_delayed_programcounter(tgt) return "goto " + str(tgt)