def test_recurse_ntuser(ntuser_hive): registry_hive = RegistryHive(ntuser_hive) EXPECTED_KEYS = ['path', 'subkey_name', 'timestamp', 'values', 'values_count'] value_types = { 'REG_BINARY': 0, 'REG_DWORD': 0, 'REG_EXPAND_SZ': 0, 'REG_MULTI_SZ': 0, 'REG_NONE': 0, 'REG_QWORD': 0, 'REG_SZ': 0 } subkey_count = 0 values_count = 0 for subkey in registry_hive.recurse_subkeys(as_json=True): subkey_values = subkey.values subkey_count += 1 values_count += len(subkey_values or []) if subkey_values: for x in subkey_values: value_types[x['value_type']] += 1 assert subkey_count == 2318 assert values_count == 4613 assert value_types == { 'REG_BINARY': 620, 'REG_DWORD': 1516, 'REG_EXPAND_SZ': 100, 'REG_MULTI_SZ': 309, 'REG_NONE': 141, 'REG_QWORD': 57, 'REG_SZ': 1870 }
def test_recurse_ntuser(ntuser_hive): registry_hive = RegistryHive(ntuser_hive) value_types = { 'REG_BINARY': 0, 'REG_DWORD': 0, 'REG_EXPAND_SZ': 0, 'REG_MULTI_SZ': 0, 'REG_NONE': 0, 'REG_QWORD': 0, 'REG_SZ': 0 } subkey_count = 0 values_count = 0 for subkey in registry_hive.recurse_subkeys(as_json=True): subkey_values = subkey.values subkey_count += 1 values_count += len(subkey_values or []) if subkey_values: for x in subkey_values: value_types[x['value_type']] += 1 assert subkey_count == 1812 assert values_count == 4094 assert value_types == { 'REG_BINARY': 531, 'REG_DWORD': 1336, 'REG_EXPAND_SZ': 93, 'REG_MULTI_SZ': 303, 'REG_NONE': 141, 'REG_QWORD': 54, 'REG_SZ': 1636 }
def parse_hive(self, hive_file, hive_name, user=''): reg = RegistryHive(hive_file) for d in reg.recurse_subkeys(as_json=True): data = {} data.update({ 'timestamp': d.timestamp, 'hive_name': hive_name, 'path': d.path, 'subkey': d.subkey_name, }) if user: data['user'] = user if not d.values: yield data continue data['values_count'] = d.values_count # Store a list of dictionaries as values data['values'] = [] for v in d.values: name = v['name'].lstrip('(').rstrip(')') value_type = 'bytes' if v[ 'value_type'] == 'REG_BINARY' else 'strings' data['values'].append({ 'value': name, 'data.{}'.format(value_type): v['value'] }) yield data
def parse_default_hive(default_hive: RegistryHive) -> dict: """ Parse default hive and return needed information. Parameters ---------- default_hive : RegistryHive The default hive to parse Returns ------- dict Dictionary with the information for systeminfo """ default_hive_dict = { "system_locale": ";".join([ default_hive.get_key(".DEFAULT\\Control Panel\\International" ).get_value("LocaleName"), default_hive.get_key(".DEFAULT\\Control Panel\\International"). get_value("sCountry"), ]) } # Return results return default_hive_dict
def test_recurse_amcache(amcache_hive): registry_hive = RegistryHive(amcache_hive) value_types = { 'REG_BINARY': 0, 'REG_DWORD': 0, 'REG_EXPAND_SZ': 0, 'REG_MULTI_SZ': 0, 'REG_NONE': 0, 'REG_QWORD': 0, 'REG_SZ': 0 } subkey_count = 0 values_count = 0 for subkey in registry_hive.recurse_subkeys(): subkey_count += 1 subkey_values = subkey.values values_count += len(subkey_values or []) if subkey_values: for x in subkey_values: value_types[x.value_type] += 1 assert subkey_count == 2105 assert values_count == 17539 assert value_types == { 'REG_BINARY': 56, 'REG_DWORD': 1656, 'REG_EXPAND_SZ': 0, 'REG_MULTI_SZ': 140, 'REG_NONE': 0, 'REG_QWORD': 1254, 'REG_SZ': 14433 }
def test_ntuser_emojis(transaction_ntuser): # There are some cases where the Registry stores utf-16 emojis as subkey names :) registry_hive = RegistryHive(transaction_ntuser) international = registry_hive.get_key(r'\Control Panel\International') subkeys = [x.name for x in international.iter_subkeys()] assert subkeys == [ 'Geo', 'User Profile', 'User Profile System Backup', '🌎🌏🌍' ]
def test_recurse_partial_ntuser(ntuser_software_partial): registry_hive = RegistryHive(ntuser_software_partial, hive_type=NTUSER_HIVE_TYPE, partial_hive_path=r'\Software') for subkey_count, subkey in enumerate( registry_hive.recurse_subkeys(as_json=True)): assert subkey.actual_path.startswith(registry_hive.partial_hive_path) assert subkey_count == 6395
def __init__(self, ntuser=None, system=None, security=None, sam=None): raise NotImplementedError self.ntuser = RegistryHive(ntuser) if ntuser is not None else None self.system = RegistryHive(system) if system is not None else None self.security = RegistryHive( security) if security is not None else None self.sam = RegistryHive(sam) if sam is not None else None
def test_hive_serialization(ntuser_hive, temp_output_file): registry_hive = RegistryHive(ntuser_hive) registry_hive.dump_hive_to_json(temp_output_file, registry_hive.root, verbose=False) counter = 0 with open(temp_output_file, 'r') as dumped_hive: for x in dumped_hive.readlines(): assert json.loads(x) counter += 1 assert counter == 2318
def test_find_keys_ntuser(ntuser_hive): registry_hive = RegistryHive(ntuser_hive) run_key = registry_hive.get_key(r'\Software\Microsoft\Windows\CurrentVersion\Run') assert run_key.name == 'Run' assert run_key.header.last_modified == 129779615948377168 values = [x for x in run_key.iter_values(as_json=True)] assert values[0].name == 'Sidebar' assert values[0].value_type == 'REG_EXPAND_SZ'
def test_find_keys_partial_ntuser_hive(ntuser_software_partial): registry_hive = RegistryHive(ntuser_software_partial, hive_type=NTUSER_HIVE_TYPE, partial_hive_path=r'\Software') run_key = registry_hive.get_key(r'\Software\Microsoft\Windows\CurrentVersion\Run') assert run_key.name == 'Run' assert run_key.header.last_modified == 132024690510209250 values = [x for x in run_key.iter_values(as_json=True)] assert values[0].name == 'OneDrive' assert values[0].value_type == 'REG_SZ'
def test_get_key(software_hive): """ # Refers to https://github.com/mkorman90/regipy/issues/144 """ registry_hive = RegistryHive(software_hive) # We verify the registry headers are similar, because this is the same subkey. assert registry_hive.get_key( 'ODBC').header == registry_hive.root.get_subkey('ODBC').header assert registry_hive.root.get_subkey( 'ODBC').header == registry_hive.get_key('SOFTWARE\\ODBC').header
def hive_to_json(hive_path, output_path, registry_path, timeline, hive_type, partial_hive_path, verbose): _setup_logging(verbose=verbose) registry_hive = RegistryHive(hive_path, hive_type=hive_type, partial_hive_path=partial_hive_path) if registry_path: try: name_key_entry = registry_hive.get_key(registry_path) except RegistryKeyNotFoundException as ex: logger.debug('Did not find the key: {}'.format(ex)) return else: name_key_entry = registry_hive.root if timeline and not output_path: click.secho( 'You must provide an output path if choosing timeline output!', fg='red') return if output_path: if timeline: with open(output_path, 'w') as csvfile: csvwriter = csv.DictWriter( csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL, fieldnames=['timestamp', 'subkey_name', 'values_count']) csvwriter.writeheader() with progressbar( registry_hive.recurse_subkeys( name_key_entry, as_json=True)) as reg_subkeys: for entry in reg_subkeys: entry_dict = entry.__dict__ path = entry.path csvwriter.writerow({ 'subkey_name': r'{}\{}'.format(entry.path, path), 'timestamp': entry_dict['timestamp'], 'values_count': entry_dict['values_count'] }) else: dump_hive_to_json(registry_hive, output_path, name_key_entry, verbose) else: for entry in registry_hive.recurse_subkeys(name_key_entry, as_json=True): click.secho(json.dumps(attr.asdict(entry), indent=4))
def apply_transaction_logs(hive_path, primary_log_path, secondary_log_path=None, restored_hive_path=None, verbose=False): """ Apply transactions logs :param hive_path: The path to the original hive :param primary_log_path: The path to the primary log path :param secondary_transaction_log_path: The path to the secondary log path (optional). :param restored_hive_path: Path to save the restored hive :param verbose: verbosity :return: """ recovered_dirty_pages_total_count = 0 if not restored_hive_path: restored_hive_path = f'{hive_path}.restored' registry_hive = RegistryHive(hive_path) log_size = os.path.getsize(primary_log_path) logger.info(f'Log Size: {log_size}') restored_hive_buffer, recovered_dirty_pages_count = _parse_transaction_log( registry_hive, hive_path, primary_log_path) logger.info( f'Recovered {recovered_dirty_pages_count} pages from primary transaction log' ) recovered_dirty_pages_total_count += recovered_dirty_pages_count # Write to disk the modified registry hive with open(restored_hive_path, 'wb') as f: restored_hive_buffer.seek(0) f.write(restored_hive_buffer.read()) if secondary_log_path: registry_hive = RegistryHive(restored_hive_path) restored_hive_buffer, recovered_dirty_pages_count = _parse_transaction_log( registry_hive, restored_hive_path, secondary_log_path) # Write to disk the modified registry hive with open(restored_hive_path, 'wb') as f: restored_hive_buffer.seek(0) f.write(restored_hive_buffer.read()) recovered_dirty_pages_total_count += recovered_dirty_pages_count logger.info( f'Recovered {recovered_dirty_pages_count} pages from secondary transaction log' ) return restored_hive_path, recovered_dirty_pages_total_count
def hive_to_json(hive_path, output_path, registry_path, timeline, hive_type, partial_hive_path, verbose): with logbook.NestedSetup( _get_log_handlers(verbose=verbose)).applicationbound(): registry_hive = RegistryHive(hive_path, hive_type=hive_type, partial_hive_path=partial_hive_path) if registry_path: try: name_key_entry = registry_hive.get_key(registry_path) except RegistryKeyNotFoundException as ex: logger.debug('Did not find the key: {}'.format(ex)) return else: name_key_entry = registry_hive.root if timeline and not output_path: click.secho( 'You must provide an output path if choosing timeline output!', fg='red') return if output_path: if timeline: with open(output_path, 'w') as csvfile: csvwriter = csv.DictWriter(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL, fieldnames=[ 'timestamp', 'subkey_name', 'values_count' ]) csvwriter.writeheader() for entry in tqdm( registry_hive.recurse_subkeys(name_key_entry, as_json=True)): subkey_name = entry.pop('subkey_name') path = entry.pop('path') entry['subkey_name'] = r'{}\{}'.format( path, subkey_name) entry.pop('values') csvwriter.writerow(entry) else: dump_hive_to_json(registry_hive, output_path, name_key_entry, verbose) else: for entry in registry_hive.recurse_subkeys(name_key_entry, as_json=True): click.secho(json.dumps(attr.asdict(entry), indent=4))
def get_registry_tree(registry_location, registry_path): """ Return a list of dictionaries of Window registry entries found under a given registry path """ registry_hive = RegistryHive(registry_location) name_key_entry = get_registry_name_key_entry(registry_hive=registry_hive, registry_path=registry_path) if not name_key_entry: return [] return [ attr.asdict(entry) for entry in registry_hive.recurse_subkeys(name_key_entry, as_json=True) ]
def apply_transaction_logs(hive_path, transaction_log_path, restored_hive_path=None, verbose=False): if not restored_hive_path: restored_hive_path = f'{hive_path}.restored' registry_hive = RegistryHive(hive_path) log_size = os.path.getsize(transaction_log_path) expected_sequence_number = registry_hive.header.secondary_sequence_num logger.info(f'Log Size: {log_size}') with open(transaction_log_path, 'rb') as transaction_log: transaction_log_regf_header = REGF_HEADER.parse_stream(transaction_log) transaction_log.seek(512, 0) if transaction_log_regf_header.major_version == 1 and transaction_log_regf_header.minor_version >= 5: # This is an HvLE block restored_hive_buffer, recovered_dirty_pages_count = _parse_hvle_block(hive_path, transaction_log, log_size, expected_sequence_number) else: # This is an old transaction log - DIRT hbins_data_size = registry_hive.header.hive_bins_data_size restored_hive_buffer, recovered_dirty_pages_count = _parse_dirt_block(hive_path, transaction_log, hbins_data_size) # Write to disk the modified registry hive with open(restored_hive_path, 'wb') as f: restored_hive_buffer.seek(0) f.write(restored_hive_buffer.read()) return restored_hive_path, recovered_dirty_pages_count
def test_parse_root_key(ntuser_hive): registry_hive = RegistryHive(ntuser_hive) assert isinstance(registry_hive, RegistryHive) assert isinstance(registry_hive.root, NKRecord) assert registry_hive.root.name == 'CMI-CreateHive{6A1C4018-979D-4291-A7DC-7AED1C75B67C}' assert registry_hive.root.subkey_count == 11 assert dict(registry_hive.root.header) == { 'access_bits': b'\x00\x00\x00\x00', 'class_name_offset': 4294967295, 'class_name_size': 0, 'flags': b',\x00', 'key_name_size': 52, 'key_name_string': b'CMI-CreateHive{6A1C4018-979D-4291-A7DC-7AED1C75B67C}', 'largest_sk_class_name': 0, 'largest_sk_name': 40, 'largest_value_name': 0, 'last_modified': 129780243434537497, 'largest_value_data': 0, 'parent_key_offset': 1656, 'security_list_offset': 1376, 'subkey_count': 11, 'subkeys_list_offset': 73760, 'values_count': 0, 'values_list_offset': 4294967295, 'volatile_subkey_count': 2, 'volatile_subkeys_list_offset': 2147486280 }
def _get_computer_name(self, reg: RegistryHive): names = [] for subkey_path in reg.get_control_sets( r'Control\ComputerName\ComputerName'): subkey = reg.get_key(subkey_path) try: names.append({ 'name': subkey.get_value('ComputerName'), 'timestamp': Time.change_output_date_format_from_epoch( subkey.header.last_modified) }) except RegistryValueNotFoundException as ex: continue return names
def test_winrar(ntuser_hive): registry_hive = RegistryHive(ntuser_hive) plugin_instance = WinRARPlugin(registry_hive, as_json=True) plugin_instance.run() assert plugin_instance.entries == [{ "last_write": "2021-11-18T13:59:04.888952+00:00", "archive_path": "C:\\Users\\tony\\Downloads\\RegistryFinder64.zip", "operation": "archive_opened" }, { "last_write": "2021-11-18T13:59:04.888952+00:00", "archive_path": "C:\\temp\\token.zip", "operation": "archive_opened" }, { "last_write": "2021-11-18T13:59:50.023788+00:00", "archive_name": "Tools.zip", "operation": "archive_created" }, { "last_write": "2021-11-18T13:59:50.023788+00:00", "archive_name": "data.zip", "operation": "archive_created" }, { "last_write": "2021-11-18T14:00:44.180468+00:00", "destination_folder": "C:\\Users\\tony\\Downloads", "operation": "archive_extracted" }, { "last_write": "2021-11-18T14:00:44.180468+00:00", "destination_folder": "C:\\temp", "operation": "archive_extracted" }]
def test_services_plugin_on_corrupted_hive(corrupted_system_hive): registry_hive = RegistryHive(corrupted_system_hive) plugin_instance = ServicesPlugin(registry_hive, as_json=True) plugin_instance.run() assert plugin_instance.entries['\\ControlSet001\\Services']['services'][0] == { 'last_modified': '2008-10-21T17:48:29.328124+00:00', 'name': 'Abiosdsk', 'parameters': [], 'values': [ {'is_corrupted': False, 'name': 'ErrorControl', 'value': 0, 'value_type': 'REG_DWORD'}, {'is_corrupted': False, 'name': 'Group', 'value': 'Primary disk', 'value_type': 'REG_SZ'}, {'is_corrupted': False, 'name': 'Start', 'value': 4, 'value_type': 'REG_DWORD'}, {'is_corrupted': False, 'name': 'Tag', 'value': 3, 'value_type': 'REG_DWORD'}, {'is_corrupted': False, 'name': 'Type', 'value': 1, 'value_type': 'REG_DWORD'} ] }
def run_plugins(hive_path, output_path, plugins, verbose): with logbook.NestedSetup( _get_log_handlers(verbose=verbose)).applicationbound(): registry_hive = RegistryHive(hive_path) click.secho('Loaded {} plugins'.format(len(PLUGINS)), fg='white') if plugins: plugin_names = {x.NAME for x in PLUGINS} plugins = plugins.split(',') plugins = set(plugins) if not plugins.issubset(plugin_names): click.secho('Invalid plugin names given: {}'.format( ','.join(set(plugins) - plugin_names)), fg='red') click.secho( 'Use --help or -h to get list of plugins and their descriptions', fg='red') return # Run relevant plugins plugin_results = run_relevant_plugins(registry_hive, as_json=True, plugins=plugins) # If output path was set, dump results to disk if output_path: with open(output_path, 'w') as f: f.write(json.dumps(plugin_results, indent=4)) else: print(json.dumps(plugin_results, indent=4)) click.secho('Finished: {}/{} plugins matched the hive type'.format( len(plugin_results), len(PLUGINS)), fg='green')
def run_regipy(result_pk, filepath): """ Runs regipy on filepath """ try: registry_hive = RegistryHive(filepath) reg_json = registry_hive.recurse_subkeys(registry_hive.root, as_json=True) root = {"values": [attr.asdict(entry) for entry in reg_json]} root = json.loads(json.dumps(root).replace(r"\u0000", "")) except Exception as e: logging.error(e) root = {} ed = ExtractedDump.objects.get(result__pk=result_pk, path=filepath) ed.reg_array = root ed.save()
def _get_usbstorage(self, reg: RegistryHive): usbs = [] try: for subkey_path in reg.get_control_sets(r'Enum\USBSTOR'): subkey = reg.get_key(subkey_path) for usb in subkey.iter_subkeys(): usbs.append({ 'device': usb.name, 'timestamp': Time.change_output_date_format_from_epoch( usb.header.last_modified) }) except: return None return usbs
def _extract_data(self, path: str): reg = RegistryHive(path) return self._clean_nones({ "SYSTEM": self._get_system_info(reg), "SOFTWARE": self._get_sofware_info(reg), "NTUSER": self._get_ntuser_info(reg), "SAM": self._get_sam_info(reg) })
def test_shimcache_plugin(system_hive): registry_hive = RegistryHive(system_hive) shimcache_plugin_result = ShimCachePlugin(registry_hive, as_json=True).run() assert len(shimcache_plugin_result) == 660 assert shimcache_plugin_result[0] == { 'last_mod_date': '2011-01-12T12:08:00+00:00', 'path': '\\??\\C:\\Program Files\\McAfee\\VirusScan Enterprise\\mfeann.exe', 'exec_flag': 'True' }
def _get_last_logon(self, reg: RegistryHive): try: key = reg.get_key( r'\Microsoft\Windows\CurrentVersion\Authentication\LogonUI') return { "LastLoggedOnUser": key.get_value("LastLoggedOnUser"), "LastLoggedOnSAMUser": key.get_value("LastLoggedOnSAMUser") } except: pass
def _get_so_version(self, reg: RegistryHive): try: subkey = reg.get_key(r'\Microsoft\Windows NT\CurrentVersion') return { 'ProductName': subkey.get_value('ProductName'), 'ReleaseId': subkey.get_value('ReleaseId') } except: return None
def test_local_sid_plugin_sam(sam_hive): registry_hive = RegistryHive(sam_hive) plugin_instance = LocalSidPlugin(registry_hive, as_json=True) plugin_instance.run() assert plugin_instance.entries == [{ "machine_sid": "S-1-5-21-1760460187-1592185332-161725925", "timestamp": "2014-09-24T03:36:43.549302+00:00" }]
def test_persistence_plugin_software(software_hive): registry_hive = RegistryHive(software_hive) plugin_instance = SoftwarePersistencePlugin(registry_hive, as_json=True) plugin_instance.run() assert plugin_instance.entries == { '\\Microsoft\\Windows\\CurrentVersion\\Run': {'timestamp': '2012-04-04T01:54:23.669836+00:00', 'values': [ { 'name': 'VMware Tools', 'value_type': 'REG_SZ', 'value': '"C:\\Program Files\\VMware\\VMware Tools\\VMwareTray.exe"', 'is_corrupted': False }, { 'name': 'VMware User Process', 'value_type': 'REG_SZ', 'value': '"C:\\Program Files\\VMware\\VMware Tools\\VMwareUser.exe"', 'is_corrupted': False }, { 'name': 'Adobe ARM', 'value_type': 'REG_SZ', 'value': '"C:\\Program Files\\Common Files\\Adobe\\ARM\\1.0\\AdobeARM.exe"', 'is_corrupted': False }, { 'name': 'McAfeeUpdaterUI', 'value_type': 'REG_SZ', 'value': '"C:\\Program Files\\McAfee\\Common Framework\\udaterui.exe" /StartedFromRunKey', 'is_corrupted': False }, { 'name': 'ShStatEXE', 'value_type': 'REG_SZ', 'value': '"C:\\Program Files\\McAfee\\VirusScan Enterprise\\SHSTAT.EXE" /STANDALONE', 'is_corrupted': False }, { 'name': 'McAfee Host Intrusion Prevention Tray', 'value_type': 'REG_SZ', 'value': '"C:\\Program Files\\McAfee\\Host Intrusion Prevention\\FireTray.exe"', 'is_corrupted': False }, { 'name': 'svchost', 'value_type': 'REG_SZ', 'value': 'c:\\windows\\system32\\dllhost\\svchost.exe', 'is_corrupted': False } ] } }