def _process_offset(offset, ea, next_offset): """Process an offset in a __got section.""" # Convert the address containing the offset into an offset in IDA, but continue if it fails. if not idc.OpOff(ea, 0, 0): _log(1, 'Could not convert {:#x} into an offset', ea) # Get the name to which the offset refers. name = idau.get_ea_name(offset, user=True) if not name: _log(3, 'Offset at address {:#x} has target {:#x} without a name', ea, offset) return False # Make sure this isn't an offset to another stub or to a jump function to another stub. See the # comment in _symbolicate_stub. if stub.symbol_references_stub(name): _log( 1, 'Offset at address {:#x} has target {:#x} (name {}) that references a stub', ea, offset, name) return False # Set the new name for the offset. symbol = next_offset(name) if symbol is None: _log(0, 'Could not generate offset symbol for {}: names exhausted', name) return False if not idau.set_ea_name(ea, symbol, auto=True): _log(2, 'Could not set name {} for offset at {:#x}', symbol, ea) return False return True
def create_offset(addr): if idc.OpOff(addr, 1, 0): return True else: common._debug('Unable to make an offset for string @ 0x%x ' % addr) return False
def add_xrefs(addr, end=idc.BADADDR): """ https://github.com/xyzz/vita-ida-physdump/blob/master/vita_phys_dump.py Searches for MOV / MOVT pair, probably separated by few instructions, and adds xrefs to things that look like addresses """ while addr < end and addr != BADADDR: addr = idc.NextHead(addr) if idc.GetMnem(addr) in ["MOV", "MOVW"]: reg = idc.GetOpnd(addr, 0) if idc.GetOpnd(addr, 1)[0] != "#": continue val = idc.GetOperandValue(addr, 1) found = False next_addr = addr for x in range(16): next_addr = idc.NextHead(next_addr) if idc.GetMnem(next_addr) in ["B", "BX"]: break # TODO: we could handle a lot more situations if we follow branches, but it's getting complicated # if there's a function call and our register is scratch, it will probably get corrupted, bail out if idc.GetMnem(next_addr) in ["BL", "BLX"] and reg in [ "R0", "R1", "R2", "R3" ]: break # if we see a MOVT, do the match! if idc.GetMnem(next_addr) in ["MOVT", "MOVT.W"] and idc.GetOpnd( next_addr, 0) == reg: if idc.GetOpnd(next_addr, 1)[0] == "#": found = True val += idc.GetOperandValue(next_addr, 1) * (2**16) break # if we see something other than MOVT doing something to the register, bail out if idc.GetOpnd(next_addr, 0) == reg or idc.GetOpnd( next_addr, 1) == reg: break if val & 0xFFFF0000 == 0: continue if found: # pair of MOV/MOVT try: idc.OpOffEx(addr, 1, idc.REF_LOW16, val, 0, 0) idc.OpOffEx(next_addr, 1, idc.REF_HIGH16, val, 0, 0) except: print "Failed xref @ %x next_addr %x val %x" % ( addr, next_addr, val) else: # a single MOV instruction try: idc.OpOff(addr, 1, 0) except: print "Failed xref at addr %x" % (addr)
def req_patch(self, hash): addr, value, length = hash['addr'], hash['value'], hash['len'] if length != 4 and length != 8: print("[x] unsupported length: %d" % length) return if length == 4: prev_value = Dword(addr) if MakeDword(addr) != 1: print("[x] MakeDword failed") if PatchDword(addr, value) != 1: print("[x] PatchDword failed") if not idc.OpOff(addr, 0, 0): print("[x] OpOff failed") elif length == 8: prev_value = Qword(addr) if MakeQword(addr) != 1: print("[x] MakeQword failed") if PatchQword(addr, value) != 1: print("[x] PatchQword failed") if not idc.OpOff(addr, 0, 0): print("[x] OpOff failed") print("[*] patched 0x%x = 0x%x (previous was 0x%x)" % (addr, value, prev_value))
def initialize_data_offsets(): """Convert offsets in data segments into offsets in IDA. Segment names must be initialized with segments.initialize_segments() first. """ # Normally, for user-space programs, this operation would be dangerous because there's a good # chance that a valid userspace address would happen to show up in regular program data that is # not actually an address. However, since kernel addresses are numerically much larger, the # chance of this happening is much less. for seg in idautils.Segments(): name = idc.SegName(seg) if not (name.endswith('__DATA_CONST.__const') or name.endswith('__got') or name.endswith('__DATA.__data')): continue for word, ea in idau.ReadWords(seg, idc.SegEnd(seg), addresses=True): if idau.is_mapped(word, value=False): idc.OpOff(ea, 0, 0)
def datify(self): ea = self.get_start_ea(self.DATA) if ea == idc.BADADDR: ea = idc.FirstSeg() print "Converting remaining data to DWORDs...", while ea != idc.BADADDR: flags = idc.GetFlags(ea) if idc.isUnknown(flags) or idc.isByte(flags): idc.MakeDword(ea) idc.OpOff(ea, 0, 0) ea = idc.NextAddr(ea) print "done."
def init_vtable(self): my_start_idx = self.vtable_start_idx() # Fix: support 64bit work if idc.__EA64__: pointer_size = idaapi.DEF_ADDRSIZE pfn_make_ptr = idc.MakeQword pfn_get_ptr_value = idc.Qword else: pointer_size = idaapi.DEF_ADDRSIZE pfn_make_ptr = idc.MakeDword pfn_get_ptr_value = idc.Dword for idx, ea in enumerate(range(self.vtable_start, self.vtable_end, pointer_size)): pfn_make_ptr(ea) idc.OpOff(ea, 0, 0) dst = pfn_get_ptr_value(ea) if idx < my_start_idx: base_method = self.base.vmethods[idx] if base_method.is_dst_equal(dst): # Method from base class self.vmethods.append(self.base.vmethods[idx]) elif Method.s_is_pure_virtual_dst(dst): # New pure virtual override opvm = PureVirtualOverrideMethod(self, base_method, idx) opvm.refresh() self.vmethods.append(opvm) elif Method.s_is_deleted_virtual_dst(dst): # New deleted override dom = DeletedOverrideMethod(self, base_method, idx) dom.refresh() self.vmethods.append(dom) else: # New override om = OverrideMethod(dst, self, base_method, idx) om.refresh() self.vmethods.append(om) elif Method.s_is_pure_virtual_dst(dst): # New pure virtual pvm = PureVirtualMethod(self, 'vf%X' % (idx*4), idx) pvm.refresh() self.vmethods.append(pvm) elif Method.s_is_deleted_virtual_dst(dst): # New deleted virtual pvm = DeletedVirtualMethod(self, 'vf%X' % (idx*4), idx) pvm.refresh() self.vmethods.append(pvm) else: # New virtual vm = VirtualMethod(dst, self, 'vf%X' % (idx*4), idx) vm.refresh() self.vmethods.append(vm)
def add_xrefs(): """ Searches for MOV / MOVT pair, probably separated by few instructions, and adds xrefs to things that look like addresses """ addr = 0 while addr != idc.BADADDR: addr = idc.NextHead(addr) if idc.GetMnem(addr) in ["MOV", "MOVW"]: reg = idc.GetOpnd(addr, 0) if idc.GetOpnd(addr, 1)[0] != "#": continue val = idc.GetOperandValue(addr, 1) found = False next_addr = addr for x in range(16): next_addr = idc.NextHead(next_addr) if idc.GetMnem(next_addr) in ["B", "BX"]: break # TODO: we could handle a lot more situations if we follow branches, but it's getting complicated # if there's a function call and our register is scratch, it will probably get corrupted, bail out if idc.GetMnem(next_addr) in ["BL", "BLX"] and reg in [ "R0", "R1", "R2", "R3" ]: break # if we see a MOVT, do the match! if idc.GetMnem(next_addr) in ["MOVT", "MOVT.W"] and idc.GetOpnd( next_addr, 0) == reg: if idc.GetOpnd(next_addr, 1)[0] == "#": found = True val += idc.GetOperandValue(next_addr, 1) * (2**16) break # if we see something other than MOVT doing something to the register, bail out if idc.GetOpnd(next_addr, 0) == reg or idc.GetOpnd( next_addr, 1) == reg: break if val & 0xFFFF0000 == 0: continue if found: # pair of MOV/MOVT idc.OpOffEx(next_addr, 1, idc.REF_HIGH16, val, 0, 0) else: # a single MOV instruction idc.OpOff(addr, 1, 0)
def datify(self): ea = self.get_start_ea(self.DATA) if ea == idc.BADADDR: ea = idc.FirstSeg() self.say("Converting remaining data to DWORDs...", ) while ea != idc.BADADDR: flags = idc.GetFlags(ea) if (idc.isUnknown(flags) or idc.isByte(flags)) and ((ea % 4) == 0): idc.MakeDword(ea) idc.OpOff(ea, 0, 0) ea = idc.NextAddr(ea) self.say("done.") self._fix_data_offsets()
def convert_vtable_to_offsets(vtable, length=None): """Convert a vtable into a sequence of offsets. Arguments: vtable: The address of the virtual method table. Options: length: The length of the vtable, if known. Returns: True if the data was successfully converted into offsets. """ if length is None: length = vtable_length(vtable) if not length: _log(0, 'Address {:#x} is not a vtable', vtable) return False successful = True for address in idau.Addresses(vtable, length=length, step=idau.WORD_SIZE): if not idc.OpOff(address, 0, 0): _log(0, 'Could not change address {:#x} into an offset', address) successful = False return successful
def fix_names(self): """ Fix the table of imports and map enums to apis. """ start_addr = idc.AskAddr(idc.here(), "Enter table start address") ## check if address is within the base address and maximum address if (start_addr < idc.MinEA()) or (start_addr > idc.MaxEA()): idc.Warning("You have entered an invalid start address") idc.Exit self.start_addr = start_addr current_addr = self.start_addr #Current size of PoisonIvy IAT end_addr = current_addr + 568 # Walk the table 8 bytes at a time while current_addr <= end_addr: idc.MakeQword(current_addr) print "DEBUG: Current address - 0x%08x" % current_addr addr = idc.Qword(current_addr) print "DEBUG: address - 0x%08x" % addr if addr == -1: print "[!] Skipping address 0x%08x - 0x%08x" % (current_addr, addr) current_addr += 8 continue # Make the current address an offset idc.OpOff(current_addr,0,0) # We need to undefine the bytes incase IDA autoanalysis had converted an incorrect byte idc.MakeUnkn(addr, 1) # Create code at this address idc.MakeCode(addr) # Create function at the same address idc.MakeFunction(addr, addr+16) # Read the second operand at the address which should be the negative API address value imp_addr = idc.GetOperandValue(addr, 1) if imp_addr == -1: print "[!] Couldn't get operand at address - 0x%08x" % addr current_addr +=8 continue # try: # int_addr = int(imp_addr,16) # except ValueError as e: # print "[!] Failed on: %s - %s\n" % (imp_addr, e) # current_addr +=8 # continue # if we know about this value then let's do the work if imp_addr in self.enums.keys(): enum_id = self.enums[imp_addr] # Convert operand to enum idc.OpEnumEx(addr, 1, enum_id,0) const_id = idc.GetConstEx(enum_id, imp_addr, 0, -1) fn_name = "fn_"+idc.GetConstName(const_id) off_name = "ptr_"+idc.GetConstName(const_id) # Rename the function to the symbol name. # We append fn_ to the symbol for the function name # and ptr_ to the offset in the table. if not idc.MakeNameEx(addr, fn_name, idaapi.SN_NOWARN): print "[!] Failed to rename function %s at 0x%08x\n" % (fn_name, addr) if not idc.MakeNameEx(current_addr, off_name, idaapi.SN_NOWARN): print "[!] Failed to rename offset %s at 0x%08x\n" % (off_name,current_addr) current_addr += 8 return
def ida_make_offset(f, ea): if f.armv7: idc.MakeDword(ea) else: idc.MakeQword(ea) idc.OpOff(ea, 0, 0)
def untag_pointer(ea, tp): _log(4, 'Untagging pointer at {:x}', ea) idau.patch_word(ea, tagged_pointer_untag(tp)) idc.OpOff(ea, 0, 0)
def untag_pointer(ea, tp): idau.patch_word(ea, tagged_pointer_untag(tp)) idc.OpOff(ea, 0, 0)
def add_xrefs(): """ Searches for MOV / MOVT pair, probably separated by few instructions, and adds xrefs to addresses """ addr = 0 while addr != idc.BADADDR: addr = idc.NextHead(addr) if idc.GetMnem(addr) in ["MOV", "MOVW"]: reg = idc.GetOpnd(addr, 0) if idc.GetOpnd(addr, 1)[0] != "#": continue val = idc.GetOperandValue(addr, 1) found = False lower16_addr = addr upper16_addr = addr for x in range(16): upper16_addr = idc.NextHead(upper16_addr) if idc.GetMnem(upper16_addr) in ["B", "BX"]: break # TODO: we could handle a lot more situations if we follow branches, but it's getting complicated # if there's a function call and our register is scratch, it will probably get corrupted, bail out if idc.GetMnem(upper16_addr) in ["BL", "BLX"] and reg in ["R0", "R1", "R2", "R3"]: break # if we see a MOVT, do the match! if idc.GetMnem(upper16_addr) in ["MOVT", "MOVT.W"] and idc.GetOpnd(upper16_addr, 0) == reg: if idc.GetOpnd(upper16_addr, 1)[0] == "#": found = True val += idc.GetOperandValue(upper16_addr, 1) << 16 break # if we see something other than MOVT doing something to the register, bail out if idc.GetOpnd(upper16_addr, 0) == reg or idc.GetOpnd(upper16_addr, 1) == reg: break # check if is valid address if idaapi.getseg(val) is not None: if found: # pair of MOV/MOVT idc.OpOffEx(lower16_addr, 1, idc.REF_LOW16, val, 0, 0) idc.OpOffEx(upper16_addr, 1, idc.REF_HIGH16, val, 0, 0) else: # a single MOV instruction idc.OpOff(addr, 1, 0) else: val_string = hex(val) if val != 0: val_string += " (" + str(val) float_repr = struct.unpack("<f", struct.pack("<I", val))[0] if float_repr > 0.00000001: val_string += ", " + str(float_repr) + ")" else: val_string += ")" if found: # pair of MOV/MOVT idc.MakeComm(lower16_addr, "lower16:" + val_string) idc.MakeComm(upper16_addr, "upper16:" + val_string) else: # a single MOV instruction if val != 0: idc.MakeComm(addr, val_string)
if op == 1: index = int(idaapi.cmd.Op1.addr) else: index = int(idaapi.cmd.Op2.addr) if index: if displace.has_key(index) == False: displace[index] = [] displace[index].append(curr_addr) for x in displace[0x130]: print hex(x), idc.GetDisasm(x) #遍历所有函数,尝试将带有立即数寻址方式的指令中立即数转化为对数据的偏移 min = MinEA() max = MaxEA() #遍历所有已知的函数 for func in idautils.Functions(): flags = idc.GetFunctionFlags(func) #跳过库函数和简单的跳转函数 if flags & FUNC_LIB or flags & FUNC_THUNK: continue dism_addr = list(idautils.FuncItems(func)) for curr_addr in dism_addr: if idc.GetOpType(curr_addr, 0) == o_imm and (min < idc.GetOperandValue( curr_addr, 0) < max): idc.OpOff(curr_addr, 0, 0) #将操作数转换为一个偏移 if idc.GetOpType(curr_addr, 1) == o_imm and (min < idc.GetOperandValue( curr_addr, 1) < max): idc.OpOff(curr_addr, 1, 0) #将操作数转换为一个偏移