public void ShouldExportHiveWithRootValues() { var samRootValue = new RegistryHive(@"..\..\..\Hives\SAM_RootValue"); samRootValue.FlushRecordListsAfterParse = false; samRootValue.ParseHive(); samRootValue.ExportDataToCommonFormat(@"SamRootValueNoDeletedStuff.txt", false); }
public void ShouldExportFileAllRecords() { var usrclassDeleted = new RegistryHive(@"..\..\..\Hives\UsrClassDeletedBags.dat"); usrclassDeleted.RecoverDeleted = true; usrclassDeleted.FlushRecordListsAfterParse = false; usrclassDeleted.ParseHive(); usrclassDeleted.ExportDataToCommonFormat(@"UsrclassDeletedNoDeletedStuff.txt", false); Check.That(usrclassDeleted.Header.Length).IsEqualTo(usrclassDeleted.HBinRecordTotalSize); }
public void ExportUsrClassToCommonFormatWithDeleted() { var UsrclassDeleted = new RegistryHive(@"..\..\Hives\UsrClassDeletedBags.dat"); UsrclassDeleted.RecoverDeleted = true; UsrclassDeleted.FlushRecordListsAfterParse = false; UsrclassDeleted.ParseHive(); UsrclassDeleted.ExportDataToCommonFormat("UsrClassDeletedExport.txt", true); UsrclassDeleted = new RegistryHive(@"..\..\Hives\UsrClassDeletedBags.dat"); UsrclassDeleted.FlushRecordListsAfterParse = true; UsrclassDeleted.ParseHive(); UsrclassDeleted.ExportDataToCommonFormat("UsrClassDeletedWithFlushExport.txt", true); }
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.HasValidateCheckSum() == false) { logger.Warn("CheckSum mismatch!"); } if (registryHive.Header.PrimarySequenceNumber != registryHive.Header.SecondarySequenceNumber) { 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.HasValidateCheckSum()}")); sb.AppendLine(string.Format($"Header sequence 1: {registryHive.Header.PrimarySequenceNumber}, Header sequence 2: {registryHive.Header.SecondarySequenceNumber}")); 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(); } } }
public void ExportUsrClassToCommonFormatWithDeleted() { var UsrclassDeleted = new RegistryHive(@"..\..\Hives\UsrClassDeletedBags.dat"); UsrclassDeleted.RecoverDeleted = true; UsrclassDeleted.FlushRecordListsAfterParse = false; UsrclassDeleted.ParseHive(); UsrclassDeleted.ExportDataToCommonFormat("UsrClassDeletedExport.txt", true); UsrclassDeleted = new RegistryHive(@"..\..\Hives\UsrClassDeletedBags.dat"); UsrclassDeleted.FlushRecordListsAfterParse = true; UsrclassDeleted.ParseHive(); UsrclassDeleted.ExportDataToCommonFormat("UsrClassDeletedWithFlushExport.txt", true); }
private static void ProcessFile(string arg) { FileInfo fi = new FileInfo(arg); if (fi.Length < 4 || !IsRegistryFile(arg)) { return; } byte[] raw = File.ReadAllBytes(arg); RegistryHive reg = new RegistryHive(raw, arg) { RecoverDeleted = true, FlushRecordListsAfterParse = false }; string name; using (FileStream fs = new FileStream(arg, FileMode.Open, FileAccess.Read)) { name = Hashes.CalculateMD5FromStream(fs); } string path = $"regdrop/{name}"; Directory.CreateDirectory(path); File.WriteAllText($"{path}/info.txt", reg.Header.ToString()); if (!reg.Header.ValidateCheckSum()) { Console.Error.WriteLine("Checksum validation error. Exiting."); return; } if (reg.Header.PrimarySequenceNumber != reg.Header.SecondarySequenceNumber) { string filePath = Path.GetDirectoryName(arg); string fileName = Path.GetFileNameWithoutExtension(arg); var logFiles = Directory.GetFiles(filePath, $"{fileName}.LOG?"); if (logFiles.Length == 0) { Console.Error.WriteLine($"[{arg}] Transaction logs missing. Exiting."); return; } else { reg.ProcessTransactionLogs(logFiles.ToList(), true); } } reg.ParseHive(); string dumpFilePathTmp = $"{path}/dump.tmp"; reg.ExportDataToCommonFormat(dumpFilePathTmp, false); string dumpFilePathCsv = $"{path}/dump.csv"; string dumpFilePathJson = $"{path}/dump.json"; using (DataTable dt = new DataTable()) { dt.Columns.Add("type", typeof(string)); dt.Columns.Add("active", typeof(string)); dt.Columns.Add("offset", typeof(decimal)); dt.Columns.Add("path", typeof(string)); dt.Columns.Add("name", typeof(string)); dt.Columns.Add("dataType", typeof(decimal)); dt.Columns.Add("value", typeof(string)); dt.Columns.Add("lastWriteTime", typeof(string)); using (var fs = new FileStream(dumpFilePathTmp, FileMode.Open, FileAccess.Read, FileShare.Read)) { dt.FromCsv(fs, false); } DataColumn type = dt.Columns["type"]; foreach (var dr in dt.Rows .OfType <DataRow>() .Where(x => (string)x[type] == "value")) { DataColumn dataType = dt.Columns["dataType"]; DataColumn value = dt.Columns["value"]; byte[] data = ConvertToBytes((string)dr[value]); decimal dataTypeVal = (decimal)dr[dataType]; if (dataTypeVal == 0x2) { string txt = Encoding.Unicode.GetString(data).TrimEnd('\0'); dr[value] = txt; } else if (dataTypeVal == 0x4 && data.Length == 4) { int val = BitConverter.ToInt32(data); dr[value] = val.ToString(); } else if (dataTypeVal == 0x5 && data.Length == 4) { int val = BitConverter.ToInt32(data.Reverse().ToArray()); dr[value] = val.ToString(); } else if (dataTypeVal == 0x7) { string txtlist = Encoding.Unicode.GetString(data).TrimEnd('\0'); string[] split = txtlist.Split('\0', StringSplitOptions.RemoveEmptyEntries); dr[value] = string.Join("\n", split); } else if (dataTypeVal == 0xb && data.Length == 8) { long val = BitConverter.ToInt64(data); dr[value] = val.ToString(); } else { dr[value] = Convert.ToBase64String(data); } } using (var fs = new FileStream(dumpFilePathCsv, FileMode.Create, FileAccess.Write, FileShare.Read)) { dt.ToCsv(fs); } JsonDocument jdoc; dt.ToJson(out jdoc); using (var fs = new FileStream(dumpFilePathJson, FileMode.Create, FileAccess.Write, FileShare.Read)) { Utf8JsonWriter writer = new Utf8JsonWriter(fs); jdoc.WriteTo(writer); writer.Flush(); } } if (File.Exists(dumpFilePathTmp)) { File.Delete(dumpFilePathTmp); } }