def guidAtAddr(self, addr): val = [idc.Dword(addr), idc.Word(addr + 4), idc.Word(addr + 6), []] addr += 8 val[3] = [idc.Byte(addr + i) for i in range(8)] h = GuidHelper() guid = h.guidOfVals(val) val = h.findGuid(guid) return (val or guid)
def get_guid(address): CurrentGUID = [] CurrentGUID.append(idc.Dword(address)) CurrentGUID.append(idc.Word(address + 4)) CurrentGUID.append(idc.Word(address + 6)) for addr in range(address + 8, address + 16, 1): CurrentGUID.append(idc.Byte(addr)) return CurrentGUID
def parseFuncType(self, offset): return sid = ida_struct.get_struc_id("funcType") in_size = idc.Word(offset + idc.get_member_offset(sid, "incount")) out_size = idc.Word(offset + idc.get_member_offset(sid, "outcount")) sz = ida_struct.get_struc_size(sid) for i in xrange(in_size + out_size): idc.SetType(offset + sz + i * self.stepper.size, "type *")
def parseFuncType(self, offset): return sid = idc.GetStrucIdByName("funcType") in_size = idc.Word(offset + idc.GetMemberOffset(sid, "incount")) out_size = idc.Word(offset + idc.GetMemberOffset(sid, "outcount")) sz = idc.GetStrucSize(sid) for i in xrange(in_size + out_size): idc.SetType(offset + sz + i * self.stepper.size, "type *")
def GetDyn(): phoff = idc.Dword(idc.MinEA() + 0x1c) + idc.MinEA() phnum = idc.Word(idc.MinEA() + 0x2c) phentsize = idc.Word(idc.MinEA() + 0x2a) for i in range(phnum): p_type = idc.Dword(phoff + phentsize * i) if p_type == 2: # PY_DYNAMIC dyn_addr = idc.Dword(phoff + phentsize * i + 8) return dyn_addr
def __init__(self, addr, deepness=0): super(InventoryInterface.Entry, self).__init__(addr, deepness) self.handleId = idc.Dword( self.addr + InventoryInterface.Entry.Offset.HandleId.value) self.ownerHandle = idc.Dword( self.addr + InventoryInterface.Entry.Offset.OwnerHandle.value) self.itemPosition = idc.Word( self.addr + InventoryInterface.Entry.Offset.ItemPosition.value) self.count = idc.Word(self.addr + InventoryInterface.Entry.Offset.Count.value)
def get_guid(address): """ get GUID located by address """ guid = [] guid.append(idc.Dword(address)) guid.append(idc.Word(address + 4)) guid.append(idc.Word(address + 6)) for addr in range(address + 8, address + 16, 1): guid.append(idc.Byte(addr)) return guid
def readValue(self): if self.value != None: return self.value operandType = self.parser.getOperandType() regName = self.parser.getRegName() regValue = idc.GetRegValue(regName) if regName != None else None if operandType == OperandType.Value64OfRegisterPlusOffset: self.value = idc.Qword(regValue + self.opValue) elif operandType == OperandType.Value32OfRegisterPlusOffset: self.value = idc.Dword(regValue + self.opValue) elif operandType == OperandType.Value16OfRegisterPlusOffset: self.value = idc.Word(regValue + self.opValue) elif operandType == OperandType.Value8OfRegisterPlusOffset: self.value = idc.Byte(regValue + self.opValue) elif (operandType == OperandType.Register64) or (operandType == OperandType.Register32): self.value = regValue elif (operandType == OperandType.Register16) or (operandType == OperandType.Register8): self.value = regValue elif operandType == OperandType.ImmediateUnkown: self.value = self.opValue else: raise Exception("Unknown operand type") return self.value
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 parse_hdr(self): ''' Refer: function [go12Init()] in https://golang.org/src/debug/gosym/pclntab.go ''' magic = idc.Dword(self.start_addr) & 0xFFFFFFFF if magic != Pclntbl.MAGIC: print magic, Pclntbl.MAGIC common._error("Invalid pclntbl header magic number!") idc.Exit(1) #raise Exception("Invalid pclntbl header magic number!") idc.MakeDword(self.start_addr) idc.MakeComm(self.start_addr, "Magic Number") idc.MakeNameEx(self.start_addr, "runtime_symtab", flags=idaapi.SN_FORCE) idaapi.autoWait() if idc.Word(self.start_addr + 4) & 0xFFFF != 0: raise Exception("Invalid pclntbl header") idc.MakeWord(self.start_addr + 4) self.min_lc = idc.Byte(self.start_addr + 6) & 0xFF if (self.min_lc != 1) and (self.min_lc != 2) and (self.min_lc != 4): raise Exception("Invalid pclntbl minimum LC!") idc.MakeComm(self.start_addr + 6, "instruction size quantum") idaapi.autoWait() self.ptr_sz = idc.Byte(self.start_addr + 7) & 0xFF if (self.ptr_sz != 4) and (self.ptr_sz != 8): raise Exception("Invalid pclntbl pointer size!") idc.MakeComm(self.start_addr + 7, "ptr size") idaapi.autoWait()
def stval(self, addr, ofs, sz=8): if addr < 20: """ argument """ if addr < 4: regs = ["rcx", "rdx", "r8", "r9"] addr = idc.GetRegValue(regs[addr]) else: rsp = idc.GetRegValue('rsp') addr = idc.Qword(rsp + addr * 8 + 8) if isinstance(ofs, basestring): sf = ofs.split('.') st = struct.Struct(sf[0]) res = st.readInst(addr) while len(sf) > 2: res = st.subInst(res, sf[1]) sf = sf[1:] if len(sf) > 1: res = res[sf[1]] return str(res) if sz == 8: return idc.Qword(addr + ofs) if sz == 4: return idc.Dword(addr + ofs) if sz == 2: return idc.Word(addr + ofs) return idc.Byte(addr + ofs)
def activate(self, ctx): arch = idc.Word(idc.MinEA() + 0x12) if arch == 0x3E: # EM_X86_64 PltResolver64() elif arch == 0x3: # EM_386 PltResolver32() else: print '[-] Only support EM_X86_64 and EM_386' return 1
def mem_read_integer(addr, read_size=4): if read_size == 2: return idc.Word(addr) % 0xFFFF elif read_size == 4: # 32bit Default return idc.Dword(addr) & 0xFFFFFFFF else: # Read Size is 8 Byte (for 64bit) return idc.Qword(addr) & 0xFFFFFFFFFFFFFFFF
def as_x0(self): """ The receiver(X0) of instance methods is always the object. :return: """ if idc.SegName( idc.Qword(self.class_ref) ) == 'UNDEF': # IMPORTED CLASS, has no method implementations. return class_data = idc.Qword(self.class_ref) class_data_ro = idc.Qword(class_data + 0x20) meths = idc.Qword(class_data_ro + 0x20) entrysize = idc.Word(meths) count = idc.Word(meths) for meth in range(meths + 8, meths + 8 + entrysize * count, entrysize): name = idc.Name(idc.Qword(meth)).replace('sel_', '') type = idc.GetDisasm(idc.Qword(meth + 8)) imp = idc.Qword(meth + 0x10) self.add_occurrences(imp, 'x0')
def decrypts_all_strings(offsets): result = [] for offset in offsets: if offset != 0: key = idc.Dword(offset) size = idc.Word(offset) ^ idc.Word(offset + 4) plaintext = '' for index in range(size): key = ((key << 29) | (key >> 3)) + index key = key & 0xFFFFFFFF ciphersymbol = idc.Byte(offset + index + 6) plainsymbol = (key ^ ciphersymbol) & 0xFF plaintext += chr(plainsymbol) result.append([offset, plaintext]) return result
def peek(self, size): ea = self.vaddr + self.offset if size == 1: raw = idc.Byte(ea) elif size == 2: raw = idc.Word(ea) elif size == 4: raw = idc.Dword(ea) else: print "bad size:", size assert (False) return raw
def rename_supposed_guids(self): EFI_GUID = "EFI_GUID *" for seg in idautils.Segments(): if idc.SegName(seg) == ".data": seg_start = idc.SegStart(seg) seg_end = idc.SegEnd(seg) break ea = seg_start while (ea <= seg_end - 15): prot_name = "" if idc.Name(ea).find("unk_") != -1: find = False CurrentGuid = [] CurrentGuid.append(idc.Dword(ea)) CurrentGuid.append(idc.Word(ea + 4)) CurrentGuid.append(idc.Word(ea + 6)) for addr in range(ea + 8, ea + 16, 1): CurrentGuid.append(idc.Byte(addr)) for name in self.Protocols["Edk2Guids"]: if self.Protocols["Edk2Guids"][name] == CurrentGuid: prot_name = name + "_" + hex(ea) find = True break for name in self.Protocols["EdkGuids"]: if self.Protocols["EdkGuids"][name] == CurrentGuid: prot_name = name + "_" + hex(ea) find = True break for name in self.Protocols["AmiGuids"]: if self.Protocols["AmiGuids"][name] == CurrentGuid: prot_name = name + "_" + hex(ea) find = True break if (find and \ idc.Name(ea) != prot_name and \ CurrentGuid[0] != 0 ): idc.SetType(ea, EFI_GUID) idc.MakeName(ea, prot_name) ea += 1
def IsInstrumentIns(ea): ''' is ea instrument instruction? ''' if idc.__EA64__: # 64bit ''' .text:0000000000412450 48 8D 64 24 80 lea rsp, [rsp-80h] .text:0000000000412455 53 push rbx .text:0000000000412456 51 push rcx .text:0000000000412457 68 30 E2 00 00 push 0E230h // z .text:000000000041245C 48 C7 C1 00 00 00+mov rcx, 0 // x .text:0000000000412463 48 C7 C3 19 D6 00+mov rbx, 0D619h .text:000000000041246A E8 51 44 00 00 call __afl_maybe_log_fun_3 .text:000000000041246F 59 pop rcx .text:0000000000412470 59 pop rcx .text:0000000000412471 5B pop rbx .text:0000000000412472 48 8D A4 24 80 00+lea rsp, [rsp+80h] ''' if 0x6851538024648D48 == idc.Qword(ea) and 0xC748 == idc.Word( ea + 0xc) and 0xC748 == idc.Word( ea + 0x13) and 0x0000008024A48D48 == idc.Qword(ea + 0x22): return True else: # 32bit ''' 52 push edx 51 push ecx 50 push eax B9 8A 7D 00 00 mov ecx, 7D8Ah E8 53 10 00 00 call __afl_maybe_log 58 pop eax 59 pop ecx 5A pop edx ''' if 0xB9505152 == idc.Dword(ea) and 0x5A595800 == idc.Dword(ea + 12): return True return False
def MakeAndGetWord(ea, comment=None): """ Creates a word at the specified address and returns the word value. :param ea: address to make word at :param comment: optional comment to place at the specified address :return: the value of the word at the specified address """ # Make the word value. idc.MakeWord(ea) # Check if the comment is valid and if so place it at the address. if comment is not None: idc.MakeComm(ea, comment) # Get the word value. return idc.Word(ea)
def read_word(ea, wordsize=WORD_SIZE): """Get the word at the given address. Words are read using Byte(), Word(), Dword(), or Qword(), as appropriate. Addresses are checked using is_mapped(). If the address isn't mapped, then None is returned. """ if not is_mapped(ea, wordsize): return None if wordsize == 1: return idc.Byte(ea) if wordsize == 2: return idc.Word(ea) if wordsize == 4: return idc.Dword(ea) if wordsize == 8: return idc.Qword(ea) raise ValueError('Invalid argument: wordsize={}'.format(wordsize))
def parse_hdr(self): ''' Refer: function [go12Init()] in https://golang.org/src/debug/gosym/pclntab.go ''' magic = idc.Dword(self.start_addr) & 0xFFFFFFFF if magic != Pclntbl.MAGIC: print magic, Pclntbl.MAGIC common._error("Invalid pclntbl header magic number!") idc.Exit(1) #raise Exception("Invalid pclntbl header magic number!") if idc.Word(self.start_addr + 4) & 0xFFFF != 0: raise Exception("Invalid pclntbl header") self.min_lc = idc.Byte(self.start_addr + 6) & 0xFF if (self.min_lc != 1) and (self.min_lc != 2) and (self.min_lc != 4): raise Exception("Invalid pclntbl minimum LC!") self.ptr_sz = idc.Byte(self.start_addr + 7) & 0xFF if (self.ptr_sz != 4) and (self.ptr_sz != 8): raise Exception("Invalid pclntbl pointer size!")
def search_rop_gadgets(self, segment, ret_preamble = 0xc3): """ Search for rop gadgets """ # Nothing to do if the option is not set if not self.searchRop: return ea = segment.startEA while True: ea = idaapi.find_binary(ea + 1, segment.endEA, "%X" % ret_preamble, 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break if ret_preamble in [ 0xc2, 0xca, 0xf2c2]: # Read imm16 value and filter large values retn_imm16 = idc.Word(ea + 1) if retn_imm16 <= self.maxRetnImm: self.retns.append((ea)) else: self.retns.append( (ea))
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 readData(ea, type, size): flag = type[1] if not flag: return '' t = flag & idc.DT_TYPE tsz = DATA['typeSize'][t] val = [] for i in range(size / tsz): if t == idc.FF_BYTE: val += [idc.Byte(ea)] elif t == idc.FF_WORD: val += [idc.Word(ea)] elif t == idc.FF_DWRD: val += [idc.Dword(ea)] elif t == idc.FF_QWRD: val += [idc.Qword(ea)] elif t == idc.FF_FLOAT: val += [idc.GetFloat(ea)] ea += tsz if len(val) == 1: val = idc.GetString(val[0], -1, DATA['strtypes'][ type[0]]) if type[0] in DATA['strtypes'] else val[0] return val
def annotate_vector_table(self, vtoffset=0x0000000000): ''' Name the vector table entries according to docs: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIFJFG.html Vector tables can appear in mulitple places in device flash Functions are not renamed because multiple vectors might point to a single function Append the address of the VT entry to the name from self.annotations to keep unique names ''' for annotation_index in range(len(self.annotations)): entry_addr = vtoffset + 4 * annotation_index entry_name = "%s_%08x" % (self.annotations[annotation_index], entry_addr) idc.MakeDword(entry_addr) ida_name.set_name(entry_addr, entry_name, 0) # get the bytes of the vt entry dword = idc.Dword(entry_addr) if dword != 0: # print "ea %08x = 0x%08x" % (ea, dword) idc.MakeCode(dword - 1) idc.MakeFunction(dword - 1) # TODO fix the offsets created here # for thumb, they show to be off by a byte # one of the end args controls stuff about this idc.OpOffEx(entry_addr, 0, idaapi.REF_OFF32, -1, 0, 0) instruction = idc.Word(dword - 1) # functions like this are common if instruction == 0xe7fe: idc.SetFunctionCmt(dword - 1, 'Infinite Loop', 1)
def getUInt16(ea) : return idc.Word(ea)
def get_data_guids(self): """ rename GUIDs in idb """ EFI_GUID = "EFI_GUID *" segments = [".text", ".data"] for segment in segments: seg_start, seg_end = 0, 0 for seg in idautils.Segments(): if idc.SegName(seg) == segment: seg_start = idc.SegStart(seg) seg_end = idc.SegEnd(seg) break ea = seg_start while (ea <= seg_end - 15): prot_name = "" if idc.Name(ea).find("unk_") != -1: find = False cur_guid = [] cur_guid.append(idc.Dword(ea)) cur_guid.append(idc.Word(ea + 4)) cur_guid.append(idc.Word(ea + 6)) for addr in range(ea + 8, ea + 16, 1): cur_guid.append(idc.Byte(addr)) if cur_guid == [0] * 11: ea += 1 continue for name in self.Protocols["Edk2Guids"]: if self.Protocols["Edk2Guids"][name] == cur_guid: prot_name = name + "_" + "{addr:#x}".format( addr=ea) record = { "address": ea, "service": "unknown", "guid": cur_guid, "protocol_name": name, "protocol_place": "edk2_guids" } find = True break for name in self.Protocols["EdkGuids"]: if self.Protocols["EdkGuids"][name] == cur_guid: prot_name = name + "_" + "{addr:#x}".format( addr=ea) prot_name = name + "_" + "{addr:#x}".format( addr=ea) record = { "address": ea, "service": "unknown", "guid": cur_guid, "protocol_name": name, "protocol_place": "edk_guids" } find = True break for name in self.Protocols["AmiGuids"]: if self.Protocols["AmiGuids"][name] == cur_guid: prot_name = name + "_" + "{addr:#x}".format( addr=ea) prot_name = name + "_" + "{addr:#x}".format( addr=ea) record = { "address": ea, "service": "unknown", "guid": cur_guid, "protocol_name": name, "protocol_place": "ami_guids" } find = True break if (find and (idc.Name(ea) != prot_name)): idc.SetType(ea, EFI_GUID) idc.MakeName(ea, prot_name) self.Protocols["Data"].append(record) ea += 1
def getWord(self, ea): return idc.Word(ea)
def get_wide_dword(addr): if idaapi.IDA_SDK_VERSION <= 699: retval = idc.Word(addr) else: retval = idc.get_wide_dword(addr) return retval
def getInt16(ea) : return toSigned(idc.Word(ea), 16)