Пример #1
0
        public bool GetNotAvFiles(out List <DbFile> entries)
        {
            entries = new List <DbFile>();

            const string SQL = "SELECT * FROM files WHERE hasvirus IS NULL ORDER BY sha256";

            IDbCommand     dbcmd       = dbCon.CreateCommand();
            IDbDataAdapter dataAdapter = dbCore.GetNewDataAdapter();

            dbcmd.CommandText = SQL;
            var dataSet = new DataSet();

            dataAdapter.SelectCommand = dbcmd;
            dataAdapter.Fill(dataSet);
            DataTable dataTable = dataSet.Tables[0];

            foreach (DataRow dRow in dataTable.Rows)
            {
                var fEntry = new DbFile
                {
                    Id     = ulong.Parse(dRow["id"].ToString()),
                    Sha256 = dRow["sha256"].ToString(),
                    Crack  = bool.Parse(dRow["crack"].ToString()),
                    Virus  = dRow["virus"].ToString(),
                    Length = long.Parse(dRow["length"].ToString())
                };

                if (dRow["hasvirus"] == DBNull.Value)
                {
                    fEntry.HasVirus = null;
                }
                else
                {
                    fEntry.HasVirus = bool.Parse(dRow["hasvirus"].ToString());
                }

                if (dRow["clamtime"] == DBNull.Value)
                {
                    fEntry.ClamTime = null;
                }
                else
                {
                    fEntry.ClamTime = DateTime.Parse(dRow["clamtime"].ToString());
                }

                if (dRow["vtotaltime"] == DBNull.Value)
                {
                    fEntry.VirusTotalTime = null;
                }
                else
                {
                    fEntry.VirusTotalTime = DateTime.Parse(dRow["vtotaltime"].ToString());
                }

                entries.Add(fEntry);
            }

            return(true);
        }
Пример #2
0
        public DbFile GetFile(string hash)
        {
            string sql = $"SELECT * FROM files WHERE sha256 = '{hash}'";

            IDbCommand     dbcmd       = dbCon.CreateCommand();
            IDbDataAdapter dataAdapter = dbCore.GetNewDataAdapter();

            dbcmd.CommandText = sql;
            var dataSet = new DataSet();

            dataAdapter.SelectCommand = dbcmd;
            dataAdapter.Fill(dataSet);
            DataTable dataTable = dataSet.Tables[0];

            foreach (DataRow dRow in dataTable.Rows)
            {
                var fEntry = new DbFile
                {
                    Id     = ulong.Parse(dRow["id"].ToString()),
                    Sha256 = dRow["sha256"].ToString(),
                    Crack  = bool.Parse(dRow["crack"].ToString()),
                    Virus  = dRow["virus"].ToString(),
                    Length = long.Parse(dRow["length"].ToString())
                };

                if (dRow["hasvirus"] == DBNull.Value)
                {
                    fEntry.HasVirus = null;
                }
                else
                {
                    fEntry.HasVirus = bool.Parse(dRow["hasvirus"].ToString());
                }

                if (dRow["clamtime"] == DBNull.Value)
                {
                    fEntry.ClamTime = null;
                }
                else
                {
                    fEntry.ClamTime = DateTime.Parse(dRow["clamtime"].ToString());
                }

                if (dRow["vtotaltime"] == DBNull.Value)
                {
                    fEntry.VirusTotalTime = null;
                }
                else
                {
                    fEntry.VirusTotalTime = DateTime.Parse(dRow["vtotaltime"].ToString());
                }

                return(fEntry);
            }

            return(null);
        }
Пример #3
0
        IDbCommand GetFileCommand(DbFile entry)
        {
            IDbCommand dbcmd = dbCon.CreateCommand();

            IDbDataParameter param1 = dbcmd.CreateParameter();
            IDbDataParameter param2 = dbcmd.CreateParameter();
            IDbDataParameter param3 = dbcmd.CreateParameter();
            IDbDataParameter param4 = dbcmd.CreateParameter();
            IDbDataParameter param5 = dbcmd.CreateParameter();
            IDbDataParameter param6 = dbcmd.CreateParameter();
            IDbDataParameter param7 = dbcmd.CreateParameter();

            param1.ParameterName = "@sha256";
            param2.ParameterName = "@crack";
            param3.ParameterName = "@hasvirus";
            param4.ParameterName = "@clamtime";
            param5.ParameterName = "@vtotaltime";
            param6.ParameterName = "@virus";
            param7.ParameterName = "@length";

            param1.DbType = DbType.String;
            param2.DbType = DbType.Boolean;
            param3.DbType = DbType.String;
            param4.DbType = DbType.String;
            param5.DbType = DbType.String;
            param7.DbType = DbType.UInt64;

            param1.Value = entry.Sha256;
            param2.Value = entry.Crack;
            param3.Value = entry.HasVirus;
            param4.Value = entry.ClamTime?.ToString("yyyy-MM-dd HH:mm");
            param5.Value = entry.VirusTotalTime?.ToString("yyyy-MM-dd HH:mm");
            param6.Value = entry.Virus;
            param7.Value = entry.Length;

            dbcmd.Parameters.Add(param1);
            dbcmd.Parameters.Add(param2);
            dbcmd.Parameters.Add(param3);
            dbcmd.Parameters.Add(param4);
            dbcmd.Parameters.Add(param5);
            dbcmd.Parameters.Add(param6);
            dbcmd.Parameters.Add(param7);

            return(dbcmd);
        }
Пример #4
0
        public bool AddFile(DbFile file)
        {
            IDbCommand     dbcmd = GetFileCommand(file);
            IDbTransaction trans = dbCon.BeginTransaction();

            dbcmd.Transaction = trans;

            const string SQL =
                "INSERT INTO `files` (`sha256`, `crack`, `hasvirus`, `clamtime`, `vtotaltime`, `virus`, `length`)" +
                " VALUES (@sha256, @crack, @hasvirus, @clamtime, @vtotaltime, @virus, @length)";

            dbcmd.CommandText = SQL;

            dbcmd.ExecuteNonQuery();
            trans.Commit();
            dbcmd.Dispose();

            return(true);
        }
Пример #5
0
        public bool UpdateFile(DbFile file)
        {
            IDbCommand     dbcmd = GetFileCommand(file);
            IDbTransaction trans = dbCon.BeginTransaction();

            dbcmd.Transaction = trans;

            const string SQL =
                "UPDATE files SET crack = @crack, hasvirus = @hasvirus, clamtime = @clamtime, vtotaltime = @vtotaltime, virus = @virus, length = @length " +
                "WHERE sha256 = @sha256";

            dbcmd.CommandText = SQL;

            dbcmd.ExecuteNonQuery();
            trans.Commit();
            dbcmd.Dispose();

            return(true);
        }
Пример #6
0
        public static void VirusTotalFileFromRepo(DbFile file)
        {
            try
            {
                if (!Context.VirusTotalEnabled)
                {
                    Failed?.Invoke("VirusTotal is not usable");

                    return;
                }

                if (vTotal == null)
                {
                    Failed?.Invoke("VirusTotal is not initalized");
                }

                FileReport fResult = null;

                UpdateProgress?.Invoke("Requesting existing report to VirusTotal", null, 0, 0);

            #if DEBUG
                stopwatch.Restart();
            #endif
                Task.Run(async() =>
                {
                    fResult = await vTotal.GetFileReportAsync(file.Sha256);
                }).Wait();
            #if DEBUG
                stopwatch.Stop();

                Console.WriteLine("Core.VirusTotalFileFromRepo({0}): VirusTotal took {1} seconds to answer for SHA256 request",
                                  file, stopwatch.Elapsed.TotalSeconds);
            #endif

                if (fResult.ResponseCode == FileReportResponseCode.NotPresent)
                {
                    Failed?.Invoke(fResult.VerboseMsg);

                    return;
                }

                if (fResult.ResponseCode != FileReportResponseCode.Queued)
                {
                    if (fResult.ResponseCode == FileReportResponseCode.Present)
                    {
                        if (fResult.Positives > 0)
                        {
                            file.HasVirus = true;

                            if (fResult.Scans != null)
                            {
                                foreach (KeyValuePair <string, ScanEngine> engine in fResult.Scans)
                                {
                                    if (!engine.Value.Detected)
                                    {
                                        continue;
                                    }

                                    file.Virus          = engine.Value.Result;
                                    file.VirusTotalTime = engine.Value.Update;
                                    dbCore.DbOps.UpdateFile(file);

                                    ScanFinished?.Invoke(file);

                                    return;
                                }
                            }
                        }
                        else
                        {
                            // If no scan has been done, mark as false.
                            // If a positive has already existed don't overwrite it.
                            file.HasVirus       = false;
                            file.Virus          = null;
                            file.VirusTotalTime = DateTime.UtcNow;

                            dbCore.DbOps.UpdateFile(file);

                            ScanFinished?.Invoke(file);

                            return;
                        }
                    }

                    string   repoPath;
                    AlgoEnum algorithm;

                    if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                 file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                 file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                 file.Sha256 + ".gz")))
                    {
                        repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                file.Sha256 + ".gz");

                        algorithm = AlgoEnum.GZip;
                    }
                    else if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                      file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                      file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                      file.Sha256 + ".bz2")))
                    {
                        repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                file.Sha256 + ".bz2");

                        algorithm = AlgoEnum.BZip2;
                    }
                    else if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                      file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                      file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                      file.Sha256 + ".lzma")))
                    {
                        repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                file.Sha256 + ".lzma");

                        algorithm = AlgoEnum.LZMA;
                    }
                    else if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                      file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                      file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                      file.Sha256 + ".lz")))
                    {
                        repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                file.Sha256 + ".lz");

                        algorithm = AlgoEnum.LZip;
                    }
                    else
                    {
                        Failed?.Invoke($"Cannot find file with hash {file.Sha256} in the repository");

                        return;
                    }

                    UpdateProgress?.Invoke("Uncompressing file...", null, 0, 0);

                    var    inFs    = new FileStream(repoPath, FileMode.Open, FileAccess.Read);
                    Stream zStream = null;

                    switch (algorithm)
                    {
                    case AlgoEnum.GZip:
                        zStream = new GZipStream(inFs, CompressionMode.Decompress);

                        break;

                    case AlgoEnum.BZip2:
                        zStream = new BZip2Stream(inFs, CompressionMode.Decompress);

                        break;

                    case AlgoEnum.LZMA:
                        byte[] properties = new byte[5];
                        inFs.Read(properties, 0, 5);
                        inFs.Seek(8, SeekOrigin.Current);
                        zStream = new LzmaStream(properties, inFs, inFs.Length - 13, file.Length);

                        break;

                    case AlgoEnum.LZip:
                        zStream = new LZipStream(inFs, CompressionMode.Decompress);

                        break;
                    }

                    ScanResult sResult = null;

                #if DEBUG
                    stopwatch.Restart();
                #endif

                    // Cannot use zStream directly, VirusTotal.NET requests the size *sigh*
                    string tmpFile = Path.Combine(Settings.Current.TemporaryFolder, Path.GetTempFileName());
                    var    outFs   = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite);
                    zStream?.CopyTo(outFs);
                    zStream?.Close();
                    outFs.Seek(0, SeekOrigin.Begin);
                #if DEBUG
                    stopwatch.Stop();

                    Console.WriteLine("Core.VirusTotalFileFromRepo({0}): Uncompressing took {1} seconds", file,
                                      stopwatch.Elapsed.TotalSeconds);
                #endif

                    UpdateProgress?.Invoke("Uploading file to VirusTotal...", null, 0, 0);

                #if DEBUG
                    stopwatch.Restart();
                #endif
                    Task.Run(async() =>
                    {
                        sResult = await vTotal.ScanFileAsync(outFs, file.Sha256); // Keep filename private, sorry!
                    }).Wait();
                #if DEBUG
                    stopwatch.Stop();

                    Console.WriteLine("Core.VirusTotalFileFromRepo({0}): Upload to VirusTotal took {1} seconds", file,
                                      stopwatch.Elapsed.TotalSeconds);
                #endif
                    outFs.Close();

                    File.Delete(tmpFile);

                    if (sResult == null ||
                        sResult.ResponseCode == ScanFileResponseCode.Error)
                    {
                        if (sResult == null)
                        {
                            Failed?.Invoke("Cannot send file to VirusTotal");
                        }
                        else
                        {
                            Failed(sResult.VerboseMsg);
                        }

                        return;
                    }

                    // Seems that we are faster than them, getting a lot of "not queued" responses...
                    Thread.Sleep(2500);

                    Task.Run(async() =>
                    {
                        fResult = await vTotal.GetFileReportAsync(file.Sha256);
                    }).Wait();
                }

                UpdateProgress?.Invoke("Waiting for VirusTotal analysis...", null, 0, 0);

            #if DEBUG
                stopwatch.Restart();
            #endif
                int counter = 0;

                while (fResult.ResponseCode == FileReportResponseCode.Queued)
                {
                    // Timeout...
                    if (counter == 10)
                    {
                        break;
                    }

                    // Wait 15 seconds so we fall in the 4 requests/minute
                    Thread.Sleep(15000);

                    Task.Run(async() =>
                    {
                        fResult = await vTotal.GetFileReportAsync(file.Sha256);
                    }).Wait();

                    counter++;
                }
            #if DEBUG
                stopwatch.Stop();

                Console.WriteLine("Core.VirusTotalFileFromRepo({0}): VirusTotal took {1} seconds to do the analysis",
                                  file, stopwatch.Elapsed.TotalSeconds);
            #endif

                if (fResult.ResponseCode != FileReportResponseCode.Present)
                {
                    Failed?.Invoke(fResult.VerboseMsg);

                    return;
                }

                if (fResult.Positives > 0)
                {
                    file.HasVirus = true;

                    if (fResult.Scans == null)
                    {
                        return;
                    }

                    foreach (KeyValuePair <string, ScanEngine> engine in fResult.Scans)
                    {
                        if (!engine.Value.Detected)
                        {
                            continue;
                        }

                        file.Virus          = engine.Value.Result;
                        file.VirusTotalTime = engine.Value.Update;
                        dbCore.DbOps.UpdateFile(file);

                        ScanFinished?.Invoke(file);

                        return;
                    }
                }
                else
                {
                    // If no scan has been done, mark as false.
                    // If a positive has already existed don't overwrite it.
                    file.HasVirus       = false;
                    file.Virus          = null;
                    file.VirusTotalTime = DateTime.UtcNow;

                    dbCore.DbOps.UpdateFile(file);

                    ScanFinished?.Invoke(file);
                }
            }
            catch (Exception ex)
            {
                Failed?.Invoke($"Exception {ex.InnerException.Message} when calling VirusTotal");
            #if DEBUG
                Console.WriteLine("Exception {0}\n{1}", ex.Message, ex.InnerException);
            #endif
            }
        }
Пример #7
0
        public static void ClamScanFileFromRepo(DbFile file)
        {
            try
            {
                if (Context.ClamdVersion == null)
                {
                    Failed?.Invoke("clamd is not usable");

                    return;
                }

                if (clam == null)
                {
                    Failed?.Invoke("clamd is not initalized");
                }

                string   repoPath;
                AlgoEnum algorithm;

                if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                             file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                             file.Sha256[3].ToString(), file.Sha256[4].ToString(), file.Sha256 + ".gz")))
                {
                    repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                            file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                            file.Sha256[3].ToString(), file.Sha256[4].ToString(), file.Sha256 + ".gz");

                    algorithm = AlgoEnum.GZip;
                }
                else if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                  file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                  file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                  file.Sha256 + ".bz2")))
                {
                    repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                            file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                            file.Sha256[3].ToString(), file.Sha256[4].ToString(), file.Sha256 + ".bz2");

                    algorithm = AlgoEnum.BZip2;
                }
                else if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                  file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                  file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                  file.Sha256 + ".lzma")))
                {
                    repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                            file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                            file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                            file.Sha256 + ".lzma");

                    algorithm = AlgoEnum.LZMA;
                }
                else if (File.Exists(Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                                  file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                                  file.Sha256[3].ToString(), file.Sha256[4].ToString(),
                                                  file.Sha256 + ".lz")))
                {
                    repoPath = Path.Combine(Settings.Current.RepositoryPath, file.Sha256[0].ToString(),
                                            file.Sha256[1].ToString(), file.Sha256[2].ToString(),
                                            file.Sha256[3].ToString(), file.Sha256[4].ToString(), file.Sha256 + ".lz");

                    algorithm = AlgoEnum.LZip;
                }
                else
                {
                    Failed?.Invoke($"Cannot find file with hash {file.Sha256} in the repository");

                    return;
                }

                ClamScanResult result  = null;
                Stream         zStream = null;

                if (Settings.Current.ClamdIsLocal)
                {
                    if (algorithm == AlgoEnum.LZMA ||
                        algorithm == AlgoEnum.LZip)
                    {
                        string tmpFile = Path.Combine(Settings.Current.TemporaryFolder, Path.GetTempFileName());
                        var    outFs   = new FileStream(tmpFile, FileMode.Create, FileAccess.Write);
                        var    inFs    = new FileStream(repoPath, FileMode.Open, FileAccess.Read);

                        if (algorithm == AlgoEnum.LZMA)
                        {
                            byte[] properties = new byte[5];
                            inFs.Read(properties, 0, 5);
                            inFs.Seek(8, SeekOrigin.Current);
                            zStream = new LzmaStream(properties, inFs, inFs.Length - 13, file.Length);
                        }
                        else
                        {
                            zStream = new LZipStream(inFs, CompressionMode.Decompress);
                        }

                        UpdateProgress?.Invoke("Uncompressing file...", null, 0, 0);

                    #if DEBUG
                        stopwatch.Restart();
                    #endif
                        zStream.CopyTo(outFs);
                        zStream.Close();
                        outFs.Close();
                    #if DEBUG
                        stopwatch.Stop();

                        Console.WriteLine("Core.ClamScanFileFromRepo({0}): Uncompressing took {1} seconds", file,
                                          stopwatch.Elapsed.TotalSeconds);
                    #endif

                        UpdateProgress?.Invoke("Requesting local scan to clamd server...", null, 0, 0);

                    #if DEBUG
                        stopwatch.Restart();
                    #endif
                        Task.Run(async() =>
                        {
                            result = await clam.ScanFileOnServerMultithreadedAsync(tmpFile);
                        }).Wait();
                    #if DEBUG
                        stopwatch.Stop();

                        Console.WriteLine("Core.ClamScanFileFromRepo({0}): Clamd took {1} seconds to scan", file,
                                          stopwatch.Elapsed.TotalSeconds);
                    #endif

                        File.Delete(tmpFile);
                    }
                    else
                    {
                        UpdateProgress?.Invoke("Requesting local scan to clamd server...", null, 0, 0);

                    #if DEBUG
                        stopwatch.Restart();
                    #endif
                        Task.Run(async() =>
                        {
                            result = await clam.ScanFileOnServerMultithreadedAsync(repoPath);
                        }).Wait();
                    #if DEBUG
                        stopwatch.Stop();

                        Console.WriteLine("Core.ClamScanFileFromRepo({0}): Clamd took {1} seconds to scan", file,
                                          stopwatch.Elapsed.TotalSeconds);
                    #endif
                    }
                }
                else
                {
                    var inFs = new FileStream(repoPath, FileMode.Open, FileAccess.Read);

                    switch (algorithm)
                    {
                    case AlgoEnum.GZip:
                        zStream = new GZipStream(inFs, CompressionMode.Decompress);

                        break;

                    case AlgoEnum.BZip2:
                        zStream = new BZip2Stream(inFs, CompressionMode.Decompress);

                        break;

                    case AlgoEnum.LZMA:
                        byte[] properties = new byte[5];
                        inFs.Read(properties, 0, 5);
                        inFs.Seek(8, SeekOrigin.Current);
                        zStream = new LzmaStream(properties, inFs, inFs.Length - 13, file.Length);

                        break;

                    case AlgoEnum.LZip:
                        zStream = new LZipStream(inFs, CompressionMode.Decompress);

                        break;
                    }

                    UpdateProgress?.Invoke("Uploading file to clamd server...", null, 0, 0);

                #if DEBUG
                    stopwatch.Restart();
                #endif
                    Task.Run(async() =>
                    {
                        result = await clam.SendAndScanFileAsync(zStream);
                    }).Wait();
                #if DEBUG
                    stopwatch.Stop();

                    Console.WriteLine("Core.ClamScanFileFromRepo({0}): Clamd took {1} seconds to scan", file,
                                      stopwatch.Elapsed.TotalSeconds);
                #endif
                    zStream.Close();
                }

                if (result.InfectedFiles != null &&
                    result.InfectedFiles.Count > 0)
                {
                    file.HasVirus = true;
                    file.Virus    = result.InfectedFiles[0].VirusName;
                }
                else if (file.HasVirus == null)
                {
                    // If no scan has been done, mark as false.
                    // If a positive has already existed don't overwrite it.
                    file.HasVirus = false;
                    file.Virus    = null;
                }

                file.ClamTime = DateTime.UtcNow;

                dbCore.DbOps.UpdateFile(file);

                ScanFinished?.Invoke(file);
            }
            catch (ThreadAbortException) {}
            catch (Exception ex)
            {
                Failed?.Invoke($"Exception {ex.Message} when calling clamd");
            #if DEBUG
                Console.WriteLine("Exception {0}\n{1}", ex.Message, ex.InnerException);
            #endif
            }
        }
Пример #8
0
        public static void AddFilesToDb()
        {
            try
            {
                long counter = 0;
            #if DEBUG
                stopwatch.Restart();
            #endif
                foreach (KeyValuePair <string, DbAppFile> kvp in Context.Hashes)
                {
                    UpdateProgress?.Invoke(null, "Adding files to database", counter, Context.Hashes.Count);

                    if (!dbCore.DbOps.ExistsFile(kvp.Value.Sha256))
                    {
                        var file = new DbFile
                        {
                            Sha256         = kvp.Value.Sha256,
                            ClamTime       = null,
                            Crack          = kvp.Value.Crack,
                            Length         = kvp.Value.Length,
                            Virus          = null,
                            HasVirus       = null,
                            VirusTotalTime = null
                        };

                        dbCore.DbOps.AddFile(file);

                        AddFile?.Invoke(file);
                    }

                    counter++;
                }
            #if DEBUG
                stopwatch.Stop();

                Console.WriteLine("Core.AddFilesToDb(): Took {0} seconds to add all files to the database",
                                  stopwatch.Elapsed.TotalSeconds);
            #endif

                UpdateProgress?.Invoke(null, "Adding application information", counter, Context.Hashes.Count);
                dbCore.DbOps.AddApp(Context.DbInfo, out Context.DbInfo.Id);
                UpdateProgress?.Invoke(null, "Creating application table", counter, Context.Hashes.Count);
                dbCore.DbOps.CreateTableForApp(Context.DbInfo.Id);

            #if DEBUG
                stopwatch.Restart();
            #endif
                counter = 0;

                foreach (KeyValuePair <string, DbAppFile> kvp in Context.Hashes)
                {
                    UpdateProgress?.Invoke(null, "Adding files to application in database", counter,
                                           Context.Hashes.Count);

                    dbCore.DbOps.AddFileToApp(kvp.Value, Context.DbInfo.Id);

                    counter++;
                }
            #if DEBUG
                stopwatch.Stop();

                Console.WriteLine("Core.AddFilesToDb(): Took {0} seconds to add all files to the application in the database",
                                  stopwatch.Elapsed.TotalSeconds);

                stopwatch.Restart();
            #endif
                counter = 0;

                foreach (KeyValuePair <string, DbFolder> kvp in Context.FoldersDict)
                {
                    UpdateProgress?.Invoke(null, "Adding folders to application in database", counter,
                                           Context.FoldersDict.Count);

                    dbCore.DbOps.AddFolderToApp(kvp.Value, Context.DbInfo.Id);

                    counter++;
                }
            #if DEBUG
                stopwatch.Stop();

                Console.WriteLine("Core.AddFilesToDb(): Took {0} seconds to add all folders to the database",
                                  stopwatch.Elapsed.TotalSeconds);

                stopwatch.Restart();
            #endif
                counter = 0;

                if (Context.SymlinksDict.Count > 0)
                {
                    dbCore.DbOps.CreateSymlinkTableForOs(Context.DbInfo.Id);
                }

                foreach (KeyValuePair <string, string> kvp in Context.SymlinksDict)
                {
                    UpdateProgress?.Invoke(null, "Adding symbolic links to application in database", counter,
                                           Context.SymlinksDict.Count);

                    dbCore.DbOps.AddSymlinkToApp(kvp.Key, kvp.Value, Context.DbInfo.Id);

                    counter++;
                }
            #if DEBUG
                stopwatch.Stop();

                Console.WriteLine("Core.AddFilesToDb(): Took {0} seconds to add all symbolic links to the database",
                                  stopwatch.Elapsed.TotalSeconds);
            #endif

                Finished?.Invoke();
            }
            catch (ThreadAbortException) {}
            catch (Exception ex)
            {
                if (Debugger.IsAttached)
                {
                    throw;
                }

                Failed?.Invoke($"Exception {ex.Message}\n{ex.InnerException}");
            #if DEBUG
                Console.WriteLine("Exception {0}\n{1}", ex.Message, ex.InnerException);
            #endif
            }
        }