def base64_decode(std): addr = idc.BADADDR ea = idc.get_screen_ea() flags = idaapi.get_flags(ea) if idc.is_strlit(flags): addr = ea # cursor is on the string elif idc.is_code(flags): addr = idc.get_first_dref_from(ea) # get data reference from the instruction if addr == idc.BADADDR: plg_print("No string or reference to the string found\n") return b64str_enc = None try: b64str_enc = idc.get_strlit_contents(addr, -1, idc.get_str_type(addr)) except: pass if not b64str_enc: plg_print("Could not get string at address 0x%X" % addr) return try: b64str_dec = base64.standard_b64decode(b64str_enc) if std else base64.urlsafe_b64decode(b64str_enc) except Exception as e: plg_print("Could not decode. %s" % str(e)) return if b64str_dec: plg_print("Base64 decode of string '%s':" % b64str_enc) process_data_result(ea, bytearray(b64str_dec))
def execute_rename(name): """ This is a wrapper to execute the renaming synchronously """ def get_name(): return idc.get_name(name["address"]) def make_name(force=False): """ Thread safe renaming wrapper """ def sync_ask_rename(): """ Dialog asking renaming confirmation to the user """ rename_flag = 0 if force or idc.ask_yn( rename_flag, "Replace %s by %s" % (get_name(), name["data"])) == 1: logger.debug("[x] renaming %s @ 0x%x as %s", get_name(), name["address"], name["data"]) ida_name.set_name(name["address"], name["data"].encode('ascii', 'ignore'), ida_name.SN_AUTO) return idaapi.execute_sync(sync_ask_rename, idaapi.MFF_FAST) old_name = get_name() if not name["data"]: return elif idaapi.has_dummy_name(idaapi.get_flags( name["address"])) or not old_name: make_name(force=True) elif get_name() != name["data"]: make_name()
def dump_type(ea): flags = idaapi.get_flags(ea) if idc.is_code(flags): return "block" if idaapi.get_func(ea) else "code" if idc.is_data(flags): return "data" return "unexplored"
def send_names(self): """ Used to send all the names to the server. Usecase: Previously analyzed IDB """ for head in idautils.Names(): if not idaapi.has_dummy_name(idaapi.get_flags(head[0])): self.skel_conn.push_name(head[0], head[1])
def iterate_vtable(vtable_addr): ea = vtable_addr while True: fn_ea = struct.unpack('<Q', idaapi.get_bytes(ea, 8))[0] if idaapi.get_name(fn_ea) != "__cxa_pure_virtual" and not idaapi.is_func(idaapi.get_flags(fn_ea)): return yield fn_ea ea += 8
def send_names(self): """ Used to send all the names to the server. Usecase: Previously analyzed IDB """ for head in idautils.Names(): if not idaapi.has_dummy_name(idaapi.get_flags(head[0])): self.skel_conn.push_name(head[0], head[1])
def renamed(self, *args): logger.debug("[IDB Hook] Something is renamed") ea, new_name, is_local_name = args min_ea = idc.get_inf_attr(idc.INF_MIN_EA) max_ea = idc.get_inf_attr(idc.INF_MAX_EA) if ea >= min_ea and ea <= max_ea: if is_local_name: logger.warning("Local names are unimplemented") else: auto = idaapi.has_auto_name(idaapi.get_flags(ea)) dummy = idaapi.has_dummy_name(idaapi.get_flags(ea)) if not dummy and not auto: self.skel_conn.push_name(ea, new_name) else: logger.warning("ea outside program...") return ida_idp.IDB_Hooks.renamed(self, *args)
def __init__(self, ea, info, cs): """Initialization function.""" # Init the node structure node_t.__init__(self) # Check if it's a code instruction try: is_c = is_code(get_flags(ea)) except: is_c = isCode(GetFlags(ea)) if not is_c: raise CodeException # # fill node_t struct # # NodeInfo self.info = NodeInfo() inst_elements = [] try: size = create_insn(ea) bytes = get_bytes(ea, size) except: size = MakeCode(ea) bytes = GetManyBytes(ea, size) (address, size, mnemonic, op_str) = cs.disasm_lite(bytes, ea, count=1).next() self.info.opcode = mnemonic.encode("ascii", "ignore") op_str_ascci = op_str.encode("ascii", "ignore") self.info.inst_str = self.info.opcode + " " + op_str_ascci splitted = op_str_ascci.split(", ") self.info.nargs = 0 if len(splitted) >= 1: self.info.arg1 = splitted[0] self.info.nargs += 1 if len(splitted) >= 2: self.info.arg2 = splitted[1] self.info.nargs += 1 if len(splitted) >= 3: self.info.arg3 = splitted[2] self.info.nargs += 1 # No node will be root but this is acceptable for CFGs self.info.is_root = False self.info.address = ea self.info.has_address = True # node_t self.node_id = self._genid()
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 has_if(c, p): # type: (...) -> bool if c.op != hr.cit_if: return False lhs = c.cif.expr.x rhs = c.cif.expr.y if not rhs or rhs.op != hr.cot_obj: return False if not idaapi.is_strlit(idaapi.get_flags(rhs.obj_ea)): return False ctx.if_statement = c.cif ctx.this_string_item = my_cexpr_t(lhs) ctx.constant_item = my_cexpr_t(rhs) # Match the if body (in an extremely approximate way) def has_counter(c, p): # type: (...) -> bool if c.op != hr.cot_asg: return False if c.x.op != hr.cot_var or not is_number(c.y, 0): return False ctx.items_to_delete.append(vu.cfunc.body.find_parent_of(c).to_specific_type) return True def has_do_while(c, p): # type: (...) -> bool if c.op != hr.cit_do: return False # don't bother matching the loop body -- just match the condition expression if c.cdo.expr.x.op != hr.cot_var: return False if c.cdo.expr.op == hr.cot_sle or c.cdo.expr.op == hr.cot_ule: if not is_number(c.cdo.expr.y, 0x80000): return False elif c.cdo.expr.op == hr.cot_slt or c.cdo.expr.op == hr.cot_ult: if not is_number(c.cdo.expr.y, 0x80001): return False else: return False ctx.items_to_delete.append(c) return True last_item_in_then = c.cif.ithen.cblock.back() if last_item_in_then.op != hr.cit_goto: ctx.is_equal_variant = False return ConstraintVisitor([ ConstraintChecker(has_counter), ConstraintChecker(has_do_while), ], "equals.inner").check(c.cif.ithen, c) # Otherwise, look after the if. ctx.is_equal_variant = True p.add_temp_constraints([ ConstraintChecker(has_counter), ConstraintChecker(has_do_while), ]) return True
def has_string(c, p): # type: (...) -> bool if c.op != hr.cot_ref: return False ref = c.x if ref.op == hr.cot_idx: ref = ref.x if ref.op != hr.cot_obj: return False if not idaapi.is_strlit(idaapi.get_flags(ref.obj_ea)): return False string = get_string(ref.obj_ea) ctx.other_string_item = my_cexpr_t(ref) return string[0] == ctx.first_chr
def has_part_2(c, p): # type: (...) -> bool if c.op != hr.cit_if: return False if c.cif.ielse or c.cif.expr.op != hr.cot_ne: return False lhs = c.cif.expr.x rhs = c.cif.expr.y if rhs.op != hr.cot_obj: return False if not idaapi.is_strlit(idaapi.get_flags(rhs.obj_ea)): return False ctx.constant_item = my_cexpr_t(rhs) if_cv = ConstraintVisitor(self._get_part_2_checks(ctx, vu), "assign_const.part2") return if_cv.check(c.cif.ithen, c)
def _sig_instruction(self, addr: int) -> Optional[str]: """ Get the bytes for a single instruction with wildcards :param addr: Instruction address :return: A signature chunk """ # I'm not sure if either of these checks will ever happen # So let it explode until it does by trying to join None if not idaapi.is_code(idaapi.get_flags(addr)): return None if not idaapi.can_decode(addr): return None insn = idaapi.insn_t() insn.size = 0 idaapi.decode_insn(insn, addr) if insn.size == 0: return None if insn.size < 5: return self._sig_bytes(insn.ea, insn.size) op_size = self._get_current_opcode_size(insn) if op_size == 0: return self._sig_bytes(insn.ea, insn.size) operand_size = insn.size - op_size sig = self._sig_bytes(insn.ea, op_size) if self._match_operands(insn.ea): sig += ' ' + self._sig_bytes(insn.ea + op_size, operand_size) else: sig += ' ' + self._sig_wildcards(operand_size) return sig
def dump_flags(ea): flags = idaapi.get_flags(ea) reply = [] for k in type_flags: if (flags & ida_bytes.MS_CLS) == (k & 0xFFFFFFFF): reply.append(type_flags[k]) if ida_bytes.is_code(flags): for k in code_flags: if (flags & ida_bytes.MS_CODE) & k: reply.append(code_flags[k]) if ida_bytes.is_data(flags): for k in data_flags: if (flags & ida_bytes.DT_TYPE) == (k & 0xFFFFFFFF): reply.append(data_flags[k]) for k in comm_flags: if (flags & ida_bytes.MS_COMM) & k: reply.append(comm_flags[k]) for k in op0_flags: if (flags & ida_bytes.MS_0TYPE) == (k & 0xFFFFFFFF): reply.append(op0_flags[k]) for k in op1_flags: if (flags & ida_bytes.MS_1TYPE) == (k & 0xFFFFFFFF): reply.append(op1_flags[k]) return " ".join(reply)
def execute_rename(name): """ This is a wrapper to execute the renaming synchronously """ def get_name(): return idc.get_name(name["address"]) def make_name(force=False): """ Thread safe renaming wrapper """ def sync_ask_rename(): """ Dialog asking renaming confirmation to the user """ rename_flag = 0 if force or idc.ask_yn(rename_flag, "Replace %s by %s" % (get_name(), name["data"])) == 1: logger.debug("[x] renaming %s @ 0x%x as %s", get_name(), name["address"], name["data"]) ida_name.set_name( name["address"], name["data"].encode( 'ascii', 'ignore'), ida_name.SN_AUTO) return idaapi.execute_sync( sync_ask_rename, idaapi.MFF_FAST) old_name = get_name() if not name["data"]: return elif idaapi.has_dummy_name(idaapi.get_flags(name["address"])) or not old_name: make_name(force=True) elif get_name() != name["data"]: make_name()
def is_op_stack_var(ea, index): """ check if operand is a stack variable """ return idaapi.is_stkvar(idaapi.get_flags(ea), index)
def is_op_offset(insn, op): """ Check is an operand has been marked as an offset (by auto-analysis or manually) """ flags = idaapi.get_flags(insn.ea) return ida_bytes.is_off(flags, op.n)
def load_file(f, neflags, format): print('# PS4 Module Loader') ps = Binary(f) # PS4 Processor, Compiler, Library bitness = ps.procomp('metapc', CM_N64 | CM_M_NN | CM_CC_FASTCALL, 'gnulnx_x64') # Load Aerolib... nids = load_nids(idc.idadir() + '/loaders/aerolib.csv') # Segment Loading... for segm in ps.E_SEGMENTS: # Process Loadable Segments... if segm.name() in [ 'CODE', 'DATA', 'SCE_RELRO', 'DYNAMIC', 'GNU_EH_FRAME', 'SCE_DYNLIBDATA' ]: address = segm.MEM_ADDR if segm.name() not in [ 'DYNAMIC', 'SCE_DYNLIBDATA' ] else segm.OFFSET + 0x1000000 size = segm.MEM_SIZE if segm.name() not in [ 'DYNAMIC', 'SCE_DYNLIBDATA' ] else segm.FILE_SIZE print('# Processing %s Segment...' % segm.name()) f.file2base(segm.OFFSET, address, address + segm.FILE_SIZE, FILEREG_PATCHABLE) if segm.name() not in ['DYNAMIC', 'GNU_EH_FRAME']: 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': stubs = {} modules = {} libraries = {} f.seek(segm.OFFSET) offset = segm.OFFSET dynamic = address dynamicsize = size for entry in xrange(size / 0x10): idc.set_cmt(address + (entry * 0x10), Dynamic(f).process(stubs, modules, libraries), False) ''' # Process Exception Handling Segment... elif segm.name() == 'GNU_EH_FRAME': # Exception Handling Frame Header Structure members = [('version', 'Version', 0x1), ('eh_frame_ptr_enc', 'Encoding of Exception Handling Frame Pointer', 0x1), ('fde_count_enc', 'Encoding of Frame Description Entry Count', 0x1), ('table_enc', 'Encoding of Table Entries', 0x1)] struct = segm.struct('EHFrame', members) idaapi.create_struct(address, 0x4, struct) # Exception Handling Structure members = [('exception', 'value', 0x8)] struct = segm.struct('Exception', members) for entry in xrange(size / 0x8): idaapi.create_struct(address + (entry * 0x8), 0x8, struct) ''' # Process SCE 'Special' Shared Object Segment... if segm.name() == 'SCE_DYNLIBDATA': # SCE Fingerprint idc.make_array(address, 0x14) idc.set_name(address, 'SCE_FINGERPRINT', SN_NOCHECK | SN_NOWARN | SN_FORCE) idc.set_cmt( address, ' '.join( x.encode('hex') for x in idc.get_bytes(address, 0x14)).upper(), False) # Dynamic Symbol Table try: # -------------------------------------------------------------------------------------------------------- # Dynamic Symbol Entry Structure members = [('name', 'Name (String Index)', 0x4), ('info', 'Info (Binding : Type)', 0x1), ('other', 'Other', 0x1), ('shtndx', 'Section Index', 0x2), ('value', 'Value', 0x8), ('size', 'Size', 0x8)] struct = segm.struct('Symbol', members) # Dynamic Symbol Table location = address + Dynamic.SYMTAB f.seek(segm.OFFSET + Dynamic.SYMTAB) symbols = {} for entry in xrange(Dynamic.SYMTABSZ / 0x18): idaapi.create_struct(location + (entry * 0x18), 0x18, struct) idc.set_cmt(location + (entry * 0x18), Symbol(f).process(symbols), False) except: pass # Dynamic String Table try: # -------------------------------------------------------------------------------------------------------- # Dynamic String Table location = address + Dynamic.STRTAB f.seek(segm.OFFSET + Dynamic.STRTAB) # Stubs for key in stubs: idc.create_strlit(location + key, BADADDR) stubs[key] = idc.get_strlit_contents( location + key, BADADDR) idc.set_cmt(location + key, 'Stub', False) #print('Stubs: %s' % stubs) # Modules for key in modules: idc.create_strlit(location + key, BADADDR) modules[key] = idc.get_strlit_contents( location + key, BADADDR) idc.set_cmt(location + key, 'Module', False) #print('Modules: %s' % modules) # Libraries and LIDs lids = {} for key, value in libraries.iteritems(): idc.create_strlit(location + key, BADADDR) lids[value] = idc.get_strlit_contents( location + key, BADADDR) libraries[key] = idc.get_strlit_contents( location + key, BADADDR) idc.set_cmt(location + key, 'Library', False) #print('LIDs: %s' % lids) # Symbols for key in symbols: idc.create_strlit(location + key, BADADDR) symbols[key] = idc.get_strlit_contents( location + key, BADADDR) idc.set_cmt(location + key, 'Symbol', False) #print('Symbols: %s' % symbols) except: pass # Resolve Export Symbols try: symbols = sorted(symbols.iteritems()) location = address + Dynamic.SYMTAB + 0x30 f.seek(segm.OFFSET + Dynamic.SYMTAB + 0x30) for entry in xrange((Dynamic.SYMTABSZ - 0x30) / 0x18): Symbol(f).resolve(location + (entry * 0x18), nids, symbols[entry][1]) except: pass # Jump Table try: # -------------------------------------------------------------------------------------------------------- # Jump Entry Structure members = [('offset', 'Offset (String Index)', 0x8), ('info', 'Info (Symbol Index : Relocation Code)', 0x8), ('addend', 'AddEnd', 0x8)] struct = segm.struct('Jump', members) # PS4 Base64 Alphabet base64 = list( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-' ) alphabet = { character: index for index, character in enumerate(base64) } #print('Base64 Table: %s' % alphabet) # Jump Table location = address + Dynamic.JMPTAB f.seek(segm.OFFSET + Dynamic.JMPTAB) for entry in xrange(Dynamic.JMPTABSZ / 0x18): idaapi.create_struct(location + (entry * 0x18), 0x18, struct) idc.set_cmt( location + (entry * 0x18), Relocation(f).resolve(alphabet, nids, symbols, lids), False) except: pass # Relocation Table try: # -------------------------------------------------------------------------------------------------------- # 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 = address + Dynamic.RELATAB f.seek(segm.OFFSET + Dynamic.RELATAB) for entry in xrange(Dynamic.RELATABSZ / 0x18): idaapi.create_struct(location + (entry * 0x18), 0x18, struct) idc.set_cmt(location + (entry * 0x18), Relocation(f).process(nids, symbols), False) except: pass # Hash Table try: # -------------------------------------------------------------------------------------------------------- # Hash Entry Structure members = [('bucket', 'Bucket', 0x2), ('chain', 'Chain', 0x2), ('buckets', 'Buckets', 0x2), ('chains', 'Chains', 0x2)] struct = segm.struct('Hash', members) # Hash Table location = address + Dynamic.HASHTAB f.seek(segm.OFFSET + Dynamic.HASHTAB) for entry in xrange(Dynamic.HASHTABSZ / 0x8): idaapi.create_struct(location + (entry * 0x8), 0x8, struct) except: pass # Dynamic Tag Table try: # -------------------------------------------------------------------------------------------------------- # Dynamic Tag Entry Structure members = [('tag', 'Tag', 0x8), ('value', 'Value', 0x8)] struct = segm.struct('Tag', members) f.seek(offset) for entry in xrange(dynamicsize / 0x10): idaapi.create_struct(dynamic + (entry * 0x10), 0x10, struct) idc.set_cmt( dynamic + (entry * 0x10), Dynamic(f).comment(address, stubs, modules, libraries), False) except: pass # Start Function idc.add_entry(ps.E_START_ADDR, ps.E_START_ADDR, 'start', True) print('# Waiting for the AutoAnalyzer to Complete...') idaapi.auto_wait() # Set No Return for __stack_chk_fail... try: function = idc.get_name_ea_simple('__stack_chk_fail') function = idaapi.get_func(function) function.flags |= FUNC_NORET idaapi.update_func(function) except: pass # Missed Function Creation... try: code = idaapi.get_segm_by_name('CODE') address = code.start_ea end = code.end_ea # Final Pass print('# Performing Final Pass...') while address < end: address = idaapi.find_not_func(address, SEARCH_DOWN) if idaapi.is_unknown(idaapi.get_flags(address)): idaapi.create_insn(address) else: idc.add_func(address) address += 4 except: pass print('# Done!') return 1
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.is_unknown(idaapi.get_flags(address)): idaapi.create_insn(address) else: idc.add_func(address) address += 4 print('# Done!') return 1
def rename_vtable_functions(names, vtable_ea, class_name): # type: (typing.Dict[int, str], int, str) -> None ea = vtable_ea i = 0 while True: function_ea = struct.unpack('<Q', idaapi.get_many_bytes(ea, 8))[0] if '__cxa_pure_virtual' not in idc.GetDisasm(function_ea) and not idaapi.is_func(idaapi.get_flags(function_ea)): break member_fn_name = names.get(i, "m%d" % i) function_name = "%s::%s" % (class_name, member_fn_name) current_name = idc.GetFunctionName(function_ea) if current_name.startswith('nullsub_') or current_name.startswith('j_nullsub_'): idc.MakeNameEx(function_ea, function_name + '_null', idaapi.SN_NOWARN) elif current_name.startswith('sub_') or \ current_name.startswith("%s::m%d" % (class_name, i)) or \ "runtimetypeinfo" in current_name.lower(): idc.MakeNameEx(function_ea, function_name, idaapi.SN_NOWARN) i += 1 ea += 8
def has_all_vtable_functions_named(vtable_ea): # type: (int) -> bool ea = vtable_ea while True: function_ea = struct.unpack('<Q', idaapi.get_many_bytes(ea, 8))[0] if '__cxa_pure_virtual' not in idc.GetDisasm(function_ea) and not idaapi.is_func(idaapi.get_flags(function_ea)): break current_name = idc.GetFunctionName(function_ea) if current_name.startswith('sub_') or current_name.startswith('j_sub_'): return False ea += 8 return True
def __init__(self, ea, cs, IDA_inst, IDA_inst_size, IDA_inst_string): """Initialization function, to disassemble with Capstone""" # Init the node structure node_t.__init__(self) # Check if it's a code instruction try: is_c = is_code(get_flags(ea)) except: is_c = isCode(GetFlags(ea)) if not is_c: raise CodeException # # fill node_t struct # # NodeInfo self.info = NodeInfo() inst_elements = [] if cs is not None: try: size = create_insn(ea) bytes = get_bytes(ea, size) except: size = MakeCode(ea) bytes = GetManyBytes(ea, size) (address, size, mnemonic, op_str) = next(cs.disasm_lite(bytes, ea, count=1)) else: address = ea size = IDA_inst_size splitted = IDA_inst_string.split(" ") mnemonic = splitted[0] op_str = " ".join(splitted[1:]) self.info.opcode = mnemonic self.info.inst_str = self.info.opcode + " " + op_str splitted = op_str.split(", ") self.info.nargs = 0 if len(splitted) >= 1: self.info.arg1 = splitted[0] self.info.nargs += 1 if len(splitted) >= 2: self.info.arg2 = splitted[1] self.info.nargs += 1 if len(splitted) >= 3: self.info.arg3 = splitted[2] self.info.nargs += 1 # No node will be root but this is acceptable for CFGs self.info.is_root = False self.info.address = ea self.info.has_address = True # node_t self.node_id = self._genid()