def find_module_ptr(self): str_ptr = idc.FindBinary(0, idc.SEARCH_DOWN | idc.SEARCH_CASE, '"SceUIDModuleClass"') if str_ptr == idc.BADADDR: raise RuntimeError("failed to apply str_ptr heuristic") log("stage 1: str_ptr at 0x{:08X}".format(str_ptr)) haystack = " ".join(chunk(p32(str_ptr).encode("hex"), 2)) cls_ptr = idc.FindBinary(0, idc.SEARCH_DOWN | idc.SEARCH_CASE, haystack) if cls_ptr == idc.BADADDR: raise RuntimeError("failed to apply cls_ptr heuristic") cls_ptr -= 0xC log("stage 2: cls_ptr at 0x{:08X}".format(cls_ptr)) haystack = " ".join(chunk(p32(cls_ptr).encode("hex"), 2)) ea = 0 while True: ea = idc.FindBinary(ea, idc.SEARCH_DOWN | idc.SEARCH_CASE, haystack) if ea == idc.BADADDR: raise RuntimeError( "failed to find the last module using the heuristic") ptr = idc.Dword(ea + 0x20) name = c_str(ptr, 0x20) if name == "SceKrm": self.last_module_ptr = ea + 4 log("stage 3: last_module_ptr at 0x{:08X}".format( self.last_module_ptr)) break ea = idc.NextAddr(ea)
def find_all(opcode_str): ret = [] ea = idc.FindBinary(0, 1, opcode_str) while ea != idc.BADADDR: ret.append(ea) ea = idc.FindBinary(ea + 4, 1, opcode_str) return ret
def find_encrypted_strings(opcode, start, end): ea = start ret = [] ea = idc.FindBinary(ea, 1, opcode) while ea != idc.BADADDR and ea < end: ret.append(ea) ea = idc.FindBinary(ea + 4, 1, opcode) return ret
def find_all_switch_jumps(self): self._switch_dict = defaultdict(list) next_switch = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, "ff 24") while next_switch != idc.BADADDR: sw = idaapi.get_switch_info_ex(next_switch) if idc.GetMnem(next_switch).startswith("jmp") and sw: ic = self.get_jlocs(sw) self._switch_dict[idaapi.get_func_name(next_switch)].append((next_switch, sw.ncases, ic)) next_switch = idc.FindBinary(idc.NextHead(next_switch), idc.SEARCH_DOWN|idc.SEARCH_NEXT, "ff 24")
def getVersionByString(self): pos = idautils.Functions().next() if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 31 30") != idc.BADADDR: return 'Go 1.10' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 39") != idc.BADADDR: return 'Go 1.9' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 38") != idc.BADADDR: return 'Go 1.8' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 37") != idc.BADADDR: return 'Go 1.7' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 36") != idc.BADADDR: return 'Go 1.6' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 35") != idc.BADADDR: return 'Go 1.5' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 34") != idc.BADADDR: return 'Go 1.4' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 33") != idc.BADADDR: return 'Go 1.3' if idc.FindBinary(pos, idc.SEARCH_DOWN, "67 6f 31 2e 32") != idc.BADADDR: return 'Go 1.2'
def iter_find_query(query, start=None, end=None, down=True): start, end = fix_addresses(start, end) if down: direction = idc.SEARCH_DOWN else: direction = idc.SEARCH_UP current = idc.FindBinary(start, direction, query) while current < end: yield current current = idc.FindBinary(current + 1, direction, query)
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 code_search(ea, val): """Search forward for the next occurance of val. Return None if no match.""" res = idc.FindBinary(ea, idc.SEARCH_DOWN, val) if res == idaapi.BADADDR: return None else: return res
def match_binary(addr, search_flag, pattern_list): ret_addr = idc.BADADDR for pattern in pattern_list: ret_addr = idc.FindBinary(addr, search_flag, pattern) if ret_addr != idc.BADADDR: break return ret_addr
def _find_function_end(location): ''' Description: If the location is the last applicable byte, assume that's the end byte. Else, search down until we find the last (highest EA) "retn" before either aligns or a function. If that fails, look for the last (higheste EA) "jmp" instruction. Input: location - The EA from which to start looking for a function end. Output: A list of applicable EAs (one per type) or idc.BADADDR if none are found. ''' if idaapi.get_func(location + 1) or idc.isAlign( idc.GetFlags(location + 1)): # This bit is inclusive return [location + 1] # This bit is exclusive eas = [] # CA + CB are retf, but aren't used often; 'EA' is 16 bit; 'FF' jumps are too rare for opcode in ['C3', 'C2', 'E9', 'EB']: ea = location function_end = idc.BADADDR while ea != idc.BADADDR: ea = idc.FindBinary(ea + 1, idc.SEARCH_DOWN, opcode) if not (idaapi.get_func(ea) or idc.isAlign(idc.GetFlags(ea))): function_end = ea else: break if function_end != idc.BADADDR: eas.append(_un_nop(function_end, idc.PrevHead) + 1) # Again, exclusive eas.sort(reverse=True) return eas
def _find_function_start(location): ''' Description: If the location is the first applicable byte, assume that's the start byte. Else, search up until we find the first (lowest EA) "push ebp" before either aligns or a function. If that fails, look for "push esp", then "push esi", and finally "push edi". Input: The EA from which to start looking for a function start Output: A list of applicable EAs (one per type) or idc.BADADDR if none are found. ''' if idaapi.get_func(location - 1) or idc.isAlign( idc.GetFlags(location - 1)): return [location] eas = [] for opcode in ['55', '54', '56', '57']: ea = location function_start = idc.BADADDR while ea != idc.BADADDR: ea = idc.FindBinary(ea - 1, idc.SEARCH_UP, opcode) if not (idaapi.get_func(ea) or idc.isAlign(idc.GetFlags(ea))): function_start = ea else: break if function_start != idc.BADADDR: eas.append(_un_nop(function_start, idc.NextHead)) eas.sort() return eas
def find_binary_instruction_start(search_start_location, search_direction, target, min_location=idc.MinEA(), max_location=idc.MaxEA()): """ Description: Given a starting location, target, and direction, find an instruction starting with the target bytes. Input: search_start_location - The EA to start searching at search_direction - either idc.SEARCH_UP or idc.SEARCH_DOWN target - The target as space separated bytes (i.e. '55' for 'push ebp') min_location - The minimum EA to accept results for (default: idc.MinEA()) max_location - The maximum EA to accept results for (default: idc.MaxEA()) Output: Returns the first matching location if found, otherwise idc.BADADDR """ target = target.upper() while search_start_location < max_location: ea = idc.FindBinary(search_start_location, search_direction, target) if (min_location <= ea < max_location and ea == idc.ItemHead(ea) and idaapi.get_many_bytes(ea, idc.ItemSize(ea)).encode('hex').upper().startswith(target.replace(' ', ''))): return ea else: search_start_location = ea + (1 if search_direction == idc.SEARCH_DOWN else -1) return idc.BADADDR
def __find_entry(self, iterate_address): possible_entry_address = self.__find_entry_jump(iterate_address) if possible_entry_address == 0 or possible_entry_address == 1: return 0 elif possible_entry_address == -1: print("ERROR.FindingEntry: Issue finding entry from " + format_address(hex(iterate_address)) + \ " to " + format_address(hex(self.end_address)) + ".") return -1 else: following_landing_address = idc.FindBinary(possible_entry_address, idc.SEARCH_DOWN, LANDING_STRIP) if following_landing_address == idc.BADADDR or following_landing_address == 0: # print("ERROR.FindingEntry: Issue finding landing for " + format_address(hex(possible_entry_address)) + ".") # assume end has not yet been reached, will continue to find the correct macro entry return 0 else: # unwrap landing strip as it is usually formatted as data idc.MakeUnknown(following_landing_address, 2, idc.DOUNK_SIMPLE) idc.MakeCode(following_landing_address) # apply logging possible_jump_location_address = get_jump_destination(possible_entry_address) log_oreans_macro_information(possible_entry_address, possible_jump_location_address, following_landing_address) self.macros.append([possible_entry_address, possible_jump_location_address, following_landing_address]) if BUFFER_NOP: nop(possible_entry_address + 5, following_landing_address) if BUFFER_HIDE: hide(possible_entry_address + 5, following_landing_address, BUFFER_NAME, BUFFER_START_NAME, BUFFER_END_NAME) # change main iterator address with that pass the landing so it will step over macro range next_macro_search_range_address = following_landing_address + 5 return next_macro_search_range_address
def find_func_pattern(pattern): # Direct Function Pattern addr = idc.FindBinary(0, SEARCH_DOWN, pattern) if addr == BADADDR: return 0 try: return idaapi.get_func(addr).startEA except exception: return 0
def FindFuncPattern(Pattern): # Find's Func. by Pattern addr = idc.FindBinary(0, SEARCH_DOWN, Pattern) if addr == BADADDR: return 0 try: return idaapi.get_func(addr).startEA except Exception: return 0
def FindFunctionByPatternStartEA(pattern): address = idc.FindBinary(0, SEARCH_DOWN, pattern) if address == BADADDR: return BADADDR try: return idaapi.get_func(address).startEA except Exception: return -1
def relocGlobalVar(sigStr, relativeOffset=0, dataOffset=0, instructionLength=0): sigAddr = idc.FindBinary(0, idc.SEARCH_DOWN, sigStr) scanResult = sigAddr + relativeOffset if (dataOffset != None): rel32 = idc.Dword(scanResult + dataOffset) scanResult = scanResult + instructionLength + rel32 return scanResult
def findGoPcLn(): pos = idautils.Functions().next() # Get some valid address in .text segment while True: possible_loc = idc.FindBinary(pos, idc.SEARCH_DOWN, lookup) #header of gopclntab if possible_loc == idc.BADADDR: break if check_is_gopclntab(possible_loc): return possible_loc pos = possible_loc+1 return None
def find_all_bin(str): start_addr = 0 res = [] while start_addr != idc.BADADDR: addr = idc.FindBinary(start_addr + 1, idc.SEARCH_DOWN, str, 16) if addr == idc.BADADDR: break yield here(addr) start_addr = addr return
def resolve_loops(): PATTERNS = ["81 FB ?? ?? ?? ?? 75"] count_patched = 0 count_not_patched = 0 for pattern in PATTERNS: ea = 0 while ea != BADADDR: ''' pattern: 81 FB ?? ?? ?? ?? 75 .text:00406AA0 01 C7 add edi, eax .text:00406AA2 66 41 inc cx .text:00406AA4 43 inc ebx .text:00406AA5 81 FB A6 01 00 00 cmp ebx, 1A6h .text:00406AAB 75 F3 jnz short loc_406AA0 patched: .text:00406AA0 01 C7 add edi, eax .text:00406AA2 66 41 inc cx .text:00406AA4 43 inc ebx .text:00406AA5 90 nop .text:00406AA6 90 nop .text:00406AA7 90 nop .text:00406AA8 90 nop .text:00406AA9 90 nop .text:00406AAA 90 nop .text:00406AAB 90 nop .text:00406AAC 90 nop ''' ea = idc.FindBinary(ea, SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE, pattern) if ea_in_bounds(ea): # Patch CMP and conditional jmp instructions in order to remove the loop idc.PatchByte(ea + 0, 0x90) idc.PatchByte(ea + 1, 0x90) idc.PatchByte(ea + 2, 0x90) idc.PatchByte(ea + 3, 0x90) idc.PatchByte(ea + 4, 0x90) idc.PatchByte(ea + 5, 0x90) idc.PatchByte(ea + 6, 0x90) idc.PatchByte(ea + 7, 0x90) idc.MakeCode(ea) count_patched += 1 print "\tPatched resolve_loops: {0}".format(count_patched) print "\tNot Patched resolve_loops: {0}".format(count_not_patched)
def findGoPcLn(): possible_loc = idc.FindBinary(0, idc.SEARCH_DOWN, lookup, 16) #header of gopclntab print "Possible gopclntab: %s" % hex(possible_loc) while possible_loc != idc.BADADDR: if check_is_gopclntab(possible_loc): return possible_loc else: possible_loc = ida_search.FindBinary(possible_loc + 1, idc.SEARCH_DOWN, lookup, 16) return None
def makeFuncsFromPreamble(funcpreamble, startea=idc.FirstSeg(), endea = idaapi.BADADDR): """ This method makes functions everywhere that the sequence 'funpreamble' is found. NOTE: this method is generally unsafe, because it will attempt to make functions where there may be no function. Use it with caution. """ ea = startea i = 0 while (ea != idaapi.BADADDR and ea < endea): ea = idc.FindBinary(ea, SEARCH_DOWN, funcpreamble) idc.MakeFunction(ea) idc.Wait() ea = ea + 1 # idc.FindBinary(ea) returns ea if ea matches, silly
def FindNOPAddr(name, offset): address = idc.FindBinary(0, SEARCH_DOWN, "\"" + name + "\"") dword = -1 if address == BADADDR: return -1 xrefs = XrefsTo(address) for xref in xrefs: dword = xref.frm + offset return dword
def FindFuncFirstReference(Reference): # Find's Func. by Reference, Returns first addr = idc.FindBinary(0, SEARCH_DOWN, "\"" + Reference + "\"") if addr == BADADDR: return 0 dword = -1 xrefs = XrefsTo(addr) for xref in xrefs: dword = xref.frm try: return idaapi.get_func(dword).startEA except Exception: return 0
def autoCode(hex_value): start = idc.MinEA(); len=idc.MaxEA()-start; addr=start; flag = False for x in range(len): addr = idc.FindBinary(addr, SEARCH_DOWN|SEARCH_CASE|SEARCH_NEXT, hex_value) if addr != idc.BADADDR: make_code(addr,addr+4) print "{:>8X} {:<32}".format(addr,idc.GetDisasm(addr)) else: flag = False #addr=idc.NextHead(addr) return 0
def FindFunctionFirstXRef(name): address = idc.FindBinary(0, SEARCH_DOWN, "\"" + name + "\"") dword = BADADDR if address == BADADDR: return BADADDR xrefs = XrefsTo(address) for xref in xrefs: dword = xref.frm try: return idaapi.get_func(dword).startEA except Exception: return -1
def processEncrypt(ea, name, CRYPTSTART_PATTERN, CRYPTEND_PATTERN, EPILOGUE_PATTERN, PROLOGUE_PATTERN): prologue = idc.FindBinary(ea, SEARCH_UP, PROLOGUE_PATTERN) if len(PROLOGUE_PATTERN) != 0 else idc.GetFunctionAttr(ea, FUNCATTR_START) epilogue = idc.FindBinary(ea, SEARCH_DOWN, EPILOGUE_PATTERN) if len(EPILOGUE_PATTERN) != 0 else idc.GetFunctionAttr(ea, FUNCATTR_END) idc.MakeFunction(prologue, epilogue + EPILOGUE_PATTERN.count(' ') + 1); cryptStart = idc.FindBinary(ea, SEARCH_DOWN if name != "BYTE" else SEARCH_UP, CRYPTSTART_PATTERN) cryptEnd = idc.FindBinary(ea, SEARCH_DOWN, CRYPTEND_PATTERN) # Generate Encrypt ea = cryptStart + CRYPTSTART_PATTERN.count(' ') + 1 opStr = "" while ea < cryptEnd: if idc.GetMnem(ea) != 'mov': result = { 'add': lambda x: "new Add({0})".format(idc.GetOperandValue(x, 1)), 'sub': lambda x: "new Sub({0})".format(idc.GetOperandValue(x, 1)), 'xor': lambda x: "new Xor({0})".format(idc.GetOperandValue(x, 1)), 'ror': lambda x: "new Ror({0})".format(idc.GetOperandValue(x, 1)), 'rol': lambda x: "new Rol({0})".format(idc.GetOperandValue(x, 1)), 'not': lambda x: "new Not()", 'inc': lambda x: "new Inc()", 'dec': lambda x: "new Dec()", }[idc.GetMnem(ea)](ea) opStr += str("{0}{1}".format(result, ", " if idc.NextNotTail(ea) != cryptEnd else "")) ea = idc.NextNotTail(ea) print "CryptOperations.Add(0x{0:X}, new Operations({1}));".format(zlib.crc32(opStr) & 0xffffffff, opStr) idc.MakeNameEx(prologue, "Encrypt_{0}_{1:X}".format(name, zlib.crc32(opStr) & 0xffffffff), SN_NOCHECK | SN_NOWARN) return;
def FindFunctionAddr(name, offset, operandValue): address = idc.FindBinary(0, SEARCH_DOWN, "\"" + name + "\"") dword = -1 if address == BADADDR: return BADADDR xrefs = XrefsTo(address) for xref in xrefs: dword = xref.frm + offset if dword == BADADDR: return BADADDR return idc.GetOperandValue(dword, operandValue)
def __seek(self): # Method 1 (biased approach) current_address = self.start_address while current_address < self.end_address: next_iter = self.__find_entry(current_address) if next_iter == 1 or next_iter == 0: next_address = idc.FindBinary(current_address + 1, idc.SEARCH_DOWN, ENTRY_ID_BYTECODE + " ?? ??") current_address = next_address elif next_iter > 1: current_address = next_iter else: print("ERROR.SeekingIteration: Issue obtaining a valid macro block to search from at " + \ format_address(hex(current_address))) break print("============================================================")
def __find_all_usages(self, name, signature): sub_instance_counter = 0 current_address = self.start_address while (current_address != idc.BADADDR or current_address != 0) and current_address <= self.end_address: current_address = idc.FindBinary(current_address, idc.SEARCH_DOWN, signature) if (current_address != idc.BADADDR or current_address != 0 ) and current_address <= self.end_address: sub_usage_name = "oreans_" + name + "_" + str( sub_instance_counter) idc.MakeUnknown(current_address, 6, idc.DOUNK_SIMPLE) idc.MakeCode(current_address) label(sub_usage_name, current_address) log_oreans_blacklist_information(sub_usage_name, current_address) self.found_counter += 1 sub_instance_counter += 1 current_address += 1