コード例 #1
0
    def analysePrototype(self, ea, force=False):

        try:
            if not isLoaded(ea):
                self.log(2, "Error! Bad address: 0x%x" % ea)
                raise

            try:
                fname = GetFunctionName(ea)
            except:
                fname = "0x%x" % ea

            xrefs = self.getXrefs(ea)
            if len(xrefs) == 0:
                self.log(3,
                         "Discarding function: %s as there is no xref" % fname)
                return None

            tmpSorterDict = {}
            mr = self.MAX_REFS_TO_CHECK
            if (len(xrefs) < self.MAX_REFS_TO_CHECK):
                mr = len(xrefs)

            xrefs = xrefs[0:mr]
            self.log(
                3,
                "\n%s\nAnalysing prototype for function 0x%x" % ('-' * 50, ea))

            if (not force) and (GetFunctionFlags(ea) &
                                (FUNC_HIDDEN | FUNC_LIB)):
                self.log(
                    3,
                    "Discarding function: %s as it is a LIB/HIDDEN function" %
                    fname)
                return None

            idbProto = print_type(ea, False)
            gt = GuessType(ea)
            if (((idbProto != None) and (idbProto.find("__usercall") != -1))
                    or ((gt != None) and (gt.find("__usercall") != -1))):
                self.argPassMech = "mov"
                self.argPassType = "__usercall"
            else:
                self.argPassType = "__cdecl"
                self.argPassMech = "push"

            for ref in xrefs:
                argvArray = []
                i = self.TRACK_BACK_LIMIT
                ref_p = ref

                proto = "int %s %s(" % (self.argPassType, fname)

                while (i):
                    g = 0
                    ref_p = idc.PrevHead(ref_p, 0)
                    if ((ref_p == BADADDR)
                            or idc.GetDisasm(ref_p).startswith("call")):
                        g = 2
                        break
                    disstr = idc.GetDisasm(ref_p)
                    if disstr.startswith(self.argPassMech):
                        itmSize = idc.ItemSize(ref_p)
                        if (itmSize == 5):
                            dataVal = self.getDataValue(
                                ref_p + self.argPassMechInsSize,
                                itmSize - self.argPassMechInsSize)
                            if isLoaded(dataVal) and (not isCode(
                                    GetFlags(dataVal))):
                                proto += "void*,"
                            else:
                                proto += "int,"
                        elif (itmSize == 2):
                            proto += "int,"
                        else:
                            proto += "int*,"
                            g = 1

                        if g == 0:
                            argvArray.append((
                                itmSize,
                                (itmSize - self.argPassMechInsSize),
                            ))
                        else:  # push reg
                            argvArray.append((
                                "BUFFER",
                                0x400,
                            ))  # flag to use buffer

                    if len(self.getXrefs(ref_p)) == 1:
                        nref = self.getXrefs(ref_p)[0]
                        refins = idc.GetDisasm(nref)
                        if refins.startswith(self.interConnectInstr):
                            ref_p = nref
                    i -= 1

                if (len(argvArray) == 0):
                    proto += "void,"

                if ((i == 0) or (g == 2)):
                    proto = proto[:-1] + ");"

                self.protoArray[proto] = argvArray
                self.log(
                    4, "Proto, args pattern found at 0x%x is: %s->%s" %
                    (ref, proto, repr(argvArray)))

                try:
                    tmpSorterDict[proto] = tmpSorterDict[proto] + 1
                except:
                    tmpSorterDict[proto] = 1

            itms = sorted(tmpSorterDict.iteritems(),
                          key=lambda (k, v): (v, k),
                          reverse=True)
            (
                prt,
                n,
            ) = itms[0]

            if (len(prt.split(",")) > self.MAX_ARGS):
                self.log(
                    2,
                    "too many arguments in proto from protoanalyser, ignoring function"
                )
                return None

            if (idbProto != None):
                self.log(3, "proto from IDB: %s" % idbProto)
                nIdbPrtArgs = len(idbProto.split(","))
                if (nIdbPrtArgs > self.MAX_ARGS):
                    self.log(
                        3,
                        "too many arguments in proto from IDB, ignoring it and using parser found proto"
                    )
                    idbProto = prt
                self.log(2,
                         "proto found by parser: %s, occurance: %d" % (prt, n))
                if (len(argvArray) > nIdbPrtArgs):
                    argvArray = argvArray[:nIdbPrtArgs]
                    self.protoArray[prt] = argvArray
                fn = Function(ea, idbProto, self.protoArray[prt],
                              self.argPassMech)
            else:
                fn = Function(ea, prt, self.protoArray[prt], self.argPassMech)

            self.log(2, repr(fn))
            n = (n * 100) / mr

            if (not force) and (self.argPassType !=
                                "__usercall") and (n < self.GCD_THRESOLD):
                self.log(
                    3,
                    "[GCD of protos from refs is %d%%, discarding above function]"
                    % n)
                return None
            self.log(
                3,
                "[GCD of protos from refs is %d%%, considering above function as a candidate, ArgPassMech:%s]"
                % (n, self.argPassMech))
            return fn

        except Exception, e:
            kprint("Exception!! @analysePrototype, ", e)
コード例 #2
0
def CALL(cpu_context, ip, mnem, opvalues):
    """
    CALL function

    Attempt to determine the number of arguments passed to the function which are purged on return
    """
    func_ea = opvalues[0].value

    if not isinstance(func_ea, (int, long)):
        cpu_logger.debug("CALL 0x{:X} :: call {!r}".format(ip, func_ea))
        cpu_logger.debug("Invalid function: {!r}".format(func_ea))
        return

    # For the called function, attempt to locate the function end and examine the "retn" instruction which
    # will contain the number of bytes to add back to SP.
    # opvalue1 = idc.GetOperandValue(ip, 0)
    cpu_logger.debug("CALL 0x{:X} :: call 0x{:X}".format(ip, func_ea))

    try:
        is_loaded = idc.isLoaded(func_ea)
    except TypeError:
        is_loaded = False

    # TODO: Disabled until we can keep track of pointer history.
    # # Emulate the effects of any known builtin functions.
    # func_name = idaapi.get_func_name(func_ea)
    # builtin_func = BUILTINS.get(func_name)
    # if builtin_func:
    #     try:
    #         args = cpu_context.get_function_args(func_ea)
    #         builtin_func(cpu_context, ip, func_name, args)
    #     except Exception as e:
    #         cpu_logger.warn(
    #             'Failed to emulate builtin function: {}() at {:#08x} with error: {}'.format(
    #                 func_name, ip, e))

    # For non-loaded files, reset esp based on number of stack arguments.
    # (We are assuming the callee is responsible for resetting the stack)
    if not is_loaded:
        try:
            func_data = utils.get_function_data(func_ea)
            for arg in func_data:
                loc_type = arg.argloc.atype()
                # Where was this parameter passed?
                if loc_type == 1:  # ALOC_STACK
                    # reset esp for each stack argument.
                    cpu_context.reg_write("RSP", cpu_context.reg_read("RSP") + cpu_context._byteness)
        except:
            # If we can't get function data for non-loaded functions, then we have no way of knowing how to handle
            # the stack...
            cpu_logger.debug(
                "{:#08x} :: Cannot identify function information for value {:#08x}. "
                "Stack pointer will not be adjusted.".format(ip, func_ea))
            return
    else:
        # Get address of retn instruction
        func_end = idc.GetFunctionAttr(func_ea, idc.FUNCATTR_END)
        if func_end == idc.BADADDR:
            cpu_logger.debug(
                "{:#08x} :: Could not retrieve retn instruction for called function: {:#08x}. "
                "Stack pointer will not be adjusted.".format(ip, func_ea))
            return

        # Find a "retn" and see if we need to adjust rsp.
        # (All retn's should have the same operand so finding any of them will work).
        # look for retn address
        ea = func_end
        while ea > func_ea:
            if idc.GetMnem(ea) == "retn":
                sp_adjust = idc.GetOperandValue(ea, 0)
                # if retn doesn't adjust the stack, -1 is returned
                if sp_adjust != -1:
                    cpu_context.reg_write("RSP", cpu_context.reg_read("RSP") + sp_adjust)
                return
            ea = idc.PrevHead(ea)
コード例 #3
0
def prev_head(curAddr):
    if idaapi.IDA_SDK_VERSION <= 699:
        prev_eip = idc.PrevHead(curAddr)
    else:
        prev_eip = idc.prev_head(curAddr)
    return prev_eip
コード例 #4
0
ファイル: database.py プロジェクト: wzr/toolbag
def prev(ea):
    '''return the previous address (instruction or data)'''
    return idc.PrevHead(ea, idc.MinEA())
コード例 #5
0
 def find_nth_arg(self, arg_idx):
     return idafind.find(idc.PrevHead(self.f.startEA),
                         self.make_arg_opnd(arg_idx))
コード例 #6
0
ファイル: coll_node.py プロジェクト: yanxxd/PathAFL
def GetFunEdgesAndBbls(function_ea):
    """
    Get bbls of function.
    @function_ea - function address
    @return - bbls of function
    """
    bbl = []  # bbl info [head, tail, call_num, mem_num]
    SingleBBS = {}  # head -> pred_bbl
    MultiBBS = {}  # head -> [pred_bbls]
    bbls = {}  # head -> bbl
    bbls2 = {}  # tail -> bbl
    edges_s = set()  # set of (tail, head)
    edges_d = {}  # dict struct.  head -> of (head, ..., head)
    edges_count = 0
    edges_s_t = set()  # tmp edges set
    edges_d_t = {}  # tmp edges dict.

    if not IsInstrumentIns(function_ea):
        return bbls, edges_d, edges_count, SingleBBS, MultiBBS

    f_start = function_ea
    f_end = idc.FindFuncEnd(function_ea)

    boundaries = set((f_start, ))  # head of bbl

    for head in idautils.Heads(f_start, f_end):
        # If the element is an instruction
        if head == idaapi.BADADDR:
            raise Exception("Invalid head for parsing")
        if not idc.isCode(idc.GetFlags(head)):
            continue

        # Get the references made from the current instruction
        # and keep only the ones local to the function.
        refs = idautils.CodeRefsFrom(head, 0)
        refs_filtered = set()
        for ref in refs:
            if ref > f_start and ref < f_end:  # can't use ref>=f_start, avoid recusion
                refs_filtered.add(ref)
        refs = refs_filtered

        if refs:
            # If the flow continues also to the next (address-wise)
            # instruction, we add a reference to it.
            # For instance, a conditional jump will not branch
            # if the condition is not met, so we save that
            # reference as well.
            next_head = idc.NextHead(head, f_end)
            if next_head != idaapi.BADADDR and idc.isFlow(
                    idc.GetFlags(next_head)):
                refs.add(next_head)

            # Update the boundaries found so far.
            boundaries.update(refs)
            for r in refs:  # enum all of next ins
                # If the flow could also come from the address
                # previous to the destination of the branching
                # an edge is created.
                if isFlow(idc.GetFlags(r)):
                    prev_head = idc.PrevHead(r, f_start)
                    if prev_head == 0xffffffffL:
                        #edges_s_t.add((head, r))
                        #raise Exception("invalid reference to previous instruction for", hex(r))
                        pass
                    else:
                        edges_s_t.add((prev_head, r))
                edges_s_t.add((head, r))

    #end of for head in idautils.Heads(chunk[0], chunk[1]):

    last_head = 0
    # NOTE: We can handle if jump xrefs to chunk address space.

    # get bbls. head of bbl is first ins addr, tail of bbl is last ins addr.
    for head in idautils.Heads(f_start, f_end):
        mnem = idc.GetMnem(head)
        if head in boundaries:
            if len(bbl) > 0:
                if bbl[0] == head:
                    continue
                if True:  # IsInstrumentIns(bbl[0]):
                    bbl[1] = last_head
                    bbls[bbl[0]] = bbl
                    bbls2[bbl[1]] = bbl
            bbl = [head, 0, 0, 0]
        #elif self.GetInstructionType(head) == self.BRANCH_INSTRUCTION:
        elif mnem.startswith('j'):
            if len(bbl) > 0 and bbl[0] == head + idc.ItemSize(head):
                continue
            if True:  # IsInstrumentIns(bbl[0]):
                bbl[1] = head  # head + idc.ItemSize(head))
                bbls[bbl[0]] = bbl
                bbls2[bbl[1]] = bbl
            bbl = [head + idc.ItemSize(head), 0, 0, 0]
        else:
            last_head = head
        if mnem.startswith('call'):
            bbl[2] += 1

        #if 2 == idc.GetOpType(head, 0):      # 2  Memory Reference
        #    bbl[3] += 1
        #if 2 == idc.GetOpType(head, 1):      # 2  Memory Reference
        #    bbl[3] += 1

    # add last basic block
    if len(bbl) and bbl[0] != f_end:  # and IsInstrumentIns(bbl[0]):
        bbl[1] = f_end
        bbls[bbl[0]] = bbl
        bbls2[bbl[1]] = bbl

    # edges set -> dict
    for e in edges_s_t:
        if e[0] in bbls2:
            bbl_head = bbls2[e[0]][0]
            if bbl_head in edges_d_t:
                edges_d_t[bbl_head].append(e[1])
            else:
                edges_d_t[bbl_head] = [e[1]]
        else:
            print('edge (%x, %x) can not find head bbl.' %
                  (e[0], e[1]))  # a small case. e1 flow e0.

    # revise edges. head bbl and tail bbl of edges must be instrumented.
    for e0 in edges_d_t:
        if not IsInstrumentIns(e0):  # e0 don't instrumented, skip.
            continue

        for e1 in edges_d_t[e0]:
            if IsInstrumentIns(e1):  # e0 e1 both instrumented, add edge.
                if e0 in edges_d:
                    edges_d[e0].append(e1)
                else:
                    edges_d[e0] = [e1]
                edges_count += 1
            else:
                # e1 don't instrumented, recursively looks for instrumented child bbls
                bbls_t = LookForInsChildBbls(e1, edges_d_t, [])
                for b in bbls_t:  # add edge
                    if e0 in edges_d:
                        edges_d[e0].append(b)
                    else:
                        edges_d[e0] = [b]
                    edges_count += 1

    # revise bbls. bbl must be instrumented.
    for b in bbls.keys():
        if not IsInstrumentIns(b):
            # if bbls[b][1] in bbls2:     # avoid multi del
            # bbls2.pop(bbls[b][1])
            bbls.pop(b)

    #print('bbls:')
    #i = 0
    #for b in bbls:
    #    i += 1
    #    print('%04d %x, %x' % (i, b, bbls[b][1]))

    #print('edges_d:')
    #i = 0
    #for e0 in edges_d:
    #    for e1 in edges_d[e0]:
    #        i += 1
    #        print('%04d %x, %x' % (i, e0, e1))

    for e0 in edges_d:
        if e0 not in bbls:
            print('error:%x have no head' % (e0))  # error
            continue
        for e1 in edges_d[e0]:
            if e1 in MultiBBS:
                MultiBBS[e1].append(bbls[e0])  # add Pred
            elif e1 in SingleBBS:
                MultiBBS[e1] = [SingleBBS[e1], bbls[e0]]  # add Pred
                SingleBBS.pop(e1)  # remove from SingleBBS
            else:
                SingleBBS[e1] = bbls[e0]  # add Pred

    # del bbls which don't instrumented

    return bbls, edges_d, edges_count, SingleBBS, MultiBBS
コード例 #7
0
 def goto_func_end(self):
     e = idc.get_func_attr(idc.here(), idc.FUNCATTR_END)
     idc.jumpto(idc.PrevHead(e))
コード例 #8
0
 def prevItem(self, ea, bounds):
     return idc.PrevHead(ea, bounds)
コード例 #9
0
def trace_param(ea, min_ea, op_type, op_val):
    '''
    trace_param: ea, min_ea, op_type, op_val

    Taking ea as start, this function does basic backtrace of
    an operand (defined by op_type and op_val) until it finds
    a data reference which we consider the "source". It stops
    when ea < min_ea (usually the function start).

    It does not support arithmetic or complex modifications of
    the source. This will be improved on future versions.
    '''
    global displ_re, msgsend, var_re

    ea_call = ea
    while ea != idc.BADADDR and ea != min_ea:
        ea = idc.PrevHead(ea, min_ea)

        if op_type == idaapi.o_reg and op_val == 0 and idaapi.is_call_insn(ea):
            # We have a BL/BLX that will modify the R0
            # we're tracking
            #TODO: resolve more situation
            return None

        if idc.GetMnem(ea) in ['LDR', 'MOV']:
            src_op = 1
            dest_op = 0
        elif idc.GetMnem(ea) == 'STR':
            src_op = 0
            dest_op = 1
        else:
            continue

        if idc.GetOpType(ea, dest_op) == op_type and idc.GetOperandValue(ea, dest_op) == op_val:
            # Found, see where it comes from
            if idc.GetOpType(ea, src_op) == idc.o_mem or idc.GetOpType(ea, src_op) == idc.o_imm: #add o_imm support
                # Got the final reference
                refs = list(idautils.DataRefsFrom(ea))
                if not refs:
                    local_ref = idc.GetOperandValue(ea, src_op)
                    far_ref = idc.Dword(local_ref)
                else:
                    while len(refs) > 0:
                        far_ref = refs[0]
                        refs = list(idautils.DataRefsFrom(refs[0]))
                #patch by lc
                if far_ref:

                return far_ref
            elif idc.GetOpType(ea, src_op) == idc.o_displ:
                if ', [SP' in idc.GetDisasm(ea):
                    if 'arg_' in idc.GetDisasm(ea):
                        # We don't track function arguments
                        return None

                    # We're tracking an stack variable
                    try:
                        var_name = var_re.search(idc.GetDisasm(ea)).group('varname')
                    except:
                        print '%08x: Unable to recognize variable' % ea
                        return None

                    while ea != idc.BADADDR and ea > min_ea:
                        if idc.GetMnem(ea) == 'STR' and var_name in idc.GetDisasm(ea):
                            # New reg to track
                            op_val = idc.GetOperandValue(ea, dest_op)
                            break
                        ea = idc.PrevHead(ea, min_ea)
                else:
                    # New reg to track
                    if '[LR]' in idc.GetDisasm(ea):
                        # Optimizations use LR as general reg
                        op_val = 14
                    else:
                        try:
                            op_val = int(displ_re.search(idc.GetDisasm(ea)).group('regnum'))
                        except:
                            print '%08x: Unable to recognize register' % ea
                            return None
            elif idc.GetOpType(ea, src_op) == idc.o_reg:
                # Direct reg-reg assignment
                op_val = idc.GetOperandValue(ea, src_op)
            else:
                # We don't track o_phrase or other complex source operands :(
                return None
    #register R0-R3 assigned by function parameter
    if ea <= min_ea and op_type == idc.o_reg and op_val in range(4):
        f_info = get_func_info(ea)
        return ['pself', 'selector', f_info['fparam_type'], f_info['sparam_name']][op_val]#fix: error
    return None



def fix_callgraph(msgsend, segname, class_param, sel_param): #class_param == 0, sel_param == 1
    '''
    fix_callgraph: msgsend, segname, class_param, sel_param

    Given the msgsend flavour address as a parameter, looks
    for the parameters (class and selector, identified by
    class_param and sel_param) and creates a new segment where
    it places a set of dummy calls named as classname_methodname
    (we use method instead of selector most of the time).
    '''

    t1 = time.time()
    if not msgsend:
        print 'ERROR: msgSend not found'
        return

    total = 0
    resolved = 0
    call_table = dict()

    for xref in idautils.XrefsTo(msgsend, idaapi.XREF_ALL):
        total += 1
        ea_call = xref.frm
        func_start = idc.GetFunctionAttr(ea_call, idc.FUNCATTR_START)
        if not func_start or func_start == idc.BADADDR:
            continue
        ea = ea_call
        method_name_ea = trace_param(ea, func_start, idc.o_reg, sel_param)#sel_param == 1
        if method_name_ea and idc.isASCII(idc.GetFlags(method_name_ea)):
            method_name = idc.GetString(method_name_ea, -1, idc.ASCSTR_C)
            if not method_name:
                method_name = '_unk_method'
        else:
            method_name = '_unk_method'

        class_name_ea = trace_param(ea, func_start, idc.o_reg, class_param)#class_param == 0
        if class_name_ea:
            class_name = idc.Name(class_name_ea)
            if not class_name:
                class_name = '_unk_class'
        else:
            class_name = '_unk_class'

        if method_name == '_unk_method' and class_name == '_unk_class':
            continue

        # Using this name convention, if the class and method
        # are identified by IDA, the patched call will point to
        # the REAL call and not one of our dummy functions
        #
        class_name = class_name.replace('_OBJC_CLASS_$_', '')
        class_name = class_name.replace('_OBJC_METACLASS_$_', '')
        new_name = '_[' + class_name + '_' + method_name + ']'
        print '%08x: %s' % (ea_call, new_name)
        call_table[ea_call] = new_name
        resolved += 1

    print '\nFinal stats:\n\t%d total calls, %d resolved' % (total, resolved)
    print '\tAnalysis took %.2f seconds' % (time.time() - t1)

    if resolved == 0:
        print 'Nothing to patch.'
        return

    print 'Adding new segment to store new nullsubs'

    # segment size = opcode ret (4 bytes) * num_calls
    seg_size = resolved * 4
    seg_start = idc.MaxEA() + 4
    idaapi.add_segm(0, seg_start, seg_start + seg_size, segname, 'CODE')

    print 'Patching database...'
    seg_ptr = seg_start
    for ea, new_name in call_table.items():
        if idc.LocByName(new_name) != idc.BADADDR:
            offset = idc.LocByName(new_name) - ea
        else:
            # create code and name it
            idc.PatchDword(seg_ptr, 0xE12FFF1E) # BX LR
            idc.MakeName(seg_ptr, new_name)
            idc.MakeCode(seg_ptr)
            idc.MakeFunction(seg_ptr, seg_ptr + 4)
            idc.MakeRptCmt(seg_ptr, new_name)
            offset = seg_ptr - ea
            seg_ptr += 4

        # patch the msgsend call
        if idc.GetReg(ea, "T") == 1:
            if offset > 0 and offset & 0xFF800000:
                print 'Offset too far for Thumb (%08x) Stopping [%08x]' % (offset, ea)
                return

            off1 = (offset & 0x7FF000) >> 12
            off2 = (offset & 0xFFF) / 2
            w1 = (0xF000 | off1)
            w2 = (0xE800 | off2) - 1
            idc.PatchWord(ea, w1)
            idc.PatchWord(ea + 2, w2)
        else:
            if offset > 0 and offset & 0xFF000000:
                print 'Offset too far (%08x) Stopping [%08x]' % (offset, ea)
            dw = (0xFA000000 | (offset - 8 >> 2))
            if dw < 0:
                dw = dw & 0xFAFFFFFF
            idc.PatchDword(ea, dw)


def make_offsets(segname):
    '''
    change the segment's data value into offset by class name
    '''
    segea = idc.SegByBase(idc.SegByName(segname))
    segend = idc.SegEnd(segea)

    while segea < segend:
        idc.OpOffset(segea, 0)
        ptr = idc.Dword(segea)
        idc.OpOffset(ptr, 0)
        segea += 4

if __name__ == '__main__':
    print 'Preparing class references segments'
    make_offsets('__objc_classrefs') #TODO: what's these two segment means?
    make_offsets('__objc_superrefs')
    idaapi.analyze_area(idc.MinEA(), idc.MaxEA())
    print 'Fixing callgraph'
    fix_callgraph(idc.LocByName('_objc_msgSend'), 'msgSend', 0, 1)
    fix_callgraph(idc.LocByName('_objc_msgSendSuper2'), 'msgSendSuper', 3, 1)
    idaapi.analyze_area(idc.MinEA(), idc.MaxEA())
    print 'Done.'
コード例 #10
0
ファイル: common.py プロジェクト: sourav-txt/decv
def prev_head(head):

    prv = idc.PrevHead(head, 0)
    assert (prv != idc.BADADDR)

    return prv
コード例 #11
0
#Entry point, look for specific function call
for seg_ea in Segments():
    for function_ea in Functions(SegStart(seg_ea), SegEnd(seg_ea)):

        f_start = function_ea
        f_end = FindFuncEnd(function_ea)

        for head in Heads(f_start, f_end):

            if isCode(GetFlags(head)):
                if GetMnem(head) == 'call':

                    call_addr = GetOperandValue(head, 0)

                    if call_addr == addr_resolve_module:

                        module_name = resolve_module_by_hash(
                            GetOperandValue(idc.PrevHead(head), 1))

                        if not module_name is None:
                            print "[*] Resolving calls for ", module_name

                            api_hashes = idc.NextHead(head)

                            api_hash_src = GetOperandValue(api_hashes, 1)
                            api_hash_dst = GetOperandValue(
                                idc.NextHead(api_hashes), 1)

                            resolve_module_apis(module_name, api_hash_src,
                                                api_hash_dst)
コード例 #12
0
def format_bb(bb):
    bbtype = {0: "fcb_normal", 1: "fcb_indjump", 2: "fcb_ret", 3: "fcb_cndret",
              4: "fcb_noret", 5: "fcb_enoret", 6: "fcb_extern", 7: "fcb_error"}
    return ("ID: %d, Start: 0x%x, End: 0x%x, Last instruction: 0x%x, Size: %d, "
            "Type: %s" % (bb.id, bb.startEA, bb.endEA, idc.PrevHead(bb.endEA),
                          (bb.endEA - bb.startEA), bbtype[bb.type]))
コード例 #13
0
def track_param(ea, min_ea, op_type, op_val):
  '''
  trace_param: ea, min_ea, op_type, op_val

  Taking ea as start, this function does basic backtrace of
  an operand (defined by op_type and op_val) until it finds
  a data reference which we consider the "source". It stops
  when ea < min_ea (usually the function start).

  It does not support arithmetic or complex modifications of
  the source. This will be improved on future versions.
  '''
  global msgsend, var_re

  ea_call = ea
  while ea != idc.BADADDR and ea != min_ea:
    ea = idc.PrevHead(ea, min_ea)

    if idc.GetMnem(ea) not in ['lea', 'mov']:
      continue

    if idc.GetOpType(ea, 0) == op_type and idc.GetOperandValue(ea, 0) == op_val:
      if idc.GetOpType(ea, 1) == idc.o_displ:
        if ', [esp' in idc.GetDisasm(ea) or ', [ebp' in idc.GetDisasm(ea):
          if 'arg_' in idc.GetDisasm(ea):
          # We don't track function arguments
            return None

          # We only track stack variables
          try:
            var_name = var_re.search(idc.GetDisasm(ea)).group('varname')
            op_type = idc.GetOpType(ea, 1)
          except:
            print '%08x: Unable to recognize variable' % ea
            return None

          while ea != idc.BADADDR and ea > min_ea:
            if idc.GetMnem(ea) == 'mov' or idc.GetMnem(ea) == 'lea' and var_name in idc.GetDisasm(ea):
              # New reg to track
              op_val = idc.GetOperandValue(ea, 0)
              break
            ea = idc.PrevHead(ea, min_ea)

      elif idc.GetOpType(ea, 1) == idc.o_mem:
        # Got the final reference
        refs = list(idautils.DataRefsFrom(ea))
        if not refs:
          local_ref = idc.GetOperandValue(ea, 1)
          far_ref = idc.Dword(local_ref)
        else:
          while len(refs) > 0:
            far_ref = refs[0]
            refs = list(idautils.DataRefsFrom(refs[0]))
        return far_ref

      elif idc.GetOpType(ea, 1) == idc.o_reg:
        # Direct reg-reg assignment
        op_val = idc.GetOperandValue(ea, 1)
        op_type =  idc.GetOpType(ea, 1)
      else:
        # We don't track o_phrase or other complex source operands :(
        return None

  return None
コード例 #14
0
def prevMnemonic(ea, mnem, minaddr=0):
    res = idc.GetMnem(ea)
    #print "%x -> %s"% (ea, res)
    if res == "": return idc.BADADDR
    if res == mnem: return ea
    return prevMnemonic(idc.PrevHead(ea, minaddr), mnem, minaddr)
コード例 #15
0
def getValue(ea,minEa,targetReg):
  global errorMessage
  #f.write("%x" % ea + "\n")
  #f.write("%x" % minEa + "\n")
  #f.write(str(targetReg) + "\n")

  #give up if you hit the top of the function
  if ea <= minEa:
    errorMessage+="ERROR: Hit top of function"
    return 0

  if idc.GetMnem(ea) in ['ADR']:
    dest_op = 0
    src_op = 1
    srcOpType = idc.GetOpType(ea, src_op)
    srcOpValue = idc.GetOperandValue(ea, src_op)
    destOpType = idc.GetOpType(ea, dest_op)
    destOpValue = idc.GetOperandValue(ea, dest_op)
    #f.write(str(destOpValue)+"\n")
    if destOpType == idc.o_reg and destOpValue == targetReg and srcOpType == idc.o_imm:
      #found goal, so return it as a string
      return srcOpValue


  #TODO deal with adding PC or some other number to the address
  #should be easy with recursion. Just get return the sum of recursively tracking both addends.
  if idc.GetMnem(ea) in ['ADD']:
    dest_op = 0
    src_op = 1
    srcOpType = idc.GetOpType(ea, src_op)
    srcOpValue = idc.GetOperandValue(ea, src_op)
    destOpType = idc.GetOpType(ea, dest_op)
    destOpValue = idc.GetOperandValue(ea, dest_op)
    #I'm assuming the source is the PC register with a 32 bit executable
    if destOpType == idc.o_reg and destOpValue == targetReg and srcOpType == idc.o_reg and srcOpValue == 15:
      pcValue = ea + 4
      #f.write("%x" % pcValue + "\n")
      ea = idc.PrevHead(ea)
      return pcValue + getValue(ea,minEa,targetReg)

  #TODO include how to handle this if the src is an address that probably points to a string
  if idc.GetMnem(ea) in ['MOV']:
    dest_op = 0
    src_op = 1
    srcOpType = idc.GetOpType(ea, src_op)
    srcOpValue = idc.GetOperandValue(ea, src_op)
    destOpType = idc.GetOpType(ea, dest_op)
    destOpValue = idc.GetOperandValue(ea, dest_op)
    if destOpType == idc.o_reg and destOpValue == targetReg: 
      if srcOpType == idc.o_reg:
	#start tracking a new register.
	targetReg = srcOpValue
	ea = idc.PrevHead(ea)
	return getValue(ea,minEa, targetReg)    
      if srcOpType == idc.o_imm:
	#this should be the address we are looking for, so return it
	return srcOpValue

  if idc.GetMnem(ea) in ['MOVT']:
    src_op = 1
    dest_op = 0
    srcOpType = idc.GetOpType(ea, src_op)
    srcOpValue = idc.GetOperandValue(ea, src_op)
    destOpType = idc.GetOpType(ea, dest_op)
    destOpValue = idc.GetOperandValue(ea, dest_op)
    #Are we writing to a register and is that register the one we are tracking?
    if destOpType == idc.o_reg and destOpValue == targetReg:
      if srcOpType == idc.o_imm:
	#this represents the top half of the value we want
	#but we need to track the register farther to know what the bottom half is
	ea = idc.PrevHead(ea)
	bottomHalf = getValue(ea,minEa,targetReg)
	#I should have a sanity check here to know when something has gone wrong.
	#I should refine my error messages to also include addresses, see dispatchExtractor for examples
	if errorMessage != "":
	  errorMessage += "ERROR: Failed to get value in MOVT."
	  return 0
	else:
	  #I hope that I'm correctly overwriting the first 16 bits with the src of MOVT
	  topHalf = srcOpValue << 16
	  botHalf = bottomHalf & 0x0000ffff
	  afterMOVT = topHalf ^ botHalf
	  return afterMOVT
      else:
	errorMessage += "ERROR: cannot handle this type of MOVT."
	return 0
    #This instruction has no impact on the register we are tracking. Skip it.
  #end of code for MOVT

  #keep backtracking and move on to previous instruction
  ea = idc.PrevHead(ea)
  return getValue(ea,minEa, targetReg)    
コード例 #16
0
ファイル: LazyIDA.py プロジェクト: sctnightcore/LazyIDA
    def check_fmt_function(name, addr):
        """
        Check if the format string argument is not valid
        """
        function_head = GetFunctionAttr(addr, idc.FUNCATTR_START)

        while True:
            addr = idc.PrevHead(addr)
            op = GetMnem(addr).lower()
            dst = GetOpnd(addr, 0)

            if op in ("ret", "retn", "jmp", "b") or addr < function_head:
                return

            c = GetCommentEx(addr, 0)
            if c and c.lower() == "format":
                break
            elif name.endswith(("snprintf_chk", )):
                if op in ("mov", "lea") and dst.endswith(
                    ("r8", "r8d", "[esp+10h]")):
                    break
            elif name.endswith(("sprintf_chk", )):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rcx", "[esp+0Ch]", "R3")) or dst.endswith("ecx")
                                             and BITS == 64):
                    break
            elif name.endswith(("snprintf", "fnprintf")):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rdx", "[esp+8]", "R2")) or dst.endswith("edx")
                                             and BITS == 64):
                    break
            elif name.endswith(
                ("sprintf", "fprintf", "dprintf", "printf_chk")):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rsi", "[esp+4]", "R1")) or dst.endswith("esi")
                                             and BITS == 64):
                    break
            elif name.endswith("printf"):
                if op in ("mov", "lea") and (dst.endswith(
                    ("rdi", "[esp]", "R0")) or dst.endswith("edi")
                                             and BITS == 64):
                    break

        # format arg found, check its type and value
        # get last oprend
        op_index = GetDisasm(addr).count(",")
        op_type = GetOpType(addr, op_index)
        opnd = GetOpnd(addr, op_index)

        if op_type == o_reg:
            # format is in register, try to track back and get the source
            _addr = addr
            while True:
                _addr = idc.PrevHead(_addr)
                _op = GetMnem(_addr).lower()
                if _op in ("ret", "retn", "jmp", "b") or _addr < function_head:
                    break
                elif _op in ("mov", "lea", "ldr") and GetOpnd(_addr,
                                                              0) == opnd:
                    op_type = GetOpType(_addr, 1)
                    opnd = GetOpnd(_addr, 1)
                    addr = _addr
                    break

        if op_type == o_imm or op_type == o_mem:
            # format is a memory address, check if it's in writable segment
            op_addr = GetOperandValue(addr, op_index)
            seg = idaapi.getseg(op_addr)
            if seg:
                if not seg.perm & idaapi.SEGPERM_WRITE:
                    # format is in read-only segment
                    return

        print "0x%X: Possible Vulnerability: %s, format = %s" % (addr, name,
                                                                 opnd)
        return ["0x%X" % addr, name, opnd]
コード例 #17
0
def GetFuncEndAddr(addr):
    return idc.PrevHead(idc.GetFunctionAttr(addr, idc.FUNCATTR_END))
コード例 #18
0
def find_mov_dword(addr):
    while True:
        addr = idc.PrevHead(addr)
        if idc.GetMnem(addr) == "mov" and "eax" in idc.GetOpnd(addr, 0):
            #print("Found mov dword at %s" % idc.GetDisasm(addr))
            return idc.GetOpnd(addr, 1)
コード例 #19
0
def trace_param(ea, min_ea, op_type, op_val):
    '''
    trace_param: ea, min_ea, op_type, op_val

    Taking ea as start, this function does basic backtrace of
    an operand (defined by op_type and op_val) until it finds
    a data reference which we consider the "source". It stops
    when ea < min_ea (usually the function start).

    It does not support arithmetic or complex modifications of
    the source. This will be improved on future versions.
    '''
    global displ_re, msgsend, var_re

    ea_call = ea
    while ea != idc.BADADDR and ea != min_ea:
        ea = idc.PrevHead(ea, min_ea)

        if op_type == idaapi.o_reg and op_val == 0 and idaapi.is_call_insn(ea):
            # We have a BL/BLX that will modify the R0
            # we're tracking
            #
            return None

        if idc.GetMnem(ea) in ['LDR', 'MOV']:
            src_op = 1
            dest_op = 0
        elif idc.GetMnem(ea) == 'STR':
            src_op = 0
            dest_op = 1
        else:
            continue


        if idc.GetOpType(ea, dest_op) == op_type and idc.GetOperandValue(ea, dest_op) == op_val:
            # Found, see where it comes from
            if idc.GetOpType(ea, src_op) == idc.o_mem:
                # Got the final reference
                refs = list(idautils.DataRefsFrom(ea))
                if not refs:
                    local_ref = idc.GetOperandValue(ea, src_op)
                    far_ref = idc.Dword(local_ref)
                else:
                    while len(refs) > 0:
                        far_ref = refs[0]
                        refs = list(idautils.DataRefsFrom(refs[0]))
                return far_ref
            elif idc.GetOpType(ea, src_op) == idc.o_displ:
                if ', [SP' in idc.GetDisasm(ea):
                    if 'arg_' in idc.GetDisasm(ea):
                        # We don't track function arguments
                        return None

                    # We're tracking an stack variable
                    try:
                        var_name = var_re.search(idc.GetDisasm(ea)).group('varname')
                    except:
                        print '%08x: Unable to recognize variable' % ea
                        return None

                    while ea != idc.BADADDR and ea > min_ea:
                        if idc.GetMnem(ea) == 'STR' and var_name in idc.GetDisasm(ea):
                            # New reg to track
                            op_val = idc.GetOperandValue(ea, dest_op)
                            break
                        ea = idc.PrevHead(ea, min_ea)
                else:
                    # New reg to track
                    if '[LR]' in idc.GetDisasm(ea):
                        # Optimizations use LR as general reg
                        op_val = 14
                    else:
                        try:
                            op_val = int(displ_re.search(idc.GetDisasm(ea)).group('regnum'))
                        except:
                            print '%08x: Unable to recognize register' % ea
                            return None
            elif idc.GetOpType(ea, src_op) == idc.o_reg:
                # Direct reg-reg assignment
                op_val = idc.GetOperandValue(ea, src_op)
            else:
                # We don't track o_phrase or other complex source operands :(
                return None
    return None
コード例 #20
0
ファイル: ida_find_ptrs.py プロジェクト: zaddach/python-vb
def get_head(va):
    if is_head(va):
        return va
    else:
        return idc.PrevHead(va)
コード例 #21
0
            out += chr(Byte(addr))
        else:
            break
        addr += 1
    return out


def string_decode(string):
    string = base64.b64decode(string)
    return string


decode_func = 0x401000
total_decode = 0
for addr in XrefsTo(decode_func, flags=0):
    next_address = addr.frm
    for i in range(0, 2):
        next_address = idc.PrevHead(next_address)
        if GetMnem(next_address) == "mov" and GetOpnd(next_address,
                                                      1).find("offset") != -1:
            String = GetOpnd(next_address, 1).split(" ")[1]
            add = get_name_ea(next_address, String)
            String = get_string(add)
            decode_str = string_decode(String)
            print_info = str(hex(next_address))[:-1] + " -> " + decode_str
            print(print_info)
            MakeComm(next_address, print_info)
            MakeComm(addr.frm, print_info)
            total_decode += 1
print "total : " + str(total_decode)
コード例 #22
0
ファイル: calls.py プロジェクト: jjo-sec/idataco
 def load(self):
     for cat in sorted(list(self.parent.call_categories)):
         self._checkbox_map[cat] = qt.qcheckbox()(cat.capitalize())
     for cat in sorted(self._checkbox_map.keys()):
         cb = self._checkbox_map[cat]
         cb.setCheckState(qt.qtcore().Qt.Checked)
         cb.clicked.connect(self.filterCallData)
         self._checkbox_layout.addWidget(cb)
     self._call_table.clear()
     self._call_table.setHorizontalHeaderLabels([
         "Category", "Caller", "Parent  Caller", "Logged API", "Called API",
         "Return", "Args"
     ])
     header = self._call_table.horizontalHeader()
     header.setStretchLastSection(True)
     if self.parent.cuckoo_version.startswith(("1.3", "2.0")):
         self._call_table.itemDoubleClicked.connect(self.clickRow)
     self._call_table.setRowCount(len(self.parent.calls))
     self._call_table.setWordWrap(True)
     row = 0
     for call in self.parent.calls:
         called_api = ""
         arg_str = "\r\n".join([
             "{}: {}".format(k,
                             unicode(v)[:80].encode("unicode-escape"))
             for k, v in call["arguments"].items()
         ])
         bg_color = self._COLOR_MAP.get(call.get("category", ""),
                                        qt.qcolor()(0xff, 0xff, 0xff))
         self._call_table.setItem(
             row, 0,
             qt.qtablewidgetitem()(call.get("category", "")))
         self._call_table.item(row, 0).setBackground(bg_color)
         call_addr = ""
         if self.parent.cuckoo_version.startswith("1.3"):
             call_addr = idc.PrevHead(int(call["caller"], 16))
             call_addr = call.get(
                 "caller", "0x00000000"
             ) if call_addr == idc.BADADDR else "0x{:08x}".format(call_addr)
         # cuckoo 2.0 stores call stack in "stack", but only enabled in DEBUG
         if self.parent.cuckoo_version.startswith(
                 "2.0") and call["stacktrace"]:
             for ret_addr in call["stacktrace"]:
                 if ret_addr.count(" ") > 2:
                     called_api = ret_addr.split("+")[0]
                 else:
                     break
             for ret_addr in call["stacktrace"]:
                 if ret_addr.count(" ") <= 2:
                     call_addr = int(ret_addr.split(" @ ")[-1], 16)
                     call_addr = idc.PrevHead(call_addr)
                     call_addr = call.get(
                         "caller", "0x00000000"
                     ) if call_addr == idc.BADADDR else "0x{:08x}".format(
                         call_addr)
                     break
         ret = call["return"] if "return" in call else str(
             call["return_value"])
         self._call_table.setItem(row, 1, qt.qtablewidgetitem()(call_addr))
         self._call_table.item(row, 1).setBackground(bg_color)
         self._call_table.setItem(
             row, 2,
             qt.qtablewidgetitem()(call.get("parentcaller", "")))
         self._call_table.item(row, 2).setBackground(bg_color)
         self._call_table.setItem(row, 3,
                                  qt.qtablewidgetitem()(call["api"]))
         self._call_table.item(row, 3).setBackground(bg_color)
         self._call_table.setItem(row, 4, qt.qtablewidgetitem()(called_api))
         self._call_table.item(row, 4).setBackground(bg_color)
         self._call_table.setItem(row, 5, qt.qtablewidgetitem()(ret))
         self._call_table.item(row, 5).setBackground(bg_color)
         self._call_table.setItem(row, 6, qt.qtablewidgetitem()(arg_str))
         self._call_table.item(row, 6).setBackground(bg_color)
         row += 1
     self._call_table.setVisible(False)
     #self._call_table.resizeRowsToContents()
     self._call_table.resizeColumnsToContents()
     self._call_table.setVisible(True)
     self._call_table.setSortingEnabled(True)
コード例 #23
0
def PrevInstr(ea):
    return idc.PrevHead(ea, ea-15)
コード例 #24
0
        0x62, 0xD8, 0xCA, 0xBE
    ]
    table = list(range(256))

    while result < 255:
        v4 += table[result] + key[result % 16]
        v5 = table[result]
        while v4 > 0xFF:
            v4 = key[result % 16]
        table[result] = table[v4]
        result += 1
        table[v4] = v5


for addr in XrefsTo(decode_func, flags=0):
    next_address = idc.PrevHead(addr.frm)
    for i in range(0, 3):
        next_address = idc.PrevHead(next_address)
        if GetMnem(next_address) == "push" and GetOpnd(next_address,
                                                       0).find("offset") != -1:
            String = GetOpnd(next_address, 0).split(" ")[1]
            add_list.append(get_name_ea(next_address, String))

add_list = sorted(add_list)
count = 0
result = []

for i in range(len(add_list)):
    next_address = add_list[i]
    count = i
    try:
コード例 #25
0
def get_name(scan_frm, scan_to, start_place):

    _info(hex(scan_frm), "start scanning: " + start_place)
    #print hex(scan_frm), "start scanning: " + start_place
    # track the operand is not likely to be reasonable, so, i parse name of the operands

    checking_place = start_place
    poluted_reg_flag = False  # if source are `may' polluted reg by function call, set the flag 2 True

    ea_cur = scan_frm
    ea_to = scan_to
    #print hex(ea)

    while ea_cur != idc.BADADDR and ea_cur != ea_to:
        ea_cur = idc.PrevHead(ea_cur, ea_to)
        #print "visiting:", hex(ea_cur), idc.GetDisasm(ea_cur)
        if idaapi.is_call_insn(ea_cur) and idc.GetOpnd(
                ea_cur, 0) not in ['_objc_retainAutoreleasedReturnValue']:

            if poluted_reg_flag == True:  # break if there is a call and the checking place is `X0 - X3', for call may pollute the `X0 - X3' reg

                _info(hex(ea_cur), checking_place + " may pollute, return")
                return None  # i will make a radical predict for all undecided classname (all class contains the same selector will be called)

        if idc.GetMnem(ea_cur) in ['LDR', 'MOV', 'LDUR', 'ADD']:  # more inst??
            src_op = 1
            dest_op = 0
        elif idc.GetMnem(ea_cur) in ['STR', 'STUR']:
            src_op = 0
            dest_op = 1
        else:
            continue

        # idc.GetOpType(ea_cur, dest_op) == idaapi.o_reg and
        operands = re.match(".*\s+(.+), ([^;]+)(;\w+)*", idc.GetDisasm(ea_cur))

        if operands.group(dest_op + 1) == checking_place:

            #print hex(ea_cur)

            if idc.GetOpType(ea_cur, src_op) == idc.o_reg:
                #print "o_reg"

                # __text:0000000100006A00                 ADD             X8, X8, #selRef_class@PAGEOFF
                if idc.GetMnem(ea_cur) == 'ADD':
                    try:
                        name = re.match(".*#.*Ref_(\w+)@PAGEOFF",
                                        idc.GetDisasm(ea_cur)).group(1)
                        return name
                    except:
                        return None

                # TODO:  __text:00000001000069C4                 ADD             X1, X1, #cfstr_Xx@PAGEOFF ; "xx"

                # Direct reg-reg assignment
                _info(hex(ea_cur),
                      checking_place + ' <-- ' + operands.group(src_op + 1))
                checking_place = operands.group(src_op + 1)

                src_reg_val = idc.GetOperandValue(ea_cur, src_op)

                if src_reg_val >= 129 and src_reg_val <= 132:
                    poluted_reg_flag = True
                else:
                    poluted_reg_flag = False

                #print cur_place

            elif idc.GetOpType(ea_cur, src_op) == idc.o_displ:
                #print "idc.o_displ"
                '''
                __text:000000010000752C                 LDR             X0, [X28,#classRef_UIView@PAGEOFF] ; void *
                __text:0000000100007530                 ADRP            X8, #selRef_alloc@PAGE
                __text:0000000100007534                 LDR             X24, [X8,#selRef_alloc@PAGEOFF]
                __text:0000000100007538                 STR             X24, [SP,#0x100+var_A0]
                __text:000000010000753C                 MOV             X1, X24 ; char *
                __text:0000000100007540                 BL              _objc_msgSend
                
                [UIView alloc], there is no implementation in the binary at all, point to the impementation in framework
                '''
                '''
                __text:00000001000076EC                 LDR             X8, [X19,X27]
                __text:00000001000076F0                 CBNZ            X8, loc_100007AA4
                __text:00000001000076F4                 ADRP            X8, #classRef_UILabel@PAGE
                __text:00000001000076F8                 LDR             X0, [X8,#classRef_UILabel@PAGEOFF] ; void *
                __text:00000001000076FC                 LDR             X1, [SP,#0x100+var_A0] ; char *
                
                value of X1 comes from stack, it's a [Base Reg + Index Reg + Displacement] mode
                
                LDR             X0, [X27,#classRef_ESInterface@PAGEOFF] ; void *
                STR             X26, [SP,#0x100+var_A8]
                
                
                the below 2 blocks are the same for a selector assignment
                                
                __text:00000001000069D8                 ADRP            X8, #selRef_setFillColor_@PAGE
                __text:00000001000069DC                 ADD             X8, X8, #selRef_setFillColor_@PAGEOFF
                __text:00000001000069E0                 LDUR            X0, [X29,#var_20]
                __text:00000001000069E4                 LDR             X1, [X8] ; "setFillColor:"
                __text:00000001000069E8                 MOV             X2, X9
                __text:00000001000069EC                 BL              _objc_msgSend                
                
                __text:00000001000069A4                 ADRP            X0, #selRef_setBounds_@PAGE
                __text:00000001000069A8                 LDR             X0, [X0,#selRef_setBounds_@PAGEOFF]
                __text:00000001000069AC                 LDUR            X1, [X29,#var_40+8]
                __text:00000001000069B0                 LDUR            X30, [X29,#var_40]
                __text:00000001000069B4                 STR             X0, [SP,#0x90+var_50]
                __text:00000001000069B8                 MOV             X0, X8  ; void *
                __text:00000001000069BC                 LDR             X8, [SP,#0x90+var_50]
                __text:00000001000069C0                 STR             X1, [SP,#0x90+var_58]
                __text:00000001000069C4                 MOV             X1, X8  ; char *
                __text:00000001000069C8                 MOV             X2, X30
                __text:00000001000069CC                 LDR             X3, [SP,#0x90+var_58]
                __text:00000001000069D0                 BL              _objc_msgSend

                __text:00000001000069FC                 ADRP            X8, #selRef_class@PAGE
                __text:0000000100006A00                 ADD             X8, X8, #selRef_class@PAGEOFF
                __text:0000000100006A04                 ADRP            X0, #classRef_AppDelegate@PAGE
                __text:0000000100006A08                 ADD             X0, X0, #classRef_AppDelegate@PAGEOFF
                __text:0000000100006A0C                 LDUR            W9, [X29,#var_28]
                __text:0000000100006A10                 LDUR            X1, [X29,#var_30]
                __text:0000000100006A14                 LDR             X0, [X0] ; _OBJC_CLASS_$_AppDelegate ; void *
                __text:0000000100006A18                 LDR             X8, [X8] ; "class"
                __text:0000000100006A1C                 STR             X1, [SP,#0x90+var_60]
                __text:0000000100006A20                 MOV             X1, X8  ; char *
                __text:0000000100006A24                 STR             W9, [SP,#0x90+var_64]
                __text:0000000100006A28                 BL              _objc_msgSend

                '''
                poluted_reg_flag = False
                try:
                    name = re.match(".*#.*Ref_(\w+)@PAGEOFF",
                                    idc.GetDisasm(ea_cur)).group(1)
                    return name
                except:
                    #print idc.GetString(idc.GetOperandValue(ea_cur, 1), -1, idc.ASCSTR_C)
                    _info(
                        hex(ea_cur),
                        checking_place + ' <-- ' + operands.group(src_op + 1))
                    checking_place = operands.group(src_op + 1)
                    '''
                    __text:0000000100006A00                 ADD             X8, X8, #selRef_class@PAGEOFF
                    ...
                    __text:0000000100006A18                 LDR             X8, [X8] ; "class"                    
                    '''
                    oprand = idc.GetOpnd(ea_cur, 1)
                    if len(oprand) <= 5 and oprand.startswith(
                            '[') and oprand.endswith(']'):
                        checking_place = oprand[1:len(oprand) - 1]
                        #print checking_place
            elif idc.GetOpType(
                    ea_cur, src_op) == idc.o_phrase:  # can find nothing at all
                #print "idc.o_phrase"
                _info(hex(ea_cur),
                      checking_place + ' <-- ' + operands.group(src_op + 1))
                checking_place = operands.group(src_op + 1)
            elif idc.GetOpType(ea_cur, src_op) == ida_ua.o_imm:
                return None
            else:

                # elif idc.GetOpType(ea_cur, src_op) == idc.o_mem:
                #    print "o_mem"

                print hex(ea_cur), idc.GetDisasm(
                    ea_cur), "<----------unknown type operand",
                # return
                exit(0)


#            ea_cur = idc.GetOperandValue(ea_cur, dest_op)
    if checking_place == "X0":
        # X0 point to `self'
        # -[ESUISendCell createSubviewsAndinitLayout]
        try:
            self_name = re.match("-\[(\w+) \w+",
                                 idc.get_func_name(ea_cur)).group(1)
            return self_name
        except:
            print '%08x: Unable to solve `self`' % ea_cur
            return None
    else:
        _info(hex(scan_frm), "reaching the start pos of the func")

    return None
コード例 #26
0
def find(from_ea,
         target_obj,
         is_recur=True,
         is_bwd=False,
         is_opposite=False,
         is_trace=True):
    def get_opnd_idx(is_writing):
        return 1 if is_writing else 0

    def get_opposite_opnd_idx(opnd_idx):
        assert opnd_idx in [0, 1]

        return 1 - opnd_idx

    def is_matched(ea, opnd_idx, target_obj):
        WRITE_MNEM = ['mov', 'lea', 'imul', 'sub']  # TBU

        obj = idaobj.IdaObj.from_opnd(ea, opnd_idx)
        '''
		if obj == target_obj:
			print obj, '|', target_obj
		'''

        return (idc.GetMnem(ea) in WRITE_MNEM) and (obj == target_obj)

    is_fwd = not is_bwd

    adjusted_ea = idc.NextHead(from_ea) if is_fwd else idc.PrevHead(from_ea)
    bb = idcnew.GetBB(adjusted_ea)

    # from_ea exclusive
    start_ea = idc.NextHead(from_ea) if is_fwd else bb.startEA
    end_ea = bb.endEA if is_fwd else from_ea

    heads = idautils.Heads(start_ea, end_ea)
    if is_bwd:
        heads = reversed(list(heads))

    # is_fwd == is_writing
    self_opnd_idx = get_opnd_idx(is_fwd)
    if is_opposite:
        self_opnd_idx = get_opposite_opnd_idx(self_opnd_idx)
    other_opnd_idx = get_opposite_opnd_idx(self_opnd_idx)

    until_cond = lambda ea: is_matched(ea, other_opnd_idx, target_obj)
    find_cond = lambda ea: is_matched(ea, self_opnd_idx, target_obj)
    make_obj = lambda ea: idaobj.IdaObj.from_opnd(ea, other_opnd_idx)
    trace_cond = lambda ea: idcnew.GetOpType(ea, other_opnd_idx) == idc.o_reg
    trace = lambda ea: find(ea, make_obj(ea), is_recur, is_bwd, is_opposite,
                            is_trace)

    for ea in heads:

        # TODO: What about xor rcx, rcx?
        if until_cond(ea):
            return None

        if find_cond(ea):
            if is_trace and trace_cond(ea):
                return trace(ea)
            else:
                return make_obj(ea)

    if is_recur:

        # TODO: IDAPython bug - bb.preds() always returns empty list.
        if is_bwd:
            raise NotImplementedError

        next_bbs = bb.succs() if is_fwd else bb.preds()

        # not deterministic
        if len(list(next_bbs)) != 1:
            return None

        next_from_ea = idcnew.PrevHead(
            next_bbs[0].startEA) if is_fwd else next_bbs[0].endEA

        return find(next_from_ea, target_obj, is_recur, is_bwd, is_opposite,
                    is_trace)
    else:
        return None
コード例 #27
0
ファイル: is_argument_check.py プロジェクト: JakovRus/diploma
def check_next_opnd(head, call_arguments):
    opnd = idc.GetOpnd(head, 1)
    prev_head = idc.PrevHead(head)
    heads = get_heads_to_address(prev_head)

    return check_operand(opnd, call_arguments, heads)
コード例 #28
0
ファイル: loader.py プロジェクト: jjo-sec/idataco
    def _parseJsonFile(self, json_data):
        _process_data = {}
        self.parent.cuckoo_version = json_data["info"].get("version", "Unknown")
        self.parent.call_categories = set()
        for proc in json_data["behavior"]["processes"]:
            ppid = proc["ppid"] if self.parent.cuckoo_version.startswith("2.0") else proc["parent_id"]
            pid = proc["pid"] if self.parent.cuckoo_version.startswith("2.0") else proc["process_id"]
            _process_data[pid] = {"process_name": proc["process_name"],
                                  "parent_id": ppid,
                                  "imports": [],
                                  "network": [],
                                  "calls": []
                                  }
            handles = {}
            exe_name = idc.GetInputFile().split(".")[0]
            for call in proc["calls"]:
                self.parent.call_categories.add(call["category"])
                if self.parent.cuckoo_version.startswith("1."):
                    args = dict([(x["name"], x["value"]) for x in call["arguments"]])
                    call["arguments"] = args
                else:
                    args = call["arguments"]
                _process_data[pid]["calls"].append(call)
                if call["api"] in ["LdrGetDllHandle", "LdrLoadDll"]:
                    if self.parent.cuckoo_version.startswith("1."):
                        if call["api"] == "LdrGetDllHandle" and args["ModuleHandle"] != "0x00000000":
                            handles[args["ModuleHandle"]] = args["FileName"]
                        elif call["api"] == "LdrLoadDll" and call["return"] == "0x00000000":
                            handles[args["BaseAddress"]] = args["FileName"]
                    # cuckoo 2.0
                    else:
                        if call["api"] == "LdrGetDllHandle" and args["module_address"] != "0x00000000":
                            handles[args["module_address"]] = args["module_name"]
                        elif call["api"] == "LdrLoadDll" and call["return_value"] == 0:
                            handles[args["module_address"]] = args["module_name"]
                elif call["api"] == "LdrGetProcedureAddress":
                    impt_type = "Indirect"
                    if args.get("FunctionName", None):
                        addr = idc.PrevHead(int(call["caller"], 16))
                        if addr != idc.BADADDR:
                            # if the call is direct to a register or stack variable
                            # assume that this is intentional obfuscation of GetProcAddress
                            if idc.GetMnem(addr) == "call" and \
                                (re.match("^e[abcds][ipx]$", idc.GetOpnd(addr, 0)) \
                                 or idc.GetOpnd(addr, 0).endswith("GetProcAddress") \
                                 or idc.GetOpnd(addr, 0).startswith(("ds:dword", "dword ptr", "[e"))):
                                impt_type = "Dynamic"
                        _process_data[pid]["imports"].append({"addr": "0x{:08X}".format(addr),
                                                              "dll": handles.get(args["ModuleHandle"], args["ModuleName"]),
                                                              "proc_name": args["FunctionName"],
                                                              "proc_address": args["FunctionAddress"],
                                                              "type": impt_type
                                                              }
                                                             )
                    elif args.get("function_name") and call.get("stacktrace", []):
                        addr = idc.BADADDR
                        if call["stacktrace"][0].count(" ") in [0,2]:
                            impt_type = "Dynamic"
                        elif len(call["stacktrace"]) > 1:
                            for i in range(1, len(call["stacktrace"])):
                                cur = call["stacktrace"][i]
                                prev = call["stacktrace"][i-1]
                                if prev.startswith("GetProcAddress") and cur.count(" ") in [0, 2]:
                                    impt_type = "Dynamic"
                                    addr = idc.PrevHead(int(cur.split(" @ ")[-1], 16))
                                    break
                                else:
                                    addr = int(cur.split(" @ ")[-1], 16)
                                    addr = idc.PrevHead(addr) if idc.PrevHead(addr) != idc.BADADDR else addr
                        else:
                            for frm in call["stacktrace"]:
                                if frm.count(" ") in [0, 2]:
                                    addr = idc.PrevHead(int(frm.split(" @ ")[-1], 16))
                                    break

                        """
                        # handle case where injected code below ImageBase so don"t get exe_name prepended
                        if call["stacktrace"][0].startswith("GetProcAddress") and \
                           call["stacktrace"][0].count(" ") == 2 and (call["stacktrace"][1].startswith(exe_name) or \
                           call["stacktrace"][0].count(" ") == 0):
                            impt_type = "Dynamic"
                        elif call["stacktrace"][0].startswith(exe_name):
                            impt_type = "Dynamic"
                            addr = idc.PrevHead(int(call["stacktrace"][0].split(" @ ")[-1], 16))
                        """
                        _process_data[pid]["imports"].append({
                                                              "addr": "0x{:08X}".format(addr),
                                                              "dll": handles.get(args["module_address"], args["module_address"]),
                                                              "proc_name": args["function_name"],
                                                              "proc_address": args["function_address"],
                                                              "type": impt_type
                                                              }
                                                             )
        self.parent.signatures = json_data["signatures"]
        self.parent.process_data = _process_data
        self.parent.process_tree = json_data["behavior"]["processtree"]
        del json_data
コード例 #29
0
ファイル: 8_指令.py プロジェクト: zengkefu/IDAPython_Note
import idaapi

#获取指定函数中所有指令地址的集合,FuncItems返回的是迭代器,可以强制转换为list
dism_addr = list(idautils.FuncItems(here()))
print type(dism_addr)

print dism_addr

for line in dism_addr:
    print hex(line), idc.GetDisasm(line)

#获取下一个指令的地址
idc.NextHead(ea)

#获取上一条指令的地址
idc.PrevHead(ea)

#获取下一个地址
idc.NextAddr(ea)

#获取上一个地址
idc.PrevAddr(ea)

#遍历所有的动态调用
for func in idautils.Functions():
    flags = idc.GetFunctionFlags(func)
    if flags & FUNC_LIB or flags & FUNC_THUNK:
        continue
    dism_addr = list(idautils.FuncItems(func))
    for line in dism_addr:
        m = idc.GetMnem(line)