コード例 #1
0
def main():
    ida_auto.set_ida_state(ida_auto.st_Work)
    root = {}

    count = 0
    sigcount = 0
    sigattempts = 0

    calc_func_segments()

    funcs = list(idautils.Functions(FUNCS_SEGSTART, FUNCS_SEGEND))

    alltime = 0.0
    avgtime = 0.0

    f = ida_kernwin.ask_file(1, "*.yml", "Choose a file to save to")
    if not f:
        return

    skip = ida_kernwin.ask_yn(1, "Skip functions that start with \"sub_\"?")
    if skip == -1:
        return

    # Clean up and get rid of shitty funcs
    funccpy = funcs[:]
    for fea in funccpy:
        funcname = ida_funcs.get_func_name(fea)
        if funcname is None or funcname.startswith("nullsub"):
            funcs.remove(fea)
            continue

        if skip and funcname.startswith("sub"):
            funcs.remove(fea)
            continue

        flags = idc.get_func_attr(fea, FUNCATTR_FLAGS)
        if flags & ida_funcs.FUNC_LIB:
            funcs.remove(fea)
            continue

    funccount = len(funcs)
    for fea in funcs:
        starttime = time()

        func = idaapi.get_func(fea)
        funcname = ida_funcs.get_func_name(fea)
        if funcname != None:
            unmangled = idc.demangle_name(funcname,
                                          idc.get_inf_attr(idc.INF_SHORT_DN))
            if unmangled is None:
                unmangled = funcname

            sig = makesig(func)
            sigattempts += 1
            root[unmangled] = {"mangled": funcname, "signature": sig}

            if sig:
                sigcount += (0 if "!" in sig else 1)

        # Only ETA makesig() attempts, otherwise the timing is really off
        # Unfortunately, sigging takes progressively longer the further along the function list
        # this goes, as makesig() searches from up to down while functions are ordered from up to down
        # So this isn't really accurate but w/e

        multpct = 2.0 - count / float(
            funccount
        )  # Scale up a bit the lower we start at the get a halfass decent eta
        alltime += time() - starttime
        avgtime = alltime / sigattempts
        eta = int(avgtime * (funccount - count) * multpct)
        etastr = strftime("%H:%M:%S", gmtime(eta))

        count += 1
        update_window("Evaluated {} out of {} ({}%)\nETA: {}".format(
            count, funccount,
            floor(count / float(funccount) * 100.0 * 10.0) / 10.0, etastr))

    while f.count(".yml") >= 2:
        f = f.replace(".yml", "", 1)
    if not f.endswith(".yml"):
        f += ".yml"

    with open(f, "w") as f:
        yaml.safe_dump(root, f, default_flow_style=False, width=999999)

    ida_kernwin.hide_wait_box()
    print("Successfully generated {} signatures from {} functions".format(
        sigcount, funccount))

    ida_auto.set_ida_state(ida_auto.st_Ready)
コード例 #2
0
    def OnSelectLine(self, n):
        segname = self.items[n][0]
        seg = ida_segment.get_segm_by_name(segname + ":__text")

        filename = segname.replace(".", "_") + "_massbp"

        fp = open(filename + ".h", "w")

        guard = filename.upper() + "_H"

        fp.write("#ifndef %s\n" % guard)
        fp.write("#define %s\n" % guard)

        # Put the ID of the function inside the immediate of the BRK
        brk = 0xd4200000
        fxnid = 0

        fxns = list(idautils.Functions(seg.start_ea, seg.end_ea))

        # orig instrs for sleh hook, indexed by function ID
        # one shot breakpoints
        fp.write("static uint32_t %s_orig_instrs[] = {\n" % filename)

        for fxnaddr in fxns:
            instr = int.from_bytes(idaapi.get_bytes(fxnaddr, 4, False),
                                   "little")
            fp.write(hex(instr) + ",\n")

        fp.write("};\n")

        fxnid = 0

        fp.write("static const char *%s_fxn_names[] = {\n" % filename)

        for fxnaddr in fxns:
            fxnname = ida_funcs.get_func_name(fxnaddr)
            fxnname_dm = idc.demangle_name(fxnname,
                                           get_inf_attr(idc.INF_LONG_DN))

            if fxnname_dm != None:
                fxnname = fxnname_dm

            fp.write("\"%s\",\n" % fxnname)

        fp.write("};\n")

        fxnid = 0

        fp.write("static void %s(void){\n" % filename)

        for fxnaddr in fxns:
            brk &= 0xffe0001f
            brk |= (fxnid << 5)
            fxnaddrh = hex(fxnaddr)
            # print("Current function {} with ID {}, brk {}".format(fxnaddrh, fxnid, hex(brk)))
            fp.write("kwrite_instr({}+kernel_slide, {}); /* FUNCTION {} */\n".
                     format(fxnaddrh, hex(brk), hex(fxnid)))
            fxnid += 1

        fp.write("}\n")

        fxnid = 0

        fp.write("static void %s(void){\n" %
                 filename.replace("massbp", "undobp"))

        for fxnaddr in fxns:
            brk &= 0xffe0001f
            brk |= (fxnid << 5)
            fxnaddrh = hex(fxnaddr)
            # print("Current function {} with ID {}, brk {}".format(fxnaddrh, fxnid, hex(brk)))
            fp.write(
                "kwrite_instr({}+kernel_slide, {}_orig_instrs[{}]);\n".format(
                    fxnaddrh, filename, hex(fxnid)))
            fxnid += 1

        fp.write("}\n")
        fp.write("#endif\n")

        print("Wrote header file to %s" % os.getcwd() + "/" + fp.name)

        fp.close()

        return n
コード例 #3
0
def _isFunctionMangled(ea: int) -> bool:
    name = get_func_name(ea)
    disable_mask = get_inf_attr(INF_SHORT_DN)
    if demangle_name(name, disable_mask) is None:
        return False
    return True
コード例 #4
0
def kernelcache_find_virtual_method_overrides(classname=None, method=None):
    import idc
    import idaapi
    import ida_name
    import ida_kernelcache as kc

    # Define the form to ask for the arguments.
    class MyForm(idaapi.Form):
        def __init__(self):
            swidth = 40
            idaapi.Form.__init__(
                self, r"""STARTITEM 0
Find virtual method overrides

<#The class#Class :{classname}>
<#The virtual method#Method:{method}>""", {
                    'classname':
                    idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT,
                                            swidth=swidth),
                    'method':
                    idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT,
                                            swidth=swidth),
                })

        def OnFormChange(self, fid):
            return 1

    kc.collect_class_info()

    if any(arg is None for arg in (classname, method)):
        f = MyForm()
        f.Compile()
        f.classname.value = classname or ''
        f.method.value = method or ''
        ok = f.Execute()
        if ok != 1:
            print('Cancelled')
            return False
        classname = f.classname.value
        method = f.method.value
        f.Free()

    if classname not in kc.class_info:
        print('Not a valid class: {}'.format(classname))
        return False

    print('Subclasses of {} that override {}:'.format(classname, method))
    baseinfo = kc.class_info[classname]
    found = False
    for classinfo in baseinfo.descendants():
        for _, override, _ in kc.vtable.class_vtable_overrides(
                classinfo, superinfo=baseinfo, methods=True):
            name = idc.get_name(
                override, ida_name.GN_VISIBLE
                | idc.calc_gtn_flags(idc.BADADDR, override))
            demangled = idc.demangle_name(
                name, idc.get_inf_attr(idc.INF_SHORT_DEMNAMES))
            name = demangled if demangled else name
            if method in name:
                print('{:#x}  {}'.format(override, classinfo.classname))
                found = True
    if not found:
        print('No subclass of {} overrides {}'.format(classname, method))
    return found
コード例 #5
0
def demangle_func_name(mangled_name, clean=True):
    demangle_attr = idc.get_inf_attr(INF_SHORT_DN if clean else INF_LONG_DN)
    return idc.demangle_name(mangled_name, demangle_attr)
コード例 #6
0
ファイル: vtable_io.py プロジェクト: xMaZax/IDA-Scripts
def prep_vtable(linuxtable, key, wintable, winv):
    if not linuxtable.get(key):
        return None

    funclist = linuxtable[key]
    # Compat for 2.7, strings are in unicode
    if version_info[0] < 3:
        funclist = [
            i if isinstance(i, (int, long)) else str(i)
            for i in linuxtable[key]
        ]
    thunks, thunklist = get_thunks(winv, key, funclist)

    # We've got the thunks, now we don't need anything beyond another typeinfo
    instance = (int, long) if version_info[0] < 3 else int
    for i, v in enumerate(funclist):
        if isinstance(v, instance):
            funclist = funclist[:i]  # Skipping thisoffs
            break

    # Get rid of extra destructor for linux
    for i, n in enumerate(funclist):
        name = idc.demangle_name(n, idc.get_inf_attr(idc.INF_SHORT_DN))
        if name:
            if "::~" in name:
                del funclist[i]
                break

    # Windows does overloads backwards, reverse them
    # Also check for thunks while we're at it
    i = 0
    funcoverloads = {}
    while i < len(funclist):  # and i < len(wintable):
        n = funclist[i]
        if n.startswith("__cxa"):
            i += 1
            continue

        # I shouldn't need to do this, but destructors are wonky
        if i == 0:
            demangled = idc.demangle_name(n,
                                          idc.get_inf_attr(idc.INF_SHORT_DN))
            if demangled and "::~" in demangled:
                i += 1
                continue

        overloadname = get_func_sname(n)
        shortname = get_func_postname(n)
        if not shortname:
            i += 1
            continue

        # Windows skips the vtable function if it exists in the thunks and
        # the thunk does not jmp into it (because the thunk is the function)
        try:
            thunkidx = thunklist.index(shortname)
            delete = 1
        except:
            thunkidx = -1
            delete = 0
        if i < len(wintable):
            if thunkidx != -1 and thunkidx < len(thunks):
                if not isinthunk(wintable[i], thunks[thunkidx]):
                    currname = idc.get_name(thunks[thunkidx][0],
                                            ida_name.GN_VISIBLE)

                    if currname and currname != funclist[
                            i] and EXPORT_MODE != Export_YesOnly:
                        nameflags = ida_name.SN_FORCE
                        if not currname.startswith("sub_"):
                            if not USE_WEAK_NAMES:
                                del funclist[i]
                                continue

                            nameflags |= ida_name.SN_WEAK
                        elif USE_WEAK_NAMES:
                            global FUNCS
                            FUNCS += 1

                        idc.set_name(thunks[thunkidx][0], funclist[i],
                                     nameflags)

                    del funclist[i]
                    continue
        else:  # Class has thunks at the end of the vtable
            # This doesn't change anything but it should link up the lengths of both tables
            if delete:
                del funclist[i]
                continue

        node = funcoverloads.get(overloadname, [])

        # Is this a half-ass decent overload
        go = 1
        for loadnode in range(len(node)):
            if not any(
                [i - funclist.index(val) > F**K for val in node[loadnode]]):
                node[loadnode].append(n)
                go = 0
                break

        if go:
            node.append([n])

        funcoverloads[overloadname] = node
        i += 1

    for k, value in get_bcompat_items(funcoverloads):
        #		if len(value) <= 1:
        #			continue

        #		split = []
        #
        #		# Since subclass overloads shouldn't scoot up next to their baseclass brethren
        #		# hackily separate overloads by classname
        #		for mname in value:
        #			found = 0
        #
        #			name = idc.demangle_name(mname, idc.get_inf_attr(idc.INF_SHORT_DN))
        #			typename = name[:name.find("::")]
        #
        #			for i2 in range(len(split)):
        #				for othermname in split[i2]:
        #					name = idc.demangle_name(othermname, idc.get_inf_attr(idc.INF_SHORT_DN))
        #					othertypename = name[:name.find("::")]
        #
        #					if typename == othertypename:
        #						found = 1
        #						split[i2].append(mname)
        #						break
        #
        #				if found:
        #					break
        #
        #			if not found:
        #				split.append([mname])

        for v in value:
            if len(v) <= 1:
                continue

            lowestidx = len(funclist)
            for func in v:
                temp = funclist.index(func)
                if lowestidx > temp:
                    lowestidx = temp

            count = 0
            while len(v):
                k = v.pop()
                funclist.insert(lowestidx + count,
                                funclist.pop(funclist.index(k)))
                count += 1

    diff = len(funclist) - len(wintable)
    if diff:
        print("WARNING: {} vtable may be wrong! L{} - W{} = {}".format(
            key, len(funclist), len(wintable), diff))

    return funclist
コード例 #7
0
    def lvar_type_changed(self, vu, v, tif):
        if (vu.cfunc):
            func_tif = ida_typeinf.tinfo_t()
            vu.cfunc.get_func_type(func_tif)

            funcdata = idaapi.func_type_data_t()
            got_data = func_tif.get_func_details(funcdata)

            if (not got_data):
                # self._log("Didnt get the data")
                pass

            lvars = vu.cfunc.get_lvars()
            for j in range(len(vu.cfunc.argidx)):
                # for i in vu.cfunc.argidx:
                i = vu.cfunc.argidx[j]
                if (lvars[i].name == v.name):
                    #self._log("lvar_type_changed: function argument changed = %s, index = %s, atype = %s" % (lvars[i].name, i, funcdata[j].argloc.atype()))
                    if (funcdata[i].argloc.atype() == 3):
                        #    self._log("lvar_type_changed: reg is : %s" %(funcdata[i].argloc.reg1()))
                        pass

                    if (funcdata[i].argloc.atype() != 3
                            or funcdata[i].argloc.reg1() != RCX_REG):
                        break

                    #self._log("applyName = %s" % (applyName))

                    firstPtrRemove = ida_typeinf.remove_pointer(tif)
                    #self._log("type name = %s" % (firstPtrRemove._print()))
                    #self._log("remove_pointer.is_ptr = %s" % (firstPtrRemove.is_ptr()))
                    #self._log("remove_pointer.is_struct = %s" % (firstPtrRemove.is_struct()))
                    if (firstPtrRemove.is_struct()
                            and not firstPtrRemove.is_ptr()):
                        currentFuncName = ida_name.get_ea_name(
                            vu.cfunc.entry_ea)
                        # self._log("before demangle current func name = %s" % (currentFuncName))
                        demangled = idc.demangle_name(
                            currentFuncName,
                            idc.get_inf_attr(idc.INF_SHORT_DN))
                        if (demangled != None):
                            self._log("Overriding mangled name = %s" %
                                      (currentFuncName))
                            currentFuncName = demangled
                        # self._log("after demangle current func name = %s" % (currentFuncName))
                        tokens = currentFuncName.split("::")
                        if len(tokens) > 1:
                            currentFuncName = tokens[1]
                        currentFuncName = currentFuncName.split("(")[0]
                        # self._log("current func name = %s" % (currentFuncName))
                        idc.set_name(
                            vu.cfunc.entry_ea,
                            firstPtrRemove._print() + "::" + currentFuncName,
                            idc.SN_NOWARN)
                        idaapi.auto_wait()
                        # self._log("Decomp Res : %s" % idaapi.decompile(vu.cfunc.entry_ea))
                        idaapi.refresh_idaview_anyway()
                        vu.refresh_ctext()
                        idaapi.refresh_idaview_anyway()
                        vu.refresh_ctext()
                        vu.refresh_view(True)

                        current_widget = idaapi.get_current_widget()
                        vu1 = idaapi.get_widget_vdui(current_widget)
                        if vu1:
                            vu1.refresh_ctext()
                    break

        #self._log("lvar_type_changed: vu=%s, v=%s, tinfo=%s" % (vu, self._format_lvar(v), tif._print()))
        return 1
コード例 #8
0
 def name(self):
     name = idaapi.get_name(self.address)
     if idaapi.is_valid_typename(name):
         return name
     name = idc.demangle_name(name, idc.get_inf_attr(idc.INF_SHORT_DN))
     return common.demangled_name_to_c_str(name)
コード例 #9
0
def FilterConstructors(old_identifier_constructors_dict, complete_vft_dict):
    identifier_constructors_dict = old_identifier_constructors_dict.copy()
    bad_functions = []

    # Prepare bad function list
    for ea in idautils.Segments():
        for funcaddress in idautils.Functions(idc.SegStart(ea),
                                              idc.SegEnd(ea)):
            f_name = idc.GetFunctionName(funcaddress)
            f_name_demangled = idc.demangle_name(
                f_name, idc.GetLongPrm(idc.INF_SHORT_DN))
            if f_name_demangled != None:
                f_name = f_name_demangled
            if "(" in f_name:
                tmp_name = f_name[:f_name.find("(")]
            else:
                tmp_name = f_name
            if "free" in tmp_name.lower():
                bad_functions.append(funcaddress)
            elif "operator delete" in tmp_name.lower():
                bad_functions.append(funcaddress)

    # Build virtual method list
    virtual_methods = []
    for vft_infos in complete_vft_dict.values():
        for vft_info in vft_infos:
            virtual_methods += vft_info[2]

    changed = True
    while changed:
        changed = False
        for class_identifier, constructors in identifier_constructors_dict.items(
        ):
            new_constructors = []
            for constructor in constructors:
                # Check virtualized function. Which means it is destructor
                if constructor.func_ea in virtual_methods:
                    bad_functions.append(constructor.func_ea)
                    changed = True
                    continue
                # Count references of bad functions
                ref_count = 0
                badref_count = 0
                f = idaapi.get_func(constructor.func_ea)
                fc = idaapi.FlowChart(f, None, 0x4)
                for bbl in fc:
                    cur_ea = bbl.startEA
                    while cur_ea < bbl.endEA:
                        for ref in idautils.XrefsFrom(cur_ea):
                            if f.startEA <= ref.to and ref.to < f.endEA:
                                continue
                            ref_count += 1
                            if ref.to in bad_functions:
                                badref_count += 1
                        cur_ea = idc.NextHead(cur_ea)
                bad_percent = (badref_count * 100.0) / ref_count
                if 50.0 <= bad_percent:
                    bad_functions.append(constructor.func_ea)
                    changed = True
                    continue
                # Okay. It is not destructor!
                new_constructors.append(constructor)
            identifier_constructors_dict[class_identifier] = new_constructors
    return identifier_constructors_dict