private static void Main(string[] args) { var testFiles = new List<string>(); var result = Parser.Default.ParseArguments<Options>(args); if (!result.Errors.Any()) { if (result.Value.HiveName == null && result.Value.DirectoryName == null) { Console.WriteLine(result.Value.GetUsage()); Environment.Exit(1); } if (!string.IsNullOrEmpty(result.Value.HiveName)) { if (!string.IsNullOrEmpty(result.Value.DirectoryName)) { Console.WriteLine("Must specify either -d or -f, but not both"); Environment.Exit(1); } } if (!string.IsNullOrEmpty(result.Value.DirectoryName)) { if (!string.IsNullOrEmpty(result.Value.HiveName)) { Console.WriteLine("Must specify either -d or -f, but not both"); Environment.Exit(1); } } if (!string.IsNullOrEmpty(result.Value.HiveName)) { testFiles.Add(result.Value.HiveName); } else { if (Directory.Exists(result.Value.DirectoryName)) { foreach (var file in Directory.GetFiles(result.Value.DirectoryName)) { testFiles.Add(file); } } else { Console.WriteLine("Directory '{0}' does not exist!", result.Value.DirectoryName); Environment.Exit(1); } } } else { Console.WriteLine(result.Value.GetUsage()); Environment.Exit(1); } var verboseLevel = result.Value.VerboseLevel; if (verboseLevel < 0) { verboseLevel = 0; } if (verboseLevel > 2) { verboseLevel = 2; } var config = GetNlogConfig(verboseLevel, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); LogManager.Configuration = config; var logger = LogManager.GetCurrentClassLogger(); foreach (var testFile in testFiles) { if (File.Exists(testFile) == false) { logger.Error("'{0}' does not exist!", testFile); continue; } logger.Info("Processing '{0}'", testFile); Console.Title = $"Processing '{testFile}'"; var sw = new Stopwatch(); try { var registryHive = new RegistryHive(testFile); if (registryHive.Header.ValidateCheckSum() == false) { logger.Warn("CheckSum mismatch!"); } if (registryHive.Header.Sequence1 != registryHive.Header.Sequence2) { logger.Warn("Sequence mismatch!"); } sw.Start(); registryHive.RecoverDeleted = result.Value.RecoverDeleted; registryHive.FlushRecordListsAfterParse = !result.Value.DontFlushLists; registryHive.ParseHive(); logger.Info("Finished processing '{0}'", testFile); Console.Title = $"Finished processing '{testFile}'"; sw.Stop(); var freeCells = registryHive.CellRecords.Where(t => t.Value.IsFree); var referencedCells = registryHive.CellRecords.Where(t => t.Value.IsReferenced); var nkFree = freeCells.Count(t => t.Value is NKCellRecord); var vkFree = freeCells.Count(t => t.Value is VKCellRecord); var skFree = freeCells.Count(t => t.Value is SKCellRecord); var lkFree = freeCells.Count(t => t.Value is LKCellRecord); var freeLists = registryHive.ListRecords.Where(t => t.Value.IsFree); var referencedList = registryHive.ListRecords.Where(t => t.Value.IsReferenced); var goofyCellsShouldBeUsed = registryHive.CellRecords.Where(t => t.Value.IsFree == false && t.Value.IsReferenced == false); var goofyListsShouldBeUsed = registryHive.ListRecords.Where(t => t.Value.IsFree == false && t.Value.IsReferenced == false); var sb = new StringBuilder(); sb.AppendLine("Results:"); sb.AppendLine(); sb.AppendLine( $"Found {registryHive.HBinRecordCount:N0} hbin records. Total size of seen hbin records: 0x{registryHive.HBinRecordTotalSize:X}, Header hive size: 0x{registryHive.Header.Length:X}"); if (registryHive.FlushRecordListsAfterParse == false) { sb.AppendLine( $"Found {registryHive.CellRecords.Count:N0} Cell records (nk: {registryHive.CellRecords.Count(w => w.Value is NKCellRecord):N0}, vk: {registryHive.CellRecords.Count(w => w.Value is VKCellRecord):N0}, sk: {registryHive.CellRecords.Count(w => w.Value is SKCellRecord):N0}, lk: {registryHive.CellRecords.Count(w => w.Value is LKCellRecord):N0})"); sb.AppendLine($"Found {registryHive.ListRecords.Count:N0} List records"); sb.AppendLine(); sb.AppendLine(string.Format($"Header CheckSums match: {registryHive.Header.ValidateCheckSum()}")); sb.AppendLine(string.Format($"Header sequence 1: {registryHive.Header.Sequence1}, Header sequence 2: {registryHive.Header.Sequence2}")); sb.AppendLine(); sb.AppendLine( $"There are {referencedCells.Count():N0} cell records marked as being referenced ({referencedCells.Count()/(double) registryHive.CellRecords.Count:P})"); sb.AppendLine( $"There are {referencedList.Count():N0} list records marked as being referenced ({referencedList.Count()/(double) registryHive.ListRecords.Count:P})"); if (result.Value.RecoverDeleted) { sb.AppendLine(); sb.AppendLine("Free record info"); sb.AppendLine( $"{freeCells.Count():N0} free Cell records (nk: {nkFree:N0}, vk: {vkFree:N0}, sk: {skFree:N0}, lk: {lkFree:N0})"); sb.AppendLine($"{freeLists.Count():N0} free List records"); } sb.AppendLine(); sb.AppendLine( $"Cells: Free + referenced + marked as in use but not referenced == Total? {registryHive.CellRecords.Count == freeCells.Count() + referencedCells.Count() + goofyCellsShouldBeUsed.Count()}"); sb.AppendLine( $"Lists: Free + referenced + marked as in use but not referenced == Total? {registryHive.ListRecords.Count == freeLists.Count() + referencedList.Count() + goofyListsShouldBeUsed.Count()}"); } sb.AppendLine(); sb.AppendLine( $"There were {registryHive.HardParsingErrors:N0} hard parsing errors (a record marked 'in use' that didn't parse correctly.)"); sb.AppendLine( $"There were {registryHive.SoftParsingErrors:N0} soft parsing errors (a record marked 'free' that didn't parse correctly.)"); logger.Info(sb.ToString()); // foreach (var cellTemplate in fName1Test.ListRecords) // { // Console.WriteLine(cellTemplate.ToString()); // } if (result.Value.ExportHiveData) { Console.WriteLine(); var baseDir = Path.Combine(Path.GetDirectoryName(testFile), "out"); if (Directory.Exists(baseDir) == false) { Directory.CreateDirectory(baseDir); } var baseFname = Path.GetFileName(testFile); var myName = string.Empty; var deletedOnly = result.Value.ExportDeletedOnly; if (deletedOnly) { myName = "_EricZ_recovered.txt"; } else { myName = "_EricZ_all.txt"; } var outfile = Path.Combine(baseDir, $"{baseFname}{myName}"); logger.Info("Exporting hive data to '{0}'", outfile); registryHive.ExportDataToCommonFormat(outfile, deletedOnly); } } catch (Exception ex) { Console.WriteLine("There was an error: {0}", ex.Message); } logger.Info("Processing took {0:N4} seconds\r\n", sw.Elapsed.TotalSeconds); Console.WriteLine(); Console.WriteLine(); if (result.Value.PauseAfterEachFile) { Console.WriteLine("Press any key to continue to next file"); Console.ReadKey(); Console.WriteLine(); Console.WriteLine(); } } }