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)
示例#2
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)
示例#3
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)
示例#5
0
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)