private void EnumerateFiles(List <string> paths, string rootPath, string currentPath, string extension) { foreach (string filePath in Directory.GetFiles(currentPath)) { var fileExtension = Path.GetExtension(filePath); if (fileExtension.ToLower() == extension) { var relativePath = filePath.Substring(rootPath.Length); if (relativePath[0] == '/' || relativePath[0] == '\\') { relativePath = relativePath.Substring(1); } paths.Add(relativePath); } } foreach (string directoryPath in Directory.GetDirectories(currentPath)) { EnumerateFiles(paths, rootPath, directoryPath, extension); } }
public AppCompatCache(string filename, int controlSet, bool noLogs) { byte[] rawBytes = null; Caches = new List <IAppCompatCache>(); var controlSetIds = new List <int>(); RegistryKey subKey = null; var isLiveRegistry = string.IsNullOrEmpty(filename); if (isLiveRegistry) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { throw new NotSupportedException("Live Registry support is not supported on non-Windows platforms."); } var keyCurrUser = Microsoft.Win32.Registry.LocalMachine; var subKey2 = keyCurrUser.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache"); if (subKey2 == null) { subKey2 = keyCurrUser.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatibility"); if (subKey2 == null) { Console.WriteLine( @"'CurrentControlSet\Control\Session Manager\AppCompatCache' key not found! Exiting"); return; } } rawBytes = (byte[])subKey2.GetValue("AppCompatCache", null); subKey2 = keyCurrUser.OpenSubKey(@"SYSTEM\Select"); ControlSet = (int)subKey2.GetValue("Current"); var is32Bit = Is32Bit(filename, null); var cache = Init(rawBytes, is32Bit, ControlSet); Caches.Add(cache); return; } RegistryHive reg; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Privilege[] privileges = { Privilege.EnableDelegation, Privilege.Impersonate, Privilege.Tcb }; using var enabler = new PrivilegeEnabler(Privilege.Backup, privileges); } ControlSet = controlSet; if (File.Exists(filename) == false && Helper.RawFileExists(filename) == false) { throw new FileNotFoundException($"File not found ({filename})!"); } var dirname = Path.GetDirectoryName(Path.GetFullPath(filename)); var hiveBase = Path.GetFileName(filename); List <RawCopyReturn> rawFiles = null; try { reg = new RegistryHive(filename) { RecoverDeleted = true }; } catch (IOException) { //file is in use if (Helper.IsAdministrator() == false) { throw new UnauthorizedAccessException("Administrator privileges not found!"); } Log.Warning("'{Filename}' is in use. Rerouting...", filename); var files = new List <string>(); files.Add(filename); var logFiles = Directory.GetFiles(dirname, $"{hiveBase}.LOG?").ToList(); var log1 = $"{dirname}\\{hiveBase}.LOG1"; var log2 = $"{dirname}\\{hiveBase}.LOG2"; if (logFiles.Count == 0) { if (Helper.RawFileExists(log1)) { logFiles.Add(log1); } if (Helper.RawFileExists(log2)) { logFiles.Add(log2); } } foreach (var logFile in logFiles) { files.Add(logFile); } rawFiles = Helper.GetRawFiles(files); var b = new byte[rawFiles.First().FileStream.Length]; rawFiles.First().FileStream.Read(b, 0, (int)rawFiles.First().FileStream.Length); reg = new RegistryHive(b, rawFiles.First().InputFilename); } if (reg.Header.PrimarySequenceNumber != reg.Header.SecondarySequenceNumber) { if (string.IsNullOrEmpty(dirname)) { dirname = "."; } var logFiles = Directory.GetFiles(dirname, $"{hiveBase}.LOG?").ToList(); var log1 = $"{dirname}\\{hiveBase}.LOG1"; var log2 = $"{dirname}\\{hiveBase}.LOG2"; if (logFiles.Count == 0) { if (File.Exists(log1)) { logFiles.Add(log1); } if (File.Exists(log2)) { logFiles.Add(log2); } } if (logFiles.Count == 0) { if (Helper.IsAdministrator()) { if (Helper.RawFileExists(log1)) { logFiles.Add(log1); } if (Helper.RawFileExists(log2)) { logFiles.Add(log2); } } else { Log.Fatal("Log files not found and no administrator access to look for them!"); } } if (logFiles.Count == 0) { if (noLogs == false) { Log.Warning( "Registry hive is dirty and no transaction logs were found in the same directory! LOGs should have same base name as the hive. Aborting!!"); throw new Exception( "Sequence numbers do not match and transaction logs were not found in the same directory as the hive. Aborting"); } Log.Warning( "Registry hive is dirty and no transaction logs were found in the same directory. Data may be missing! Continuing anyways..."); } else { if (noLogs == false) { if (rawFiles != null) { var lt = new List <TransactionLogFileInfo>(); foreach (var rawCopyReturn in rawFiles.Skip(1).ToList()) { var b = new byte[rawCopyReturn.FileStream.Length]; var tt = new TransactionLogFileInfo(rawCopyReturn.InputFilename, b); lt.Add(tt); } reg.ProcessTransactionLogs(lt, true); } else { reg.ProcessTransactionLogs(logFiles.ToList(), true); } } else { Log.Warning( "Registry hive is dirty and transaction logs were found in the same directory, but --nl was provided. Data may be missing! Continuing anyways..."); } } } reg.ParseHive(); if (controlSet == -1) { for (var i = 0; i < 10; i++) { subKey = reg.GetKey($@"ControlSet00{i}\Control\Session Manager\AppCompatCache"); if (subKey == null) { subKey = reg.GetKey($@"ControlSet00{i}\Control\Session Manager\AppCompatibility"); } if (subKey != null) { controlSetIds.Add(i); } } if (controlSetIds.Count > 1) { Log.Warning( "***The following ControlSet00x keys will be exported: {Cs}. Use -c to process keys individually", string.Join(",", controlSetIds)); } } else { //a control set was passed in subKey = reg.GetKey($@"ControlSet00{ControlSet}\Control\Session Manager\AppCompatCache"); if (subKey == null) { subKey = reg.GetKey($@"ControlSet00{ControlSet}\Control\Session Manager\AppCompatibility"); } if (subKey == null) { throw new Exception($"Could not find ControlSet00{ControlSet}. Exiting"); } controlSetIds.Add(ControlSet); } var is32 = Is32Bit(filename, reg); Log.Debug("**** Found {Count} ids to process", controlSetIds.Count); foreach (var id in controlSetIds) { Log.Debug("**** Processing id {Id}", id); // var hive2 = new RegistryHiveOnDemand(filename); subKey = reg.GetKey($@"ControlSet00{id}\Control\Session Manager\AppCompatCache"); if (subKey == null) { Log.Debug("**** Initial subkey null, getting appCompatability key"); subKey = reg.GetKey($@"ControlSet00{id}\Control\Session Manager\AppCompatibility"); } Log.Debug("**** Looking for AppCompatcache value"); var val = subKey?.Values.SingleOrDefault(c => c.ValueName == "AppCompatCache"); if (val != null) { Log.Debug("**** Found AppCompatcache value"); rawBytes = val.ValueDataRaw; } if (rawBytes == null) { Log.Error("'AppCompatCache' value not found for 'ControlSet00{Id}'! Exiting", id); } var cache = Init(rawBytes, is32, id); Caches.Add(cache); } }
private static void UpdateFromRepo() { Console.WriteLine(); _logger.Info( "Checking for updated maps at https://github.com/EricZimmerman/evtx/tree/master/evtx/Maps..."); Console.WriteLine(); var archivePath = Path.Combine(BaseDirectory, "____master.zip"); if (File.Exists(archivePath)) { File.Delete(archivePath); } using (var client = new WebClient()) { ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; client.DownloadFile("https://github.com/EricZimmerman/evtx/archive/master.zip", archivePath); } var fff = new FastZip(); if (Directory.Exists(Path.Combine(BaseDirectory, "Maps")) == false) { Directory.CreateDirectory(Path.Combine(BaseDirectory, "Maps")); } var directoryFilter = "Maps"; // Will prompt to overwrite if target file names already exist fff.ExtractZip(archivePath, BaseDirectory, FastZip.Overwrite.Always, null, null, directoryFilter, true); if (File.Exists(archivePath)) { File.Delete(archivePath); } var newMapPath = Path.Combine(BaseDirectory, "evtx-master", "evtx", "Maps"); var orgMapPath = Path.Combine(BaseDirectory, "Maps"); var newMaps = Directory.GetFiles(newMapPath); var newlocalMaps = new List <string>(); var updatedlocalMaps = new List <string>(); if (File.Exists(Path.Combine(orgMapPath, "Security_4624.map"))) { _logger.Warn($"Old map format found. Zipping to '!!oldMaps.zip' and cleaning up old maps"); //old maps found, so zip em first var oldZip = Path.Combine(orgMapPath, "!!oldMaps.zip"); fff.CreateZip(oldZip, orgMapPath, false, @"\.map$"); foreach (var m in Directory.GetFiles(orgMapPath, "*.map")) { File.Delete(m); } } if (File.Exists(Path.Combine(orgMapPath, "!!!!README.txt"))) { File.Delete(Path.Combine(orgMapPath, "!!!!README.txt")); } foreach (var newMap in newMaps) { var mName = Path.GetFileName(newMap); var dest = Path.Combine(orgMapPath, mName); if (File.Exists(dest) == false) { //new target newlocalMaps.Add(mName); } else { //current destination file exists, so compare to new var fiNew = new FileInfo(newMap); var fi = new FileInfo(dest); if (fiNew.GetHash(HashType.SHA1) != fi.GetHash(HashType.SHA1)) { //updated file updatedlocalMaps.Add(mName); } } File.Copy(newMap, dest, CopyOptions.None); } if (newlocalMaps.Count > 0 || updatedlocalMaps.Count > 0) { _logger.Fatal("Updates found!"); Console.WriteLine(); if (newlocalMaps.Count > 0) { _logger.Error("New maps"); foreach (var newLocalMap in newlocalMaps) { _logger.Info(Path.GetFileNameWithoutExtension(newLocalMap)); } Console.WriteLine(); } if (updatedlocalMaps.Count > 0) { _logger.Error("Updated maps"); foreach (var um in updatedlocalMaps) { _logger.Info(Path.GetFileNameWithoutExtension(um)); } Console.WriteLine(); } Console.WriteLine(); } else { Console.WriteLine(); _logger.Info("No new maps available"); Console.WriteLine(); } Directory.Delete(Path.Combine(BaseDirectory, "evtx-master"), true); }
private static bool CanRemove(string folderName) { if (!Directory.Exists(folderName)) { return(false); } try { //nothing at all if (Directory.GetFiles(folderName).Length == 0 && Directory.GetDirectories(folderName).Length == 0) { return(true); } bool containsMovieFiles = Directory.GetFiles(folderName).Any(s => s.IsMovieFile()); if (!containsMovieFiles) { return(true); } } catch (ArgumentException a) { LOGGER.Warn($"Could not determine whether {folderName} can be removed as we got as ArgumentException {a.Message}"); } catch (FileReadOnlyException) { LOGGER.Warn($"Could not find {folderName} as we got a FileReadOnlyException"); } catch (DirectoryReadOnlyException) { LOGGER.Warn($"Could not find {folderName} as we got a DirectoryReadOnlyException"); } catch (UnauthorizedAccessException) { LOGGER.Warn($"Could not find {folderName} as we got a UnauthorizedAccessException"); } catch (System.IO.PathTooLongException) { LOGGER.Warn($"Could not find {folderName} as we got a PathTooLongException"); } catch (System.IO.DirectoryNotFoundException) { LOGGER.Info($"Could not find {folderName} as we got a DirectoryNotFoundException"); } catch (DirectoryNotEmptyException) { LOGGER.Warn($"Could not find {folderName} as we got a DirectoryNotEmptyException"); } catch (OperationCanceledException) { LOGGER.Info($"Could not find {folderName} as we got a OperationCanceledException"); } catch (System.IO.IOException i) { LOGGER.Warn($"Could not find {folderName} as we got a OperationCanceledException: {i.Message}"); } return(false); }
private static void UpdateFromRepo() { Console.WriteLine(); Log.Information("Checking for updated maps at {Url}...", "https://github.com/EricZimmerman/evtx/tree/master/evtx/Maps"); Console.WriteLine(); var archivePath = Path.Combine(BaseDirectory, "____master.zip"); if (File.Exists(archivePath)) { File.Delete(archivePath); } // using (var client = new WebClient()) // { // ServicePointManager.Expect100Continue = true; // ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // client.DownloadFile("https://github.com/EricZimmerman/evtx/archive/master.zip", archivePath); // } "https://github.com/EricZimmerman/evtx/archive/master.zip".DownloadFileTo(archivePath); var fff = new FastZip(); if (Directory.Exists(Path.Combine(BaseDirectory, "Maps")) == false) { Directory.CreateDirectory(Path.Combine(BaseDirectory, "Maps")); } var directoryFilter = "Maps"; // Will prompt to overwrite if target file names already exist fff.ExtractZip(archivePath, BaseDirectory, FastZip.Overwrite.Always, null, null, directoryFilter, true); if (File.Exists(archivePath)) { File.Delete(archivePath); } var newMapPath = Path.Combine(BaseDirectory, "evtx-master", "evtx", "Maps"); var orgMapPath = Path.Combine(BaseDirectory, "Maps"); var newMaps = Directory.GetFiles(newMapPath); var newLocalMaps = new List <string>(); var updatedLocalMaps = new List <string>(); if (File.Exists(Path.Combine(orgMapPath, "Security_4624.map"))) { Log.Warning("Old map format found. Zipping to {Old} and cleaning up old maps", "!!oldMaps.zip"); //old maps found, so zip em first var oldZip = Path.Combine(orgMapPath, "!!oldMaps.zip"); fff.CreateZip(oldZip, orgMapPath, false, @"\.map$"); foreach (var m in Directory.GetFiles(orgMapPath, "*.map")) { File.Delete(m); } } if (File.Exists(Path.Combine(orgMapPath, "!!!!README.txt"))) { File.Delete(Path.Combine(orgMapPath, "!!!!README.txt")); } foreach (var newMap in newMaps) { var mName = Path.GetFileName(newMap); var dest = Path.Combine(orgMapPath, mName); if (File.Exists(dest) == false) { //new target newLocalMaps.Add(mName); } else { //current destination file exists, so compare to new var s1 = new StreamReader(newMap); var newSha = Helper.GetSha1FromStream(s1.BaseStream, 0); var s2 = new StreamReader(dest); var destSha = Helper.GetSha1FromStream(s2.BaseStream, 0); s2.Close(); s1.Close(); if (newSha != destSha) { //updated file updatedLocalMaps.Add(mName); } } #if !NET6_0 File.Copy(newMap, dest, CopyOptions.None); #else File.Copy(newMap, dest, true); #endif } if (newLocalMaps.Count > 0 || updatedLocalMaps.Count > 0) { Log.Information("Updates found!"); Console.WriteLine(); if (newLocalMaps.Count > 0) { Log.Information("New maps"); foreach (var newLocalMap in newLocalMaps) { Log.Information("{File}", Path.GetFileNameWithoutExtension(newLocalMap)); } Console.WriteLine(); } if (updatedLocalMaps.Count > 0) { Log.Information("Updated maps"); foreach (var um in updatedLocalMaps) { Log.Information("{File}", Path.GetFileNameWithoutExtension(um)); } Console.WriteLine(); } Console.WriteLine(); } else { Console.WriteLine(); Log.Information("No new maps available"); Console.WriteLine(); } Directory.Delete(Path.Combine(BaseDirectory, "evtx-master"), true); }
static void Main(string[] args) { Exceptionless.ExceptionlessClient.Default.Startup("fTcEOUkt1CxljTyOZfsr8AcSGQwWE4aYaYqk7cE1"); SetupNLog(); _logger = LogManager.GetCurrentClassLogger(); _fluentCommandLineParser = new FluentCommandLineParser <ApplicationArguments> { IsCaseSensitive = false }; _fluentCommandLineParser.Setup(arg => arg.Directory) .As('d') .WithDescription( "Directory to look for hives (recursively). -f or -d is required."); _fluentCommandLineParser.Setup(arg => arg.HiveFile) .As('f') .WithDescription("Hive to process. -f or -d is required.\r\n"); _fluentCommandLineParser.Setup(arg => arg.OutDirectory) .As("out") .WithDescription( "Directory to save updated hives to. Only dirty hives with logs applied will end up in --out directory\r\n"); _fluentCommandLineParser.Setup(arg => arg.CopyAlways) .As("ca") .WithDescription( "When true, always copy hives to --out directory, even if they aren't dirty. Default is TRUE").SetDefault(true); _fluentCommandLineParser.Setup(arg => arg.CompressNames) .As("cn") .WithDescription( "When true, compress names for profile based hives. Default is TRUE\r\n").SetDefault(true); _fluentCommandLineParser.Setup(arg => arg.Debug) .As("debug") .WithDescription("Show debug information during processing").SetDefault(false); _fluentCommandLineParser.Setup(arg => arg.Trace) .As("trace") .WithDescription("Show trace information during processing").SetDefault(false); var header = $"rla version {Assembly.GetExecutingAssembly().GetName().Version}" + "\r\n\r\nAuthor: Eric Zimmerman ([email protected])" + "\r\nhttps://github.com/EricZimmerman/RECmd\r\n\r\nNote: Enclose all strings containing spaces (and all RegEx) with double quotes"; var footer = @"Example: rla.exe --f ""C:\Temp\UsrClass 1.dat"" --out C:\temp" + "\r\n\t " + @"rla.exe --d ""D:\temp\"" --out c:\temp" + "\r\n"; _fluentCommandLineParser.SetupHelp("?", "help").WithHeader(header) .Callback(text => _logger.Info(text + "\r\n" + footer)); var result = _fluentCommandLineParser.Parse(args); if (_fluentCommandLineParser.Object.HiveFile.IsNullOrEmpty() == false || _fluentCommandLineParser.Object.Directory.IsNullOrEmpty() == false) { if (_fluentCommandLineParser.Object.OutDirectory.IsNullOrEmpty()) { _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options); Console.WriteLine(); _logger.Warn($"--out is required. Exiting"); Console.WriteLine(); return; } } if (_fluentCommandLineParser.Object.Debug) { foreach (var r in LogManager.Configuration.LoggingRules) { r.EnableLoggingForLevel(LogLevel.Debug); } LogManager.ReconfigExistingLoggers(); _logger.Debug("Enabled debug messages..."); } if (_fluentCommandLineParser.Object.Trace) { foreach (var r in LogManager.Configuration.LoggingRules) { r.EnableLoggingForLevel(LogLevel.Trace); } LogManager.ReconfigExistingLoggers(); _logger.Trace("Enabled trace messages..."); } if (result.HelpCalled) { return; } if (result.HasErrors) { _logger.Error(""); _logger.Error(result.ErrorText); _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options); return; } var hivesToProcess = new List <string>(); _logger.Info(header); _logger.Info(""); _logger.Info($"Command line: {string.Join(" ", Environment.GetCommandLineArgs().Skip(1))}\r\n"); if (_fluentCommandLineParser.Object.HiveFile?.Length > 0) { if (File.Exists(_fluentCommandLineParser.Object.HiveFile) == false) { _logger.Error($"File '{_fluentCommandLineParser.Object.HiveFile}' does not exist."); return; } hivesToProcess.Add(_fluentCommandLineParser.Object.HiveFile); } else if (_fluentCommandLineParser.Object.Directory?.Length > 0) { if (Directory.Exists(_fluentCommandLineParser.Object.Directory) == false) { _logger.Error($"Directory '{_fluentCommandLineParser.Object.Directory}' does not exist."); return; } var okFileParts = new HashSet <string>(); okFileParts.Add("USRCLASS"); okFileParts.Add("NTUSER"); okFileParts.Add("SYSTEM"); okFileParts.Add("SAM"); okFileParts.Add("SOFTWARE"); okFileParts.Add("AMCACHE"); okFileParts.Add("SYSCACHE"); okFileParts.Add("SECURITY"); okFileParts.Add("DRIVERS"); okFileParts.Add("COMPONENTS"); var f = new DirectoryEnumerationFilters(); f.InclusionFilter = fsei => { if (fsei.Extension.ToUpperInvariant() == ".LOG1" || fsei.Extension.ToUpperInvariant() == ".LOG2" || fsei.Extension.ToUpperInvariant() == ".DLL" || fsei.Extension.ToUpperInvariant() == ".LOG" || fsei.Extension.ToUpperInvariant() == ".CSV" || fsei.Extension.ToUpperInvariant() == ".BLF" || fsei.Extension.ToUpperInvariant() == ".REGTRANS-MS" || fsei.Extension.ToUpperInvariant() == ".EXE" || fsei.Extension.ToUpperInvariant() == ".TXT" || fsei.Extension.ToUpperInvariant() == ".INI") { return(false); } var foundOkFilePart = false; foreach (var okFilePart in okFileParts) { if (fsei.FileName.ToUpperInvariant().Contains(okFilePart)) { foundOkFilePart = true; // return true; } } if (foundOkFilePart == false) { return(false); } var fi = new FileInfo(fsei.FullPath); if (fi.Length < 4) { return(false); } try { using (var fs = new FileStream(fsei.FullPath, FileMode.Open, FileAccess.Read)) { using (var br = new BinaryReader(fs, new ASCIIEncoding())) { try { var chunk = br.ReadBytes(4); var sig = BitConverter.ToInt32(chunk, 0); if (sig == 0x66676572) { return(true); } } catch (Exception) { } return(false); } } } catch (IOException) { if (Helper.IsAdministrator() == false) { throw new UnauthorizedAccessException("Administrator privileges not found!"); } var files = new List <string>(); files.Add(fsei.FullPath); var rawf = Helper.GetFiles(files); if (rawf.First().FileStream.Length == 0) { return(false); } try { var b = new byte[4]; rawf.First().FileStream.ReadExactly(b, 4); var sig = BitConverter.ToInt32(b, 0); if (sig == 0x66676572) { return(true); } } catch (Exception) { } return(false); } }; f.RecursionFilter = entryInfo => !entryInfo.IsMountPoint && !entryInfo.IsSymbolicLink; f.ErrorFilter = (errorCode, errorMessage, pathProcessed) => true; var dirEnumOptions = DirectoryEnumerationOptions.Files | DirectoryEnumerationOptions.Recursive | DirectoryEnumerationOptions.SkipReparsePoints | DirectoryEnumerationOptions.ContinueOnException | DirectoryEnumerationOptions.BasicSearch; if (Directory.Exists(_fluentCommandLineParser.Object.OutDirectory) == false) { _logger.Info($"Creating --out directory '{_fluentCommandLineParser.Object.OutDirectory}'..."); Directory.CreateDirectory(_fluentCommandLineParser.Object.OutDirectory); } else { if (Directory.GetFiles(_fluentCommandLineParser.Object.OutDirectory).Length > 0 && _fluentCommandLineParser.Object.CompressNames) { _logger.Warn($"'{_fluentCommandLineParser.Object.OutDirectory}' contains files! This may cause --cn to revert back to uncompressed names. Ideally, '{_fluentCommandLineParser.Object.OutDirectory}' should be empty."); Console.WriteLine(); } } _logger.Fatal($"Searching '{_fluentCommandLineParser.Object.Directory}' for hives..."); var files2 = Directory.EnumerateFileSystemEntries(_fluentCommandLineParser.Object.Directory, dirEnumOptions, f); var count = 0; try { hivesToProcess.AddRange(files2); count = hivesToProcess.Count; _logger.Info($"\tHives found: {count:N0}"); } catch (Exception ex) { _logger.Fatal($"Could not access all files in '{_fluentCommandLineParser.Object.Directory}'! Error: {ex.Message}"); _logger.Error(""); _logger.Fatal("Rerun the program with Administrator privileges to try again\r\n"); //Environment.Exit(-1); } } else { _fluentCommandLineParser.HelpOption.ShowHelp(_fluentCommandLineParser.Options); return; } if (hivesToProcess.Count == 0) { _logger.Warn("No hives were found. Exiting..."); return; } _sw = new Stopwatch(); _sw.Start(); foreach (var hiveToProcess in hivesToProcess) { _logger.Info(""); byte[] updatedBytes = null; _logger.Info($"Processing hive '{hiveToProcess}'"); if (File.Exists(hiveToProcess) == false) { _logger.Warn($"'{hiveToProcess}' does not exist. Skipping"); continue; } try { RegistryHive reg; var dirname = Path.GetDirectoryName(hiveToProcess); var hiveBase = Path.GetFileName(hiveToProcess); List <RawCopyReturn> rawFiles = null; try { using (var fs = new FileStream(hiveToProcess, FileMode.Open, FileAccess.Read)) { reg = new RegistryHive(fs.ReadFully(), hiveToProcess) { }; } } catch (IOException) { //file is in use if (Helper.IsAdministrator() == false) { throw new UnauthorizedAccessException("Administrator privileges not found!"); } _logger.Warn($"\t'{hiveToProcess}' is in use. Rerouting...\r\n"); var files = new List <string>(); files.Add(hiveToProcess); var logFiles = Directory.GetFiles(dirname, $"{hiveBase}.LOG?"); foreach (var logFile in logFiles) { files.Add(logFile); } rawFiles = Helper.GetFiles(files); if (rawFiles.First().FileStream.Length == 0) { continue; } var bb = rawFiles.First().FileStream.ReadFully(); reg = new RegistryHive(bb, rawFiles.First().InputFilename); } if (reg.Header.PrimarySequenceNumber != reg.Header.SecondarySequenceNumber) { if (string.IsNullOrEmpty(dirname)) { dirname = "."; } var logFiles = Directory.GetFiles(dirname, $"{hiveBase}.LOG?"); if (logFiles.Length == 0) { if (_fluentCommandLineParser.Object.CopyAlways) { _logger.Info($"\tHive '{hiveToProcess}' is dirty, but no logs were found in the same directory. --ca is true. Copying..."); updatedBytes = File.ReadAllBytes(hiveToProcess); } else { _logger.Info($"\tHive '{hiveToProcess}' is dirty and no transaction logs were found in the same directory. --ca is false. Skipping..."); continue; } } if (updatedBytes == null) { if (rawFiles != null) { var lt = new List <TransactionLogFileInfo>(); foreach (var rawCopyReturn in rawFiles.Skip(1).ToList()) { var bb1 = rawCopyReturn.FileStream.ReadFully(); var tt = new TransactionLogFileInfo(rawCopyReturn.InputFilename, bb1); lt.Add(tt); } updatedBytes = reg.ProcessTransactionLogs(lt); } else { updatedBytes = reg.ProcessTransactionLogs(logFiles.ToList()); } } } if (updatedBytes == null) { if (_fluentCommandLineParser.Object.CopyAlways) { _logger.Info($"\tHive '{hiveToProcess}' is not dirty, but --ca is true. Copying..."); updatedBytes = File.ReadAllBytes(hiveToProcess); } else { _logger.Info($"\tHive '{hiveToProcess}' is not dirty and --ca is false. Skipping..."); continue; } } var outFile = hiveToProcess.Replace(":", "").Replace("\\", "_"); var outFileAll = Path.Combine(_fluentCommandLineParser.Object.OutDirectory, outFile); if (_fluentCommandLineParser.Object.CompressNames && (outFileAll.ToUpperInvariant().Contains("NTUSER") || outFileAll.ToUpperInvariant().Contains("USRCLASS"))) { var dl = hiveToProcess[0].ToString(); var segs = hiveToProcess.SplitAndTrim('\\'); var profile = segs[2]; var filename = Path.GetFileName(hiveToProcess); var outFile2 = $"{dl}_{profile}_{filename}"; outFileAll = Path.Combine(_fluentCommandLineParser.Object.OutDirectory, outFile2); } if (File.Exists(outFileAll)) { var oldOut = outFileAll; outFileAll = Path.Combine(_fluentCommandLineParser.Object.OutDirectory, outFile); _logger.Warn($"\tFile '{oldOut}' exists! Saving as non-compressed name: '{outFileAll}'"); } _logger.Fatal($"\tSaving updated hive to '{outFileAll}'"); using (var fs = new FileStream(outFileAll, FileMode.Create)) { fs.Write(updatedBytes, 0, updatedBytes.Length); fs.Flush(); fs.Close(); } } catch (Exception ex) { if (ex.Message.Contains("Sequence numbers do not match and transaction") == false) { if (ex.Message.Contains("Administrator privileges not found")) { _logger.Fatal($"Could not access '{hiveToProcess}' because it is in use"); _logger.Error(""); _logger.Fatal("Rerun the program with Administrator privileges to try again\r\n"); } else { _logger.Error($"There was an error: {ex.Message}"); } } } } _sw.Stop(); _logger.Info(""); _logger.Info($"Total processing time: {_sw.Elapsed.TotalSeconds:N3} seconds"); _logger.Info(""); }