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); }
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); }
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); }
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); }
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); }
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 } }
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 } }
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 } }