def resolve_symbols(self, dll): tmpdir = tempfile.gettempdir().replace('\\', '/') + '/' # File who will first contain ordinals then symbols tmpfile = tmpdir + "dotNIETsymbols.txt" tmplog = tmpdir + "dotNIETlogs.txt" # Destination path for a copy of SharedLibrary.dll tmpdll = tmpdir + os.path.basename(dll) # Path to the idat binary, needed to parse a remote idb idat = idc.idadir().replace('\\','/') + '/' + 'idat' + \ ['64' if utils.is_x64(dll) else ''][0] if os.getenv("windir") is not None: idat += '.exe' # script called along with idat in order to parse SharedLibrary.idb parsing_script_path = '"' + os.path.dirname(os.path.realpath(__file__)).replace('\\','/')\ + '/dotNIET/resolve.py"' # we first copy SharedLibrary.dll to tmp to be sure we are in a # writable location shutil.copyfile(dll, tmpdll) # we have to use temporary files because of the ida headless stuff... # pretty dirty ordinals = [] with open(tmpfile, 'w') as f: for i in range(self.nb_symbols): ordinals.append((idaapi.get_qword(self.ordinals + i * 8) & ~0x8000000000000000) * 4) f.write(",".join([str(x) for x in ordinals])) # be prepared to wait as this will load the binary + pdb idaapi.msg("Starting parsing of %d symbols...\n" % self.nb_symbols) subprocess.run([idat, "-L" + tmplog, "-c", "-A", "-S" + \ parsing_script_path + " " + tmpfile, tmpdll], creationflags=subprocess.CREATE_NO_WINDOW, check=True) # we read back tmpfile which now contains symbols symbols = [] with open(tmpfile, 'r') as f: symbolsArray = f.read() symbols = symbolsArray.split(',') # we first have to undef structure as it is an array and ida will # refuse to set names within it idc.del_items(self.ordinals) idc.set_cmt(self.ordinals - 8, "Custom imports from SharedLibrary.dll", 0) # we then apply the symbols at this very same location (start of .idata) for i in range(self.nb_symbols): idc.set_name(self.ordinals + i * 8, symbols[i], SN_NOCHECK | SN_FORCE | SN_NODUMMY) # finally we remove our temp files os.remove(tmpfile) os.remove(tmpdll) # ida generate a db os.remove(tmpdll + '.i64') # if everything went smoothly, we should not need this anymore os.remove(tmplog)
def load_nids(directory, library): try: path = '%s/%s/%s' % (idc.idadir(), directory, library) with open(path) as database: if library == AEROLIB: NIDS = dict(row for row in csv.reader(database, delimiter=' ')) else: NIDS = [row.strip() for row in database] except IOError: retry = idaapi.ask_file(0, '%s|*.csv|All files (*.*)|*.*', 'Please gimme your %s file' % (library)) if retry != None: try: with open(retry) as database: if library == AEROLIB: NIDS = dict( row for row in csv.reader(database, delimiter=' ')) else: NIDS = [row.strip() for row in database] shutil.copy2(retry, path) except: print('Ok, no NIDs for you!') else: print('Ok, no NIDs for you!') return NIDS
def __init__(self, wrapper, utilsJar, config_file): self.packageName = None self.launchActivity = None self.android_server = None self.device = None self.adb = wrapper self.utilsJar = utilsJar self.config_file = config_file if hasattr(idc, "idadir"): # ida 7.0 self.bindir = os.path.abspath(idc.idadir() + "/dbgsrv") else: import idaapi self.bindir = os.path.abspath(idaapi.get_idcpath() + "/../dbgsrv")
def save_nids(directory, library, NIDS): try: path = '%s/%s/%s' % (idc.idadir(), directory, library) mode = 'a' if library == AEROLIB else 'w' with open(path, mode) as database: if library == AEROLIB: for nid, name in sorted(NIDS.items(), key=lambda x: x[1]): database.write('%s %s\n' % (nid, name)) else: for nid in NIDS: database.write('%s\n' % nid) except: idc.error('Error saving the %s :(' % library)
def find_pdb(dll_path): # we first check if the pdb is available symbol_paths = [] cfg_known_locations = [ ida_diskio.get_user_idadir() + "/cfg/pdb.cfg", idc.idadir() + "/cfg/pdb.cfg" ] for cfg in cfg_known_locations: if os.path.exists(cfg): symbol_paths = _parse_cfg_file(cfg) # ida first check IDAUSR dir and if ok ignore IDADIR cfg if symbol_paths is not None and len(symbol_paths): break nt_symbol_path_env = os.getenv("_NT_SYMBOL_PATH") # assume Windows + it overrides values of ida cfg file if nt_symbol_path_env is not None and nt_symbol_path_env != "": symbol_paths = _parse_symbol_path(os.getenv("_NT_SYMBOL_PATH")) if symbol_paths is None or not len(symbol_paths): idaapi.msg("Error: \'_NT_SYMBOL_PATH\' could not be found. One must" +\ " set for .NIET to work.\n") return False else: # we then compute pdb guid of SharedLibrary.dll pdbguid = pdbg.get_guid(dll_path) if pdbguid is None: return False # we can have multiple paths, we check all of them for paths in symbol_paths: pdb_path = paths.replace('\\','/') + "/SharedLibrary.pdb/" + \ pdbguid + "/SharedLibrary.pdb" if not os.path.exists(pdb_path): idaapi.msg("Error: %s could not be found\n" % pdb_path) return False else: return True
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
import os import logging import idc try: import configparser except ImportError: # for python 2 import ConfigParser as configparser CONFIG_FILE_PATH = os.path.join(idc.idadir(), 'cfg', 'HexRaysPyTools.cfg') DEBUG_MESSAGE_LEVEL = logging.INFO # Whether propagate names (Propagate name feature) through all names or only defaults like v11, a3, this, field_4 PROPAGATE_THROUGH_ALL_NAMES = False # Store Xref information in database. I don't know how much size it consumes yet STORE_XREFS = True # There're some types that can be pointers to structures like int, PVOID etc and by default plugin scans only them # Full list can be found in `Const.LEGAL_TYPES`. # But if set this option to True than variable of every type could be possible to scan SCAN_ANY_TYPE = False def add_default_settings(config): updated = False if not config.has_option("DEFAULT", "DEBUG_MESSAGE_LEVEL"): config.set(None, 'DEBUG_MESSAGE_LEVEL', str(DEBUG_MESSAGE_LEVEL)) updated = True if not config.has_option("DEFAULT", "PROPAGATE_THROUGH_ALL_NAMES"): config.set(None, 'PROPAGATE_THROUGH_ALL_NAMES', str(PROPAGATE_THROUGH_ALL_NAMES))