/// <summary> /// Non referenced file scan /// </summary> /// <param name="filePath">File to scan.</param> /// <param name="Signatures">Signatures to scan with</param> /// <returns>Null or signature matching or found in file. </returns> //public static ScanResultArgs ScanFile(string filePath, SignatureController Signatures) //{ // return ScanFile(filePath, ref Signatures); //} /// <summary> /// Performs a scan on the provided file /// </summary> /// <param name="filePath">The file to scan.</param> /// <param name="Signatures">The signature controller</param> /// <param name="cached">The cache controller</param> /// <returns>Null or a signature</returns> public static ScanResultArgs ScanFile(string filePath, SignatureController Signatures) { //return ScanFileV2(filePath, Signatures); try { // Final args to return var args = new ScanResultArgs(); // *** NEW *** // Create a new filestream to read the file with FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // Before performing any kind of scan, we need to make sure it's a executable file if (!isScannable(filePath)) { // If it's not, return null and theres no point of scanning it //return null; return(new ScanResultArgs() { Detection = null, Size = fs.Length }); } // Determine if the file is too large to scan based on settings if (fs.Length > Settings.MaxFileSize) { // If so, just return null... return(new ScanResultArgs() { Detection = null, Size = fs.Length }); } // *********** // Some local variables to store scan information in //byte[] hash = MD5.quickMD5(filePath); // If a cache database is supplied with the scan request //if (cached != null) //{ // // Try to obtain a md5 hash from the file (see exception below for possible issues) // //hash = MD5.FromFile(ref fs); // hash = MD5.quickMD5(filePath); // // Check the file cache to see if the file has already been scanned // var found = cached.GetById(hash); // // If a cached item was found in the db // if(found != null) // { // // Return the matching signature if any... // //return Signatures.GetById(found.SignatureId); // return new ScanResultArgs() { Detection = Signatures.GetById(found.SignatureId), Size = fs.Length, Cached = found }; // } //} // Either the file cache database is not being used or no entry was found // So we must perform a new scan on the file byte[] buffer = new byte[1024 * Settings.BufferSize]; // Scan in 32kb increments int read = -1; // count how many bytes have been read on each read here // Make sure our buffer isn't bigger than the file if (buffer.Length > fs.Length) { // If it is, resize the buffer accordinly buffer = new byte[fs.Length]; } // While there is data to read in the file stream while (read != 0) { // Attempt to read the buffered amount.. read = fs.Read(buffer, 0, buffer.Length); // If the buffered amount if greater than the amount read... // Lets shrink buffer to speed up the pattern search if (read < buffer.Length) { Array.Resize(ref buffer, read); } // Analyze the buffer with the pattern analyzer var result = PatternAnalyzer.AnalyzeByteArray(buffer, Signatures); // try version 2.... //var result = PatternAnalyzer.AnyalyzeByteArrayv2(buffer, Signatures); // If the result is not null... a detection was found if (result != null) { // Create args before closing args = new ScanResultArgs() { Detection = result, Size = fs.Length, }; // Detected upx packing... if (args.Detection.Definition == "PACKED") { // UPX ISNT WORKING YET //return new ScanResultArgs() { Detection = null, Size = 0 }; // unpack the file and store the unpacked path... string unpacked = API.UPXHelper.UnpackFile(filePath); // Perform another scan args = ScanFile(unpacked, Signatures); // this was an unpacked program... //if(args.Detection != null) //{ // //args.Detection.Definition = args.Detection.Definition + "/UPX"; //} // delete the unpacked file File.DeleteFile(unpacked); // Remove the unpacked file from white lsit Settings.WhiteList.Remove(unpacked); } // We already detected the threat so we do not need to read any more.. fs.Dispose(); // return the threat return(args); } } // We finished reading the file and no threat was detected // Time to clean and and may be log to cache // Create clean args args = new ScanResultArgs() { Detection = null, Size = fs.Length, }; // Close up the file stream fs.Close(); fs.Dispose(); // clear buffer buffer = null; // Return a clean scan return(args); } catch (Exception ex) // for debugging purposes { #if DEBUG Console.WriteLine(ex.Message); #endif // Throw an exception with info about what may have caused the error. throw new Exception(String.Format("[2] Unable to scan file at location {0}. File may be use or additional rights may be required.", filePath)); //return new ScanResultArgs() { Detection = null, Size = 0 }; } }
public static ScanResultArgs ScanFileV2(string filePath, SignatureController signatures) { try { // Create a new scan result to return with var args = new ScanResultArgs(); // open new file stream FileStream fs = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // set file size args.Size = fs.Length; // Check if scannable file type if (!isScannable(filePath)) { return(new ScanResultArgs() { Detection = null }); } // any other additional checks to perform here // Create variables to load file buffers into //byte[] buffer = new byte[1024 * Settings.BufferSize]; int read = 1; // check if buffer is bigger than file //if(buffer.Length > fs.Length) //{ // fix buffer //buffer = new byte[fs.Length]; //} // Create list of tasks to perform scan on List <ThreadedAnalysis> scans = new List <ThreadedAnalysis>(); int max = Environment.ProcessorCount;; if (Settings.ReducePriority) { max = Environment.ProcessorCount / 2; } // Loop to read file while possible while (read > 0 && args.Detection == null) { // read the file chunk //read = fs.Read(buffer, 0, buffer.Length); // create new threaded scan of the buffer read ThreadedAnalysis t = new ThreadedAnalysis(); read = fs.Read(t.Buffer, 0, t.Buffer.Length); scans.Add(t); t.run(signatures); // we now have to do a check if (scans.Count > max) { // if we have max number of scans running we need to clear up some space for (int i = 0; i < scans.Count; i++) { // check if a scan is done... if (scans[i].Complete) { // if it is, check it's result if (scans[i].Result != null) { // copy detection over args.Detection = scans[i].Result; // Detected upx packing... if (args.Detection.Definition == "PACKED") { // unpack the file and store the unpacked path... string unpacked = API.UPXHelper.UnpackFile(filePath); // Perform another scan args = ScanFileV2(unpacked, signatures); // delete the unpacked file File.DeleteFile(unpacked); // Remove the unpacked file from white lsit Settings.WhiteList.Remove(unpacked); } return(args); } else { // no detection so clear up the scan list scans.Remove(scans[i]); } } } } } while (scans.Count > 0) { // if we have max number of scans running we need to clear up some space for (int i = 0; i < scans.Count; i++) { // check if a scan is done... if (scans[i].Complete) { // if it is, check it's result if (scans[i].Result != null) { // copy detection over args.Detection = scans[i].Result; // Detected upx packing... if (args.Detection.Definition == "PACKED") { // unpack the file and store the unpacked path... string unpacked = API.UPXHelper.UnpackFile(filePath); // Perform another scan args = ScanFileV2(unpacked, signatures); // delete the unpacked file File.DeleteFile(unpacked); // Remove the unpacked file from white lsit Settings.WhiteList.Remove(unpacked); } return(args); } else { // no detection so clear up the scan list scans.Remove(scans[i]); } } else { scans[i].waiting(); } } } fs.Dispose(); //buffer = null; // return scan results return(args); } catch (Exception ex) { #if DEBUG Console.WriteLine(ex.Message); #endif throw new Exception("Unable to scan file at location: " + filePath); } }