def read_mem(addr, forced_addr_sz=None, read_only=False): global ADDR_SZ if not read_only: if forced_addr_sz: idc.MakeUnknown(addr, forced_addr_sz, idc.DOUNK_SIMPLE) else: idc.MakeUnknown(addr, ADDR_SZ, idc.DOUNK_SIMPLE) idaapi.autoWait() if forced_addr_sz == 2: if not read_only: idc.MakeWord(addr) idaapi.autoWait() return idc.Word(addr) if forced_addr_sz == 4 or ADDR_SZ == 4: if not read_only: idc.MakeDword(addr) idaapi.autoWait() return idc.Dword(addr) if forced_addr_sz == 8 or ADDR_SZ == 8: if not read_only: idc.MakeQword(addr) idaapi.autoWait() return idc.Qword(addr)
def create_string(addr, string_len): # if idaapi.get_segm_name(addr) is None: if idc.get_segm_name(addr) is None: common._debug( 'Cannot load a string which has no segment - not creating string @ 0x%02x' % addr) return False common._debug('Found string load @ 0x%x with length of %d' % (addr, string_len)) # This may be overly aggressive if we found the wrong area... if idc.GetStringType(addr) is not None and idc.GetString( addr) is not None and len(idc.GetString(addr)) != string_len: common._debug( 'It appears that there is already a string present @ 0x%x' % addr) idc.MakeUnknown(addr, string_len, idc.DOUNK_SIMPLE) idaapi.autoWait() if idc.GetString(addr) is None and idc.MakeStr(addr, addr + string_len): idaapi.autoWait() return True else: # If something is already partially analyzed (incorrectly) we need to MakeUnknown it idc.MakeUnknown(addr, string_len, idc.DOUNK_SIMPLE) idaapi.autoWait() if idc.MakeStr(addr, addr + string_len): idaapi.autoWait() return True common._debug('Unable to make a string @ 0x%x with length of %d' % (addr, string_len)) return False
def check_address(address): # Checks if given address contains virtual table. Returns True if more than 2 function pointers found # Also if table's addresses point to code in executable section, than tries to make functions at that addresses if helper.is_code_ea(address): return False if not idaapi.get_name(address): return False functions_count = 0 while True: func_address = helper.get_ptr(address) # print "[INFO] Address 0x{0:08X}".format(func_address) if helper.is_code_ea(func_address) or helper.is_imported_ea( func_address): functions_count += 1 address += const.EA_SIZE else: segment = idaapi.getseg(func_address) if segment and segment.perm & idaapi.SEGPERM_EXEC: idc.MakeUnknown(func_address, 1, idaapi.DOUNK_SIMPLE) if idc.MakeFunction(func_address): functions_count += 1 address += const.EA_SIZE continue break idaapi.autoWait() return functions_count
def markSwitchTables(self, sc, aggressive=True): """Help IDA by marking all of the needed information from the observed switch tables. Args: sc (segment): (sark) code segment in which we are interested right now aggressive (bool, optional): True iff the marking operation should be aggressive, see notes. (True by default) Notes ----- 1. Make sure the switch case jump instruction is indeed a code line 2. Make sure the jump instruction has a code reference to all of the switch cases 3. (Aggressive) Make sure each switch table entry is a proper code pointer to it's matching case 4. (Aggressive) Enforce the correct code type over the entire gap between the minimal and maximal case """ for switch_instr, table_start, table_end in filter( lambda x: sc.startEA <= x[0] and x[1] < sc.endEA, self._switch_case_entries): cases = [] if not sark.Line(switch_instr).is_code: idc.MakeUnknown(switch_instr, self._analyzer.addressSize(), 0) idc.MakeCode(switch_instr) for ea in xrange(table_start, table_end, self._analyzer.addressSize()): entry = self._analyzer.parseAdderss(ea) if aggressive: self._analyzer.markCodePtr(ea, entry) fixed_entry = self._analyzer.cleanPtr(entry) cases.append(fixed_entry) idc.add_cref(switch_instr, fixed_entry, idc.XREF_USER | idc.dr_O) if aggressive: self._analyzer.setCodeType(min(cases), max(cases), self._analyzer.ptrCodeType(entry))
def ida_main(): import idc filepath = idc.AskFile(0, "*.map", "Load a Dolphin emulator symbol map") if filepath is None: return symbol_map = load_dolphin_map(filepath) for symbol in symbol_map: addr = int(symbol.vaddr, 16) size = int(symbol.size, 16) idc.MakeUnknown(addr, size, 0) if symbol.section in [".init", ".text"]: idc.MakeCode(addr) success = idc.MakeFunction( addr, idc.BADADDR if not size else (addr + size)) else: success = idc.MakeData(addr, idc.FF_BYTE, size, 0) if not success: idc.Message("Can't apply properties for symbol:" " {0.vaddr} - {0.name}\n".format(symbol)) flags = idc.SN_NOCHECK | idc.SN_PUBLIC if symbol.name.startswith("zz_"): flags |= idc.SN_AUTO | idc.SN_WEAK else: flags |= idc.SN_NON_AUTO idc.MakeNameEx(addr, symbol.name, flags)
def make_array(ea, size): if ea != idc.BADADDR and ea != 0: flags = idc.GetFlags(ea) if not idc.isByte(flags) or idc.ItemSize(ea) != 1: idc.MakeUnknown(ea, 1, idc.DOUNK_SIMPLE) idc.MakeByte(ea) idc.MakeArray(ea, size)
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 apply_struct(ea, name, size): sid = idc.GetStrucIdByName(name) if (size == -1): size = idc.GetStrucSize(sid) idc.MakeUnknown(ea, size, idc.DOUNK_DELNAMES) idaapi.doStruct(ea, size, sid) return size
def define(self): """ Defines the string in the IDB. """ try: idc.MakeUnknown(self.startEA, self.byte_length, idc.DOUNK_SIMPLE) idaapi.make_ascii_string(self.startEA, self.byte_length, self.string_type) except: append_debug('Unable to define string at 0x%X' % self.startEA)
def read_string(ea): s = idc.GetString(ea, -1, idc.ASCSTR_C) if s: slen = len(s) + 1 idc.MakeUnknown(ea, slen, idc.DOUNK_SIMPLE) idaapi.make_ascii_string(ea, slen, idc.ASCSTR_C) return s, ea + slen else: return s, ea
def apply_struct(ea, sid, size): if size == -1: size = idc.GetStrucSize(sid) idc.MakeUnknown(ea, size, idc.DOUNK_DELNAMES) idaapi.doStruct(ea, size, sid) return size
def markCodePtr(self, src, dest, aggressive=True): """Mark a code pointer from src to dest. Args: src (int): effective address for the pointer's location dest (int): effective address for the pointed code address aggressive (bool, optional): True iff should redefine the src & dest (True by default) """ clean_dest = self.cleanPtr(dest) if aggressive: idc.MakeUnknown(src, self.addressSize(), 0) if self.makeAddress(src): idc.add_dref(src, clean_dest, idc.XREF_USER | idc.dr_O) idc.add_cref(src, clean_dest, idc.XREF_USER | idc.dr_O) ida_offset.op_offset(src, 0, idc.REF_OFF32) if aggressive: idc.MakeUnknown(dest, self.addressSize(), 0) idc.MakeCode(self.cleanPtr(dest))
def delCodePtr(self, src, dest): """Delete a code pointer (probably was found to be a False Positive). Args: src (int) effective address for the pointer's location dest (int): effective address for the (assumed) pointed code address """ idc.del_dref(src, dest) idc.del_cref(src, dest, 0) idc.MakeUnknown(src, self.addressSize(), 0)
def markDataPtr(self, src, dest, aggressive=True): """Mark a data pointer from src to dest. Args: src (int): effective address for the pointer's location dest (int): effective address for the pointed data address aggressive (bool, optional): True iff should redefine the src (True by default) """ if aggressive: idc.MakeUnknown(src, self.addressSize(), 0) if self.makeAddress(src): idc.add_dref(src, dest, idc.XREF_USER | idc.dr_O) ida_offset.op_offset(src, 0, idc.REF_OFF32)
def PatchCall(addr): ''' To improve IDA's analysis, the patch converts call abuse into push and jmp instructions. The patched data is saved as a comment. ''' if idc.Byte(addr) == 0xE8: logger = logging.getLogger(__name__) logger.info("Patching push as call @ %x" % addr) data_size = idc.Dword(addr + 1) if (data_size) >= 0xfe: logger.info("Can't patch: 0x%x" % addr) return fname = idc.GetFunctionName(addr) target = idc.GetOperandValue(addr, 0) data_addr = addr + idautils.DecodeInstruction(addr).size orig_data = idc.Word(data_addr) orig_asm = idc.GetDisasm(addr) idc.MakeUnknown(addr, target - addr, idaapi.DOUNK_EXPAND | idaapi.DOUNK_DELNAMES) idc.PatchByte(addr, 0x68) idc.PatchDword(addr + 1, data_addr) idc.PatchByte(data_addr, 0xEB) idc.PatchByte(data_addr + 1, data_size - 2) # idaapi.analyze_area(addr, data_addr + 2) uksize = 0 if fname != idc.GetFunctionName(target) and fname is not None: while uksize < 32: x = idautils.DecodeInstruction(target + uksize) if x is None: break uksize += x.size idc.MakeUnknown(target, uksize, idaapi.DOUNK_EXPAND | idaapi.DOUNK_DELNAMES) # idaapi.analyze_area(target, target + uksize + 1) idc.MakeComm(addr, "Original: " + orig_asm) idc.MakeComm(data_addr, "Original: %x" % orig_data)
def make_str(address): """Calculate the length, undefine and make an ascii string.""" # calculate the length, with a hardcoded maximum length ret = '' for offset in xrange(MAX_STRING_LENGTH): ch = idc.GetOriginalByte(address + offset) if not ch: break ret += chr(ch) idc.MakeUnknown(address, offset, idc.DOUNK_SIMPLE) idc.MakeStr(address, address + offset) return ret
def dbg_trace(self, tid, ea): if ea >> 12 == 0x18f: self.ctx = 3 if self.ctx == 0: return 1 self.ctx -= 1 idc.RefreshDebuggerMemory() idc.MakeUnknown(ea, 20, 0) idc.MakeCode(ea) mnem = idc.GetDisasm(ea) print(hex(ea), mnem) regs = 'eax ebx ecx edx esi edi eip'.split(' ') regs = {x: idc.GetRegValue(x) for x in regs} self.ins.append(Attributize(None, mnem=mnem, **regs)) return 1
def define_string(decoded_string): ''' Defines a string object in the IDB for the provided string. Input: decoded_string - The EncodedString object to define in IDA ''' try: idc.MakeUnknown(decoded_string.startEA, decoded_string.byte_length, idc.DOUNK_SIMPLE) idaapi.make_ascii_string(decoded_string.startEA, decoded_string.byte_length, decoded_string.string_type) except: append_debug('Unable to define string at 0x%X' % decoded_string.startEA)
def defineAsciiString(self, ea): r"""Define an ascii string at the given address. Args: ea (int): effective start address of the wanted ascii string Return Value: The length of the defined string + 1 for the '\0' terminator """ content = idc.GetString(ea, -1, -1) if not sark.Line(ea).is_string: self._analyzer.logger.debug("Defined a unique ascii string at: 0x%x (Length of %d)", ea, len(content) + 1) idc.MakeUnknown(ea, len(content) + 1, 0) # Backward compatibility is always fun if idaapi.IDA_SDK_VERSION <= 700: idaapi.make_ascii_string(ea, len(content) + 1, idc.ASCSTR_C) else: idc.MakeStr(ea, ea + len(content) + 1) return len(content) + 1
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
def resizeRegion(analyzer, start_ea, end_ea, new_start_ea, new_end_ea): """Resize a given code region, according to the new dimensions. Args: analyzer (instance): analyzer instance to be used start_ea (int): effective start address of the original region end_ea (int): effective end address of the original region new_start_ea (int): effective start address for the new region new_end_ea (int): effective end address for the new region """ analyzer.logger.info( "Resizing code region of type %d: 0x%x (0x%x) - 0x%x (0x%x)", analyzer.codeType(start_ea), new_start_ea, start_ea, end_ea, new_end_ea) code_type_before = analyzer.codeType(min(start_ea, new_start_ea) - 1) code_type_middle = analyzer.codeType(start_ea) code_type_after = analyzer.codeType(max(end_ea, new_end_ea)) # Make sure it will be treated as code fix_regions = [] if new_start_ea < start_ea: fix_regions.append((new_start_ea, start_ea)) elif new_start_ea != start_ea: fix_regions.append((start_ea, new_start_ea)) if end_ea < new_end_ea: fix_regions.append((end_ea, new_end_ea)) elif end_ea != new_end_ea: fix_regions.append((new_end_ea, end_ea)) # Make the changed parts unknown, before re-analyzing them for region_start, region_end in fix_regions: idc.MakeUnknown(region_start, region_end - region_start, 0) # manually set the wanted value over the entire region if start_ea < new_start_ea: analyzer.setCodeType(start_ea, new_start_ea, code_type_before) elif start_ea != new_start_ea: analyzer.setCodeType(new_start_ea, start_ea, code_type_middle) if end_ea < new_end_ea: analyzer.setCodeType(end_ea, new_end_ea, code_type_middle) elif end_ea != new_end_ea: analyzer.setCodeType(new_end_ea, end_ea, code_type_after) # now reanalyze the new section for region_start, region_end in fix_regions: idaapi.analyze_area(region_start, region_end)
def convertRegion(analyzer, start_ea, end_ea): """Convert (Cancel) a given code region (change it's code type). Args: analyzer (instance): analyzer instance to be used start_ea (int): effective start address of the region end_ea (int): effective end address of the region """ wanted_code_type = analyzer.codeType(end_ea) analyzer.logger.info( "Converting code region of type %d to %d: 0x%x - 0x%x (%d)", analyzer.codeType(start_ea), wanted_code_type, start_ea, end_ea, end_ea - start_ea) # Make sure it will be treated as code idc.MakeUnknown(start_ea, end_ea - start_ea, 0) # manually set the wanted value over the entire region analyzer.setCodeType(start_ea, end_ea, wanted_code_type) # now reanalyze the new section idaapi.analyze_area( analyzer.alignTransitionAddress(start_ea, wanted_code_type), end_ea)
def rename(beg, ptr, make_funcs=True): base = beg pos = beg + 8 #skip header size = ptr.ptr(pos) pos += ptr.size end = pos + (size * ptr.size * 2) print "%x" % end while pos < end: offset = ptr.ptr(pos + ptr.size) ptr.maker(pos) #in order to get xrefs ptr.maker(pos + ptr.size) pos += ptr.size * 2 ptr.maker(base + offset) func_addr = ptr.ptr(base + offset) if make_funcs == True: idc.MakeUnknown(func_addr, 1, idc.DOUNK_SIMPLE) idc.MakeFunction(func_addr) name_offset = idc.Dword(base + offset + ptr.size) name = idc.GetString(base + name_offset) name = Utils.relaxName(name) Utils.rename(func_addr, name)
def check_address(address): # Checks if given address contains virtual table. Returns True if more than 2 function pointers found # Also if table's addresses point to code in executable section, than tries to make functions at that addresses functions_count = 0 while True: func_address = idaapi.get_64bit(address) if Const.EA64 else idaapi.get_32bit(address) flags = idaapi.getFlags(func_address) # flags_t # print "[INFO] Address 0x{0:08X}".format(func_address) if idaapi.isCode(flags): functions_count += 1 address += Const.EA_SIZE else: segment = idaapi.getseg(func_address) if segment and segment.perm & idaapi.SEGPERM_EXEC: idc.MakeUnknown(func_address, 1, idaapi.DOUNK_SIMPLE) if idc.MakeFunction(func_address): functions_count += 1 address += Const.EA_SIZE continue break idaapi.autoWait() return functions_count
def apply_struct(objname, address): """Apply a Structure to an address.""" structure = _struct_by_name(objname) size = ctypes.sizeof(structure) # it is known idc.MakeUnknown(address, size, idc.DOUNK_SIMPLE) idc.MakeStruct(address, objname) # read the structure and return that data data = (idc.GetOriginalByte(x) for x in xrange(address, address + size)) _ret = structure.from_buffer_copy(''.join(chr(x) for x in data)) class _Structure: pass ret = _Structure() offset = 0 for name, typ in structure._fields_: # pointer to an ascii string if typ == ctypes.c_char_p: value = idc.Dword(address + offset) setattr(ret, name, make_str(value)) # pointer to an unicode string elif typ == ctypes.c_wchar_p: # TODO implement unicode string stuff pass # this is a pointer to another structure elif hasattr(typ, 'contents'): _name = _registered_structures[typ._type_][0] _addr = idc.Dword(address + offset) setattr(ret, name, apply_struct(_name, _addr)) else: setattr(ret, name, getattr(_ret, name)) offset += ctypes.sizeof(typ) return ret
def __seek(self): # Method 2 (reversal approach) one of the most accurate methods current_address = self.start_address while current_address < self.end_address: current_address = idc.FindBinary(current_address, idc.SEARCH_DOWN, LANDING_STRIP) presumed_landing_address = current_address if presumed_landing_address == idc.BADADDR or presumed_landing_address == 0: # have reached the end break else: # [macro + [macro + normal]] renders (macro + normal) usually not interp'd by ida idc.MakeUnknown(presumed_landing_address, 2, idc.DOUNK_SIMPLE) idc.MakeCode(presumed_landing_address) zoning_address = presumed_landing_address next_iter = 0 if len(self.macros) > 0: # finding following macro... entry_search_limit_address = (self.macros[-1])[2] next_iter = self.__find_entry(entry_search_limit_address, zoning_address, presumed_landing_address) else: # landing is above start, finding first macro... next_iter = self.__find_entry(self.start_address, zoning_address, presumed_landing_address) if next_iter == 0: print( "ERROR.SeekingIteration: Issue obtaining a valid macro block to search from." ) break else: current_address = next_iter print("============================================================")
def undefine(start, end): idc.MakeUnknown(start, end - start, idc.DOUNK_SIMPLE)
def write_data(ea, blob, reanalyze=True): """ Write bytes to idb """ if reanalyze: idc.MakeUnknown(ea, len(blob), 0) idaapi.patch_many_bytes(ea, blob) if reanalyze: idc.MakeCode(ea)
def reset(): idc.MakeUnknown(idc.MinEA(), 0x1000, 0) for i in range(0x1000): idc.PatchByte(idc.MinEA() + i, 0)
def make_string(addr, siz): print("Creating string at %x %d size" % (addr, siz)) idc.MakeUnknown(addr, siz, idc.DOUNK_SIMPLE) ida_bytes.create_strlit(addr, siz, -1)