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 msr_parse(): start = idc.MinEA() stop = idc.MaxEA() rdmsr_addr = idaapi.find_binary(start, stop, "0F 32", 0, 0) wrmsr_addr = idaapi.find_binary(start, stop, "0F 30", 0, 0) cpuid_addr = idaapi.find_binary(start, stop, "0F A2", 0, 0) idc.MakeCode(each)
def search_ea(sig, segment="", callback=None): eas = [] if segment != "": seg = idaapi.get_segm_by_name(segment) if not seg: return ea, maxea = seg.startEA, seg.endEA count = 0 while ea != idaapi.BADADDR: ea = idaapi.find_binary(ea, maxea, sig, 16, idaapi.SEARCH_DOWN) if ea != idaapi.BADADDR: count = count + 1 if callback != None: callback(ea) else: eas.append(ea) ea += 2 else: for seg in Segments(): ea = SegStart(seg) maxea = SegEnd(ea) count = 0 while ea != idaapi.BADADDR: ea = idaapi.find_binary(ea, maxea, sig, 16, idaapi.SEARCH_DOWN) if ea != idaapi.BADADDR: count = count + 1 if callback != None: callback(ea) else: eas.append(ea) ea += 2 return eas
def formbook_patch_encrypted_bytecode(): text_segm = ida_segment.get_segm_by_name('.text') if not text_segm: return idaapi.BADADDR seg_start = text_segm.startEA seg_end = text_segm.endEA fb_decrypt = FormBookDecryption() rc4_key = "faddefad156c45629c95d5f429363b0653ad5c1d".decode('hex') # same as rc4_final from formbook_decrypt_hashes_and_strings() for i in [(0x40, 0x48), (0x41, 0x49), (0x42, 0x4a), (0x43, 0x4b), (0x44, 0x4c)]: egg_pattern = ''.join('{:02x} '.format(x) for x in [i[0], 0x90, 0x90, 0x90, i[1]]) encrypted_start = idaapi.find_binary(seg_start, seg_end, egg_pattern, 16, idaapi.SEARCH_DOWN) if encrypted_start != idaapi.BADADDR: encrypted_end = idaapi.find_binary(encrypted_start + 5, seg_end, "90 90 90 90", 16, idaapi.SEARCH_DOWN) if encrypted_end != idaapi.BADADDR: encrypted_start += 5 patch_length = encrypted_end - encrypted_start if idaapi.visit_patched_bytes(encrypted_start, encrypted_end, callback_on_patched_bytes) == 0: encrypted_buff = idaapi.get_bytes(encrypted_start, patch_length) decrypted_buff = fb_decrypt.decrypt_func2(encrypted_buff, rc4_key) print('Patching encrypted bytecode at 0x{:x} ({:d} bytes)'.format(encrypted_start, patch_length)) idaapi.patch_many_bytes(encrypted_start, decrypted_buff) else: print('Encrypted bytecode at 0x{:x} ({:d} bytes) is already patched'.format(encrypted_start, patch_length))
def findGoPcLn(): possible_loc = idaapi.find_binary(0, idc.BADADDR, lookup, 16, idc.SEARCH_DOWN) #header of gopclntab while possible_loc != idc.BADADDR: if check_is_gopclntab(possible_loc): return possible_loc else: #keep searching till we reach end of binary possible_loc = idaapi.find_binary(possible_loc + 1, idc.BADADDR, lookup, 16, idc.SEARCH_DOWN) return None
def find_byte_sequence(start, end, seq): """ find byte sequence args: start: min virtual address end: max virtual address seq: bytes to search e.g. b'\x01\x03' """ if sys.version_info[0] >= 3: return idaapi.find_binary(start, end, " ".join(["%02x" % b for b in seq]), 0, idaapi.SEARCH_DOWN) else: return idaapi.find_binary(start, end, " ".join(["%02x" % ord(b) for b in seq]), 0, idaapi.SEARCH_DOWN)
def find_all_pattern(pat): first = idc.FirstSeg() last = idc.BADADDR result = [] ea = idaapi.find_binary(first, last, pat, 16, idaapi.SEARCH_DOWN) while ea != idaapi.BADADDR and ea < last: result.append(ea) ea = idaapi.find_binary(ea, last, pat, 16, idaapi.SEARCH_DOWN | idaapi.SEARCH_NEXT) return result
def process_func_for_string(str, f): loc = idaapi.find_binary(0, idc.BADADDR, "\"%s" % str, 16, 0) if loc == idc.BADADDR: print "String '%s' not found" % str return False xrEa = 0 for xr in idautils.XrefsTo(loc): xrEa = xr.frm break if xrEa == 0: print "No xrefs to string '%s'" % str return False fn = idaapi.get_func(xrEa) if not fn: print "No function at xref to string '%s' (at %x)" % (str, xrEa) return False fnEa = fn.startEA if isThumb(fnEa): fnEa += 1 if f: f.write("\t// %s\n" % str) f.write("\t{0x%x, 0x%x, 0x%x},\n" % (loc, xrEa, fnEa)) print "// %s" % str print "{0x%x, 0x%x, 0x%x}," % (loc, xrEa, fnEa) return True
def chendo(address, end, search, struct): while address < end: address = idaapi.find_binary(address, end, search, 0x10, SEARCH_DOWN) idaapi.do_unknown_range(address, 0xB0, 0) idaapi.create_struct(address, 0xB0, struct) address += 0x8
def ports_analisys(): ports_struc = idc.AddEnum(-1, "ports", (FF_WRD|FF_DATA)) idc.AddConstEx(ports_struc, "PCI_CONFIG_ADDRESS", PCI_CONFIG_ADDRESS, -1) idc.AddConstEx(ports_struc, "PCI_CONFIG_DATA", PCI_CONFIG_DATA, -1) for each in idaapi.find_binary(start, stop, "", 0, 0): # find_binary(ea_t startea, ea_t endea, char ubinstr, int radix, int sflag) -> ea_t idc.MakeCode(each)
def kiwidog(address, end, search): magic = idaapi.find_binary(address, end, search, 0x0, SEARCH_DOWN) function = idaapi.get_func(idaapi.get_first_dref_to(magic)) idaapi.set_name(function.start_ea, '__stack_chk_fail', SN_NOCHECK | SN_NOWARN) function.flags |= FUNC_NORET idaapi.update_func(function)
def create_runtime_ms(): debug('Attempting to find runtime_morestack function for hooking on...') text_seg = get_text_seg() if text_seg is None: debug('Failed to get text segment') return None # Opcodes for "mov large dword ptr ds:1003h, 0", binary search is faster than text search opcodes = 'c7 05 03 10 00 00 00 00 00 00' if idaapi.get_inf_structure().is_64bit(): # Opcodes for "mov qword ptr ds:dword_1000+3, 0" opcodes = '48 c7 04 25 03 10 00 00 00 00 00 00' runtime_ms_end = idaapi.find_binary(text_seg.startEA, text_seg.endEA, opcodes, 0, SEARCH_DOWN) if runtime_ms_end == BADADDR: debug('Failed to find opcodes associated with runtime_morestack: %s' % opcodes) return None runtime_ms = idaapi.get_func(runtime_ms_end) if runtime_ms is None: debug('Failed to get runtime_morestack function from address @ 0x%x' % runtime_ms_end) return None if idc.MakeNameEx(runtime_ms.startEA, "runtime_morestack", SN_PUBLIC): debug('Successfully found runtime_morestack') else: debug('Failed to rename function @ 0x%x to runtime_morestack' % runtime_ms.startEA) return runtime_ms
def znullptr(address, end, search, struct): magic = idaapi.find_binary(address, end, search, 0x10, idc.SEARCH_DOWN) pattern = '%02X %02X %02X %02X FF FF FF FF' % (magic & 0xFF, ((magic >> 0x8) & 0xFF), ((magic >> 0x10) & 0xFF), ((magic >> 0x18) & 0xFF)) sysvec = idaapi.find_binary(address, cvar.inf.maxEA, pattern, 0x10, idc.SEARCH_UP) - 0x60 idaapi.set_name(sysvec, 'sysentvec', SN_NOCHECK | SN_NOWARN | SN_FORCE) sysent = idaapi.get_qword(sysvec + 0x8) idaapi.set_name(sysent, 'sv_table', SN_NOCHECK | SN_NOWARN | SN_FORCE) sysnames = idaapi.get_qword(sysvec + 0xD0) idaapi.set_name(sysnames, 'sv_syscallnames', SN_NOCHECK | SN_NOWARN | SN_FORCE) # Get the list of syscalls offset = idaapi.find_binary(address, cvar.inf.maxEA, '73 79 73 63 61 6C 6C 00 65 78 69 74 00', 0x10, SEARCH_DOWN) numsyscalls = idaapi.get_qword(sysvec) for entry in xrange(numsyscalls): initial = sysnames + (entry * 0x8) idc.create_data(initial, FF_QWORD, 0x8, BADNODE) offset = idaapi.get_qword(initial) length = idaapi.get_max_strlit_length(offset, STRTYPE_C) name = idaapi.get_strlit_contents(offset, length, STRTYPE_C) sysentoffset = sysent + 0x8 + (entry * 0x30) idaapi.do_unknown_range(sysentoffset - 0x8, 0x30, 0) idaapi.create_struct(sysentoffset - 0x8, 0x30, struct) idc.set_cmt(sysentoffset - 0x8, '#%i' % entry, False) if '{' in name: continue # Rename the functions function = idaapi.get_qword(sysentoffset) idaapi.set_name(function, name.replace('#', 'sys_'), SN_NOCHECK | SN_NOWARN | SN_FORCE)
def function_search(mode, search, address=0): while address < BADADDR: address = ida.find_binary(address, BADADDR, search, 0x10, SEARCH_DOWN) if address < BADADDR: address += mode ida.do_unknown(address, 0) ida.add_func(address, BADADDR) address += 1
def Binaries(*args): """ Enumerate binary search matches @param <range>: see getrange @param searchstr: @param flags: for instance SEARCH_CASE @return: list of addresses matching searchstr Example:: sysenum= GetEnum("enum_syscalls") for ea in Binaries((FirstSeg(), BADADDR), "00 00 00 ef"): insn= DecodePreviousInstruction(ea) if insn.itype==idaapi.ARM_mov and insn.Op1.is_reg(7) and insn.Op2.type==o_imm: OpEnumEx(insn.ea, 1, sysenum, 0) if Dword(insn.ea-4)==0xe92d0090 and Dword(insn.ea+8)==0xe8bd0090: syscall= GetConstName(GetConst(sysenum, insn.Op2.value, 0)) if syscall: MakeName(insn.ea-4, "syscall_%s" % syscall[4:]) else: print "unknown syscall number: %08x" % insn.Op2.value This will name all syscall stubs in an android binary. Assumes a enum exists with all syscall numbers """ (first, last) = getrange(args) i = getstringpos(args) if i < 0: raise Exception("missing searchstring") searchstr = args[i] flags = args[i + 1] if i + 1 < len(args) else 0 ea = idaapi.find_binary(first, last, searchstr, 16, idaapi.SEARCH_DOWN | flags) while ea != idaapi.BADADDR and ea < last: yield ea ea = idaapi.find_binary( ea, last, searchstr, 16, idaapi.SEARCH_DOWN | idaapi.SEARCH_NEXT | flags)
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 find_sig(segment, sig, callback): seg = idaapi.get_segm_by_name(segment) if not seg: return ea, maxea = seg.start_ea, seg.end_ea while ea != idaapi.BADADDR: ea = idaapi.find_binary(ea, maxea, sig, 16, idaapi.SEARCH_DOWN) if ea != idaapi.BADADDR: callback(ea) ea += 4
def Pablo(address, end): while address < end: offset = idaapi.find_binary(address, end, '?? FF FF FF FF', 0x10, SEARCH_DOWN) offset -= 0x3 if idaapi.is_unknown(idaapi.get_flags(offset)): if text.start_ea <= idaapi.get_qword(offset) <= abs.end_ea: idaapi.create_data(offset, FF_QWORD, 0x8, BADNODE) address = offset + 0x4
def Binaries(*args): """ Enumerate binary search matches @param <range>: see getrange @param searchstr: @return: list of addresses matching searchstr Example:: sysenum= GetEnum("enum_syscalls") for ea in Binaries(FirstSeg(), BADADDR, "00 00 00 ef"): insn= DecodePreviousInstruction(ea) if insn.itype==idaapi.ARM_mov and insn.Op1.is_reg(7) and insn.Op2.type==o_imm: OpEnumEx(insn.ea, 1, sysenum, 0) if Dword(insn.ea-4)==0xe92d0090 and Dword(insn.ea+8)==0xe8bd0090: syscall= GetConstName(GetConst(sysenum, insn.Op2.value, 0)) if syscall: MakeName(insn.ea-4, "syscall_%s" % syscall[4:]) else: print "unknown syscall number: %08x" % insn.Op2.value This will name all syscall stubs in an android binary. Assumes a enum exists with all syscall numbers """ (first, last)= getrange(args) i= getstringpos(args) if i<0: raise Exception("missing searchstring") searchstr= args[i] ea= idaapi.find_binary(first, last, searchstr, 16, idaapi.SEARCH_DOWN) while ea!=idaapi.BADADDR and ea<last: yield ea ea= idaapi.find_binary(ea, last, searchstr, 16, idaapi.SEARCH_DOWN|idaapi.SEARCH_NEXT)
def find_byte_sequence(start, end, seq): """yield all ea of a given byte sequence args: start: min virtual address end: max virtual address seq: bytes to search e.g. b"\x01\x03" """ seq = " ".join(["%02x" % b for b in seq]) while True: ea = idaapi.find_binary(start, end, seq, 0, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break start = ea + 1 yield ea
def find_bytes(start, end, seq, seq_len): hits = [] while start < end-seq_len: hit_ea = idaapi.find_binary(start, end, seq, 16, idaapi.BIN_SEARCH_FORWARD) if hit_ea == idaapi.BADADDR: break start = hit_ea+seq_len #if idaapi.isCode(idc.GetFlags(hit_ea)): # hits.append(hit_ea) hits.append(hit_ea) return hits
def pci_analisys(): # searching snippets: # ------------------- # mov eax, 8000xxxxh ; optional line # mov dx, CF8h # out dx, eax # ------------------- # mov dx, CF8h # mov eax, 8000xxxxh # out dx, eax # ------------------- position_start = idc.MinEA() position_stop = idc.MaxEA() outdxeax = position_start while outdxeax : outdxeax = idaapi.find_binary(position_start, position_stop, "66 EF", 0, 0) if outdxeax: position_start = outdxeax + 1
def find_bytes(start, end, seq, seq_len): hits = [] while start < end - seq_len: hit_ea = idaapi.find_binary(start, end, seq, 16, idaapi.BIN_SEARCH_FORWARD) if hit_ea == idaapi.BADADDR: break start = hit_ea + seq_len #if idaapi.isCode(idc.GetFlags(hit_ea)): # hits.append(hit_ea) hits.append(hit_ea) return hits
def pablo(address, end, search): while address < end: address = idaapi.find_binary(address, end, search, 0x10, SEARCH_DOWN) if address > idaapi.get_segm_by_name('CODE').end_ea: offset = address - 0x3 if idaapi.isUnknown(idaapi.getFlags(offset)): if idaapi.get_qword(offset) <= end: idaapi.create_data(offset, FF_QWORD, 0x8, BADNODE) address = offset + 4 else: idaapi.do_unknown(address, 0) idaapi.create_insn(address) idaapi.add_func(address, BADADDR) address += 4
def find_sig(next_seg, pat, dump_cb): """ Scan binary image for pattern and run dump callback function. @param next_seg: Start address @param pat: Dict with config @param dump_cb: Certificate dump callback """ ea = SegStart(next_seg) seg_end = SegEnd(next_seg) Message('Searching for %s\n' % pat['name']) # Message('Current Seg %s\n' % SegName(next_seg)) while next_seg != BADADDR: ea = idaapi.find_binary(ea, seg_end, pat['sig'], 16, 1) if ea != BADADDR: ea = dump_cb(ea, pat) else: next_seg = ea = NextSeg(seg_end) seg_end = SegEnd(next_seg)
def load_file(f, neflags, format): print('# PS3 Syscon Loader') # PS3 Syscon Processor and Library processor('arm', 'gnulnx_arm') print('# Creating ROM Segment...') address = 0x0 end = address + f.size() f.file2base(address, address, end, FILEREG_PATCHABLE) idaapi.add_segm(0x0, address, end, 'ROM', 'CODE', 0x0) # Processor Specific Segment Details idc.set_segm_addressing(address, 0x1) idc.set_segm_alignment(address, saAbs) idc.set_segm_combination(address, scPriv) idc.set_segm_attr(address, SEGATTR_PERM, SEGPERM_MAXVAL) idc.set_default_sreg_value(address, 'T', 0x0) idc.set_default_sreg_value(address, 'DS', 0x1) print('# Waiting for the AutoAnalyzer to Complete...') idaapi.auto_wait() # Create some missing functions... while address < end: address = idaapi.find_binary(address, end, '?? B5', 0x10, SEARCH_DOWN) idaapi.create_insn(address) # Pablo escobar if idc.print_insn_mnem(address + 2) in ['LDR', 'MOVS', 'SUB']: idc.add_func(address) else: idaapi.do_unknown(address) address += 4 print('# Done!') return 1 # PROGRAM END
def search_dll_hashes(db): ''' Search for DLL hashes ''' # Get information about the .text section text_segm = ida_segment.get_segm_by_name('.text') seg_start = text_segm.startEA seg_end = text_segm.endEA # Iter over dll names for (dll, funcs) in db.items(): print("Searching for the {} DLL".format(dll)) new_hash = sdbm_hash(dll) #search for hashes ea = idaapi.find_binary(seg_start, seg_end, "0x{:08X}".format(new_hash), 16, SEARCH_DOWN) if ea != BADADDR: inst_ea = PrevHead(ea) print("Match the hash: {:X} which is the DLL {}, match: 0x{:X}".format(new_hash, dll, inst_ea)) MakeComm(inst_ea, "{}".format(dll))
def search_sys_gadgets(self, segment, jump_preamble = 0xFF): """ Search for SYS jump gadgets """ # Nothing to do if the option is not set if not self.searchSys: return # Search all instances of JMP reg (FF /4) and CALL reg (FF /2) ea = segment.startEA while True: ea = idaapi.find_binary(ea + 1, segment.endEA, "%X" % jump_preamble, 16, idaapi.SEARCH_DOWN) if ea == idaapi.BADADDR: break # Read possible ModR/M, SIB, and IMM8/IMM32 bytes sys_op = idc.GetManyBytes(ea + 1, self.maxRopSize) if self.is_sys_gadget(jop): self.retns.append((ea))
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 search_hashes(db, args): ''' Resolution of the API Arguments: - db (dict): database generated by shellcode_hash - args (dict): call arguments ''' # Get information about the .text section text_segm = ida_segment.get_segm_by_name('.text') seg_start = text_segm.startEA seg_end = text_segm.endEA # Iter over the sdbm hashes generated by shellcode_hash for (dll, funcs) in db.items(): print("Searching for functions inside the {} DLL".format(dll)) for func, hash in funcs: new_hash = xor_hash(hash, args["key"]) #search for hashes ea = idaapi.find_binary(seg_start, seg_end, "0x{:08X}".format(new_hash), 16, SEARCH_DOWN) if ea != BADADDR: # Add comment inst_ea = PrevHead(ea) print("Match the hash: {:X} which is the function {}!{} matches: 0x{:X}".format(new_hash, dll, func, inst_ea)) MakeComm(inst_ea, "{}!{}".format(dll, func)) # Fix variable name in the function array off = (GetOperandValue(inst_ea, 0) ^ 0xffffffff) + 1 array_off = (args['size'] * 4) - off array_va = args['array'] + array_off MakeDword(array_va) if not MakeName(array_va, "{}".format(func)): MakeName(array_va, "{}_{}".format(dll, func)) print("Fix the name at 0x{:08X}".format(array_va))
else : print "Certs processing fail!" # TODO: Parse rights of the keys # TODO: Parse ASN1 from digests # Processing Images i = 0 while i < 4 : print "images type %s " % type (certppa.images) if certppa.images[i].image_offset != 0 : print "Found PPA image at %x offset " % certppa.images[i].image_offset if certisw.images[i].image_offset != 0 : print "Found ISW image at %x offset " % certisw.images[i].image_offset i += 1 # image start at certppa mark address + certppa.images[i].image_offset # Script body start = idc.MinEA() stop = idc.MaxEA() version_addr = idaapi.find_binary(start, stop, "43 65 72 74 49 53 57 00", 0, 0) + 0x79e # "CertISW" string version_minor = idaapi.get_byte(version_addr) version_major = idaapi.get_byte(version_addr + 1) print "MBM loader Major Version: %x " % version_major print "MBM loader Minor Version: %x " % version_minor parse_structures()
def parse_structures(): # Searching structures, and if not exists - creating them # RSA KEY structure rsa_key = idc.GetStrucIdByName("rsa_key") rsa_key_str = """ struct rsa_key { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; }; """ if rsa_key == -1: rsa_key = idc.AddStrucEx(-1, "rsa_key", 0) idc.AddStrucMember(rsa_key, "key_id", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "key_type", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "key_rights", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "modul_length", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "e_value", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_key, "modul", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 256) # RSA ASN1 DIGEST structure rsa_asn1_digest = idc.GetStrucIdByName("rsa_asn1_digest") rsa_asn1_digest_str = """ struct rsa_asn1_digest { char signer_info[16]; long signature_info; long key_id; char digest[256]; }; """ if rsa_asn1_digest == -1: rsa_asn1_digest = idc.AddStrucEx(-1, "rsa_asn1_digest", 0) idc.AddStrucMember(rsa_asn1_digest, "signer_info", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 16) idc.AddStrucMember(rsa_asn1_digest, "signature_info", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_asn1_digest, "key_id", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(rsa_asn1_digest, "digest", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 256) # Cert PK - Public Keys structure certpk_struct = idc.GetStrucIdByName("Cert_Public") certpk_str = """ struct certpk { char cert_mark[8]; long cert_version; long cert_type; long minver_pk; long minver_ppa; long minver_rd1; long minver_rd2; long minver_isw; long minver_ki; long minver_pau; long minver_pas; long unkn1; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } root_key; long keys_active; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_02; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_03; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_04; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_05; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_06; struct { long key_id; long key_type; long key_rights; long modul_length; long e_value; char modul[256]; } key_07; long rights; long msv_mask; char zero_hole_2[120]; struct { char signer_info[16]; long signature_info; long key_id; char digest[256]; } digest; };""" if certpk_struct == -1: certpk_struct = idc.AddStrucEx(-1, "Cert_Public", 0) idc.AddStrucMember(certpk_struct, "cert_mark", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 8) idc.AddStrucMember(certpk_struct, "cert_version", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "cert_type", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_pk", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_ppa", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_rd1", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_rd2", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_isw", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_ki", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_pau", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "minver_pas", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "unkn1", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "root_key", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "keys_active", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "key_02", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_03", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_04", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_05", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_06", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "key_07", -1, 0x60000400, rsa_key, idc.GetStrucSize(rsa_key)) idc.AddStrucMember(certpk_struct, "rights", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "msv_mask", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certpk_struct, "zero_hole_2", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 120) idc.AddStrucMember(certpk_struct, "digest", -1, 0x60000400, rsa_asn1_digest, idc.GetStrucSize(rsa_asn1_digest)) # CertPPA - Primary Protected Application Certificate structure certppa_struct = idc.GetStrucIdByName("Cert_Primary") certppa_str = """ struct certppa { char cert_mark[8]; long cert_version; long cert_type; long minver_src; long minver_pk; long minver_ppa; long minver_rd1; long minver_rd2; long minver_isw; struct { int image_offset; int image_size; int data_byte[5]; } images[4]; char zero_hole[128]; struct { char signer_info[16]; long signature_info; long key_id; char digest[256]; } digest; };""" if certppa_struct == -1: certppa_struct = idc.AddStrucEx(-1, "Cert_Primary", 0) idc.AddStrucMember(certppa_struct, "cert_mark", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 8) idc.AddStrucMember(certppa_struct, "cert_version", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "cert_type", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_src", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_pk", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_ppa", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_rd1", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_rd2", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "minver_isw", -1, (FF_DWRD|FF_DATA)&0xFFFFFFFF, -1, 4) idc.AddStrucMember(certppa_struct, "images", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 21) idc.AddStrucMember(certppa_struct, "zero_hole", -1, (FF_BYTE|FF_DATA)&0xFFFFFFFF, -1, 128) idc.AddStrucMember(certppa_struct, "digest", -1, 0x60000400, rsa_asn1_digest, idc.GetStrucSize(rsa_asn1_digest)) # CertISW - Initial Software Certificate structure certisw_struct = idc.GetStrucIdByName("Cert_ISW") certisw_str = """struct certisw { char cert_mark[8]; int cert_version; int cert_type; int minver_src; int minver_pk; int minver_ppa; int minver_rd1; int minver_rd2; int minver_isw; int watchdog_param; int use_DMA; int active_images; struct { int image_offset; int image_size; int data_byte[5]; } images[4]; int magic_1; int reg_bitfield; struct { int reg_address; int reg_value; } reg_table[32]; int reg_type_01; int reg_type_02; int entry_point_offset; int zero_hole[32]; struct { char signer_info[16]; long signature_info; long key_id; char digest[256]; } digest; };""" mbmloader_hdr_str = """struct mbmloader_head { void *entry_point; int anonymous_0; void *anonymous_1; void *anonymous_2; void *anonymous_3; void *anonymous_4; int anonymous_5; int field_1C; void *anonymous_7; int field_24; void *anonymous_8; int anonymous_9; int ruler[4]; char srk_part_1[128]; int srk_1; void *srk_1_pointer; int field_C8; int field_CC; char srk_part_2[128]; int srk_2; void *srk_2_pointer; int field_158; int field_15C; char sha_160_hash[20]; };""" # Searching main structures marks start = idc.MinEA() stop = idc.MaxEA() certpk_addr = idaapi.find_binary(start, stop, "43 65 72 74 50 4B 5F 00", 0, 0) # "CertPK_" string print "Found CertPK at 0x%x" % certpk_addr certppa_addr = idaapi.find_binary(start, stop, "43 65 72 74 50 50 41 00", 0, 0) # "CertPPA" string print "Found CertPPA at 0x%x" % certppa_addr certisw_addr = idaapi.find_binary(start, stop, "43 65 72 74 49 53 57 00", 0, 0) # "CertISW" string print "Found CertISW at 0x%x" % certisw_addr # Apply structure types on Cert* addresses # Read Structures from such data # If type is not parsed already, then... if idc.ParseTypes("certpk;", idc.PT_SILENT) != 0: # ...define the type idc.ParseTypes(certpk_str, idc.PT_SILENT) if idc.ParseTypes("certppa;", idc.PT_SILENT) != 0: idc.ParseTypes(certppa_str, idc.PT_SILENT) if idc.ParseTypes("certisw;", idc.PT_SILENT) != 0: idc.ParseTypes(certisw_str, idc.PT_SILENT) certpk_ = idaapi.Appcall.typedobj("certpk;") certpk_read, certpk = certpk_.retrieve(idaapi.get_many_bytes(certpk_addr, certpk_.size)) certppa_ = idaapi.Appcall.typedobj("certppa;") certppa_read, certppa = certppa_.retrieve(idaapi.get_many_bytes(certppa_addr, certppa_.size)) certisw_ = idaapi.Appcall.typedobj("certisw;") certisw_read, certisw = certisw_.retrieve(idaapi.get_many_bytes(certisw_addr, certisw_.size)) # Make PEM keys if certpk_read == 1 : root_key = construct_public_key(certpk.root_key.e_value, int(certpk.root_key.modul[0:certpk.root_key.modul_length].encode("hex"), 16), certpk.root_key.modul_length * 8) root_key.save_key("root_key.pem") # TODO: add automatic export of all ACTIVE keys from certpk.active_keys pk_02 = construct_public_key(certpk.key_02.e_value, int(certpk.key_02.modul[0:certpk.key_02.modul_length].encode("hex"), 16), certpk.key_02.modul_length * 8) pk_02.save_key("pk_02.pem") pk_03 = construct_public_key(certpk.key_03.e_value, int(certpk.key_03.modul[0:certpk.key_03.modul_length].encode("hex"), 16), certpk.key_03.modul_length * 8) pk_03.save_key("pk_03.pem") pk_04 = construct_public_key(certpk.key_04.e_value, int(certpk.key_04.modul[0:certpk.key_04.modul_length].encode("hex"), 16), certpk.key_04.modul_length * 8) pk_04.save_key("pk_04.pem") else : print "CertPK read fail!" # Verify digests if (certpk_read == 1) & (certppa_read == 1) & (certisw_read == 1) : certpk_digest = certpk.digest.digest.encode("hex") certppa_digest = certppa.digest.digest.encode("hex") certisw_digest = certisw.digest.digest.encode("hex") # pk_03.public_decrypt(certisw_digest, 1) # pk_03.verify(idaapi.get_many_bytes(certisw_addr, certisw_.size), certisw_digest, "sha1") # decoder.decode(certpk.digest.signer_info, ) print "CertPK signer info: %s " % certpk.digest.signer_info.encode("hex") print "CertPK digest: %s " % certpk.digest.digest.encode("hex") print "CertPPA signer info: %s " % certppa.digest.signer_info.encode("hex") print "CertPPA digest: %s " % certppa.digest.digest.encode("hex") print "CertISW signer info: %s " % certisw.digest.signer_info.encode("hex") print "CertISW digest: %s " % certisw.digest.digest.encode("hex") else : print "Certs processing fail!" # TODO: Parse rights of the keys # TODO: Parse ASN1 from digests # Processing Images i = 0 while i < 4 : print "images type %s " % type (certppa.images) if certppa.images[i].image_offset != 0 : print "Found PPA image at %x offset " % certppa.images[i].image_offset if certisw.images[i].image_offset != 0 : print "Found ISW image at %x offset " % certisw.images[i].image_offset i += 1
def byBytes(ea, string, reverse=False): flags = idaapi.SEARCH_UP if reverse else idaapi.SEARCH_DOWN return idaapi.find_binary(ea, -1, ' '.join(str(ord(c)) for c in string), 10, idaapi.SEARCH_CASE | flags)
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 byRegex(ea, string, radix=16, reverse=False, sensitive=False): flags = idaapi.SEARCH_UP if reverse else idaapi.SEARCH_DOWN flags |= idaapi.SEARCH_CASE if sensitive else 0 return idaapi.find_binary(ea, -1, string, radix, flags)
def load_file(f, neflags, format): print('# PS4 Kernel Loader') ps = Binary(f) # PS4 Processor, Compiler, Library bitness = ps.procomp('metapc', CM_N64 | CM_M_NN | CM_CC_FASTCALL, 'gnulnx_x64') # Segment Loading... for segm in ps.E_SEGMENTS: if segm.name() == 'PHDR': kASLR = False if segm.FILE_SIZE == 0x118 else True # Process Loadable Segments... if segm.name() in ['CODE', 'DATA', 'SCE_RELRO']: address = segm.MEM_ADDR size = segm.MEM_SIZE # Dumped Kernel Fix-ups if segm.name() in ['DATA', 'SCE_RELRO'] and (idaapi.get_segm_by_name('CODE').start_ea != 0xFFFFFFFF82200000 or not kASLR): offset = address - idaapi.get_segm_by_name('CODE').start_ea dumped = segm.MEM_SIZE else: offset = segm.OFFSET dumped = segm.FILE_SIZE print('# Creating %s Segment...' % segm.name()) f.file2base(offset, address, address + dumped, FILEREG_PATCHABLE) idaapi.add_segm(0, address, address + size, segm.name(), segm.type(), ADDSEG_NOTRUNC | ADDSEG_FILLGAP) # Processor Specific Segment Details idc.set_segm_addressing(address, bitness) idc.set_segm_alignment(address, segm.alignment()) idc.set_segm_attr(address, SEGATTR_PERM, segm.flags()) # Process Dynamic Segment... elif segm.name() == 'DYNAMIC': code = idaapi.get_segm_by_name('CODE') data = idaapi.get_segm_by_name('DATA') relro = idaapi.get_segm_by_name('SCE_RELRO') # ------------------------------------------------------------------------------------------------------------ # Dynamic Tag Entry Structure members = [('tag', 'Tag', 0x8), ('value', 'Value', 0x8)] struct = segm.struct('Tag', members) # Dynamic Tag Table stubs = {} modules = {} location = segm.MEM_ADDR # Dumps are offset by a small amount if code.start_ea != 0xFFFFFFFF82200000: dumped = code.start_ea - 0xFFFFFFFF82200000 else: dumped = 0 f.seek(location - code.start_ea) for entry in xrange(segm.MEM_SIZE / 0x10): idaapi.create_struct(location + (entry * 0x10), 0x10, struct) idc.set_cmt(location + (entry * 0x10), Dynamic(f).process(dumped, stubs, modules), False) # ------------------------------------------------------------------------------------------------------------ # Hash Entry Structure members = [('bucket', 'Bucket', 0x2), ('chain', 'Chain', 0x2), ('buckets', 'Buckets', 0x2), ('chains', 'Chains', 0x2)] struct = segm.struct('Hash', members) # Hash Table try: location = Dynamic.HASHTAB size = Dynamic.HASHTABSZ except: location = Dynamic.HASH size = Dynamic.SYMTAB - location f.seek(location - code.start_ea) for entry in xrange(size / 0x8): idaapi.create_struct(location + (entry * 0x8), 0x8, struct) if kASLR: # -------------------------------------------------------------------------------------------------------- # Relocation Entry Structure (with specific addends) members = [('offset', 'Offset (String Index)', 0x8), ('info', 'Info (Symbol Index : Relocation Code)', 0x8), ('addend', 'AddEnd', 0x8)] struct = segm.struct('Relocation', members) # Relocation Table (with specific addends) location = Dynamic.RELATAB f.seek(location - code.start_ea) for entry in xrange(Dynamic.RELATABSZ / 0x18): idaapi.create_struct(location + (entry * 0x18), 0x18, struct) idc.set_cmt(location + (entry * 0x18), Relocation(f).process(dumped, code.end_ea), False) # Initialization Function idc.add_entry(Dynamic.INIT, Dynamic.INIT, '.init', True) else: # -------------------------------------------------------------------------------------------------------- # Symbol Entry Structure members = [('name', 'Name (String Index)', 0x4), ('info', 'Info (Binding : Type)', 0x1), ('other', 'Other', 0x1), ('shtndx', 'Section Index', 0x2), ('offset', 'Value', 0x8), ('size', 'Size', 0x8)] struct = segm.struct('Symbol', members) # Symbol Table location = Dynamic.SYMTAB f.seek(location - code.start_ea) functions = {} # .symtab idc.add_entry(location, location, '.symtab', False) for entry in xrange((Dynamic.STRTAB - location) / 0x18): idaapi.create_struct(location + (entry * 0x18), 0x18, struct) idc.set_cmt(location + (entry * 0x18), Symbol(f).process(functions), False) # -------------------------------------------------------------------------------------------------------- # Dynamic String Table location = Dynamic.STRTAB # .strtab idc.add_entry(location, location, '.strtab', False) # Functions for key in functions: idc.create_strlit(location + key, BADADDR) functions[key] = idc.get_strlit_contents(location + key, BADADDR) idc.set_cmt(location + key, 'Function', False) functions = sorted(functions.iteritems(), key = operator.itemgetter(0)) #print('Functions: %s' % functions) # Resolve Functions location = Dynamic.SYMTAB f.seek(location - code.start_ea + 0x18) for entry in xrange((Dynamic.STRTAB - location - 0x18) / 0x18): Symbol(f).resolve(functions[entry][1]) # Fix-up if kASLR: address = relro.start_ea del_items(address, DELIT_SIMPLE, relro.end_ea - address) while address < relro.end_ea: create_data(address, FF_QWORD, 0x8, BADNODE) address += 0x8 address = code.start_ea # ELF Header Structure members = [('File format', 0x4), ('File class', 0x1), ('Data encoding', 0x1), ('File version', 0x1), ('OS/ABI', 0x1), ('ABI version', 0x1), ('Padding', 0x7), ('File type', 0x2), ('Machine', 0x2), ('File version', 0x4), ('Entry point', 0x8), ('PHT file offset', 0x8), ('SHT file offset', 0x8), ('Processor-specific flags', 0x4), ('ELF header size', 0x2), ('PHT entry size', 0x2), ('Number of entries in PHT', 0x2), ('SHT entry size', 0x2), ('Number of entries in SHT', 0x2), ('SHT entry index for string table\n', 0x2)] for (comment, size) in members: flags = idaapi.get_flags_by_size(size) idc.create_data(address, flags if flags != 0 else FF_STRLIT, size, BADNODE) idc.set_cmt(address, comment, False) address += size for index, entry in enumerate(ps.E_SEGMENTS): # ELF Program Header Structure members = [('Type: %s' % entry.name(), 0x4), ('Flags', 0x4), ('File offset', 0x8), ('Virtual address', 0x8), ('Physical address', 0x8), ('Size in file image', 0x8), ('Size in memory image', 0x8), ('Alignment\n', 0x8)] for (comment, size) in members: flags = idaapi.get_flags_by_size(size) idc.create_data(address, flags if flags != 0 else FF_STRLIT, size, BADNODE) idc.set_cmt(address, comment, False) address += size # Wait for the AutoAnalyzer to Complete... print('# Waiting for the AutoAnalyzer to Complete...') idaapi.auto_wait() if kASLR: # Start Function idc.add_entry(ps.E_START_ADDR, ps.E_START_ADDR, 'start', True) # Xfast_syscall address = idaapi.find_binary(code.start_ea, code.end_ea, '0F 01 F8 65 48 89 24 25 A8 02 00 00 65 48 8B 24', 0x10, SEARCH_DOWN) idaapi.do_unknown(address, 0) idaapi.create_insn(address) idaapi.add_func(address, BADADDR) idaapi.set_name(address, 'Xfast_syscall', SN_NOCHECK | SN_NOWARN) # -------------------------------------------------------------------------------------------------------- # Znullptr's syscalls print('# Processing Znullptr\'s Syscalls...') # Syscall Entry Structure members = [('narg', 'Number of Arguments', 0x4), ('_pad', 'Padding', 0x4), ('function', 'Function', 0x8), ('auevent', 'Augmented Event?', 0x2), ('_pad1', 'Padding', 0x2), ('_pad2', 'Padding', 0x4), ('trace_args_func', 'Trace Arguments Function', 0x8), ('entry', 'Entry', 0x4), ('return', 'Return', 0x4), ('flags', 'Flags', 0x4), ('thrcnt', 'Thread Count?', 0x4)] struct = segm.struct('Syscall', members) znullptr(code.start_ea, code.end_ea, '4F 52 42 49 53 20 6B 65 72 6E 65 6C 20 53 45 4C 46', struct) # -------------------------------------------------------------------------------------------------------- # Chendo's cdevsw con-struct-or print('# Processing Chendo\'s cdevsw structs...') # cdevsw Entry Structure members = [('d_version', 'Version', 0x4), ('d_flags', 'Flags', 0x4), ('d_name', 'Name', 0x8), ('d_open', 'Open', 0x8), ('d_fdopen', 'File Descriptor Open', 0x8), ('d_close', 'Close', 0x8), ('d_read', 'Read', 0x8), ('d_write', 'Write', 0x8), ('d_ioctl', 'Input/Ouput Control', 0x8), ('d_poll', 'Poll', 0x8), ('d_mmap', 'Memory Mapping', 0x8), ('d_strategy', 'Strategy', 0x8), ('d_dump', 'Dump', 0x8), ('d_kqfilter', 'KQFilter', 0x8), ('d_purge', 'Purge', 0x8), ('d_mmap_single', 'Single Memory Mapping', 0x8), ('d_spare0', 'Spare0', 0x8), ('d_spare1', 'Spare1', 0x8), ('d_spare2', 'Spare2', 0x8), ('d_spare3', 'Spare3', 0x8), ('d_spare4', 'Spare4', 0x8), ('d_spare5', 'Spare5', 0x8), ('d_spare6', 'Spare6', 0x4), ('d_spare7', 'Spare7', 0x4)] struct = segm.struct('cdevsw', members) chendo(data.start_ea, data.end_ea, '09 20 12 17', struct) # -------------------------------------------------------------------------------------------------------- # Pablo's IDC try: print('# Processing Pablo\'s Push IDC...') # Script 1) Push it real good... pablo(code.start_ea, code.end_ea, 'C5 FA 5A C0 C5 F2 5A C9 C5 EA 5A D2 C5 FB 59 C1') pablo(code.start_ea, code.end_ea, 'C5 F9 7E C0 31 C9') pablo(code.start_ea, code.end_ea, '48 89 E0 55 53') pablo(code.start_ea, code.end_ea, 'B8 2D 00 00 00 C3') pablo(code.start_ea, code.end_ea, '31 C0 C3') pablo(code.start_ea, code.end_ea, '55 48 89') pablo(code.start_ea, code.end_ea, '48 81 EC A0 00 00 00 C7') pablo(code.start_ea, code.end_ea, '48 81 EC A8 00 00 00') # Script 2) Fix-up Dumped Data Pointers... if dumped or not kASLR: print('# Processing Pablo\'s Dumped Data Pointers IDC...') pablo(data.start_ea, data.end_ea, '?? FF FF FF FF') except: pass # -------------------------------------------------------------------------------------------------------- # Kiwidog's __stack_chk_fail if kASLR: print('# Processing Kiwidog\'s Stack Functions...') kiwidog(code.start_ea, code.end_ea, '73 74 61 63 6B 20 6F 76 65 72 66 6C 6F 77 20 64 65 74 65 63 74 65 64 3B') # -------------------------------------------------------------------------------------------------------- # Final Pass print('# Performing Final Pass...') address = code.start_ea while address < code.end_ea: address = idaapi.find_not_func(address, SEARCH_DOWN) if idaapi.isUnknown(idaapi.getFlags(address)): idaapi.create_insn(address) else: idc.add_func(address) address += 4 print('# Done!') return 1