def pedatacmd(args: argparse.Namespace) -> NoReturn: # arguments xname: str = args.xname headeronly: bool = args.headeronly imports: bool = args.imports headers: bool = args.headers sections: bool = args.sections section: Optional[str] = args.section try: (path, xfile) = UC.get_path_filename(xname) UC.prepare_executable(path, xfile, doreset=False, doresetx=False, hints=[]) except UF.CHBError as e: print(str(e.wrap())) exit(1) xinfo = XI.XInfo() xinfo.load(path, xfile) if not xinfo.is_pe32: UC.print_error("File is not a PE32 file: " + xinfo.format) exit(1) app = UC.get_app(path, xfile, xinfo) peheader = app.header if headeronly: print(peheader) exit(0) if imports: for i in list(peheader.import_tables.values()): print(str(i)) exit(0) if headers: for h in list(peheader.section_headers.values()): print(str(h)) exit(0) if sections: for (name, s) in peheader.sections.items(): print(str(s)) exit(0) if section is not None: s = peheader.get_section(section) if s is None: UC.print_error("Unable to find section at virtual address: " + str(section)) exit(1) print(str(s)) exit(0) print(peheader) for i in list(peheader.import_tables.values()): print(str(i)) for h in list(peheader.section_headers.values()): print(str(h)) exit(0)
def relational_analysis_cmd(args: argparse.Namespace) -> NoReturn: # arguments xname1: str = args.xname1 xname2: str = args.xname2 xfunctions1: List[str] = args.functions1 xfunctions2: List[str] = args.functions2 showfunctions: bool = args.functions showinstructions: bool = args.instructions usermappingfile: Optional[str] = args.usermapping callees: List[str] = args.callees usermapping: Dict[str, str] = {} if usermappingfile is not None: if os.path.isfile(usermappingfile): with open(usermappingfile, "r") as fp: userdata = json.load(fp) usermapping = userdata["function-mapping"] else: UC.print_error("Usermapping file " + usermappingfile + " not found") exit(1) try: (path1, xfile1) = UC.get_path_filename(xname1) UF.check_analysis_results(path1, xfile1) except UF.CHBError as e: print(str(e.wrap())) exit(1) xinfo1 = XI.XInfo() xinfo1.load(path1, xfile1) try: (path2, xfile2) = UC.get_path_filename(xname2) UF.check_analysis_results(path2, xfile2) except UF.CHBError as e: print(str(e.wrap())) exit(1) xinfo2 = XI.XInfo() xinfo2.load(path2, xfile2) app1 = UC.get_app(path1, xfile1, xinfo1) app2 = UC.get_app(path2, xfile2, xinfo2) relanalysis = RelationalAnalysis(app1, app2, faddrs1=xfunctions1, faddrs2=xfunctions2, usermapping=usermapping, callees=callees) print(relanalysis.report(showfunctions, showinstructions)) exit(0)
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, environment_variables: str = None) -> NoReturn: bigendian = app.header.is_big_endian print("big endian " if bigendian else "little endian") if environment_variables is not None: if os.path.isfile(environment_variables): try: with open(environment_variables, "r") as fp: environmentvars: Dict[str, str] = json.load(fp) print("Environment variables read: " + str(len(environmentvars))) except ValueError as e: raise UF.CHBJSONParseError(environment_variables, e) else: UC.print_error("Environment-variables file: " + environment_variables + " not found") else: environmentvars = {} 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, environment_variables=environmentvars, 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, environment_variables=environmentvars, 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 simulate_function_cmd(args: argparse.Namespace) -> NoReturn: # arguments xname: str = args.xname faddr: str = args.faddr stepcount: int = args.steps libs: List[str] = args.libs support: Optional[str] = args.support stub_imports: List[str] = args.stub_imports mainargs: List[str] = args.mainargs optargaddrstr: Optional[str] = args.optargaddr optargstatestr: Optional[str] = args.optargstate patched_globals: List[str] = args.patched_globals envptr_addr: Optional[str] = args.envptr_addr mainargs = [a.strip() for a in mainargs] try: (path, xfile) = UC.get_path_filename(xname) UF.check_analysis_results(path, xfile) except UF.CHBError as e: print(str(e.wrap())) exit(1) libnames = unpack_named_strings(libs) libapps: Dict[str, Tuple["MIPSAccess", "MIPSAssembly"]] = {} for (name, libxname) in libnames.items(): libapps[name] = load_mips_lib_file(libxname) xinfo = XI.XInfo() xinfo.load(path, xfile) print(str(xinfo)) app = UC.get_app(path, xfile, xinfo) asm = UC.get_asm(app) if xinfo.is_mips: app = cast("MIPSAccess", app) asm = cast("MIPSAssembly", asm) simulate_mips_function( xname, app, asm, faddr, stepcount=stepcount, libs=libapps, support=support, stub_imports=stub_imports, mainargs=[x.lstrip() for x in mainargs], optargaddrstr=optargaddrstr, optargstatestr=optargstatestr, patched_globals=unpack_named_strings(patched_globals), envptr_addr=envptr_addr) elif xinfo.is_arm: app = cast("ARMAccess", app) asm = cast("ARMAssembly", asm) simulate_arm_function(xname, app, asm, faddr) else: UC.print_error( "Simulation not yet implemented for " + app.__class__.__name__) exit(1)
def run_commands(args: argparse.Namespace) -> NoReturn: # arguments name: str = args.cname maxp: int = args.maxp targets: List[str] = args.targets showtargets: bool = args.showtargets if not (os.path.isfile(name)): UC.print_error( "Please specify a json file that lists the analysis commands.") exit(1) try: with open(name, "r") as fp: cmdsfile = json.load(fp) except json.decoder.JSONDecodeError as e: UC.print_error("Error in json commands file: " + str(e)) exit(1) if "targets" not in cmdsfile: UC.print_error( "Please provide a list of targets with analysis arguments.") exit(1) cmdtargets = cmdsfile["targets"] if showtargets: print("Targets available:") print("-" * 80) for tgt in cmdtargets: print(" " + tgt) print("-" * 80) exit(0) results: Dict[str, List[Tuple[List[str], int]]] = {} for tgt in targets: print("Target: " + tgt) tgts = cmdtargets[tgt] if "cmd" not in tgts: UC.print_error("Please specify a command (with cmd) for target " + tgt) exit(1) if "instances" not in tgts: UC.print_error("Please specify instances for target " + tgt) exit(1) cmd = tgts["cmd"] cmdinstances = tgts["instances"] cmdlines: List[Tuple[Optional[str], List[str]]] = [] for cmdinst in cmdinstances: cmdline = (cmdinst.get("output", None), cmd + cmdinst["args"]) cmdlines.append(cmdline) pool = Pool(maxp) with timing(tgt): results[tgt] = pool.map(do_cmd, cmdlines) if "collect" in tgts: collectitems = tgts["collect"] collecteddata: Dict[str, Dict[str, int]] = {} unknowns: Dict[str, Dict[str, int]] = {} opcode_distribution: Dict[str, int] = {} filenames: List[str] = [ cmdinst["args"][0] for cmdinst in tgts["instances"] ] for filename in filenames: (path, xfile) = UC.get_path_filename(filename) xinfo = XI.XInfo() xinfo.load(path, xfile) app = UC.get_app(path, xfile, xinfo) asm = UC.get_asm(app) if "opcode-distribution" in collectitems: opcd: Dict[str, int] = asm.opcode_distribution() for (k, v) in opcd.items(): opcode_distribution.setdefault(k, 0) opcode_distribution[k] += v if "unknowns" in collectitems and xinfo.is_arm: for instr in asm.unknown_instructions: instr = cast("ARMAssemblyInstruction", instr) if instr.mnemonic == "unknown": hint = instr.unknown_hint() unknowns.setdefault(hint, {}) unknowns[hint].setdefault(xfile, 0) unknowns[hint][xfile] += 1 if "output" in tgts: outputfilename = tgts["output"] opcode_output: Dict[str, Any] = {} opcode_output["name"] = tgt opcode_output["opcode-distribution"] = opcode_distribution opcode_output["unknowns"] = unknowns with open(outputfilename, "w") as fp: json.dump(opcode_output, fp, indent=2) else: print("\nOpcode distribution") for (opc, c) in sorted(opcode_distribution.items()): print(str(c).rjust(10) + " " + opc) print("\nUnknowns") for (hint, ufiles) in sorted(unknowns.items()): print("\n" + hint) for (f, c) in sorted(ufiles.items()): print(" " + str(c).rjust(5) + " " + f) for tgt in results: print("\nResults for " + tgt) for fresult in results[tgt]: status = " ok " if fresult[1] == 0 else "fail" print(status + " " + " ".join(fresult[0])) exit(0)