Exemple #1
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)
Exemple #2
0
def report_calls(args: argparse.Namespace) -> NoReturn:

    # arguments
    xname: str = args.xname

    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)

    xinfo = XI.XInfo()
    xinfo.load(path, xfile)

    app = UC.get_app(path, xfile, xinfo)

    calls = app.call_instructions()
    calllist: List[Tuple[str, str]] = []

    for faddr in sorted(calls):
        print("\nFunction " + faddr)
        for baddr in calls[faddr]:
            print("  Block " + baddr)
            for instr in calls[faddr][baddr]:
                calllist.append((instr.annotation, faddr))
                print("     " + str(instr))

    print("\nCalls aggregated")
    print("------------------")
    for (c, faddr) in sorted(calllist):
        print(faddr.ljust(12) + c)

    exit(0)
    def check_test(self, r) -> None:
        testfilename = UF.get_test_filename("arm32", "elf", "DT", r[0])
        try:
            (path, xfile) = UC.get_path_filename(testfilename)
        except UF.CHBError as e:
            print(str(e.wrap()))
            exit(1)

        xinfo = XI.XInfo()
        xinfo.load(path, xfile)

        app = UC.get_app(path, xfile, xinfo)
        if app.has_function("0x1000"):
            f = app.function("0x1000")
            instr = list(f.instructions.values())[0]
            mnemonic = instr.mnemonic
            ops = instr.operandstring
            refmnemonic = r[2]
            refopstring = r[3]
            if mnemonic != refmnemonic:
                print("Mismatch in mnemonic: " + mnemonic + ", " + refmnemonic)
            if ops != refopstring:
                print("Mismatch in operandstring: " + ops + ", " + refopstring)
            else:
                print(
                    "["
                    + r[0].ljust(8)
                    + r[1].ljust(10)
                    + r[2].ljust(8)
                    + r[3].ljust(12)
                    + "ok]")
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 elfdatacmd(args: argparse.Namespace) -> NoReturn:

    # arguments
    xname: str = args.xname
    savesectionheaders: str = args.save_section_headers
    showlibs: bool = args.libs
    showheader: bool = args.header

    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_elf:
        print("File is not an ELF file: " + xinfo.format)
        exit(1)

    app = UC.get_app(path, xfile, xinfo)
    elfheader = app.header

    try:
        if showheader:
            print(elfheader.fileheaderstr())
        elif showlibs:
            if elfheader.has_dynamic_table():
                for s in elfheader.get_dynamic_table().dynamic_libraries:
                    print("  " + s)
            else:
                print("=")
                print("Binary does not have a dynamic table")
                print("=")
        else:
            print(str(elfheader))
    except UF.CHBError as e:
        print(str(e.wrap()))
        exit(1)

    if savesectionheaders:
        result: Dict[str, Any] = {}
        result["file"] = xinfo.file
        result["md5"] = xinfo.md5
        result["section-headers"] = []
        for s in elfheader.sectionheaders:
            result["section-headers"].append(s.attribute_values())
        filename = xname + "_section_headers.json"
        with open(filename, "w") as fp:
            json.dump(result, fp, indent=3)
        UC.print_info("Saved section headers in " + filename)

    exit(0)
def load_mips_lib_file(libxname: str) -> Tuple["MIPSAccess", "MIPSAssembly"]:
    try:
        (libpath, libxfile) = UC.get_path_filename(libxname)
        UF.check_analysis_results(libpath, libxfile)
    except UF.CHBError as e:
        print(str(e.wrap()))
        exit(1)

    libxinfo = XI.XInfo()
    libxinfo.load(libpath, libxfile)

    libapp = cast("MIPSAccess", UC.get_app(libpath, libxfile, libxinfo))
    libasm = cast("MIPSAssembly", UC.get_asm(libapp))

    return (libapp, libasm)
def check_test_case(filename: str) -> int:
    testdatafile = filename + ".json"

    try:
        with open(testdatafile, "r") as fp:
            testdata = json.load(fp)
    except Exception as e:
        print(str(e))
        return (-1)

    try:
        (path, xfile) = UC.get_path_filename(filename)
        UF.check_analysis_results(path, xfile)
    except UF.CHBError as e:
        print(str(e.wrap()))
        exit(1)

    xinfo = XI.XInfo()
    xinfo.load(path, xfile)

    app = UC.get_app(path, xfile, xinfo)

    for faddr in testdata["functions"]:
        if app.has_function(faddr):
            f = app.function(faddr)
            fstats = app.result_metrics.get_function_metrics(faddr)
            result = check_test_function(f, fstats,
                                         testdata["functions"][faddr])
            if result != 0:
                break
        else:
            print("Function " + faddr + " not found in results")
            result = (-1)
            break

    else:
        result = 0

    return result
Exemple #8
0
def report_memops(args: argparse.Namespace) -> NoReturn:

    # arguments
    xname: str = args.xname

    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)

    xinfo = XI.XInfo()
    xinfo.load(path, xfile)

    app = UC.get_app(path, xfile, xinfo)

    memloads = app.load_instructions()
    memstores = app.store_instructions()

    loadstats: Dict[str, Tuple[int, int]] = {}
    storestats: Dict[str, Tuple[int, int]] = {}

    def add_load_unknown(faddr: str) -> None:
        loadstats.setdefault(faddr, (0, 0))
        v = loadstats[faddr]
        loadstats[faddr] = (v[0] + 1, v[1])

    def add_load_known(faddr: str) -> None:
        loadstats.setdefault(faddr, (0, 0))
        v = loadstats[faddr]
        loadstats[faddr] = (v[0] + 1, v[1] + 1)

    loadxrefs: Dict[str, List[str]] = {}

    def add_load_xref(gv: str, faddr: str) -> None:
        loadxrefs.setdefault(gv, [])
        loadxrefs[gv].append(faddr)

    print("Load instructions")
    print("-----------------")
    for faddr in sorted(memloads):
        print("\nFunction " + faddr)
        for baddr in memloads[faddr]:
            print("  Block: " + baddr)
            for instr in memloads[faddr][baddr]:
                print("     " + str(instr))
                for rhs in instr.rhs:
                    add_load_xref(str(rhs), faddr)
                    if str(rhs) == "?":
                        add_load_unknown(faddr)
                    else:
                        add_load_known(faddr)

    def add_store_unknown(faddr: str) -> None:
        storestats.setdefault(faddr, (0, 0))
        v = storestats[faddr]
        storestats[faddr] = (v[0] + 1, v[1])

    def add_store_known(faddr: str) -> None:
        storestats.setdefault(faddr, (0, 0))
        v = storestats[faddr]
        storestats[faddr] = (v[0] + 1, v[1] + 1)

    storexrefs: Dict[str, List[str]] = {}

    def add_store_xref(gv: str, faddr: str) -> None:
        storexrefs.setdefault(gv, [])
        storexrefs[gv].append(faddr)

    print("\n\nStore instructions")
    print("----------------------")
    for faddr in sorted(memstores):
        print("\nFunction " + faddr)
        for baddr in memstores[faddr]:
            print("  Block: " + baddr)
            for instr in memstores[faddr][baddr]:
                print("     " + str(instr))
                for lhs in instr.lhs:
                    add_store_xref(str(lhs), faddr)
                    if str(lhs) in ["?", "??operand??"]:
                        add_store_unknown(faddr)
                    else:
                        add_store_known(faddr)

    print("\nLoad xreferences")
    print("------------------")
    for gv in sorted(loadxrefs):
        if gv.startswith("gv_"):
            print(gv.ljust(24) + "[" + ", ".join(loadxrefs[gv]) + "]")

    print("\nStore xreferences")
    print("-------------------")
    for gv in sorted(storexrefs):
        if gv.startswith("gv"):
            print(gv.ljust(24) + "[" + ", ".join(storexrefs[gv]) + "]")

    print("\nLoad statistics")
    print("-----------------")
    loadtotal: int = 0
    loadknown: int = 0
    for faddr in sorted(loadstats):
        ftotal = loadstats[faddr][0]
        fknown = loadstats[faddr][1]
        loadtotal += ftotal
        loadknown += fknown
        print(faddr + ": " + str(fknown).rjust(4) + " / " +
              str(ftotal).ljust(4))

    perc = (loadknown / loadtotal) * 100
    fperc = "{:.2f}".format(perc)
    print("\nTotal: " + str(loadknown) + " / " + str(loadtotal) + " (" +
          fperc + "%)")

    print("\nStore statistics")
    print("------------------")
    storetotal = 0
    storeknown = 0
    for faddr in sorted(storestats):
        ftotal = storestats[faddr][0]
        fknown = storestats[faddr][1]
        storetotal += ftotal
        storeknown += fknown
        print(faddr + ": " + str(fknown).rjust(4) + " / " +
              str(ftotal).ljust(4))

    perc = (storeknown / storetotal) * 100
    fperc = "{:.2f}".format(perc)
    print("\nTotal: " + str(storeknown) + " / " + str(storetotal) + " (" +
          fperc + "%)")
    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)
Exemple #10
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)
 def remove_test(self, r) -> None:
     testfilename = UF.get_test_filename("arm32", "elf", "DT", r[0])
     (path, xfile) = UC.get_path_filename(testfilename)
     os.remove(os.path.join(path, xfile))
     shutil.rmtree(os.path.join(path, xfile + ".ch"))