예제 #1
0
def xref_global(node, ctx):
    var = ctx.get_obj("written")
    print("%x at %x" % (var.addr, node.ea))
    # Terrible check to see if we're in a function
    if idc.get_func_flags(var.addr) == -1:
        ida_xref.add_dref(node.ea, var.addr, ida_xref.XREF_USER)
    return False
def main():
    global cfgTree
    cfgTree = CFGTree()

    seg = idaapi.get_segm_by_name("__text")

    # Loop from segment start to end
    func_ea = seg.startEA

    # Get a function at the start of the segment (if any)
    func = idaapi.get_func(func_ea)
    if func is None:
        # No function there, try to get the next one
        func = idaapi.get_next_func(func_ea)

    seg_start = seg.startEA
    seg_end = seg.end_ea
    while func is not None and func.start_ea < seg_end:
        funcea = func.start_ea
        fflags = idc.get_func_flags(funcea)
        if (fflags & idc.FUNC_LIB) or (fflags & idc.FUNC_THUNK):
            continue

        # print("Function %s at 0x%x" % (idc.get_func_name(funcea), funcea))
        flow = idaapi.FlowChart(idaapi.get_func(funcea), flags=idaapi.FC_PREDS)
        construct_cfg(flow, funcea, seg_start, seg_end)
        func = idaapi.get_next_func(funcea)
    cfgTree.print_deepest_path()
def find_dispatch_by_cfg():
    """ 
    Finds the functions in the binary which are not directly called anywhere and counts how many other functions they call,
    returing all functions which call > 0 other functions but are not called themselves. As a dispatch function is not normally directly
    called but will normally many other functions this is a fairly good way to guess which function it is.
    """

    out = []
    called = set()
    caller = dict()
    # Loop through all the functions in the binary
    for function_ea in idautils.Functions():
        flags = idc.get_func_flags(function_ea)
        # skip library functions
        if flags & idc.FUNC_LIB:
            continue
        f_name = idc.get_func_name(function_ea)
        # For each of the incoming references
        for ref_ea in idautils.CodeRefsTo(function_ea, 0):
            called.add(f_name)
            # Get the name of the referring function
            caller_name = idc.get_func_name(ref_ea)
            if caller_name not in caller.keys():
                caller[caller_name] = 1
            else:
                caller[caller_name] += 1
    while True:
        if len(caller.keys()) == 0:
            break
        potential = max(caller, key=caller.get)
        if potential not in called:
            out.append(potential)
        del caller[potential]
    return out
        def ext_instruction(file_name, addr_start, addr_end):
            name_fun = GetFunctionName(addr_start)
            row = ''
            for addr in Heads(addr_start, addr_end):

                ins = ''
                thisOperand = idc.GetMnem(addr)
                oPtype1 = idc.GetOpType(addr, 0)
                oPtype2 = idc.GetOpType(addr, 1)
                # assemblydata = parametertype(oPtype1)+' '+parametertype(oPtype2)
                if (oPtype1 == 1 or oPtype1 == 4):
                    oPtype1 = idc.GetOpnd(addr, 0)
                if (oPtype2 == 1 or oPtype2 == 4):
                    oPtype2 = idc.GetOpnd(addr, 1)
                if thisOperand == "call":
                    call_fun_name = GetOpnd(addr, 0)
                    keyInstr = LocByName(call_fun_name)
                    fflags = idc.get_func_flags(keyInstr)
                    if (fflags & idc.FUNC_LIB) or (fflags & idc.FUNC_THUNK):
                        ins = thisOperand + '_' + idc.GetOpnd(addr, 0) + '_0'
                        row = row + ' ' + ins
                        continue
                ins = str(thisOperand)+'_'+tran(str(oPtype1)) + \
                    '_'+tran(str(oPtype2))
                row = row + ' ' + ins
            return row
    def getXRefsTo(self):
        """
        Computes a list of the names of the xrefs to the function.
        This includes all functions that call this, but also data xrefs.
        :returns: a tuple of two lists: crefs and drefs
        """
        # type: () -> (list[int], list[int])
        crefs = []
        drefs = []
        # If the current address is function process it
        if idc.get_func_flags(self.func_ea) != -1:
            # Find all code references to func
            ref = idc.get_first_cref_to(self.func_ea)
            while ref != idaapi.BADADDR:
                # name = get_func_name(ref)
                # if not name: name = "ROM:%08X" % ref
                crefs.append(ref)
                ref = idaapi.get_next_cref_to(self.func_ea, ref)
            # Find all data references to func
            for ref in idautils.DataRefsTo(self.func_ea):
                drefs.append(ref)
            for ref in idautils.DataRefsTo(self.func_ea + 1):
                drefs.append(ref)

            return crefs, drefs
예제 #6
0
def analysis():
    for ea in idautils.Functions():
        flags = idc.get_func_flags(ea)
        # 筛选 THUNK (跳转) or 典型库函数
        if flags & idc.FUNC_LIB or flags & idc.FUNC_THUNK:
            continue
        features['EA'].append(f"{ea:X}")
예제 #7
0
파일: ida_binaryai.py 프로젝트: jilir/sdk
 def query_all_callback(self, threshold=0.8, minsize=3):
     for ea in idautils.Functions():
         pfn = idaapi.get_func(ea)
         func_name = idaapi.get_func_name(ea)
         if idaapi.FlowChart(pfn).size < minsize:
             print(
                 "[BinaryAI] {} is skipped because basicblock size lower than minsize({})"
                 .format(func_name, minsize))
             continue
         funcs = self.query_function(ea)
         if funcs is None:
             print(
                 "[BinaryAI] {} is skipped because get function feature error"
                 .format(func_name, threshold))
             continue
         func = funcs[0]
         if func['score'] < threshold:
             print(
                 "[BinaryAI] {} is skipped because top1_score lower than threshold({})"
                 .format(func_name, threshold))
             continue
         idc.set_color(ea, idc.CIC_FUNC, 0xFFFFE1)
         idc.set_func_flags(ea, idc.get_func_flags(ea) | 0x10000)
         comment = SourceCodeViewer.source_code_comment(func_name, func)
         idaapi.set_func_cmt(pfn, comment, 0)
    def __init__(self, func_ea):
        """
        :raises: InvalidFunctionException if func_ea does not live within a function, or the function is not defined.
        :param func_ea: long: Effective Address of function to manipulate
        """
        # If the current address is a function, process it
        if idc.get_func_flags(func_ea) != -1:

            self.func = idaapi.get_func(func_ea)
            self.func_ea = self.func.startEA

            if self.func.tails:
                raise (FunctionException(
                    "%07X: Function Chunks are not supported" % func_ea))
        else:
            raise (FunctionException(
                "Address %08x does not live within a function" % func_ea))
def find_dispatch_by_struct_index():
    """Attempts to locate the dispatch function based off it being loaded in a structure
    at offset 70h, based off of https://github.com/kbandla/ImmunityDebugger/blob/master/1.73/Libs/driverlib.py """
    
    out = set()
    for function_ea in idautils.Functions():
        flags = idc.get_func_flags(function_ea)
        # skip library functions
        if flags & idc.FUNC_LIB:
            continue
        func = idaapi.get_func(function_ea)
        addr = func.start_ea
        while addr < func.end_ea:
            if idc.print_insn_mnem(addr) == 'mov':
                if '+70h' in idc.print_operand(addr, 0) and idc.get_operand_type(addr, 1) == 5:
                    out.add(idc.print_operand(addr, 1))
            addr = idc.next_head(addr)
    return out
예제 #10
0
    def __init__(self, func_ea):
        """
        :raises: InvalidFunctionException if func_ea does not live within a function, or the function is not defined.
        :param func_ea: long: Effective Address of function to manipulate
        """
        # If the current address is a function process it
        if idc.get_func_flags(func_ea) != -1:

            self.func = idaapi.get_func(func_ea)
            self.func_ea = self.func.startEA

            # TODO: these shouldn't be unsupported. detect each chunk as its own function? fix func_ea
            # function chunks can give invalid behavior when definind functions!
            if self.func.tails:
                raise (FunctionException(
                    "%07X: Function Chunks are not supported" % func_ea))
        else:
            raise (FunctionException(
                "Address %08x does not live within a function" % func_ea))
예제 #11
0
def disassemble_func(address):
    func_dis = {}
    symbolic_calls = {}
    inst_num = 0
    flags = idc.get_func_flags(address)
    last_addr = address
    asm = ''
    cnt = 0
    for addr in FuncItems(address):
        cnt += 1
        ins = idautils.DecodeInstruction(addr)
        # print('decoded')
        byte_instr = idc.get_bytes(addr, ins.size)
        asm = asm + str(binascii.hexlify(byte_instr))
        inst_num = inst_num + 1
        last_addr = addr
        if idc.print_insn_mnem(addr) in ["call"]:
            # print('Call:'+str(ins))
            call_address = idc.get_operand_value(addr, 0)
            # print(call_address)
            start_addr = idc.first_func_chunk(call_address)
            symbolic_calls[start_addr] = idc.get_func_name(call_address)

    func_dis['bytecode'] = asm
    func_dis['symbolic_calls'] = symbolic_calls
    func_dis['start_address'] = idc.first_func_chunk(address)
    func_dis['end_address'] = last_addr
    func_dis['segment_address'] = idc.get_segm_start(address)
    func_dis['segment_name'] = idc.SegName(address)
    func_dis['name'] = idc.get_func_name(address)
    func_dis['inst_numbers'] = inst_num
    # attenzione sta cosa ci da la roba riconosciuta con flirt.
    func_dis['library_flag'] = flags & idc.FUNC_LIB

    print("Function contains {} instructions".format(cnt))

    return func_dis
예제 #12
0
        offset = -stack_size + var.get_stkoff()
        hexrays_types[idc.get_func_name(ea)][offset] = var.width, ownertype
        # print(dir(var))

# get global variables
get_data_symbols()

for ea in idautils.Functions():
    if not str(idc.get_func_name(ea)) in functions:
        continue
        # print(dir(va))
    # print(ida_hexrays.decompile(ea).arguments)
    # check if library function
    if not idc.get_segm_name(ea) == ".text":
        continue
    if idc.get_func_flags(ea) & FUNC_LIB:
        continue
    if decompiler:
        get_hexrays_vars(ea, idc.get_func_attr(ea, idc.FUNCATTR_FRSIZE))
    # function name
    fun_name = idc.get_func_name(ea)
    # print(dir(idc))
    # function stack size and boundaries
    stack_size = idc.get_func_attr(ea, idc.FUNCATTR_FRSIZE)
    fun_entry = format(idc.get_func_attr(ea, FUNCATTR_START), 'x')
    fun_exit = format(idc.get_func_attr(ea, FUNCATTR_END), 'x')
    # instructions
    instructions = {item:Instruction(item, ea) for item in idautils.FuncItems(ea)}

    # check if rbp or rsp relative addressing
    adjust_off = 0
예제 #13
0
def xex_load_imports(li):
    global directory_entry_headers

    li.seek(directory_entry_headers[XEX_HEADER_IMPORTS])
    import_desc = read_struct(li, XEXImportDescriptor)

    # seperate the library names in the name table
    import_libnames = []
    cur_lib = ""
    for i in range(0, import_desc.NameTableSize):
        name_char = li.read(1)

        if name_char == '\0' or name_char == '\xCD':
            if cur_lib != "":
                import_libnames.append(cur_lib)
                cur_lib = ""
        else:
            cur_lib += name_char

    # read each import library table
    for i in range(0, import_desc.ModuleCount):
        table_addr = li.tell()
        table_header = read_struct(li, XEXImportTable)
        libname = import_libnames[table_header.ModuleIndex]
        variables = {}
        for i in range(0, table_header.ImportCount):
            record_addr = read_dwordBE(li)

            record_value = ida_bytes.get_dword(record_addr)
            record_type = (record_value & 0xFF000000) >> 24
            ordinal = record_value & 0xFFFF

            import_name = x360_imports.DoNameGen(libname, 0, ordinal)
            if record_type == 0:
                # variable
                idc.create_data(record_addr, idc.FF_WORD, 2, idc.BADADDR)
                idc.create_data(record_addr + 2, idc.FF_WORD, 2, idc.BADADDR)
                idc.make_array(record_addr, 2)
                idc.set_name(record_addr, "__imp__" + import_name)
                variables[ordinal] = record_addr

            elif record_type == 1:
                # thunk
                # have to rewrite code to set r3 & r4 like xorlosers loader does
                # r3 = module index afaik
                # r4 = ordinal
                # important to note that basefiles extracted via xextool have this rewrite done already, but raw basefile from XEX doesn't!
                # todo: find out how to add to imports window like xorloser loader...

                ida_bytes.put_dword(record_addr + 0,
                                    0x38600000 | table_header.ModuleIndex)
                ida_bytes.put_dword(record_addr + 4, 0x38800000 | ordinal)
                idc.add_func(record_addr, record_addr + 0x10)
                idc.set_name(record_addr, import_name)

                # add comment to thunk like xorloser's loader
                idc.set_cmt(
                    record_addr + 4,
                    "%s :: %s" % (libname.rsplit('.', 1)[0], import_name), 1)

                # this should mark the func as a library function, but it doesn't do anything for some reason
                # tried a bunch of things like idaapi.autoWait() before running it, just crashes IDA with internal errors...
                idc.set_func_flags(
                    record_addr,
                    idc.get_func_flags(record_addr) | idc.FUNC_LIB)

                # thunk means it's not a variable, so remove from variables dict
                if ordinal in variables:
                    variables.pop(ordinal)

            else:
                print(
                    "[+] %s import %d (%s) (@ 0x%X) unknown type %d!" %
                    (libname, ordinal, import_name, record_addr, record_type))

        # remove "__imp__" part from variable import names
        for ordinal in variables:
            import_name = x360_imports.DoNameGen(libname, 0, ordinal)
            idc.set_name(variables[ordinal], import_name)

        # Seek to end of this import table
        li.seek(table_addr + table_header.TableSize)

    return
예제 #14
0
파일: findcrypt.py 프로젝트: sanchahua/ida
def main():
    print("[*] loading crypto constants")
    for const in non_sparse_consts:
        const["byte_array"] = convert_to_byte_array(const)

    for start in idautils.Segments():
        print("[*] searching for crypto constants in %s" %
              idc.get_segm_name(start))
        ea = start
        while ea < idc.get_segm_end(start):
            bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4)))
            for const in non_sparse_consts:
                if bbbb != const["byte_array"][:4]:
                    continue
                if list(
                        map(lambda x: x if type(x) == int else ord(x),
                            idc.get_bytes(ea, len(
                                const["byte_array"])))) == const["byte_array"]:
                    print(("0x%0" + str(digits) +
                           "X: found const array %s (used in %s)") %
                          (ea, const["name"], const["algorithm"]))
                    idc.set_name(ea, const["name"], ida_name.SN_FORCE)
                    if const["size"] == "B":
                        idc.create_byte(ea)
                    elif const["size"] == "L":
                        idc.create_dword(ea)
                    elif const["size"] == "Q":
                        idc.create_qword(ea)
                    idc.make_array(ea, len(const["array"]))
                    ea += len(const["byte_array"]) - 4
                    break
            ea += 4

        ea = start
        if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == idc.SEG_CODE:
            while ea < idc.get_segm_end(start):
                d = ida_bytes.get_dword(ea)
                for const in sparse_consts:
                    if d != const["array"][0]:
                        continue
                    tmp = ea + 4
                    for val in const["array"][1:]:
                        for i in range(8):
                            if ida_bytes.get_dword(tmp + i) == val:
                                tmp = tmp + i + 4
                                break
                        else:
                            break
                    else:
                        print(("0x%0" + str(digits) +
                               "X: found sparse constants for %s") %
                              (ea, const["algorithm"]))
                        cmt = idc.get_cmt(idc.prev_head(ea), 0)
                        if cmt:
                            idc.set_cmt(idc.prev_head(ea),
                                        cmt + ' ' + const["name"], 0)
                        else:
                            idc.set_cmt(idc.prev_head(ea), const["name"], 0)
                        ea = tmp
                        break
                ea += 1

    print("[*] searching for crypto constants in immediate operand")
    funcs = idautils.Functions()
    for f in funcs:
        flags = idc.get_func_flags(f)
        if (not flags & (idc.FUNC_LIB | idc.FUNC_THUNK)):
            ea = f
            f_end = idc.get_func_attr(f, idc.FUNCATTR_END)
            while (ea < f_end):
                imm_operands = []
                insn = ida_ua.insn_t()
                ida_ua.decode_insn(insn, ea)
                for i in range(len(insn.ops)):
                    if insn.ops[i].type == ida_ua.o_void:
                        break
                    if insn.ops[i].type == ida_ua.o_imm:
                        imm_operands.append(insn.ops[i].value)
                if len(imm_operands) == 0:
                    ea = idc.find_code(ea, idc.SEARCH_DOWN)
                    continue
                for const in operand_consts:
                    if const["value"] in imm_operands:
                        print(("0x%0" + str(digits) +
                               "X: found immediate operand constants for %s") %
                              (ea, const["algorithm"]))
                        cmt = idc.get_cmt(ea, 0)
                        if cmt:
                            idc.set_cmt(ea, cmt + ' ' + const["name"], 0)
                        else:
                            idc.set_cmt(ea, const["name"], 0)
                        break
                ea = idc.find_code(ea, idc.SEARCH_DOWN)
    print("[*] finished")
def isFunction(ea):
    return idc.get_func_flags(ea) != -1
    def print_deepest_path(self):
        # CS_OP_INVALID = 0,  ///< uninitialized/invalid operand.
        # CS_OP_REG,      1   ///< Register operand.
        # CS_OP_IMM,      2   ///< Immediate operand.
        # CS_OP_MEM,      3   ///< Memory operand.
        def ext_instruction(file_name, addr_start, addr_end):
            name_fun = GetFunctionName(addr_start)
            row = ''
            for addr in Heads(addr_start, addr_end):

                ins = ''
                thisOperand = idc.GetMnem(addr)
                oPtype1 = idc.GetOpType(addr, 0)
                oPtype2 = idc.GetOpType(addr, 1)
                # assemblydata = parametertype(oPtype1)+' '+parametertype(oPtype2)
                if (oPtype1 == 1 or oPtype1 == 4):
                    oPtype1 = idc.GetOpnd(addr, 0)
                if (oPtype2 == 1 or oPtype2 == 4):
                    oPtype2 = idc.GetOpnd(addr, 1)
                if thisOperand == "call":
                    call_fun_name = GetOpnd(addr, 0)
                    keyInstr = LocByName(call_fun_name)
                    fflags = idc.get_func_flags(keyInstr)
                    if (fflags & idc.FUNC_LIB) or (fflags & idc.FUNC_THUNK):
                        ins = thisOperand + '_' + idc.GetOpnd(addr, 0) + '_0'
                        row = row + ' ' + ins
                        continue
                ins = str(thisOperand)+'_'+tran(str(oPtype1)) + \
                    '_'+tran(str(oPtype2))
                row = row + ' ' + ins
            return row
            # file_name.writerow([name_fun, hex(addr_start), hex(addr_end), row])

        deepset = list()
        path = list()
        all_path = list()

        def print_path_deepest(head):
            global deepset
            global path
            global all_path
            # print(deepset)
            if head is None:
                return
            if head in all_path:
                return
            # print(path)
            all_path.append(head)
            path.append(head)
            # print("********\n",path)
            if len(deepset) < len(path):
                # print(len(deepset),len(path))
                deepset = [i for i in path]
                # print(deepset)
            for elem in head.child:
                print_path_deepest(elem)
            path.remove(head)
            # print("#######\n",path)

        def print_path_all(head):
            global path
            # print(deepset)
            if head is None:
                return
            if head in path:
                return
            path.append(head)
            for elem in head.child:
                print_path_all(elem)

        f = open(file_store_path + '\\' + 'test' + '.csv', 'wb')
        saveFile = csv.writer(f)
        saveFile.writerow(["name", "start", "end", "Op"])
        for fun_node in self.root:
            name_fun = GetFunctionName(fun_node.addr)
            fflags = idc.get_func_flags(fun_node.addr)
            if not ((fflags & idc.FUNC_LIB) or (fflags & idc.FUNC_THUNK)):
                global path
                path = list()
                global deepset
                deepset = list()
                global all_path
                all_path = list()
                # print(deepset)
                # path.clear()

                print_path_deepest(fun_node)
                row_fun = ''
                fun_addr_end = idc.FindFuncEnd(fun_node.addr)
                for bb in deepset:
                    ins_bb = ext_instruction(saveFile, bb.block.startEA,
                                             bb.block.end_ea)
                    row_fun = row_fun + ' ' + ins_bb
                saveFile.writerow(
                    [name_fun,
                     hex(fun_node.addr),
                     hex(fun_addr_end), row_fun])
예제 #17
0
def main():
    eh = flare_emu.EmuHelper()

    # dictionary that stores data used across emulation runs, function emulation specific data is set below
    userData = {
        # found stackstrings in stack memory
        "stackstrings": [],
        # found stackstrings in global memory (globalstrings)
        "globalstrings": []
    }

    cnt_functions = 0
    cnt_analyzed = 0
    cnt_found_ss = 0
    cnt_commented_ss = 0
    errors = []

    start = time.time()
    print("Started ironstrings stackstring deobfuscation")
    print_header()

    if ANALYZE_SINGLE_FUNC:
        fvas = [idc.get_func_attr(idc.here(), idc.FUNCATTR_START)]
    else:
        fvas = idautils.Functions()

    for fva in fvas:
        logging.debug("running on 0x%X", fva)
        if JUMP_TO_FUNC:
            idc.jumpto(fva)

        if fva == idaapi.BADADDR:
            logging.debug("skipping invalid function address")
            continue
        if idc.get_func_flags(fva) & (idc.FUNC_LIB | idc.FUNC_THUNK):
            logging.debug("skipping library or thunk function 0x%X", fva)
            continue

        # function start address
        userData["funcStart"] = fva

        # list of addresses of last instruction for all basic blocks in function
        userData["bb_ends"] = get_bb_ends(fva)

        # memory writes in current function
        userData["mem_writes"] = {}

        # start and end addresses of all memory writes in function
        userData["writelog"] = set()

        # memory write count in current basic block
        userData["mem_write_count"] = 0

        # cache previous address to count instructions that are executed multiple times, e.g. rep prefixed
        userData["prevAddress"] = 0

        # number same instruction has been executed in a row
        userData["repCount"] = 0

        cnt_functions += 1
        try:
            # emulate various paths through function via flare-emu, use hooks to reconstruct strings
            eh.iterateAllPaths(fva, noop, hookData=userData, callHook=call_hook, instructionHook=instr_hook,
                               memAccessHook=hook_mem_write, hookApis=False, maxPaths=MAX_CODE_PATHS)
        except unicorn.UcError as e:
            errors.append("Error analyzing function 0x{:X}: {}".format(fva, str(e)))
        else:
            cnt_analyzed += 1

            # print stackstrings found in this function
            f_ss = filter(lambda s: s.fva == fva, userData["stackstrings"])
            cnt_found_ss += len(f_ss)
            for ss in sorted(f_ss, key=lambda s: s.written_at):
                print_string(ss.fva, ss.written_at, ss.offset, ss.s)
                # IMPROVEMENT adjust stack frame member size in IDA view

            # print globalstrings found in this function
            f_gs = filter(lambda g: g.fva == fva, userData["globalstrings"])
            cnt_found_ss += len(f_gs)
            for gs in sorted(f_gs, key=lambda g: g.written_at):
                print_string(gs.fva, gs.written_at, gs.offset, gs.s)

            if COMMENT_STACKSTRINGS:
                for ss in f_ss:
                    if not ss.written_at:
                        errors.append("Can't get location where '{}' was written in 0x{:X}.".format(ss.s, ss.fva))
                        continue
                    ss_cmt = format_comment(ss.s)
                    if append_comment(ss.written_at, ss_cmt):
                        cnt_commented_ss += 1
                    else:
                        errors.append("Failed to set comment at 0x{:X}: {}".format(ss.written_at, ss_cmt))

                for gs in f_gs:
                    if COMMENT_STACKSTRING_GLOBAL_REPEATABLE:
                        repeatable = True
                        cmt_va = gs.offset
                    else:
                        repeatable = False
                        cmt_va = gs.written_at

                    if not cmt_va:
                        errors.append("Can't get location where '{}' was written in 0x{:X}.".format(gs.s, gs.fva))
                        continue
                    gs_cmt = format_comment(gs.s)
                    if append_comment(cmt_va, gs_cmt, repeatable):
                        cnt_commented_ss += 1
                    else:
                        errors.append("Failed to set comment at 0x{:X}: {}".format(cmt_va, gs_cmt))

        # update IDA view
        idc.refresh_idaview_anyway()

        # clean up memory after each function
        eh.resetEmulatorHeapAndStack()

    print_summary(cnt_functions, cnt_analyzed, cnt_found_ss, cnt_commented_ss, errors)

    if PRINT_PLAIN_SUMMARY:
        print_plain_summary(userData["stackstrings"] + userData["globalstrings"])

    print("\nFinished ironstrings stackstring deobfuscation after {:.2f} seconds".format(time.time() - start))
예제 #18
0
def main():
    eh = flare_emu.EmuHelper()

    # dictionary that stores data used across emulation runs, function emulation specific data is set below
    userData = {
        # found stackstrings in stack memory
        "stackstrings": [],
        # found stackstrings in global memory (globalstrings)
        "globalstrings": []
    }

    cnt_functions = 0
    cnt_analyzed = 0
    cnt_found_ss = 0
    cnt_commented_ss = 0
    errors = []

    start = time.time()
    print("Started ironstrings stackstring deobfuscation")
    print_header()

    if ANALYZE_SINGLE_FUNC:
        fvas = [idc.get_func_attr(idc.here(), idc.FUNCATTR_START)]
    else:
        fvas = idautils.Functions()

    for fva in fvas:
        logging.debug("running on 0x%X", fva)
        if JUMP_TO_FUNC:
            idc.jumpto(fva)

        if fva == idaapi.BADADDR:
            logging.debug("skipping invalid function address")
            continue
        if idc.get_func_flags(fva) & (idc.FUNC_LIB | idc.FUNC_THUNK):
            logging.debug("skipping library or thunk function 0x%X", fva)
            continue

        # function start address
        userData["funcStart"] = fva

        # list of addresses of last instruction for all basic blocks in function
        userData["bb_ends"] = get_bb_ends(fva)

        # memory writes in current function
        userData["mem_writes"] = {}

        # start and end addresses of all memory writes in function
        userData["writelog"] = set()

        # memory write count in current basic block
        userData["mem_write_count"] = 0

        # cache previous address to count instructions that are executed multiple times, e.g. rep prefixed
        userData["prevAddress"] = 0

        # number same instruction has been executed in a row
        userData["repCount"] = 0

        cnt_functions += 1
        try:
            # emulate various paths through function via flare-emu, use hooks to reconstruct strings
            eh.iterateAllPaths(fva,
                               noop,
                               hookData=userData,
                               callHook=call_hook,
                               instructionHook=instr_hook,
                               memAccessHook=hook_mem_write,
                               hookApis=False,
                               maxPaths=MAX_CODE_PATHS)
        except unicorn.UcError as e:
            errors.append("Error analyzing function 0x{:X}: {}".format(
                fva, str(e)))
        else:
            cnt_analyzed += 1

            # print stackstrings found in this function
            f_ss = filter(lambda s: s.fva == fva, userData["stackstrings"])
            cnt_found_ss += len(f_ss)
            for ss in sorted(f_ss, key=lambda s: s.written_at):
                print_string(ss.fva, ss.written_at, ss.offset, ss.s)
                # IMPROVEMENT adjust stack frame member size in IDA view

            # print globalstrings found in this function
            f_gs = filter(lambda g: g.fva == fva, userData["globalstrings"])
            cnt_found_ss += len(f_gs)
            for gs in sorted(f_gs, key=lambda g: g.written_at):
                print_string(gs.fva, gs.written_at, gs.offset, gs.s)

            if COMMENT_STACKSTRINGS:
                for ss in f_ss:
                    if not ss.written_at:
                        errors.append(
                            "Can't get location where '{}' was written in 0x{:X}."
                            .format(ss.s, ss.fva))
                        continue
                    ss_cmt = format_comment(ss.s)
                    if append_comment(ss.written_at, ss_cmt):
                        cnt_commented_ss += 1
                    else:
                        errors.append(
                            "Failed to set comment at 0x{:X}: {}".format(
                                ss.written_at, ss_cmt))

                for gs in f_gs:
                    if COMMENT_STACKSTRING_GLOBAL_REPEATABLE:
                        repeatable = True
                        cmt_va = gs.offset
                    else:
                        repeatable = False
                        cmt_va = gs.written_at

                    if not cmt_va:
                        errors.append(
                            "Can't get location where '{}' was written in 0x{:X}."
                            .format(gs.s, gs.fva))
                        continue
                    gs_cmt = format_comment(gs.s)
                    if append_comment(cmt_va, gs_cmt, repeatable):
                        cnt_commented_ss += 1
                    else:
                        errors.append(
                            "Failed to set comment at 0x{:X}: {}".format(
                                cmt_va, gs_cmt))

        # update IDA view
        idc.refresh_idaview_anyway()

        # clean up memory after each function
        eh.resetEmulatorHeapAndStack()

    print_summary(cnt_functions, cnt_analyzed, cnt_found_ss, cnt_commented_ss,
                  errors)

    if PRINT_PLAIN_SUMMARY:
        print_plain_summary(userData["stackstrings"] +
                            userData["globalstrings"])

    print(
        "\nFinished ironstrings stackstring deobfuscation after {:.2f} seconds"
        .format(time.time() - start))
예제 #19
0
 def withinFunction(self):
     return idc.get_func_flags(self.ea) != -1
예제 #20
0
#
# invoke with:
#   idat64 -c -A -S"ida-analysis.py $HOME/analysis.txt" <file.bin>
#

import sys
import idc
import idautils

f = open(idc.ARGV[1], 'a') if len(idc.ARGV) > 1 else sys.stdout
log = f.write

# log current file path
log(idc.get_input_file_path() + '\n')

# wait for auto-analysis to complete
idc.auto_wait()

# count functions
log( 'count %d\n' % len(list(idautils.Functions())) )

# print function name and addresses
for ea in idautils.Functions():
    if idc.get_func_flags(ea) & (idc.FUNC_LIB | idc.FUNC_THUNK): continue
    log( hex(ea) + ' ' + idc.get_func_name(ea)  + '\n' )

# if logging to a file, close it and exit IDA Pro
if f != sys.stdout:
    f.close()
    idc.qexit(0)