def getBBconsts(bl): strings = [] consts = [] start = bl[0] end = bl[1] invoke_num = 0 inst_addr = start while inst_addr < end: opcode = idc.print_insn_mnem(inst_addr) if opcode in ['la','jalr','call', 'jal']: inst_addr = idc.next_head(inst_addr) continue strings_src, consts_src = getConst(inst_addr, 0) strings_dst, consts_dst = getConst(inst_addr, 1) strings += strings_src strings += strings_dst consts += consts_src consts += consts_dst try: strings_dst, consts_dst = getConst(inst_addr, 2) consts += consts_dst strings += strings_dst except: pass inst_addr = idc.next_head(inst_addr) return strings, consts
def clean(): """Removes the background color of all the database. It can be used to remove the colors added by `apply()`, but it doesn't remove the prefixes.""" ida_auto.auto_wait() ea = idc.next_head(0) while ea != idaapi.BADADDR: idc.set_color(ea, idc.CIC_ITEM, 0xFFFFFF) ea = idc.next_head(ea) print("ANA color: Enjoy your boring database")
def main(): print('[*] start debfuscation') for s in get_code_segments(): print('[*] try to deobfuscate {} section'.format( ida_segment.get_segm_name(s))) if s.use32(): junk_patterns = junk_patterns_x86 elif s.use64(): junk_patterns = junk_patterns_x64 else: print('[!] unsupported arch') print('[*] replace junk code to nop') for pattern, pattern_len in junk_patterns: addr_from = idc.find_binary(s.start_ea, ida_search.SEARCH_DOWN, pattern) while addr_from != idaapi.BADADDR and addr_from < s.end_ea: ida_bytes.patch_bytes(addr_from, '\x90' * pattern_len) addr_from = idc.find_binary(addr_from + pattern_len, ida_search.SEARCH_DOWN, pattern) print('[*] hide nop code') addr_from = ida_search.find_text( s.start_ea, 0, 0, 'nop', ida_search.SEARCH_CASE | ida_search.SEARCH_DOWN) while addr_from != idaapi.BADADDR and addr_from < s.end_ea: func_offset = idc.get_func_off_str(addr_from) if type(func_offset) == str and func_offset.find('+') == -1: addr_from = ida_search.find_text( idc.next_head(addr_from), 0, 0, 'nop', ida_search.SEARCH_CASE | ida_search.SEARCH_DOWN) else: i = 0 while True: if ida_bytes.get_byte(addr_from + i) == 0x90: i += 1 else: break if i >= 3: idc.add_hidden_range(addr_from, addr_from + i, 'nop', None, None, 0xFFFFFFFF) print("%08X" % addr_from) addr_from = ida_search.find_text( idc.next_head(addr_from + i), 0, 0, 'nop', ida_search.SEARCH_CASE | ida_search.SEARCH_DOWN) #print('[*] renanlyze') #idc.del_items(s.start_ea, size=s.size()) #time.sleep(1) #idc.plan_and_wait(s.start_ea, s.end_ea) print('[*] done')
def isinthunk(winname, thunk): ea, name = thunk funcstart = idc.get_func_attr(ea, idc.FUNCATTR_START) funcend = idc.get_func_attr(ea, idc.FUNCATTR_END) if funcend - funcstart > 20: # Highest I've seen is 13 opcodes but this works ig return False addr = idc.next_head(funcstart, funcend) if addr == idc.BADADDR: return False b = idc.get_wide_byte(addr) if b in (0xEB, 0xE9): dis = idc.generate_disasm_line(addr, 0) try: funcname = dis[dis.find("jmp") + 3:].strip() if funcname.find("short") != -1: funcname = funcname[funcname.find("short") + 5:].strip() # When this function gets typed, a comment is added # Remove it if funcname.find(";") != -1: funcname = funcname[:funcname.find(";")] if funcname == winname: return True except: pass return False
def get_f5_comments(self): cmts = [] for seg in idautils.Segments(): ea = idc.SegStart(seg) if idc.GetSegmentAttr(ea, idc.SEGATTR_TYPE) != idaapi.SEG_CODE: continue seg_name = idc.SegName(seg) end = idc.SegEnd(seg) while ea < end: if ea != idc.BADADDR and idc.GetFunctionFlags( ea) != 0xffffffff: try: cfunc = idaapi.decompile(ea) for tl, citem in cfunc.user_cmts.items(): current_cmt = [ "%s:%-16X" % (seg_name, tl.ea), 'F5', idc.GetDisasm(tl.ea), citem.c_str() ] # F5 comments cmts.append(current_cmt) self.n += 1 except idaapi.DecompilationFailure: pass finally: ea = idc.GetFunctionAttr(ea, idc.FUNCATTR_END) else: ea = idc.next_head(ea, end) return cmts
def get_asm_comments(self): cmts = [] for seg in idautils.Segments(): seg_name = idc.SegName(seg) ea = idc.SegStart(seg) end = idc.SegEnd(seg) while ea < end: if ea != idc.BADADDR: cmt = idc.GetCommentEx(ea, True) # repeatable comments if cmt: if not self.check_isin_filter(cmt): current_cmt = [ "%s:%-16X" % (seg_name, ea), 'R', idc.GetDisasm(ea), cmt ] cmts.append(current_cmt) self.n += 1 cmt2 = idc.GetCommentEx(ea, False) # usual comments if cmt2: if not self.check_isin_filter(cmt2): current_cmt = [ "%s:%-16X" % (seg_name, ea), 'N', idc.GetDisasm(ea), cmt2 ] cmts.append(current_cmt) self.n += 1 ea = idc.next_head(ea, end) return cmts
def get_branch_type(self): if self.bbl == None: return -1 addr = self.addr while addr != self.bbl.end_ea: mnem = idc.print_insn_mnem(addr).lower() if mnem.startswith("call"): if op_type[idc.get_operand_type(addr,0)] != "o_near" and\ op_type[idc.get_operand_type(addr,0)] != "o_far": return ICALL else: return CALL addr = idc.next_head(addr) addr = idc.prev_head(self.bbl.end_ea) mnem = idc.print_insn_mnem(addr).lower() if mnem in u_jumps or mnem in c_jumps: if op_type[idc.get_operand_type(addr,0)] != "o_near" and\ op_type[idc.get_operand_type(addr,0)] != "o_far": return IJMP else: if mnem in u_jumps: return JMP else: return CJMP elif self.bbl.type >= 2 and self.bbl.type <= 5: return RET return NA
def get_FULL_CONFIG(): global config_extract_ea, FULL_CONFIG # get FULL_CONFIG size curr_ea = config_extract_ea stop_bytes = 0 # this should be 0xDEADBEEF FULL_CONFIG_ea = 0 while True: next_instruction_ea = idc.next_head(curr_ea) if idc.print_insn_mnem(next_instruction_ea) == 'cmp': stop_bytes = idc.get_operand_value(next_instruction_ea, 1) break elif idc.print_insn_mnem(next_instruction_ea) == 'lea': FULL_CONFIG_ea = idc.get_operand_value(next_instruction_ea, 1) curr_ea = next_instruction_ea config_length = 0 while True: if int.from_bytes(idaapi.get_bytes(FULL_CONFIG_ea + config_length, 4), 'little') == stop_bytes: break config_length += 1 FULL_CONFIG = [ each_byte for each_byte in idaapi.get_bytes(FULL_CONFIG_ea, config_length) ] FULL_CONFIG = decrypt_config(FULL_CONFIG, config_length)
def _btn_trace_color_clicked(self): col = 0xccffcc col2 = 0xbbeebb if False: for ea, basic_block in self.infoparser.basic_blocks.iteritems(): while ea != idaapi.BADADDR: idc.set_color(ea, idc.CIC_ITEM, col) ea = idc.next_head(ea, basic_block['end']) for target_pc, flow in self.infoparser.flows.iteritems(): refs = [] for xref in idautils.XrefsTo(target_pc): refs.append(xref.frm) for jump_from_pc, flowtype in flow.iteritems(): if jump_from_pc in refs: continue if ida_ua.ua_mnem(jump_from_pc) == 'call': flowtype = idaapi.fl_CN else: flowtype = idaapi.fl_JN idc.set_color(jump_from_pc, idc.CIC_ITEM, col2) idc.AddCodeXref(jump_from_pc, target_pc, flowtype)
def get_boot_services(self): """found boot services in idb""" code = list(idautils.Functions())[0] start = idc.get_segm_start(code) end = idc.get_segm_end(code) ea = start while (ea <= end): if idc.print_insn_mnem(ea) != 'call': ea = idc.next_head(ea) continue for service_name in self.BOOT_SERVICES_OFFSET: # yapf: disable if (idc.get_operand_value(ea, 0) == self.BOOT_SERVICES_OFFSET[service_name]): if not self.gBServices[service_name].count(ea): self.gBServices[service_name].append(ea) ea = idc.next_head(ea)
def decrypt(start_ea, end_ea, type, a, b): encrypted_buffer = [] if start_ea is None or end_ea is None: print('cant decrypt') return curr = start_ea while curr <= end_ea: encrypted_buffer.append(idc.get_operand_value(curr, 1)) print(hex(idc.get_operand_value(curr, 1))) curr = idc.next_head(curr) result = '' # a*(b-buff[i]) if type == 1: for each in encrypted_buffer: temp = (a * (b - each) % 127 + 127) % 127 if temp != 0: result += chr(temp) elif type == 2: # a * (buffer[i] - b) for each in encrypted_buffer: temp = (a * (each - b) % 127 + 127) % 127 if temp != 0: result += chr(temp) return result
def get_sequences(start, end): seq = [] inst_addr = start while inst_addr <= end: opcode = idc.print_insn_mnem(inst_addr) seq.append(opcode) inst_addr = idc.next_head(inst_addr) return seq
def execute(self, ip=None): """ "Execute" the instruction at IP and store results in the context. The RIP/EIP register will be set to the value supplied in IP so that it is correct. :param ip: instruction address to execute (defaults to currently set ip) """ if not ip: ip = self.ip # Set instruction pointer to where we are currently executing. self.ip = ip # Determine if a rep* instruction and add termination condition. term_condition = None if idc.get_wide_byte(ip) in (0xF2, 0xF3): insn = idc.GetDisasm(ip) # IDA pro never has operands for rep opcodes. if insn.startswith("rep "): term_condition = lambda: self.registers.ecx == 0 elif insn.startswith(("repe ", "repz ")): term_condition = lambda: self.registers.ecx == 0 or self.registers.zf == 0 elif insn.startswith(("repne ", "repnz ")): term_condition = lambda: self.registers.ecx == 0 or self.registers.zf == 1 # Emulate instruction. mnem = idc.print_insn_mnem(ip) operands = self.operands instruction = self.OPCODES.get(mnem) if instruction: try: if term_condition: # As a safety measure, don't allow rep instructions to surpass # our max memory read limit. if self.registers.ecx > self.memory.MAX_MEM_READ: logger.warning( "0x{:08X} :: Emulation attempted to read {} instruction {} times. " "Ignoring instruction.".format(ip, mnem, self.registers.ecx) ) else: logger.debug("Emulating {} instruction {} times.".format(mnem, self.registers.ecx)) while not term_condition(): instruction(self, ip, mnem, operands) self.registers.ecx -= 1 else: instruction(self, ip, mnem, operands) except Exception: logger.exception("Failed to execute address 0x{:X}: {}".format(ip, idc.GetDisasm(ip))) else: logger.debug("{} instruction not implemented.".format(mnem)) # Record executed instruction. self.executed_instructions.append(ip) # After execution, set instruction pointer to next instruction assuming # standard code flow and if no jump was made. if self.ip == ip: self.ip = idc.next_head(ip)
def calInsts(bl): start = bl[0] end = bl[1] ea = start num = 0 while ea < end: num += 1 ea = idc.next_head(ea) return num
def getStmtNum(node): start = node[0] end = node[1] stmt_num = 0 inst_addr = start while inst_addr < end: inst_addr = idc.next_head(inst_addr) stmt_num += 1 return stmt_num
def find_function_ends_near(location, end_mnem_bytes=None): """ Description: Identifies the nearest possible function ends before the next function or Align for each end mnem. Input: location - The EA to search after end_mnem_bytes - Try to end functions on a particular instruction Instructions are entered as space separated bytes (i.e. 'C2' for 'retn') The specified pattern will be used first, then the defaults will be used If no pattern is specified, the defaults will be used, which prefers 'retn' Output: ends - A list of function end EAs sorted: end_mnem_bytes, retn, jmp """ # foreach target bytes: # step instructions down # if instruction matches the target bytes, add to output list # then move on to the next target bytes # if we hit a function or an align, quit # return ends in the order # end_nmem_bytes # retn # jmp # others, sorted ascending max_location = None ea = location while max_location is None: ea = idc.next_head(ea) if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)): max_location = ea elif ea == idc.BADADDR: max_location = idaapi.getseg(location).end_ea max_location = min(max_location, idaapi.getseg(location).end_ea) targets = ['C2', 'C3', 'E9', 'EA', 'EB'] if end_mnem_bytes: targets.insert(0, end_mnem_bytes) ends = {} for target in targets: ea = find_binary_instruction_start(location, idc.SEARCH_DOWN, target, max_location=max_location) if ea <= max_location: ends[target] = ea return [ end + idc.get_item_size(end) for end in (([ ends.get(end_mnem_bytes, None), ends.get('C2', None), ends.get('C3', None) ]) + sorted(ends.get(target, None) for target in targets[-3:])) if end ]
def checkCB(bl): start = bl[0] end = bl[1] ea = start while ea < end: if checkCondition(ea): return ea ea = idc.next_head(ea) return idc.PrevHead(end)
def __extractJpt(self, jptEa): '''return a list of location in function''' addr = list(idautils.DataRefsFrom(jptEa))[0] instruction = idc.GetDisasm(addr).split() opcode = instruction[0] while opcode == 'DCD': self.locations.append(self.__locationToEa(instruction[1])) addr = idc.next_head(addr, idc.BADADDR) instruction = idc.GetDisasm(addr).split() opcode = instruction[0]
def _emit_fnbytes(emit_instr_cb, header, footer, indent, fva=None, warn=True): """Emit function bytes in a format defined by the callback and headers/footers provided. Warns if any instruction operands are not consistent with position-independent code, in which case the user may need to templatize the position-dependent portions. """ fva = fva or idc.here() fva = idc.get_func_attr(fva, idc.FUNCATTR_START) va_end = idc.get_func_attr(fva, idc.FUNCATTR_END) # Operand types observed in position-independent code: optypes_position_independent = set([ ida_ua.o_reg, # 1: General Register (al,ax,es,ds...) ida_ua.o_phrase, # 3: Base + Index ida_ua.o_displ, # 4: Base + Index + Displacement ida_ua.o_imm, # 5: Immediate ida_ua.o_near, # 7: Immediate Near Address ]) # Notably missing because I want to note and handle these if/as they are # encountered: # ida_ua.o_idpspec0 = 8: FPP register # ida_ua.o_idpspec1 = 9: 386 control register # ida_ua.o_idpspec2 = 10: 386 debug register # ida_ua.o_idpspec3 = 11: 386 trace register va = fva nm = idc.get_name(fva) optypes_found = set() s = header.format(name=nm) while va not in (va_end, idc.BADADDR): size = idc.get_item_size(va) the_bytes = idc.get_bytes(va, size) for i in range(0, 8): optype = idc.get_operand_type(va, i) if optype: optypes_found.add(optype) s += indent + emit_instr_cb(va, the_bytes, size) va = idc.next_head(va) s += footer position_dependent = optypes_found - optypes_position_independent if position_dependent: msg = ('This code may have position-dependent operands (optype %s)' % (', '.join([str(o) for o in position_dependent]))) if warn: Warning(msg) else: logger.warn(msg) return s
def __iter__(self): addr = idc.next_head(self.start_ea) prev_a = self.start_ea yield Instr(prev_a, addr - prev_a) for a in idautils.Heads(addr): if a >= self.end_ea: break s = a - prev_a prev_a = a yield Instr(a, s)
def patch(addr): nop = [0x00, 0xBF] # IN LE 00 BF nop in thumb mode (iphone uses thumb code] addr = idc.next_head(addr) mnem = GetMnem(addr) dlsym_result_reg = None if mnem == "MOV": dlsym_result_reg = GetOpnd(addr, 0) print("\t\t %08x: MOV %s, %s" % (addr, GetOpnd(addr, 0), GetOpnd(addr, 1))) while True: addr = idc.next_head(addr) mnem = GetMnem(addr) if mnem == "BLX" and GetOpnd(addr, 0) == dlsym_result_reg: print("\t\t\t %08x: BLX %s" % (addr, GetOpnd(addr, 0))) # patch the code. for i in xrange(len(nop)): PatchByte(addr + i, nop[i]) break
def calSconstants(bl): start = bl[0] end = bl[1] invoke_num = 0 inst_addr = start while inst_addr < end: opcode = idc.print_insn_mnem(inst_addr) if opcode in calls: invoke_num += 1 inst_addr = idc.next_head(inst_addr) return invoke_num
def main(): print("[*] Start Set Color JMP or CALL") for start in idautils.Segments(): ea = start end = idc.get_segm_end(start) while ea < end: ea = idc.next_head(ea, end) op = idc.print_insn_mnem(ea) if (op.find("j") == 0 or op == "call"): set_color(ea, 1, color) print("[*] Finished Set Color JMP or CALL")
def calCalls(bl): calls = {'call':1, 'jal':1, 'jalr':1} start = bl[0] end = bl[1] invoke_num = 0 inst_addr = start while inst_addr < end: opcode = idc.print_insn_mnem(inst_addr) if opcode in calls: invoke_num += 1 inst_addr = idc.next_head(inst_addr) return invoke_num
def calNconstants(bl): start = bl[0] end = bl[1] invoke_num = 0 inst_addr = start while inst_addr < end: optype1 = idc.get_operand_type(inst_addr, 0) optype2 = idc.get_operand_type(inst_addr, 1) if optype1 == 5 or optype2 == 5: invoke_num += 1 inst_addr = idc.next_head(inst_addr) return invoke_num
def extractJpt(jptEa): '''return a list of location in function''' locations = [] addr = list(idautils.DataRefsFrom(jptEa))[0] instruction = idc.GetDisasm(addr).split() opcode = instruction[0] while opcode == 'DCD': locations.append(instruction[1]) addr = idc.next_head(addr, idc.BADADDR) instruction = idc.GetDisasm(addr).split() opcode = instruction[0] print locations
def ptrs(self): for seg_beg in filter(lambda x: getseg(x).type == SEG_DATA, Segments()): seg_end = get_segm_end(seg_beg) head = seg_beg while True: head = next_head(head, seg_end) if head == BADADDR: break head_ptr = Pointer(head) if head_ptr.type.rstrip(" *") == self.name: yield head_ptr
def parse_function(ea): func = ida_funcs.func_t(ea) res = ida_funcs.find_func_bounds(func, ida_funcs.FIND_FUNC_DEFINE) if res == ida_funcs.FIND_FUNC_UNDEF: idc.ask_yn(1, 'can not find func bounds.') exit(0) addr = func.start_ea hit_count = 0 gnm_name = '' packet_count = 0 while addr < func.end_ea: if idc.print_insn_mnem(addr) == 'call': sub_name = idc.print_operand(addr, 0) if 'SetAllocatedNodes@SchedulerProxy' in sub_name: arg_addrs = ida_typeinf.get_arg_addrs(addr) gnm_name_arg_addr = arg_addrs[1] if idc.print_insn_mnem(gnm_name_arg_addr) != 'lea': idc.ask_yn( 1, 'gnm name not passed by lea: {:X}'.format( gnm_name_arg_addr)) exit(0) name_addr = idc.get_operand_value(gnm_name_arg_addr, 1) gnm_name = idc.get_strlit_contents(name_addr).decode('ascii') hit_count += 1 if 'set_packet_count' in sub_name: # we need to manually set set_packet_count function's type (press key Y) # or get_arg_addrs will return None arg_addrs = ida_typeinf.get_arg_addrs(addr) packet_count_arg_addr = arg_addrs[1] packet_count_inst = idc.print_insn_mnem(packet_count_arg_addr) if packet_count_inst == 'mov': op_type = idc.get_operand_type(packet_count_arg_addr, 1) if op_type == idc.o_imm: packet_count = idc.get_operand_value( packet_count_arg_addr, 1) else: packet_count = 0 elif packet_count_inst == 'lea': packet_count = 0 else: idc.ask_yn( 1, 'packet count passed by {} at {:X}'.format( packet_count_inst, packet_count_arg_addr)) exit(0) hit_count += 1 if hit_count == 2: break addr = idc.next_head(addr) return gnm_name, packet_count
def get_func_sequences(ea): funcs_bodylist = {} funcs = get_funcs(ea) for funcname in funcs: if funcname not in funcs_bodylist: funcs_bodylist[funcname] = [] for start, end in funcs[funcname]: inst_addr = start while inst_addr <= end: opcode = idc.print_insn_mnem(inst_addr) funcs_bodylist[funcname].append(opcode) inst_addr = idc.next_head(inst_addr) return funcs_bodylist
def is_nonvoid_ret(self): xrefs = list(idautils.CodeRefsTo(self.addr, 0)) #hueristic 1: check if any of the callers uses value in eax for caller in xrefs: if is_eax_used(idc.next_head(caller)): return FNONVOID #hueristic 2: check if function always set eax before returning if xrefs == [] and self.func_returns(): return FNONVOID if self.func_returns(): return FNONVOIDWARN return FVOID
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine start, end = idc.SelStart(), idc.SelEnd() bs = bin_stream_ida() machine = guess_machine(addr=start) mdis = machine.dis_engine(bs) if start == idc.BADADDR and end == idc.BADADDR: start = idc.ScreenEA() end = idc.next_head(start) # Get next instruction address mdis.dont_dis = [end] asmcfg = mdis.dis_multiblock(start) ira = machine.ira(loc_db=mdis.loc_db) ircfg = ira.new_ircfg_from_asmcfg(asmcfg) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.run_at(ircfg, start) modified = {} for dst, src in sb.modified(init_state=machine.mn.regs.regs_init): modified[dst] = src view = symbolicexec_t() all_views.append(view) if not view.Create(modified, machine, mdis.loc_db, "Symbolic Execution - 0x%x to 0x%x" % (start, idc.prev_head(end))): return view.Show()