Example #1
0
        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);
            }
        }
Example #2
0
    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);
        }
    }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
    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);
    }
Example #6
0
        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("");
        }