def get_mnemonic(self, addr): """Return the mnemonic for the current instruction. """ if idaapi.ua_mnem(addr) in self.no_op_instr: return idc.GetDisasm(addr) else: return idaapi.ua_mnem(addr)
def decode_instr(eip): MakeCode(eip) mnem = idaapi.ua_mnem(eip) sz = idaapi.decode_insn(eip) x = dict(nextip=[], inst=mnem, ops=[]) if not idaapi.cmd.itype in (idaapi.NN_jmp, idaapi.NN_retn): x['nextip'].append(eip + sz) for n, op in enumerate(idaapi.cmd.Operands): if op.type == 0: break ty = op.type text = idaapi.tag_remove(idaapi.ua_outop2(eip, n)) if op.dtyp == 0: bits = 8 elif op.dtyp == 1: bits = 16 elif op.dtyp == 2: bits = 32 if ty == idc.o_reg: x['ops'].append(IR.Var(text, bits)) elif ty == idc.o_mem: x['ops'].append(IR.Mem(IR.Const(op.addr), bits)) elif ty in (idc.o_phrase, idc.o_displ): x['ops'].append(IR.Mem(parse_mem(op), bits)) elif ty == idc.o_imm: x['ops'].append(IR.Const(op.value, bits)) elif ty == idc.o_near: x['ops'].append(IR.Const(op.addr)) x['nextip'].append(op.addr) else: raise UnknownError return x
def to_masm(self): if self.verbatim: return "\t%s" % (idaapi.tag_remove( idaapi.generate_disasm_line(self.ea))) else: return "\t%s %s" % (idaapi.ua_mnem(self.ea), ", ".join( map(lambda e: e.to_masm(), self.ops)))
def decode_instr(eip): MakeCode(eip) mnem = idaapi.ua_mnem(eip) sz = idaapi.decode_insn(eip) x = dict(nextip=[],inst=mnem, ops=[]) if not idaapi.cmd.itype in (idaapi.NN_jmp, idaapi.NN_retn): x['nextip'].append(eip+sz) for n, op in enumerate(idaapi.cmd.Operands): if op.type == 0: break ty = op.type text = idaapi.tag_remove(idaapi.ua_outop2(eip, n)) if op.dtyp == 0: bits = 8 elif op.dtyp == 1: bits = 16 elif op.dtyp == 2: bits = 32 if ty == idc.o_reg: x['ops'].append(IR.Var(text, bits)) elif ty == idc.o_mem: x['ops'].append(IR.Mem(IR.Const(op.addr),bits)) elif ty in (idc.o_phrase, idc.o_displ): x['ops'].append(IR.Mem(parse_mem(op),bits)) elif ty == idc.o_imm: x['ops'].append(IR.Const(op.value,bits)) elif ty == idc.o_near: x['ops'].append(IR.Const(op.addr)) x['nextip'].append(op.addr) else: raise UnknownError return x
def get_mnemonic(self, addr): """Return the mnemonic for the current instruction. Achitecture specific modules can define a new method to process mnemonics in different ways. """ return idaapi.ua_mnem(addr)
def codeRefs(func): resultData,resultCode = [],[] for ea in iterate(func): if len(database.down(ea)) == 0: insn = idaapi.ua_mnem(ea) if insn and insn.startswith('call'): resultCode.append((ea, 0)) continue resultData.extend( (ea,x) for x in database.dxdown(ea) ) resultCode.extend( (ea,x) for x in database.cxdown(ea) if func.startEA == x or not contains(func,x) ) return resultData,resultCode
def blocks(start, end): '''Returns each block between the specified range of instructions''' block = start for ea in iterate(start, end): nextea = next(ea) if idaapi.ua_mnem(ea).startswith('call'): # FIXME: heh. ;) continue if idaapi.ua_mnem(ea).startswith('ret'): # whee yield block,nextea block = ea elif cxdown(ea): yield block,nextea block = nextea elif cxup(ea) and block != ea: yield block,ea block = ea continue return
def blocks(start, end): '''Returns each block between the specified range of instructions''' block = start for ea in iterate(start, end): nextea = next(ea) if idaapi.ua_mnem(ea).startswith('call'): # FIXME: heh. ;) continue if idaapi.ua_mnem(ea).startswith('ret'): # whee yield block, nextea block = ea elif cxdown(ea): yield block, nextea block = nextea elif cxup(ea) and block != ea: yield block, ea block = ea continue return
def codeRefs(ea): fn = top(ea) resultData,resultCode = [],[] for l,r in chunks(fn): for ea in database.iterate(l,r): if len(database.down(ea)) == 0: insn = idaapi.ua_mnem(ea) if insn and insn.startswith('call'): resultCode.append((ea, 0)) continue resultData.extend( (ea,x) for x in database.dxdown(ea) ) resultCode.extend( (ea,x) for x in database.cxdown(ea) if not contains(fn,x) ) continue return resultData,resultCode
def find_putchar(base_ea): str_ea = ida_name.get_name_ea(idaapi.BADADDR, "aPanic") if str_ea != idaapi.BADADDR: apanic_ea = list(idautils.XrefsTo(str_ea))[0].frm if apanic_ea == idaapi.BADADDR: return idaapi.BADADDR opnd0 = idc.print_operand(apanic_ea + 8, 0) ins_str = idaapi.ua_mnem(apanic_ea + 8) if ins_str == "BL": func_ea = ida_name.get_name_ea(idaapi.BADADDR, opnd0) ea = func_ea while ea != idaapi.BADADDR: ins_str = idaapi.ua_mnem(ea) if ins_str == "ADD": opnd2 = idc.print_operand(ea, 2) if opnd2 == "#1": ins_ea = ea - 4 opnd0 = idc.print_operand(ins_ea, 0) ins_str = idaapi.ua_mnem(ins_ea) if ins_str == "BL": pc_ea = ida_name.get_name_ea(idaapi.BADADDR, opnd0) print("\t[+] _putchar = 0x%x" % (pc_ea)) ida_name.set_name(pc_ea, "_putchar") return pc_ea ea = ea + 4 return idaapi.BADADDR
def custom_mnem(self, *args): """ custom_out(self) -> bool Return 0 - No customization Return 2 - Did customization """ if self.am_in_hook or not self.active: return _idaapi.IDP_Hooks_custom_mnem(self, *args) for checker, color in INSN_RULES: if checker(idaapi.cmd.ea): self.am_in_hook = True mnem = idaapi.ua_mnem(idaapi.cmd.ea) self.am_in_hook = False mnem = mnem + " " * (7 - len(mnem)) return color_inject(mnem, idaapi.SCOLOR_INSN, color) return _idaapi.IDP_Hooks_custom_mnem(self, *args)
def custom_mnem(self, *args): """ custom_out(self) -> bool Return 0 - No customization Return 2 - Did customization """ if self.am_in_hook or not self.active: return hook_place.IDP_Hooks_custom_mnem(self, *args) for checker, color in INSN_RULES: if checker(idaapi.cmd.ea): self.am_in_hook = True mnem = idaapi.ua_mnem(idaapi.cmd.ea) self.am_in_hook = False mnem = mnem + " " * (7 - len(mnem)) return color_inject(mnem, idaapi.SCOLOR_INSN, color) return hook_place.IDP_Hooks_custom_mnem(self, *args)
def operands_parser(self, address, operands): """Parse operands. Can be defined in architecture specific modules to process the whole list of operands before or after parsing, if necessary. In Intel, for instance, is used to post process operands where the target is also used as source but included only once, that happens for instance with the IMUL instruction. """ op_list = [] if idaapi.ua_mnem(address) in self.no_op_instr: return op_list for op, idx in operands: # The following will make sure it's an operand that IDA displays. # IDA sometimes encodes implicit operand's information into the # structures representing instructions but chooses not to display # those operands. We try to reproduce IDAs output # if idc.GetOpnd(address, idx) != '': current_operand = self.single_operand_parser(address, op, idx) if not current_operand: continue if isinstance(current_operand[0], (list, tuple)): op_list.extend( current_operand ) else: op_list.append( current_operand ) operands = op_list return op_list
def operands_parser(self, address, operands): """Parse operands. Can be defined in architecture specific modules to process the whole list of operands before or after parsing, if necessary. In Intel, for instance, is used to post process operands where the target is also used as source but included only once, that happens for instance with the IMUL instruction. """ op_list = [] if idaapi.ua_mnem(address) in self.no_op_instr: return op_list for op, idx in operands: # The following will make sure it's an operand that IDA displays. # IDA sometimes encodes implicit operand's information into the # structures representing instructions but chooses not to display # those operands. We try to reproduce IDAs output # if idc.GetOpnd(address, idx) != '': current_operand = self.single_operand_parser(address, op, idx) if not current_operand: continue if isinstance(current_operand[0], (list, tuple)): op_list.extend(current_operand) else: op_list.append(current_operand) operands = op_list return op_list
def AnalyzeRange(self, startEA, endEA): CurrentAddress = startEA CurrentBlockAddress = CurrentAddress NewBlockStart = True last_op_code = '' while CurrentAddress < endEA: if idaapi.isCode(idaapi.get_flags_novalue(CurrentAddress)): idaapi.decode_insn(CurrentAddress) op_code = idaapi.ua_mnem(CurrentAddress) operands = [] disasm_line = op_code + ' ' for i in range(0, 6, 1): operand = idaapi.ua_outop2(CurrentAddress, i) if not operand: break operand = idaapi.tag_remove(operand) operands.append(operand) if i != 0: disasm_line += ',' disasm_line += operand #disasm_line = idaapi.tag_remove( idaapi.generate_disasm_line( CurrentAddress ) ) xref = idaapi.xrefblk_t() ret = xref.first_to(CurrentAddress, idaapi.XREF_FAR) while ret: ret = xref.next_to() NewBlockStart = True if NewBlockStart and last_op_code[ 0:3] != 'ret' and last_op_code != 'new block': self.AddToMap(CurrentBlockAddress, CurrentAddress, None, 'link') if NewBlockStart: CurrentBlockAddress = CurrentAddress self.BlockData[CurrentBlockAddress] = [] if self.DebugLevel > 2: print '=' * 80 if self.DebugLevel > 2: print hex(CurrentAddress), disasm_line self.BlockData[CurrentBlockAddress].append( (CurrentAddress, disasm_line)) NewBlockStart = False CallIsResolved = False ret = xref.first_from(CurrentAddress, idaapi.XREF_FAR) while ret: if xref.iscode: if op_code == 'jmp' and xref.to == CurrentAddress + idaapi.cvar.cmd.size: NewBlockStart = True elif op_code == 'call': CallIsResolved = True self.AddToMap(CurrentBlockAddress, xref.to, operands[0], 'call') else: if len(operands) > 0: self.AddToMap(CurrentBlockAddress, xref.to, operands[0], 'from') NewBlockStart = True ret = xref.next_from() if (op_code == 'call' or op_code == '') and not CallIsResolved: self.AddToMap(CurrentBlockAddress, operands[0], operands[0], 'call') if NewBlockStart and op_code != 'jmp': self.AddToMap(CurrentBlockAddress, CurrentAddress + idaapi.cvar.cmd.size, '', 'link') if op_code[0:3] == 'ret': NewBlockStart = True last_op_code = op_code CurrentAddress += idaapi.cvar.cmd.size else: CurrentAddress += 1
def is_line_code(line_address): """ Check if a given line contains code. """ # Use a hack of trying to get the mnemonic: return idaapi.ua_mnem(line_address) is not None
def mnem(ea): '''Returns the mnemonic of an instruction''' return idaapi.ua_mnem(ea) or ''
def AnalyzeRange( self, startEA, endEA ): CurrentAddress = startEA CurrentBlockAddress = CurrentAddress NewBlockStart = True last_op_code = '' while CurrentAddress < endEA: if idaapi.isCode( idaapi.get_flags_novalue( CurrentAddress ) ): idaapi.decode_insn( CurrentAddress ) op_code = idaapi.ua_mnem( CurrentAddress ) operands=[] disasm_line = op_code + ' ' for i in range(0, 6, 1): operand = idaapi.ua_outop2( CurrentAddress, i ) if not operand: break; operand = idaapi.tag_remove( operand ) operands.append( operand ) if i != 0: disasm_line += ',' disasm_line += operand #disasm_line = idaapi.tag_remove( idaapi.generate_disasm_line( CurrentAddress ) ) xref = idaapi.xrefblk_t() ret = xref.first_to( CurrentAddress, idaapi.XREF_FAR ) while ret: ret = xref.next_to() NewBlockStart = True if NewBlockStart and last_op_code[0:3] != 'ret' and last_op_code != 'new block': self.AddToMap( CurrentBlockAddress, CurrentAddress, None, 'link') if NewBlockStart: CurrentBlockAddress = CurrentAddress self.BlockData[CurrentBlockAddress]=[] if self.DebugLevel > 2: print '='*80 if self.DebugLevel > 2: print hex(CurrentAddress), disasm_line self.BlockData[CurrentBlockAddress].append( ( CurrentAddress, disasm_line ) ) NewBlockStart = False CallIsResolved = False ret = xref.first_from( CurrentAddress, idaapi.XREF_FAR ) while ret: if xref.iscode: if op_code == 'jmp' and xref.to == CurrentAddress + idaapi.cvar.cmd.size: NewBlockStart = True elif op_code == 'call': CallIsResolved = True self.AddToMap( CurrentBlockAddress,xref.to, operands[0], 'call') else: if len(operands) > 0 : self.AddToMap( CurrentBlockAddress,xref.to, operands[0], 'from') NewBlockStart = True ret = xref.next_from() if ( op_code == 'call' or op_code =='' ) and not CallIsResolved: self.AddToMap( CurrentBlockAddress, operands[0], operands[0], 'call') if NewBlockStart and op_code != 'jmp': self.AddToMap( CurrentBlockAddress, CurrentAddress + idaapi.cvar.cmd.size, '', 'link') if op_code[0:3] == 'ret': NewBlockStart = True last_op_code = op_code CurrentAddress += idaapi.cvar.cmd.size else: CurrentAddress += 1
def load_file(fd, neflags, format): global prologues size = 0 base_addr = 0 ea = 0 nfunc = 0 idaapi.set_processor_type("arm", idaapi.SETPROC_LOADER) idaapi.get_inf_structure().lflags |= idaapi.LFLG_64BIT if (neflags & idaapi.NEF_RELOAD) != 0: return 1 fd.seek(0, idaapi.SEEK_END) size = fd.tell() segm = idaapi.segment_t() segm.bitness = 2 # 64-bit segm.start_ea = 0 segm.end_ea = size idaapi.add_segm_ex(segm, "iBoot", "CODE", idaapi.ADDSEG_OR_DIE) fd.seek(0) fd.file2base(0, 0, size, False) idaapi.add_entry(0, 0, "start", 1) idaapi.add_func(ea, idaapi.BADADDR) print("[+] Marked as code") # heuristic while (True): mnemonic = idaapi.ua_mnem(ea) if mnemonic == None: mnemonic = '' if "LDR" in mnemonic: base_str = idc.print_operand(ea, 1) base_addr = int(base_str.split("=")[1], 16) break ea += 4 print("[+] Rebasing to address 0x%x" % (base_addr)) idaapi.rebase_program(base_addr, idc.MSF_NOFIX) ida_auto.auto_wait() segment_start = base_addr segment_end = idc.get_segm_attr(segment_start, idc.SEGATTR_END) ea = segment_start print("[+] Searching and defining functions") for prologue in prologues: while ea != idc.BADADDR: ea = ida_search.find_binary(ea, idc.ida_search.SEARCH_DOWN, prologue, 16, ida_search.SEARCH_DOWN) if ea != idc.BADADDR: ea = ea - 2 if (ea % 4) == 0 and ida_bytes.get_flags(ea) < 0x200: print("[+] Defining a function at 0x%x" % (ea)) idaapi.add_func(ea, idaapi.BADADDR) nfunc = nfunc + 1 ea = ea + 4 ida_auto.plan_and_wait(segment_start, segment_end) print("[+] Identified %d new functions" % (nfunc)) print("[+] Looking for interesting functions") find_interesting(segment_start) return 1 # EOF
def to_masm(self): if self.verbatim: return "\t%s" % (idaapi.tag_remove(idaapi.generate_disasm_line(self.ea))) else: return "\t%s %s" % (idaapi.ua_mnem(self.ea), ", ".join(map(lambda e: e.to_masm(), self.ops)))