def get_disasm(self, start_address, end_address) -> list: result = [] start = int(start_address, 16) end = int(end_address, 16) while start <= end: # https://github.com/idapython/src/blob/master/python/idautils.py#L202 next_start = ida_bytes.next_head(start, ida_ida.cvar.inf.max_ea) result.append(idc.GetDisasm(start)) start = next_start return result
def findFirstGadget(self, eip): if idc.GetDisasm(eip)[:4] == "mov ": if GetOpnd(eip, 0)[0] == "e" and (GetOpnd( eip, 1)[:7] == "(offset" or GetOpnd(eip, 1)[:6] == "offset" or GetOpnd(eip, 1)[-1] == "h"): return True else: return False else: return False
def findSecondGadget(self, eip, reg): if idc.GetDisasm(eip)[:4] == "mov ": if GetOpnd(eip, 0) == reg and (GetOpnd(eip, 1)[:2] == "[e" or GetOpnd(eip, 1)[:-2] == "h]"): return True else: return False else: return False
def GetContentStr(func): fcode = '' funcfc = idaapi.FlowChart(func) for bblock in funcfc: fcode += 'loc_' + hex(bblock.startEA).replace('0x', '').replace( 'L', ':') + '\r\n' for head in idautils.Heads(bblock.startEA, bblock.endEA): fcode += '%s \r\n' % (unicode(idc.GetDisasm(head), errors='replace')) return fcode
def isHighlightedEffective(): ip = idaversion.get_screen_ea() instr = idc.GetDisasm(ip) if '[' in instr: val = instr.split('[', 1)[1].split(']')[0] highlighted = idaversion.getHighlight() if highlighted in val: return True else: return False
def isHighlightedEffective(): ip = idc.ScreenEA() instr = idc.GetDisasm(ip) if '[' in instr: val = instr.split('[', 1)[1].split(']')[0] highlighted = idaapi.get_highlighted_identifier() if highlighted in val: return True else: return False
def parseArgs(self, ref): i = self.trackBackLimit argsToParse = self.func.nargs argv = [] ref_p = ref while (i and argsToParse): insSize, dataSize = self.func.getInstrDataPair(self.func.nargs - argsToParse) if (insSize > self.func.ESCAPE_CODE_BEGIN): argsToParse -= 1 else: if (dataSize > insSize): self.log( 3, "[!!] invalid argument size pair (%d, %d) for arg no: %d" % (insSize, dataSize, self.func.nargs - argsToParse)) raise ref_p = idc.PrevHead(ref_p, 0) if ref_p == BADADDR: break disstr = idc.GetDisasm(ref_p) if disstr.startswith( self.func.argPassMech) and (idc.ItemSize(ref_p) == insSize): arVal = self.getDataValue(ref_p + insSize - dataSize, dataSize) argv.append(arVal) self.log(4, "Arg found: (0x%x)" % arVal) argsToParse -= 1 if not argsToParse: break 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(argv) > 0: self.log( 4, "[-] Adding args for call at 0x%x->%s" % (ref, repr(argv))) self.params[ref] = argv
def test_printf(ea): args = walk_stack(ea, 1) trace = trace_arg(args[0][0]) arg = idc.GetDisasm(trace).split(',')[1].strip() arg_dict = {} arg_dict['format'] = arg if "esp" in arg: return True, hex(ea), arg_dict else: return False, hex(ea), arg_dict
def has_all_vtable_functions_named(vtable_ea): # type: (int) -> bool ea = vtable_ea while True: function_ea = struct.unpack('<Q', idaapi.get_many_bytes(ea, 8))[0] if '__cxa_pure_virtual' not in idc.GetDisasm(function_ea) and not idaapi.is_func(idaapi.get_flags(function_ea)): break current_name = idc.GetFunctionName(function_ea) if current_name.startswith('sub_') or current_name.startswith('j_sub_'): return False ea += 8 return True
def __PltResolver(jmprel, strtab, symtab, pltgot): seg_sec = idc.selector_by_name('.plt.sec') sec_start = idc.get_segm_by_sel(seg_sec) sec_end = idc.get_segm_end(sec_start) if sec_start == idaapi.BADADDR: print("[-] can't find .plt.sec segment") return idx = 0 while True: r_off = idc.get_wide_dword(jmprel + 0x8 * idx) r_info1 = idc.get_wide_byte(jmprel + 0x8 * idx + 0x4) r_info2 = idc.get_wide_byte(jmprel + 0x8 * idx + 0x5) if r_off > 0x7fffffff: return if r_info1 == 7: st_name = idc.get_wide_dword(symtab + r_info2 * 0x10) name = idc.get_strlit_contents(strtab + st_name) # rename got idc.set_name(r_off, name.decode("ascii") + '_ptr') plt_func = idc.get_wide_dword(r_off) # rename plt idc.set_name(plt_func, 'j_' + name.decode("ascii")) SetFuncFlags(plt_func) # rename plt.sec for addr in idautils.DataRefsTo(r_off): plt_sec_func = idaapi.get_func(addr) if plt_sec_func: plt_sec_func_addr = plt_sec_func.start_ea idc.set_name(plt_sec_func_addr, '_' + name.decode("ascii")) SetFuncFlags(plt_sec_func_addr) else: print("[!] idaapi.get_func({}) failed".format( hex(addr))) got_off = r_off - pltgot target = '+{}h'.format( hex(got_off).lower().replace('0x', '').replace('l', '').rjust(2, '0')) for func_ea in idautils.Functions(sec_start, sec_end): func = idaapi.get_func(func_ea) cur = func.start_ea end = func.endEA find = False while cur <= end: code = idc.GetDisasm(cur).lower().replace(' ', '') if target in code: find = True break cur = idc.NextHead(cur, end) if find: idc.set_name(func_ea, '_' + name) SetFuncFlags(func_ea) idx += 1
def is_stdcall(normalized_cfg): for bb in normalized_cfg: # Get the last instruction instructions = get_bb_instructions(bb.bb) if not len(instructions): print "codegraph::is_stdcall Failed to get instructions from bb [%x : %x] skipping" % (bb.bb.startEA, bb.bb.endEA) continue last_ins = instructions[-1] if idc.GetMnem(last_ins) == "retn": return len(idc.GetDisasm(last_ins).split()) > 1
def Get_Code_List(ea, code_list, os_len): if os_len == 8: flag = 1 j_flag = 1 while (flag == 1 and j_flag == 1): code = idc.GetDisasm(ea) # print(code) code_list.append(str(hex(ea)) + "##" + code) if "retn" in code: break if "jmp null" in code: break x_code = code[0:3] if "jmp" == x_code or "cal" == x_code: j_flag = 0 fun_addr = "0x" + code.split("_")[1] ea = int(fun_addr[0:18], 16) Get_Code_List(ea, code_list, os_len) ea = idc.NextHead(ea) elif os_len == 4: flag = 1 j_flag = 1 while (flag == 1 and j_flag == 1): code = idc.GetDisasm(ea) code_list.append(str(hex(ea)) + "##" + code) if "retn" in code: break if "jmp null" in code: break x_code = code[0:3] if "jmp" == x_code or "cal" == x_code: j_flag = 0 if "nullsub" in code: break elif "_" in code: fun_addr = "0x" + code.split("_")[1] ea = int(fun_addr[0:10], 16) Get_Code_List(ea, code_list, os_len) else: print("!!!!!Get Code Error!!!!!") ea = idc.NextHead(ea)
def visit_minsn(self): # we only care about external (unsupported) instructions if self.curins.opcode != ida_hexrays.m_ext: return 0 ins_text = idc.GetDisasm(self.curins.ea) ins_op = ins_text.split(" ")[0] print("- 0x%08X: UNSUPPORTED %s" % (self.curins.ea, ins_text)) self.found.add(ins_op) return 0
def getOrigDisasm(self): # type: () -> str """ Gets the original disassembly without any further applied transformations However, the formatting is different from the original and is more convenient for parsing :return: the disassembly """ flags = idc.GetFlags(self.ea) if idc.isStruct(flags): disasm = "INVALID" elif idc.isAlign(flags): disasm = idc.GetDisasm(self.ea) elif idc.isData(flags): disasm = self._getDataDisasm(self.ea) else: disasm = idc.GetDisasm(self.ea) disasm = self._filterComments(disasm) while ' ' in disasm: disasm = disasm.replace(' ', ' ') return disasm
def map_shared_bridges(dsc_file, adrfind): """ finds branch islands in a given dyld_shared_cache file, maps them to IDA's db and extract its addresses """ dsc_file.seek(0, 2) filesize = dsc_file.tell() dsc_file.seek(0) ACCESS_READ = 1 a = mmap.mmap(dsc_file.fileno(), length=filesize, access=ACCESS_READ) reexp = re.compile( "\xcf\xfa\xed\xfe.{340,360}dyld_shared_cache_branch_islands") print "[+] scanning dsc for BRANCH ISLANDS" # this list will hold all our branch_islands segments branch_islands_segments = [] jmp_to_code = collections.defaultdict(list) for ma in reexp.finditer(a): print "[+] WRITING BRANCH ISLAND: 0x%08X" % (ma.start()) fif = FileInFile(dsc_file, ma.start()) m = MachO_patched(fif) if _IN_IDA: for seg in m.segments: for sec in seg.sections: idc.AddSegEx(sec.addr, sec.addr + sec.size, 0, 0, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_FILLGAP) name = "branch_islands_%X%s%s" % (ma.start(), seg.segname, sec.sectname) idc.RenameSeg(sec.addr, name) idc.SetSegClass(sec.addr, "CODE") idc.SetSegAddressing(sec.addr, 2) dsc_file.seek(sec.offset) memcpy(sec.addr, dsc_file.read(sec.size)) branch_islands_segments.append(sec.addr) # make code codeea = sec.addr print "Going through the code!" while codeea < (sec.addr + sec.size): res = idc.MakeCode(codeea) if not res: print "[!] EA:0x%X ERR while making code" % codeea codeea += 4 continue d = idc.GetDisasm(codeea) # if it's a "B 0x4dd13550" if d.startswith("B "): addr = d.split()[1] if addr.startswith("0x"): branchaddr = int(addr, 16) jmp_to_code[branchaddr].append(codeea) # idc.MakeRptCmt(codeea, "0x%X was taken!" % branchaddr) codeea = idc.FindUnexplored(codeea, idc.SEARCH_DOWN) label_and_fix_branch_islands(dsc_file, adrfind, jmp_to_code)
def find_loc(self, addr): opcode = idc.GetMnem(addr) operand0 = idc.print_operand( addr, 0 ) # when instruction has only 1 argument, it oprand[1] = oprand[0] operand1 = idc.print_operand(addr, 1) operand2 = idc.print_operand(addr, 2) if opcode == 'ADR': if self.jptRe.match(operand1): code = idc.GetDisasm(addr) print(str(hex(addr)) + ' ' + str(code)) return
def get_vtable_line(ea, stop_ea=None, ignore_list=None, pure_virtual_name=None): if ignore_list is None: ignore_list = [] func_ea = utils.get_ptr(ea) if not utils.is_func_start(func_ea): return None, 0 if stop_ea is not None and ea >= stop_ea: return None, 0 is_pure_func = pure_virtual_name is not None and idc.GetDisasm(ea).endswith(pure_virtual_name) if func_ea in ignore_list and not is_pure_func: return None, 0 return func_ea, ea + utils.WORD_LEN
def getGadget(self, eip, ep, flow): #under IDA 7.4 #return dict({ 'flow' : flow,'entrypoint' :ep, 'addr': eip, 'gadget': idc.GetDisasm(eip), 'reg': GetOpnd(eip,0), 'const': get_operand_value(eip,1)}) #over IDA 7.4 return dict({ 'flow': flow, 'entrypoint': ep, 'addr': eip, 'gadget': idc.GetDisasm(eip), 'reg': idc.print_operand(eip, 0), 'const': get_operand_value(eip, 1) })
def functionTracer(self, addr, debug = False): idx = 0 depth = self.depth result = [] ep = addr while idx < depth: idx = idx + 1 if debug is True: print( '{0} {1} {2} {3}'.format(idx, hex(addr), idc.GetDisasm(addr), hex(get_operand_value(addr,0)) )) if idc.GetDisasm(addr)[:4] == "retn": break elif idc.GetDisasm(addr)[:3] == "jmp" or idc.GetDisasm(addr)[:4] == "call": #print get_operand_value(addr,0) addr = get_operand_value(addr,0) elif self.findFirstGadget(addr) == True: if len(result) > 0: result = [] result.append(self.getGadget(addr, ep, 1)) addr = idc.NextHead(addr) elif len(result) == 1 and self.findSecondGadget(addr, result[0]['reg']) == True: #input gadget result.append(self.getGadget(addr,ep, 2)) addr = idc.NextHead(addr) elif len(result) == 2 and self.findThirdGadget(addr, result[0]['reg']) == True: result.append(self.getGadget(addr,ep, 3)) addr = idc.NextHead(addr) else: addr = idc.NextHead(addr) if len(result) == 3: return result else: return False
def find_unusual_xors(functions): # TODO find xors in tight loops candidate_functions = [] for fva in functions: cva = fva while cva != idaapi.BADADDR and cva < idc.FindFuncEnd(fva): if idc.GetMnem(cva) == "xor": if idc.GetOpnd(cva, 0) != idc.GetOpnd(cva, 1): g_logger.debug( "suspicious XOR instruction at 0x%08X in function 0x%08X: %s", cva, fva, idc.GetDisasm(cva)) ph = idc.PrevHead(cva) nh = idc.NextHead(cva) ip = idc.GetDisasm(ph) ia = idc.GetDisasm(nh) if ip and ia: g_logger.debug("Instructions: %s; %s; %s", ip, idc.GetDisasm(cva), ia) if ph or nh: if is_security_cookie(cva, ph, nh): g_logger.debug( "XOR related to security cookie: %s", idc.GetDisasm(cva)) else: g_logger.debug("unusual XOR: %s", idc.GetDisasm(cva)) candidate_functions.append(fva) break cva = idc.NextHead(cva) return candidate_functions
def taintStop(self): Print("Taint Stop pressed!") #Remove the stopping breakpoint if self.taintStop is not None: idc.DelBpt(self.taintStop) #Add a new stopping breakpoint self.taintStop = idc.here() Print( idc.GetDisasm(self.taintStop) ) idc.AddBpt(self.taintStop) idc.SetBptAttr(self.taintStop, idc.BPT_BRK, 0) idc.SetBptCnd(self.taintStop, "interactivemodeCallback.stopTrace()")
def disasm(start, end): head = start l = [] while head < end: if isCode(GetFlags(head)): OpHex(head, 0) OpHex(head, 1) dis = idc.GetDisasm(head) l.append(dis) head = idc.NextHead(head, 0x7fffffff) dis = "\n".join(l) return dis
def findSecondDummyGadget(self, eip, reg): if idc.GetDisasm(eip)[:4] == "lea ": #under IDA 7.4 #if GetOpnd(eip,0) == reg and GetOpnd(eip,1)[1:4] == reg and GetOpnd(eip,1)[-3:] == "+1]": #over IDA 7.4 if idc.print_operand(eip, 0) == reg and idc.print_operand( eip, 1)[1:4] == reg and idc.print_operand(eip, 1)[-3:] == "+1]": return True else: return False else: return False
def mark_instruction(ea): ori_commt = idc.GetDisasm(ea) if '|' in ori_commt: # be handled by this python script before ori_commt = ori_commt.split('|')[-1] elif ';' in ori_commt: ori_commt = ori_commt.split(';')[-1] else: ori_commt = '' commt = '(%s, %s), (%s, %s) |%s' % (opertype[idc.GetOpType( ea, 0)], idc.GetOperandValue(ea, 0), opertype[idc.GetOpType( ea, 1)], idc.GetOperandValue(ea, 1), ori_commt) idc.MakeComm(ea, commt)
def get_syms_to_find(): sym_addr = idc.LocByName('find_sym') mp = {} for xref in idautils.XrefsTo(sym_addr): addr = xref.frm prelude = addr - 0x5 mnemonic = idc.GetDisasm(prelude) func_addr = idc.GetFunctionAttr(addr, idc.FUNCATTR_START) print(addr, prelude, mnemonic) cst = int(re.search(', ([0-9A-F]+)h', mnemonic).group(1), 16) mp[cst] = func_addr print(mp) return mp
def findThirdDummyGadget(self, eip, reg): if idc.GetDisasm(eip)[:4] == "mov ": #under IDA 7.4 #if GetOpnd(eip,0)[:5] == "[esp+" and GetOpnd(eip,1) == reg: #over IDA 7.4 if idc.print_operand(eip, 0)[:5] == "[esp+" and idc.print_operand( eip, 1) == reg: return True else: return False else: return False
def renameDword(self): proc_addr = self._import_table.item(self._import_table.currentRow(), 3).text() proc_name = str(self._import_table.item(self._import_table.currentRow(), 2).text()) renamed = 0 if proc_addr: try: proc_addr = int(proc_addr, 16) proc_bin_str = " ".join([x.encode("hex") for x in struct.pack("<I", proc_addr)]) next_dword = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) while next_dword != idc.BADADDR: log.debug("Trying to fix-up 0x{:08x}".format(next_dword)) # DWORDs can be "inaccessible" for many reasons and it requires "breaking up" the data blobs # and manually fixing them # Reason 1: In a dword array in an unknown section if idc.isUnknown(next_dword): idc.MakeUnkn(next_dword, idc.DOUNK_EXPAND) idc.MakeDword(next_dword) # Reason 2: In a dword array in a data section elif idc.isData(next_dword): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Reason 3: In a dword array in a code section (validate via "dd <dword>,") elif idc.isCode(next_dword) and idc.GetDisasm(next_dword).startswith("dd "): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Only perform if idc.Name(next_dword).startswith(("off_", "dword_")) or idc.Name(next_dword) == "": success = idc.MakeNameEx(next_dword, proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i = 0 new_proc_name = proc_name while not success and i < 10: new_proc_name = "{}{}".format(proc_name, i) success = idc.MakeNameEx(next_dword, new_proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i += 1 if success: renamed += 1 item = self._import_table.item(self._import_table.currentRow(), 5) item.setText("{}, {}".format(str(item.text()), new_proc_name)) log.debug("DWORD @ 0x{:08x} now has name {}".format(next_dword, new_proc_name)) else: log.error("Unable to auto-rename successfully, terminating search") break else: log.debug("Value at 0x{:08x} does not meet renaming requirements".format(next_dword)) next_dword = idc.FindBinary(next_dword+4, idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) except Exception, e: log.error("Error encountered: {}".format(e)) log.debug("Renamed {:d} instances of {}".format(renamed, proc_name))
def decompile(ea): ea = idaapi.get_func(ea).startEA rpb_in = -1 name = function_name(GetFunctionName(ea)) emit(".global {}".format(name)) emit("{}:".format(name)) for (startea, endea) in Chunks(ea): for addr in Heads(startea, endea): # Display a comment for easier debugging emit("// 0x{:08X}".format(addr)) # If we've reached rpe of current repeat/erepeat, we will jump back to rpb in 2 instructions if addr == rpe: rpb_in = 2 insn = idautils.DecodeInstruction(addr) # print "0x{:X}".format(addr), insn, hex(insn.itype) code = insn.itype output.append(Loc(addr)) if code in codegen: try: codegen[code](insn) except: print("Errored at 0x{:08X}!".format(addr)) raise else: dis = idc.GetDisasm(addr) print("at 0x{:08X}: unknown instruction code={:3}, disasm={}". format(addr, code, dis)) emit("BRK #0") # If there's a jump to rpb pending, decrease its counter... if rpb_in > 0: rpb_in -= 1 # If we need to jump to rpb, go ahead and do that! if rpb_in == 0: rpb_in = -1 if is_erepeat: emit("// erepeat -> 0x{:08X}".format(rpb)) emit("B {}".format(use_loc(rpb))) else: emit("// repeat -> 0x{:08X}".format(rpb)) emit("SUBS {0}, {0}, #1".format(g_arm_rpc_reg)) emit("BNE {}".format(use_loc(rpb)))
def updateDataWatch(self): print("in updateDataWatch") #self.Close() #self.Create() #print('did create') retval = [] self.ClearLines() #self.Refresh() print('did refresh of clear') command = '@cgc.getWatchMarks()' simicsString = gdbProt.Evalx('SendGDBMonitor("%s");' % command) if type(simicsString) is int: print('updateStackTrace got an int? %d' % simicsString) return if simicsString.startswith('None'): simicsString = simicsString[5:] try: data_json = json.loads(simicsString) except: print('could not get json from %s' % simicsString) return index = 0 for entry in data_json: instruct = idc.GetDisasm(entry['ip']) uline = '%3d 0x%08x 0x%08x %s' % (index, entry['ip'], entry['cycle'], entry['msg']) line = uline.encode('ascii', 'replace') #print('do %s' % line) if 'return from' in str(line): cline = idaapi.COLSTR(str(line), idaapi.SCOLOR_DREF) elif 'closed FD' in str(line): cline = idaapi.COLSTR(str(line), idaapi.SCOLOR_DREF) else: cline = str(line) #print("added %s" % line) retval.append(str(line)) self.AddLine(cline) index += 1 self.Refresh() command = '@cgc.nextWatchMark()' simicsString = gdbProt.Evalx('SendGDBMonitor("%s");' % command) try: index = int(simicsString) except: print('%s' % simicsString) return self.Jump(index) #self.Show() return retval
def hook_code(uc, address, size, user_data): instruction = uc.mem_read(address, size) if instruction == b'\xc3': uc.emu_stop() if address == 0: uc.emu_stop() if address != 0 and address != IMAGE_BASE: idc.set_color(address, idc.CIC_ITEM, 0xFFB6C1) if DEBUG: _code = idc.GetDisasm(address) print("0x%016x \t%s" % (address, _code))