def search_retns(self): if not self.debug: print("found %d modules" % len(self.modules)) for m in self.modules: # Iterate over segments in the module # BUG: Iterating over all loaded segments is more stable than looking up by address if not self.debug: print("found %d segments" % idaapi.get_segm_qty()) for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) # Locate executable segments in a selected modules # NOTE: Each module may have multiple executable segments if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size): # If the debugger is attached then we can check if the segment is executable, else # just check if it is code or not. if idaapi.dbg_can_query() and idaapi.get_process_state() < 0: if seg.perm & idaapi.SEGPERM_EXEC == 0: continue elif seg.type & idaapi.SEG_CODE == 0: continue ####################################################### # Search for ROP gadgets if self.searchRop: #Search all instances of BLR ea = seg.startEA while True: ea = idaapi.find_binary(ea + 1, seg.endEA, "4E 80 00 20", 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break self.retns.append((ea, m.file)) # Search all instances of BTCTR ea = seg.startEA while True: ea = idaapi.find_binary(ea + 1, seg.endEA, "4E 80 04 20", 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break self.retns.append((ea, m.file)) # Search all instances of BTCTRL ea = seg.startEA while True: ea = idaapi.find_binary(ea + 1, seg.endEA, "4E 80 04 21", 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break self.retns.append((ea, m.file))
def PopulateTree(self): self.tree.clear() executable_segments = [(idc.SegName(idaapi.getnseg(x).startEA), 0!=(idaapi.getnseg(x).perm & idaapi.SEGPERM_EXEC)) for x in range(idaapi.get_segm_qty())] for segment in executable_segments: if not segment[1]: continue caves = self.findCodeCavez(segment[0]) for cave in caves: self.addEntryToTree(segment[0], cave[0], cave[1])
def __init__(self): self.sym_file_path = idc.AskFile(0, "*.map;*.txt", "open symbol file") self.sym_file = None self.seg = idaapi.get_segm_by_name(".text") if self.seg is None: self.seg = idaapi.getnseg(0) self.base = self.seg.startEA
def __init__(self, ea=UseCurrentAddress, name=None, index=None): """Wrapper around IDA segments. There are 3 ways to get a segment - by name, ea or index. Only use one. Args: ea - address in the segment name - name of the segment index - index of the segment """ if sum((ea not in (self.UseCurrentAddress, None), name is not None, index is not None,)) > 1: raise ValueError( "Expected only one (ea, name or index). Got (ea={!r}, name={!r}, index={!r})".format(ea, name, index)) elif name is not None: seg = idaapi.get_segm_by_name(name) elif index is not None: seg = idaapi.getnseg(index) elif ea == self.UseCurrentAddress: seg = idaapi.getseg(idc.here()) elif ea is None: raise ValueError("`None` is not a valid address. To use the current screen ea, " "use `Function(ea=Function.UseCurrentAddress)` or supply no `ea`.") else: seg = idaapi.getseg(ea) self._segment = seg
def processDataSegments(M, new_eas): for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) ea = seg.startEA segtype = idc.GetSegmentAttr(ea, idc.SEGATTR_TYPE) if segtype in [idc.SEG_DATA, idc.SEG_BSS]: start = idc.SegStart(ea) end = idc.SegEnd(ea) addDataSegment(M, start, end, new_eas)
def search_binary(binary_string): for i in range(idaapi.get_segm_qty()): segm = idaapi.getnseg(i) current_ea = segm.startEA while True: current_ea = idaapi.find_binary(current_ea + 1, segm.endEA, binary_string, 16, idaapi.SEARCH_DOWN) if current_ea == idaapi.BADADDR: break return current_ea return 0
def AnalyzeAllSections( self ): BlockData = {} Map = [] CurrentAddress = idc.MinEA() i = 0 while i < idaapi.get_segm_qty(): seg = idaapi.getnseg( i ) self.AnalyzeRange( seg.startEA, seg.endEA ) i+=1
def Segments(): """ Get list of segments (sections) in the binary image @return: List of segment start addresses. """ for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) if seg: yield seg.startEA
def get_padded_bytes(self, count): result = "\x00" * count ranges_left = [MemoryRange(self.address, self.address + count)] segment_count = idaapi.get_segm_qty() valid_memory_ranges = [] for i in range(segment_count): segment = idaapi.getnseg(i) # Skip segments with unstable data if segment.type == idaapi.SEG_XTRN: continue valid_memory_ranges.append( MemoryRange(segment.startEA, segment.endEA)) while len(ranges_left) > 0: # Get a requested memory range and remove it from the list current_range = ranges_left.pop() intersection = None for memory_range in valid_memory_ranges: start = max(current_range.start, memory_range.start) end = min(current_range.end, memory_range.end) if end > start: intersection = MemoryRange(start, end) break # No segment can satisfy any part of requested range if intersection is None: continue chunk = idc.GetManyBytes( intersection.start, intersection.end - intersection.start) if chunk is None: print('[librgb] Some bytes are unreadable in %s..%s' % ( idc.atoa(intersection.start), idc.atoa(intersection.end))) continue result = \ result[0:intersection.start - self.address] \ + chunk \ + result[intersection.end - self.address:] assert(len(result) == count) # If necessary, enqueue ranges unsatisfied by chosen mem segment range1 = MemoryRange(current_range.start, intersection.start) range2 = MemoryRange(intersection.end, current_range.end) if range1.length > 0: ranges_left.append(range1) if range2.length > 0: ranges_left.append(range2) assert(len(result) == count) return result
def get_functions_ida(): #Repeat for list of segments for n in xrange(idaapi.get_segm_qty()): #Get number of segments seg = idaapi.getnseg(n) if seg: #Get list of functions in that segment funcs=idautils.Functions(seg.startEA, seg.endEA) for funcname in funcs: name = GetFunctionName(funcname) print name
def rename_functions_ida(): # Repeat for list of segments for n in xrange(idaapi.get_segm_qty()): # Get number of segments seg = idaapi.getnseg(n) if seg: # Get list of functions in that segment funcs = idautils.Functions(seg.startEA, seg.endEA) for funcaddress in funcs: name = GetFunctionName(funcaddress) if name in functions_in_library: MakeNameEx(funcaddress, "glibc_" + name, SN_NOWARN)
def code_segments_iter(): """Iterates over the possible code sections within an input binary.""" for i in range(idaapi.get_segm_qty()): seg = idaapi.getnseg(i) if not seg: continue seg_class = idaapi.get_segm_class(seg) if seg_class != "CODE": continue seg_name = idaapi.get_segm_name(seg.startEA) yield seg.startEA, seg.endEA, seg_name
def rename_functions_ida(func_library_map): print func_library_map.keys() #Repeat for list of segments for n in xrange(idaapi.get_segm_qty()): #Get number of segments seg = idaapi.getnseg(n) if seg: #Get list of functions in that segment funcs=idautils.Functions(seg.startEA, seg.endEA) for funcaddress in funcs: name=GetFunctionName(funcaddress) if func_library_map.has_key(name): MakeNameEx(funcaddress,func_library_map[name][1:]+"_"+name,SN_NOWARN)
def rename_functions_ida(): #Get number of segments seg = idaapi.getnseg(0) if seg: #Get list of functions in that segment funcs = idautils.Functions(seg.startEA, seg.endEA) for funcaddress in funcs: f_name = GetFunctionName(funcaddress) if f_name == 'giant_keyloggercase_structure': for address in Heads(funcaddress, FindFuncEnd(funcaddress)): if GetMnem(address) == 'call': t1 = GetOpnd(address, 0) if t1.startswith('sub_'): t2 = t1.split('_') MakeNameEx(int(t2[1], 16), "keylog_charbychar_" + t2[1], SN_NOWARN)
def get_segments_info(seg_names=default_seg_names): res = {} for name in seg_names: seg = idaapi.get_segm_by_name(name) if not seg: continue res[name] = {} res[name]['startEA'] = seg.startEA for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) for name, d in res.items(): if d['startEA'] == seg.startEA: res[name][ 'ID'] = seg.name # this is an ID, not a name, kthx IDA :( res[name]['endEA'] = seg.endEA return res
def tag_functions(): seg = idaapi.getnseg(0) min = seg.start_ea max = seg.end_ea if min > 0: min = min - 1 curaddr = ida_search.find_not_func(min, SEARCH_DOWN) while curaddr < max: idc.create_insn(curaddr) line_asm = idc.generate_disasm_line(curaddr, 0) ## If you need to bypass the padding instructions, use this: # if "se_or" in line_asm: # curaddr = curaddr + 2 if ida_funcs.add_func(curaddr) != True: idc.create_insn(curaddr) curaddr = ida_search.find_not_func(curaddr, SEARCH_DOWN)
def __init__(self, ea=UseCurrentAddress, name=None, index=None, segment_t=None): """Wrapper around IDA segments. There are 3 ways to get a segment - by name, ea or index. Only use one. Args: ea - address in the segment name - name of the segment index - index of the segment """ if sum(( ea not in (self.UseCurrentAddress, None), name is not None, index is not None, segment_t is not None, )) > 1: raise ValueError( ("Expected only one (ea, name, index or segment_t)." " Got (ea={!r}, name={!r}, index={!r}, segment_t={!r})" ).format(ea, name, index, segment_t)) elif segment_t is not None: seg = segment_t elif name is not None: seg = idaapi.get_segm_by_name(name) elif index is not None: seg = idaapi.getnseg(index) elif ea == self.UseCurrentAddress: seg = idaapi.getseg(idc.here()) elif ea is None: raise ValueError( "`None` is not a valid address. To use the current screen ea, " "use `Function(ea=Function.UseCurrentAddress)` or supply no `ea`." ) else: seg = idaapi.getseg(ea) self._segment = seg
def Segments(): """ Get list of segments (sections) in the binary image @return: List of segment start addresses. """ seglist = [] for n in range(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) if not seg: break else: seglist.append(seg.startEA) return seglist
def processpltSegs(): funcdata = {} datafunc = {} for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) ea = seg.startEA segname = idc.get_segm_name(ea) #SegName(ea) if segname in ['.plt', 'extern', '.MIPS.stubs']: start = seg.startEA end = seg.endEA cur = start while cur < end: name = get_unified_funcname(cur) funcdata[name] = hex(cur) datafunc[cur] = name cur = idc.next_head(cur) return funcdata, datafunc
def analyze_qwords(): # Get kernel boundaries kernel_start = BADADDR kernel_stop = 0x0 seg_count = 0 for ea in Segments(): seg_count += 1 kernel_start = min(kernel_start, SegStart(ea)) kernel_stop = max(kernel_stop, SegEnd(ea)) # Transform every potential kernel pointer to a qword for i in range(seg_count): seg = idaapi.getnseg(i) for ea in range(seg.startEA, seg.endEA, 8): if get_item_size(ea) >= 8: continue value = get_qword(ea) if kernel_start <= value < kernel_stop: create_qword(ea)
def analyze_qwords(): # Get user boundaries user_start = BADADDR user_stop = 0x0 seg_count = 0 for ea in Segments(): seg_count += 1 user_start = min(user_start, SegStart(ea)) user_stop = max(user_stop, SegEnd(ea)) # Transform every potential user pointer to a qword for i in range(seg_count): seg = idaapi.getnseg(i) for ea in range(seg.startEA, seg.endEA, 8): if get_item_size(ea) >= 8: continue value = get_qword(ea) if user_start <= value < user_stop: create_qword(ea)
def get_extrn_funcs(): exfunclist = [] for n in xrange(idaapi.get_segm_qty()): print n seg = idaapi.getnseg(n) start = seg.startEA segname = idc.SegName(start) if segname == 'extern': cur = start end = seg.endEA while cur <= end: externfunc = GetFunctionName(cur) if '@' in externfunc: externfunc = externfunc.split('@')[0] exfunclist.append(externfunc) else: exfunclist.append(externfunc) cur = NextHead(cur) return exfunclist
def analyze_qwords(): # Get kernel boundaries kernel_start = NOT_FOUND kernel_stop = 0x0 seg_count = 0 for ea in Segments(): seg_count += 1 kernel_start = min(kernel_start, SegStart(ea)) kernel_stop = max(kernel_stop, SegEnd(ea)) # Transform every potential kernel pointer to a qword for i in range(seg_count): seg = idaapi.getnseg(i) for ea in range(seg.startEA, seg.endEA, 8): if get_item_size(ea) >= 8: continue value = get_qword(ea) if kernel_start <= value < kernel_stop: create_qword(ea)
def tag_code(): seg = idaapi.getnseg(0) min = seg.start_ea max = seg.end_ea if min > 0: min = min - 1 curaddr = ida_search.find_unknown(min, idc.SEARCH_DOWN) while curaddr < max: idc.create_insn(curaddr) line_asm = idc.generate_disasm_line(curaddr, 0) ## If you need to bypass the padding instructions, use this: # if "se_or" in line_asm: # curaddr = curaddr + 2 if ida_funcs.add_func(curaddr) != True: idc.create_insn(curaddr) curaddr = ida_search.find_unknown(curaddr, idc.SEARCH_DOWN) print("Waiting for auto-analysis to finish") ida_auto.auto_wait() save_functions() print("Done.")
def get_segments_info(): # Note this must match the list of segments in the current file seg_names = [".init", ".plt", ".text", ".fini", ".rodata", ".eh_frame_hdr", "eh_frame", ".gcc_except_table", ".tdata", ".ctors", ".dtors", ".jcr", ".got", ".got.plt", ".data", "freq_data_section", ".bss", "extern", "abs", ".rdata"] res = {} for name in seg_names: seg = idaapi.get_segm_by_name(name) if not seg: continue res[name] = {} res[name]['startEA'] = seg.startEA for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) for name,d in res.items(): if d['startEA'] == seg.startEA: res[name]['ID'] = seg.name # this is an ID, not a name, kthx IDA :( res[name]['endEA'] = seg.endEA return res
def search_for_vuln_api(): #Repeat for list of segments for n in xrange(idaapi.get_segm_qty()): #Get number of segments seg = idaapi.getnseg(n) if seg: #Get list of functions in that segment funcs=idautils.Functions(seg.startEA, seg.endEA) #Search for vuln functions inside binary and print occurences to output file. This is NOT to be directly reported; perform manual analysis before doing so. if funcs: for name in funcs: each_function_disassembly = list(idautils.FuncItems(name)) for e in each_function_disassembly: for vulnfunc in vuln_function_list: pattern=vulnfunc+r'$' m=re.search(pattern,idc.GetDisasm(e)) if m: f.write(idc.GetFuncOffset(e)+' --> '+idc.GetDisasm(e)+'\n\n') else: f.write('Failed to get function names and hence cannot parse stuff\n')
def get_sreg_base_x64(name): sdb = idaapi.dbg_get_thread_sreg_base(idc.GetCurrentThreadId(), int(getattr(cpu, name))) if not sdb: for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) sgname = idaapi.get_segm_name(seg, 0) if sgname.startswith('TIB['): _sdb = seg.startEA + 0x1000 sdb_self = int( base64.b16encode( idaapi.dbg_read_memory(_sdb + 0x30, 8)[::-1]), 16) if (sdb_self == _sdb): sdb = _sdb print("\nwarning: the segname:%s is zero,I give %016x" % (name, sdb)) break if not sdb: print( "\n\nwarning: the segname:%s is zero, U need set it by yourself\n" % (name)) return sdb
def search_for_vuln_api(): #Repeat for list of segments for n in xrange(idaapi.get_segm_qty()): #Get number of segments seg = idaapi.getnseg(n) if seg: #Get list of functions in that segment funcs = idautils.Functions(seg.startEA, seg.endEA) #Search for vuln functions inside binary and print occurences to output file. This is NOT to be directly reported; perform manual analysis before doing so. if funcs: for name in funcs: each_function_disassembly = list(idautils.FuncItems(name)) for e in each_function_disassembly: for vulnfunc in vuln_function_list: pattern = vulnfunc + r'$' m = re.search(pattern, idc.GetDisasm(e)) if m: f.write( idc.GetFuncOffset(e) + ' --> ' + idc.GetDisasm(e) + '\n\n') else: f.write( 'Failed to get function names and hence cannot parse stuff\n' )
def analyze_code(): seg = idaapi.getnseg(0) for ea in range(seg.startEA, seg.endEA, 1): MakeCode(ea)
def iterate(): '''Iterate through each segment_t defined in the database''' for n in xrange(idaapi.get_segm_qty()): yield idaapi.getnseg(n) return
def writeMem(self, binfile): regs = self.getRegs() segm = self.init_segm_mem() idaapi.refresh_debugger_memory() print( "+-------------------+----------------------+--------------------+----------+--------+" ) print( "| segment | VA | size | flag | status |" ) print( "+-------------------+----------------------+--------------------+----------+--------+" ) for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) if seg: name = Dump.getSegName(seg, segm) address = seg.startEA length = seg.endEA - seg.startEA db_data = idaapi.dbg_read_memory(address, length) print("| %-17s | %18x | %8x -> %5dkb| %2d | " % (name, address, length, length / 1024, seg.flags), end="") if db_data: segm[name] = [address, length, db_data] print('ok |') length = len(db_data) segm[name] = [address, length, db_data] else: if (length >= 0x400): print( "war |\n+-------------------+----------------------+--------------------+----------+--------+" ) data = Dump.getDbgMemPage(address, length) data.append([b"", 0, 0]) is_unmap = False tmp = b'' begin = address fbegin = address fsize = 0 for i, d in enumerate(data): db, ea, size = d if is_unmap: if db: # 0 1 is_unmap = False begin = ea tmp = db print( "| %-17s | %18x | %8x -> %5dkb| %2d | faild |" % (name, fbegin, fsize, fsize / 1024, seg.flags)) else: # 0 0 fsize += size if (i == len(data) - 1): print( "| %-17s | %18x | %8x -> %5dkb| %2d | faild |" % (name, fbegin, fsize, fsize / 1024, seg.flags)) pass else: if db: # 1 1 is_unmap = False tmp += db else: # 1 0 fbegin = ea fsize = size is_unmap = True if tmp: name = Dump.getSegName(seg, segm) segm[name] = [begin, len(tmp), tmp] print( "| %-17s | %18x | %8x -> %5dkb| %2d | ok |" % (name, begin, len(tmp), len(tmp) / 1024, seg.flags)) else: print( "| %-17s | %18x | %8x -> %5dkb| %2d | faild |" % (name, fbegin, fsize, fsize / 1024, seg.flags)) break print( "+-------------------+----------------------+--------------------+----------+--------+" ) else: print(' faild') continue print( "+-------------------+----------------------+--------------------+----------+--------+" ) # GetBptQty() GetBptEA(n): nameoffset_p = 0 dataoffset_p = 0 all_ab_name = 0 for regAddress in regs: INT = regs[regAddress] regName = self.register_names[regAddress] size = self.registers[regName][1] up = None if INT < 0: up = lambda x: x.lower() else: up = lambda x: x try: if size == 1: db_data = struct.pack(up("<B"), INT) elif size == 2: db_data = struct.pack(up("<H"), INT) elif size == 4: db_data = struct.pack(up("<I"), INT) elif size == 8: db_data = struct.pack(up("<Q"), INT) elif size == 16: db_data = struct.pack(up("<QQ"), int(INT & 0xffffffffffffffff), int(INT >> 64)) elif size == 32: db_data = struct.pack(up("<QQQQ"), INT & 0xffffffffffffffff, (INT >> 64) & 0xffffffffffffffff, (INT >> 128) & 0xffffffffffffffff, INT >> 192) else: continue segm['registers' + str(regAddress)] = [regAddress, len(db_data), db_data] print(" (%-10s IR_offset: %-5d) (regValue: %-32x nb: %2d) " % (regName, regAddress, (INT), len(db_data))) except Exception as e: print("-=1-=1-=1-=1- error:", e, regName, hex(INT), size, "-=1-=1-=1-=1- ") def find_segm(va, length, bpt_l): global BPNORMAL for ea, bptype, hwtype_hwsize, code in bpt_l: if va <= ea and ea < va + length: if bptype == BPNORMAL: yield (code, ea - va) bpt_list = [i for i in Breakpoints()] for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') all_ab_name += len(ab_name) # 将软件断点pass掉 len_db_data = len(db_data) for code, offset in find_segm(address, length, bpt_list): db_data = db_data[:offset] + struct.pack( up("<H"), code) + db_data[offset + 2:] segm[name] = [address, length, db_data] assert (len(db_data) == len_db_data) print("bkp found: address: %x code: %s" % (address + offset, base64.b16encode(struct.pack(up("<H"), code)))) for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') nameoffset = len(segm) * 32 + nameoffset_p dataoffset = len(segm) * 32 + all_ab_name + dataoffset_p db1 = struct.pack("<Q", nameoffset) db2 = struct.pack("<Q", address) db3 = struct.pack("<Q", length) db4 = struct.pack("<Q", dataoffset) self.mem_mmap[name] = [address, dataoffset, length] binfile.write(db1) binfile.write(db2) binfile.write(db3) binfile.write(db4) nameoffset_p += len(ab_name) dataoffset_p += length for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') binfile.write(ab_name) for name in segm: address, length, db_data = segm[name] binfile.write(db_data)
def writeMem(binfile, regs): segm = {} for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) if seg: count = 0 h = '' while (idaapi.get_segm_name(seg, 0) + h) in segm.keys(): count += 1 h = str(count) name = idaapi.get_segm_name(seg, 0) + h address = seg.startEA length = seg.endEA - seg.startEA db_data = idaapi.dbg_read_memory(address, length) if db_data: print('ok ', name, seg.flags, length, 'bytes', length / 1024, 'kb') segm[name] = [address, length, db_data] else: print('faild', name, seg.flags, length, 'bytes', length / 1024, 'kb') pass nameoffset_p = 0 dataoffset_p = 0 all_ab_name = 0 register_names = { 16: 'rax', 24: 'rcx', 32: 'rdx', 40: 'rbx', 48: 'rsp', 56: 'rbp', 64: 'rsi', 72: 'rdi', 80: 'r8', 88: 'r9', 96: 'r10', 104: 'r11', 112: 'r12', 120: 'r13', 128: 'r14', 136: 'r15', 144: 'cc_op', 152: 'cc_dep1', 160: 'cc_dep2', 168: 'cc_ndep', 176: 'd', 184: 'rip', 192: 'ac', 200: 'id', 208: 'fs', 216: 'sseround', 224: 'ymm0', 256: 'ymm1', 288: 'ymm2', 320: 'ymm3', 352: 'ymm4', 384: 'ymm5', 416: 'ymm6', 448: 'ymm7', 480: 'ymm8', 512: 'ymm9', 544: 'ymm10', 576: 'ymm11', 608: 'ymm12', 640: 'ymm13', 672: 'ymm14', 704: 'ymm15', 736: 'ymm16', 768: 'ftop', 776: 'mm0', 784: "mm1", 792: "mm2", 800: "mm3", 808: "mm4", 816: "mm5", 824: "mm6", 832: "mm7", 840: 'fptag', 848: 'fpround', 856: 'fc3210', 864: 'emnote', 872: 'cmstart', 880: 'cmlen', 888: 'nraddr', 904: 'gs', 912: 'ip_at_syscall' } registers = { 'rax': (16, 8), 'eax': (16, 4), 'ax': (16, 2), 'al': (16, 1), 'ah': (17, 1), 'rcx': (24, 8), 'ecx': (24, 4), 'cx': (24, 2), 'cl': (24, 1), 'ch': (25, 1), 'rdx': (32, 8), 'edx': (32, 4), 'dx': (32, 2), 'dl': (32, 1), 'dh': (33, 1), 'rbx': (40, 8), 'ebx': (40, 4), 'bx': (40, 2), 'bl': (40, 1), 'bh': (41, 1), 'rsp': (48, 8), 'sp': (48, 8), 'esp': (48, 4), 'rbp': (56, 8), 'bp': (56, 8), 'ebp': (56, 4), 'rsi': (64, 8), 'esi': (64, 4), 'si': (64, 2), 'sil': (64, 1), 'sih': (65, 1), 'rdi': (72, 8), 'edi': (72, 4), 'di': (72, 2), 'dil': (72, 1), 'dih': (73, 1), 'r8': (80, 8), 'r9': (88, 8), 'r10': (96, 8), 'r11': (104, 8), 'r12': (112, 8), 'r13': (120, 8), 'r14': (128, 8), 'r15': (136, 8), 'cc_op': (144, 8), 'cc_dep1': (152, 8), 'cc_dep2': (160, 8), 'cc_ndep': (168, 8), 'd': (176, 8), 'dflag': (176, 8), 'rip': (184, 8), 'ip': (184, 8), 'pc': (184, 8), 'ac': (192, 8), 'acflag': (192, 8), 'id': (200, 8), 'idflag': (200, 8), 'fs': (208, 8), 'fs_const': (208, 8), 'sseround': (216, 8), 'ymm0': (224, 32), 'xmm0': (224, 16), 'ymm1': (256, 32), 'xmm1': (256, 16), 'ymm2': (288, 32), 'xmm2': (288, 16), 'ymm3': (320, 32), 'xmm3': (320, 16), 'ymm4': (352, 32), 'xmm4': (352, 16), 'ymm5': (384, 32), 'xmm5': (384, 16), 'ymm6': (416, 32), 'xmm6': (416, 16), 'ymm7': (448, 32), 'xmm7': (448, 16), 'ymm8': (480, 32), 'xmm8': (480, 16), 'ymm9': (512, 32), 'xmm9': (512, 16), 'ymm10': (544, 32), 'xmm10': (544, 16), 'ymm11': (576, 32), 'xmm11': (576, 16), 'ymm12': (608, 32), 'xmm12': (608, 16), 'ymm13': (640, 32), 'xmm13': (640, 16), 'ymm14': (672, 32), 'xmm14': (672, 16), 'ymm15': (704, 32), 'xmm15': (704, 16), 'ymm16': (736, 32), 'xmm16': (736, 16), 'ftop': (768, 4), 'fpreg': (776, 64), 'fpu_regs': (776, 64), 'mm0': (776, 8), 'mm1': (784, 8), 'mm2': (792, 8), 'mm3': (800, 8), 'mm4': (808, 8), 'mm5': (816, 8), 'mm6': (824, 8), 'mm7': (832, 8), 'fptag': (840, 8), 'fpu_tags': (840, 8), 'fpround': (848, 8), 'fc3210': (856, 8), 'emnote': (864, 4), 'cmstart': (872, 8), 'cmlen': (880, 8), 'nraddr': (888, 8), 'gs': (904, 8), 'gs_const': (904, 8), 'ip_at_syscall': (912, 8) } for regAddress in regs: INT = regs[regAddress] regName = register_names[regAddress] size = registers[regName][1] if size == 1: db_data = struct.pack("<B", INT) elif size == 2: db_data = struct.pack("<H", INT) elif size == 4: db_data = struct.pack("<I", INT) elif size == 8: db_data = struct.pack("<Q", INT) elif size == 16: db_data = struct.pack("<QQ", int(INT & 0xffffffffffffffff), int(INT >> 64)) elif size == 32: db_data = struct.pack("<QQQQ", INT & 0xffffffffffffffff, (INT >> 64) & 0xffffffffffffffff, (INT >> 128) & 0xffffffffffffffff, INT >> 192) else: continue segm['registers' + str(regAddress)] = [regAddress, len(db_data), db_data] for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') all_ab_name += len(ab_name) for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') nameoffset = len(segm) * 32 + nameoffset_p dataoffset = len(segm) * 32 + all_ab_name + dataoffset_p db1 = struct.pack("<Q", nameoffset) db2 = struct.pack("<Q", address) db3 = struct.pack("<Q", length) db4 = struct.pack("<Q", dataoffset) binfile.write(db1) binfile.write(db2) binfile.write(db3) binfile.write(db4) nameoffset_p += len(ab_name) dataoffset_p += length for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') binfile.write(ab_name) for name in segm: address, length, db_data = segm[name] binfile.write(db_data)
def search_pointers(self): # HACK: A separate flag is used to track user canceling the search, # because multiple calls to idaapi.wasBreak() do not properly # detect cancellations. breakFlag = False # Show wait dialog idaapi.show_wait_box("Searching writable function pointers...") for m in self.modules: ################################################################### # Locate all of the CALL and JMP instructions in the current module # which use an immediate operand. # List of call/jmp pointer calls in a given module ptr_calls = list() # Iterate over segments in the module # BUG: Iterating over all loaded segments is more stable than looking up by address for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) # Segment in a selected modules if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size): # Locate executable segments # NOTE: Each module may have multiple executable segments # TODO: Search for "MOV REG, PTR # CALL REG" if seg.perm & idaapi.SEGPERM_EXEC: # Search all instances of CALL /2 imm32/64 - FF 15 # TODO: Alternative pointer calls using SIB: FF 14 E5 11 22 33 44 - call dword/qword ptr [0x44332211] # FF 14 65 11 22 33 44 # FF 14 25 11 22 33 44 call_ea = seg.startEA while True: call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, "FF 15", 16, idaapi.SEARCH_DOWN) if call_ea == idaapi.BADADDR: break ptr_calls.append(call_ea) # Search all instances of JMP /2 imm32/64 - FF 25 # TODO: Alternative pointer calls using SIB: FF 24 E5 11 22 33 44 - jmp dword/qword ptr [0x44332211] # FF 24 65 11 22 33 44 # FF 24 25 11 22 33 44 call_ea = seg.startEA while True: call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, "FF 25", 16, idaapi.SEARCH_DOWN) if call_ea == idaapi.BADADDR: break ptr_calls.append(call_ea) ################################################################### # Extract all of the function pointers and make sure they are # are writable. # List of writable function pointer objects in a given module ptrs = list() for call_ea in ptr_calls: # Decode CALL/JMP instruction # NOTE: May result in invalid disassembly of split instructions insn_size = idaapi.decode_insn(call_ea) if insn_size: insn = idaapi.cmd insn_op1 = insn.Operands[0].type # Verify first operand is a direct memory reference if insn.Operands[0].type == idaapi.o_mem: # Get operand address ptr_ea = insn.Operands[0].addr # Apply pointer offset ptr_ea -= self.ptrOffset # Locate segment where the pointer is located ptr_seg = idaapi.getseg(ptr_ea) # Make sure a valid segment writeable segment was found if ptr_seg and ptr_seg.perm & idaapi.SEGPERM_WRITE: # Get pointer charset ptr_charset = self.sploiter.get_ptr_charset(ptr_ea) # Filter the pointer if not self.filterP2P: if ptr_charset == None: continue if self.ptrNonull and not "nonull" in ptr_charset: continue if self.ptrUnicode and not "unicode" in ptr_charset: continue if self.ptrAscii and not "ascii" in ptr_charset: continue if self.ptrAsciiPrint and not "asciiprint" in ptr_charset: continue if self.ptrAlphaNum and not "alphanum" in ptr_charset: continue if self.ptrNum and not "numeric" in ptr_charset: continue if self.ptrAlpha and not "alpha" in ptr_charset: continue # Increment the fptr counter # Get pointer disassembly insn_disas = idc.GetDisasmEx(call_ea, idaapi.GENDSM_FORCE_CODE) # Add pointer to the list ptr = Ptr(m.file, ptr_ea, self.ptrOffset, ptr_charset, call_ea, insn_disas) ptrs.append(ptr) ################################################################### # Cache Pointers to Pointers ptr_ea_prefix_cache = dict() if self.searchP2P: # CACHE: Running repeated searches over the entire memory space is # very expensive. Let's cache all of the addresses containing # bytes corresponding to discovered function pointers in a # single search and simply reference this cache for each # function pointer. Specifically running idaapi.find_binary() # is much more expensive than idaapi.dbg_read_memory(). # # NOTE: For performance considerations, the cache works on a per # module basis, but could be expanded for the entire memory # space. # # prefix_offset - how many bytes of discovered function # pointers to cache. # # Example: For function pointers 0x00401234, 0x00404321, 0x000405678 # we are going to use prefix_offset 2, so we will cache all of the # values located at addresses 0x0040XXXX if self.sploiter.addr64: pack_format = "<Q" addr_bytes = 8 prefix_offset = 6 else: pack_format = "<I" addr_bytes = 4 prefix_offset = 2 # Set of unique N-byte address prefixes to search in memory ea_prefix_set = set() for ptr in ptrs: ptr_ea = ptr.ptr_ea ptr_bytes = struct.pack(pack_format, ptr_ea) ptr_bytes = ptr_bytes[-prefix_offset:] ea_prefix_set.add(ptr_bytes) # Search the module for all bytes corresponding to the prefix # and use them as candidates for pointers-to-pointers for ea_prefix in ea_prefix_set: # NOTE: Make sure you search using 44 33 22 11 format and not 11223344 ea_prefix_str = " ".join(["%02x" % ord(b) for b in ea_prefix]) # Initialize search parameters for a given module ea = m.addr maxea = m.addr + m.size while True: ea = idaapi.find_binary(ea + 1, maxea, ea_prefix_str, 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break p2p_ea = ea - (addr_bytes - prefix_offset) dbg_mem = read_module_memory(p2p_ea, addr_bytes) ptr_ea_prefix = unpack(pack_format, dbg_mem)[0] if ptr_ea_prefix in ptr_ea_prefix_cache: ptr_ea_prefix_cache[ptr_ea_prefix].add(p2p_ea) else: ptr_ea_prefix_cache[ptr_ea_prefix] = set([p2p_ea, ]) # Detect search cancellation, but allow the loop below # to run to create already cached/found function pointers # Canceled if breakFlag or idaapi.wasBreak(): breakFlag = True break # Canceled if breakFlag or idaapi.wasBreak(): breakFlag = True break ################################################################### # Locate Pointer to Pointers for ptr in ptrs: ptr_ea = ptr.ptr_ea # Locate pointers-to-pointers for a given function pointer in the cache if self.searchP2P and ptr_ea in ptr_ea_prefix_cache: for p2p_ea in ptr_ea_prefix_cache[ptr_ea]: # Apply pointer-to-pointer offset p2p_ea -= self.p2pOffset p2p_charset = self.sploiter.get_ptr_charset(p2p_ea) # Filter the pointer if self.filterP2P: if p2p_charset == None: continue if self.ptrNonull and not "nonull" in p2p_charset: continue if self.ptrUnicode and not "unicode" in p2p_charset: continue if self.ptrAscii and not "ascii" in p2p_charset: continue if self.ptrAsciiPrint and not "asciiprint" in p2p_charset: continue if self.ptrAlphaNum and not "alphanum" in p2p_charset: continue if self.ptrNum and not "numeric" in p2p_charset: continue if self.ptrAlpha and not "alpha" in p2p_charset: continue # Copy existing pointer object to modify it for the particular p p2p = copy.copy(ptr) p2p.p2p_ea = p2p_ea p2p.p2p_offset = self.p2pOffset p2p.p2p_charset = p2p_charset # Apppend p2p specific pointer object to the global list self.ptrs.append(p2p) # Exceeded maximum number of pointers if self.maxPtrs and len(self.ptrs) >= self.maxPtrs: breakFlag = True print "[idasploiter] Maximum number of pointers exceeded." break # Simply append pointer object to the global list else: self.ptrs.append(ptr) # Exceeded maximum number of pointers if self.maxPtrs and len(self.ptrs) >= self.maxPtrs: breakFlag = True print "[idasploiter] Maximum number of pointers exceeded." break if breakFlag or idaapi.wasBreak(): breakFlag = True break # Canceled # NOTE: Only works when started from GUI not script. if breakFlag or idaapi.wasBreak(): breakFlag = True print "[idasploiter] Canceled." break print "[idasploiter] Found %d total pointers." % len(self.ptrs) idaapi.hide_wait_box()
def search_retns(self): if not self.debug: print("found %d modules" % len(self.modules)) for m in self.modules: # Iterate over segments in the module # BUG: Iterating over all loaded segments is more stable than looking up by address if not self.debug: print("found %d segments" % idaapi.get_segm_qty()) for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) # Locate executable segments in a selected modules # NOTE: Each module may have multiple executable segments if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size): # If the debugger is attached then we can check if the segment is executable, else # just check if it is code or not. if idaapi.dbg_can_query() and idaapi.get_process_state() < 0: if seg.perm & idaapi.SEGPERM_EXEC == 0: continue elif seg.type & idaapi.SEG_CODE == 0: continue ####################################################### # Search for ROP gadgets if self.searchRop: # Search all instances of RETN ea = seg.startEA while True: ea = idaapi.find_binary(ea + 1, seg.endEA, "C3", 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break self.retns.append((ea, m.file)) # Search all instances of RETN imm16 ea = seg.startEA while True: ea = idaapi.find_binary(ea + 1, seg.endEA, "C2", 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break # Read imm16 value and filter large values retn_imm16 = read_module_memory(ea + 1, 0x2) retn_imm16 = unpack("<H", retn_imm16)[0] if retn_imm16 <= self.maxRetnImm: self.retns.append((ea, m.file)) ####################################################### # Search for JOP gadgets if self.searchJop: # Search all instances of JMP reg (FF /4) and CALL reg (FF /2) ea = seg.startEA while True: ea = idaapi.find_binary(ea + 1, seg.endEA, "FF", 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break # Read possible ModR/M, SIB, and IMM8/IMM32 bytes jop = read_module_memory(ea + 1, 0x6) if jop == None or len(jop) == 0: continue ################################################### # JMP/CALL reg if jop[0] in ["\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7", "\xd0", "\xd1", "\xd2", "\xd3", "\xd4", "\xd5", "\xd6", "\xd7"]: self.retns.append((ea, m.file)) ################################################### # JMP/CALL [reg] no SIB # NOTE: Do not include pure [disp] instruction. # JMP/CALL [reg] no *SP,*BP elif jop[0] in ["\x20", "\x21", "\x22", "\x23", "\x26", "\x27", "\x10", "\x11", "\x12", "\x13", "\x16", "\x17"]: self.retns.append((ea, m.file)) # JMP/CALL [reg + imm8] no *SP elif jop[0] in ["\x60", "\x61", "\x62", "\x63", "\x65", "\x66", "\x67", "\x50", "\x51", "\x52", "\x53", "\x55", "\x56", "\x57"]: jop_imm8 = jop[1] jop_imm8 = unpack("b", jop_imm8)[0] # signed if jop_imm8 <= self.maxJopImm: self.retns.append((ea, m.file)) # JMP/CALL [reg + imm32] no *SP elif jop[0] in ["\xa0", "\xa1", "\xa2", "\xa3", "\xa5", "\xa6", "\xa7", "\x90", "\x91", "\x92", "\x93", "\x95", "\x96", "\x97"]: jop_imm32 = jop[1:5] jop_imm32 = unpack("<i", jop_imm32)[0] # signed if jop_imm32 <= self.maxJopImm: self.retns.append((ea, m.file)) ################################################### # JMP/CALL [reg] with SIB # NOTE: Do no include pure [disp] instructions in SIB ([*] - none) elif (jop[0] in ["\x24", "\x64", "\xa4"] and not jop[1] in ["\x25", "\x65", "\xad", "\xe5"]) or \ (jop[0] in ["\x14", "\x54", "\x94"] and not jop[1] in ["\x25", "\x65", "\xad", "\xe5"]): # Check for displacement if jop[0] in ["\x64", "\x54"]: jop_imm8 = jop[2] jop_imm8 = unpack("b", jop_imm8)[0] # signed if jop_imm8 <= self.maxJopImm: self.retns.append((ea, m.file)) elif jop[0] in ["\xa4", "\x94"]: jop_imm32 = jop[2:6] jop_imm32 = unpack("<i", jop_imm32)[0] # signed if jop_imm32 <= self.maxJopImm: self.retns.append((ea, m.file)) else: self.retns.append((ea, m.file)) print "[idasploiter] Found %d returns" % len(self.retns)
def writeMem(self, binfile): regs = self.getRegs() segm = self.init_segm_mem() for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) if seg: count = 0 h = '' while (idaapi.get_segm_name(seg, 0) + h) in segm.keys(): count += 1 h = str(count) name = idaapi.get_segm_name(seg, 0) + h address = seg.startEA length = seg.endEA - seg.startEA db_data = idaapi.dbg_read_memory(address, length) if db_data: print('ok ', name, seg.flags, length, 'bytes', length / 1024, 'kb') segm[name] = [address, length, db_data] else: print('faild', name, seg.flags, length, 'bytes', length / 1024, 'kb') pass nameoffset_p = 0 dataoffset_p = 0 all_ab_name = 0 for regAddress in regs: INT = regs[regAddress] regName = self.register_names[regAddress] size = self.registers[regName][1] try: if size == 1: db_data = struct.pack("<B", INT) elif size == 2: db_data = struct.pack("<H", INT) elif size == 4: db_data = struct.pack("<I", INT) elif size == 8: db_data = struct.pack("<Q", INT) elif size == 16: db_data = struct.pack("<QQ", int(INT & 0xffffffffffffffff), int(INT >> 64)) elif size == 32: db_data = struct.pack("<QQQQ", INT & 0xffffffffffffffff, (INT >> 64) & 0xffffffffffffffff, (INT >> 128) & 0xffffffffffffffff, INT >> 192) else: continue segm['registers' + str(regAddress)] = [regAddress, len(db_data), db_data] print(" (%-10s : %-5d) (%-x) (%d)" % (regName, regAddress, (INT), len(db_data))) except Exception as e: print("--------- error:", e, regName, hex(INT), size, "--------- ") for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') all_ab_name += len(ab_name) for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') nameoffset = len(segm) * 32 + nameoffset_p dataoffset = len(segm) * 32 + all_ab_name + dataoffset_p db1 = struct.pack("<Q", nameoffset) db2 = struct.pack("<Q", address) db3 = struct.pack("<Q", length) db4 = struct.pack("<Q", dataoffset) binfile.write(db1) binfile.write(db2) binfile.write(db3) binfile.write(db4) nameoffset_p += len(ab_name) dataoffset_p += length for name in segm: address, length, db_data = segm[name] ab_name = (name + '\x00').encode('utf-8') binfile.write(ab_name) for name in segm: address, length, db_data = segm[name] binfile.write(db_data)
def newsegment(index): res = idaapi.getnseg(index) res.index = index return res
def newsegment(index): seg = idaapi.getnseg(index) seg.index, _ = index, ui.navigation.set(interface.range.start(seg)) return seg
def __init__(self): self.segs = [] for i in range(idaapi.get_segm_qty()): self.segs.append(create_segment_node(idaapi.getnseg(i)))
def get_current_segment(ea): '''Gets the segment start ea of the current segment''' for index in xrange(idaapi.get_segm_qty()): segm = idaapi.getnseg(index) if segm.startEA <= ea < segm.endEA: return segm.startEA