def codeType(self, ea): """Query IDA for the code type at the given address. Args: ea (int): effective code address Return Value: The current code type at the given address """ return idc.GetReg(ea, 'T')
def nextarm(self, ea, ui=True): # type: (int) -> str """ Finds the next ARM item, which has a Segment register value 'T' of 0 :param ea: address to start searching from :param ui: if True, jump to address automatically :return: the address (in str) of the next ARM instruction """ # don't count this item ea += Data.Data(ea).getSize() output = idaapi.BADADDR while ea < self.end_ea: d = Data.Data(ea) # detect next code32 if idc.GetReg(ea, 'T') == 0: output = ea break ea += d.getSize() return '%07X' % output
def extendThumbFuncToLastPop(func_ea, lastInsn_ea, verbose=True): """ Looks for another POP {..., PC}. Stops at the start of a new function, or at the start of labeled data. Otherwise, it makes sure the code is disassembled, and is thumb, and it extends the range of the function to the found POP {..., PC}. A corner case not accounted by this algorithm, is if the data is in the middle of code, but is jumped over. :param func_ea: addr to function to fix :param lastInsn_ea: address to the last instruction within the function, as registered in the IDB. :return: whether a fix ocurred or not """ ea = lastPop_ea = lastInsn_ea while not idc.Name(ea) or not idc.isData(idc.GetFlags(ea)): if idc.GetReg(ea, 'T') == 0: idc.SetRegEx(ea, 'T', 1, idc.SR_user) # if idc.isData(idc.GetFlags(ea)): # # if not thumb, make thumb # idc.del_items(ea, 0, 2) # idc.MakeCode(ea) if Instruction.isInsn(ea): insn = Instruction.Insn(ea) # update last POP {..., PC} detected if insn.itype == idaapi.ARM_pop and ((insn.getPushPopFlags() & (1 << 15)) != 0): lastPop_ea = ea # stop condition, assuming no PUSH {..., LR} in current function if insn.itype == idaapi.ARM_push and ((insn.getPushPopFlags() & (1 << 14)) != 0): break ea += idaapi.get_item_size(ea) # extend last function to last pop detected if lastPop_ea != lastInsn_ea: if verbose: print('%07X: End -> %07X <%s>' % (func_ea, lastPop_ea, Data.Data(lastPop_ea).getDisasm())) idc.SetFunctionEnd(func_ea, lastPop_ea + 2) return True return False
def GetFuncInputSurrogate(func): info = idaapi.get_inf_structure() arch = info.procName.lower() function_ea = func.startEA f_name = GetFunctionName(func) function = dict() function['name'] = f_name function['id'] = function_ea # ignore call-graph at this moment function['call'] = list() function['sea'] = function_ea function['see'] = idc.FindFuncEnd(function_ea) function['blocks'] = list() # basic bloc content for bblock in idaapi.FlowChart(idaapi.get_func(function_ea)): sblock = dict() sblock['id'] = bblock.id sblock['sea'] = bblock.startEA if (arch == 'arm'): sblock['sea'] += idc.GetReg(bblock.startEA, 'T') sblock['eea'] = bblock.endEA sblock['name'] = 'loc_' + format(bblock.startEA, 'x').upper() dat = {} sblock['dat'] = dat s = idc.GetManyBytes(bblock.startEA, bblock.endEA - bblock.startEA) if (s != None): sblock['bytes'] = "".join("{:02x}".format(ord(c)) for c in s) tlines = [] for head in idautils.Heads(bblock.startEA, bblock.endEA): tline = [] tline.append( str(hex(head)).rstrip("L").upper().replace("0X", "0x")) mnem = idc.GetMnem(head) if mnem == "": continue tline.append(mnem) for i in range(5): opd = idc.GetOpnd(head, i) if opd == "": continue tline.append(opd) tlines.append(tline) refdata = list(idautils.DataRefsFrom(head)) if (len(refdata) > 0): for ref in refdata: dat[head] = binascii.hexlify( struct.pack("<Q", idc.Qword(ref))) sblock['src'] = tlines # flow chart bcalls = list() for succ_block in bblock.succs(): bcalls.append(succ_block.id) sblock['call'] = bcalls function['blocks'].append(sblock) return function
def is_thumb(address): return idc.GetReg(address, 'T') == 1
def assemble32(line, ea): return idaapi.assemble(ea, idc.GetReg(ea, "cs"), ea, True, line)
def fix_callgraph(msgsend, segname, class_param, sel_param): ''' 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) 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) 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 _get_ida_func_surrogate(func, arch): func_surrogate = dict() func_surrogate['name'] = idc.GetFunctionName(func.startEA) func_surrogate['id'] = func.startEA # ignore call-graph at this moment func_surrogate['call'] = list() func_surrogate['sea'] = func.startEA func_surrogate['see'] = idc.FindFuncEnd(func.startEA) # api is optional func_surrogate['api'] = _get_api(func.startEA)[1] func_surrogate['blocks'] = list() # comments func_surrogate['comments'] = [] func_surrogate['comments'].extend(get_comments(func.startEA)) for bb in idaapi.FlowChart(idaapi.get_func(func.startEA)): block = dict() block['id'] = bb.id block['sea'] = bb.startEA if arch is 'arm': # for arm; the last bit indicates thumb mode. block['sea'] += idc.GetReg(bb.startEA, 'T') block['eea'] = bb.endEA block['name'] = 'loc_' + format(bb.startEA, 'x').upper() dat = {} block['dat'] = dat s = idc.GetManyBytes(bb.startEA, bb.endEA - bb.startEA) if s is not None: block['bytes'] = "".join("{:02x}".format(ord(c)) for c in s) func_surrogate['comments'].extend(get_comments(bb.startEA)) instructions = list() for head in idautils.Heads(bb.startEA, bb.endEA): ins = list() ins.append(str(hex(head)).rstrip("L").upper().replace("0X", "0x")) opr = idc.GetMnem(head) if opr == "": continue ins.append(opr) for i in range(5): opd = idc.GetOpnd(head, i) if opd == "": continue ins.append(opd) instructions.append(ins) refs = list(idautils.DataRefsFrom(head)) for ref in refs: dat[head] = binascii.hexlify(struct.pack("<Q", idc.Qword(ref))) block['src'] = instructions # flow chart block_calls = list() for success_block in bb.succs(): block_calls.append(success_block.id) block['call'] = block_calls func_surrogate['blocks'].append(block) return func_surrogate
def InsIsThumb(i): return idc.GetReg(i, "T") == 1