public void addReadEvent(FileIOReadWriteTraceData readEvent) { //first check for correlation string currFileName = Path.GetFileNameWithoutExtension(readEvent.FileName); ReadEventTracker existingReadEvent = null; foreach (ReadEventTracker ret in readEvents) { if (Path.GetFileNameWithoutExtension(ret.fileName).ToLower() == currFileName.ToLower()) { existingReadEvent = ret; break; } } //new read event if (existingReadEvent == null) { ReadEventTracker ret = new ReadEventTracker(readEvent); readEvents.Add(ret); } else { readEvents.Remove(existingReadEvent); existingReadEvent.updateEvent(readEvent); readEvents.Add(existingReadEvent); } }
private void HandleFileIoReadWrite(FileIOReadWriteTraceData data) { if (data.ProcessID == pid) { traceOutput.Write(data.TimeStampRelativeMSec, data.ProcessID, data.ThreadID, data.EventName, $"'{data.FileName}' (0x{data.FileObject:X})" + $" 0x{data.Offset:X} {data.IoSize}b"); if (data.FileName != null) { FileIoSummary summary; if (!fileIoSummary.TryGetValue(data.FileName, out summary)) { summary = new FileIoSummary(); fileIoSummary.Add(data.FileName, summary); } if ((byte)data.Opcode == 67) // read { summary.Read += data.IoSize; summary.Total += data.IoSize; } else if ((byte)data.Opcode == 68) // write { summary.Write += data.IoSize; summary.Total += data.IoSize; } } } }
//when a file is written check to see if it's the same PID that read it then check time stamp public static void fileWriteEvent(FileIOReadWriteTraceData writeEvent) { string currDir = Path.GetDirectoryName(writeEvent.FileName); if (pidList.Contains(writeEvent.ProcessID)) { if (directoryOperations.ContainsKey(currDir)) { //add our write event to the existing entry DirectoryEventTracker tempDirEvent = (DirectoryEventTracker)directoryOperations[currDir]; tempDirEvent.addWriteEvent(writeEvent); directoryOperations[currDir] = tempDirEvent; } else { //existing pid, new dir. Make new entry DirectoryEventTracker tempDirEvent = new DirectoryEventTracker(writeEvent.ProcessID, writeEvent.TimeStampRelativeMSec, currDir, writeEvent.ProcessName, (StreamWriter)Out); tempDirEvent.addWriteEvent(writeEvent); directoryOperations[currDir] = tempDirEvent; } } else { //otherwise add it to the list and create a new entry in dirOps pidList.Add(writeEvent.ProcessID); DirectoryEventTracker tempDirEvent = new DirectoryEventTracker(writeEvent.ProcessID, writeEvent.TimeStampRelativeMSec, currDir, writeEvent.ProcessName, (StreamWriter)Out); tempDirEvent.addWriteEvent(writeEvent); directoryOperations[currDir] = tempDirEvent; } }
//update time and file size. public void updateEvent(FileIOReadWriteTraceData data, bool isSuspicious = false) { if (data.Offset + data.IoSize > fileSize) { fileSize = (int)data.Offset + data.IoSize; lastWrite = data.TimeStampRelativeMSec; } }
public void updateEvent(FileIOReadWriteTraceData data) { if (data.IoSize >= fileSize) { fileSize = data.IoSize; eventTime = data.TimeStampRelativeMSec; } }
public ReadEventTracker(FileIOReadWriteTraceData data) { isCorrelated = false; fileSize = data.IoSize; eventTime = data.TimeStampRelativeMSec; fileName = data.FileName; pid = data.ProcessID; }
public WriteEventTracker(FileIOReadWriteTraceData data, bool isSuspicious = false) { isCorrelated = false; correlatedReadEvent = -1; isSuspiciousEvent = isSuspicious; pid = data.ProcessID; fileName = data.FileName; }
public void LogEvent(FileIOReadWriteTraceData data) { //--------- // Filter event data // Not written yet.. //---------- //--------------- // Log ImageLoad event LogRow text = new LogRow(); _fileIOWriter.WriteHeader(data, text); text.Add(data.FileName); _fileIOWriter.WriteRow(text); //------------------ }
// To improve performace we drop IO events that are multiples of 4096 // This helps filter out large IO events with the obvious disadvantage // of possibly overlooking needed data. In testing we found that rarely // happened and the benefit far outweighed (small) risk. static void FilterIOEvents(TraceEvent data) { // Ctrl-C will stop the sessions, but buffered events may still come in, ignore these. if (s_stopping) { return; } if (data.GetType().Name == "FileIOReadWriteTraceData") { FileIOReadWriteTraceData parsedData = (FileIOReadWriteTraceData)data; // Sometimes filenames can be blank. Not exactly sure why // See nano sample for example if (parsedData.FileName.Length > 0) { if (DO_READ_WRITE) { if (parsedData.OpcodeName == "Read") { if (parsedData.IoSize % 4096 == 0) { return; } else { fileReadEvent(parsedData); } } if (parsedData.OpcodeName == "Write") { if (parsedData.IoSize % 4096 == 0) { return; } else { fileWriteEvent(parsedData); } } } } } }
//For each fileRead event that occurs we must check if we have a directory entry for it public static void fileReadEvent(FileIOReadWriteTraceData readEvent) { //Avoid cached files for some apps (see IE_plus.zip_test.etl.zip) if (!Path.HasExtension(readEvent.FileName)) { Out.WriteLine("No extension, disregarding file read for: " + readEvent.FileName); return; } string currDir = Path.GetDirectoryName(readEvent.FileName); //first check if we have a directory entry for the incoming pid if (pidList.Contains(readEvent.ProcessID)) { //if PID exists append check for previos ops in the dir if (directoryOperations.ContainsKey(currDir)) { //if there's allready a read event for this Dir and PID just add the new one to the list //and update the hashtable DirectoryEventTracker tempDirEvent = (DirectoryEventTracker)directoryOperations[currDir]; tempDirEvent.addReadEvent(readEvent); directoryOperations[currDir] = tempDirEvent; } else { //otherwise make a new entry for it and add in the read event DirectoryEventTracker tempDirEvent = new DirectoryEventTracker(readEvent.ProcessID, readEvent.TimeStampRelativeMSec, currDir, readEvent.ProcessName, (StreamWriter)Out); tempDirEvent.addReadEvent(readEvent); directoryOperations[currDir] = tempDirEvent; } } else { //otherwise add it to the list and create a new entry in dirOps pidList.Add(readEvent.ProcessID); DirectoryEventTracker tempDirEvent = new DirectoryEventTracker(readEvent.ProcessID, readEvent.TimeStampRelativeMSec, currDir, readEvent.ProcessName, (StreamWriter)Out); tempDirEvent.addReadEvent(readEvent); directoryOperations[currDir] = tempDirEvent; } }
private void Kernel_FileIOWrite(FileIOReadWriteTraceData data) { if (_context.IsTestEvent(data)) if(_data != null) _data.addItem(data.FileName, data.IoSize); }
public void addWriteEvent(FileIOReadWriteTraceData writeEvent) { //first check for correlation string currFileName = Path.GetFileNameWithoutExtension(writeEvent.FileName); ReadEventTracker correspondingReadEvent = null; int corrReadEvent = -1; int i = 0; foreach (ReadEventTracker ret in readEvents) { if (Path.GetFileNameWithoutExtension(ret.fileName).ToLower() == currFileName.ToLower()) { corrReadEvent = i; correspondingReadEvent = ret; break; } i++; } // There are times when we receive writes before reads are detected. The obvious case is // when the file written to has changed it's name drastically and we fail to recognize it. // For now these events are dropped. if (corrReadEvent == -1) { return; } // check timestamp // doesn't matter if the writeEvent is new or old it still needs to be under the threshold if (writeEvent.TimeStampRelativeMSec - correspondingReadEvent.eventTime > IO_DELTA_THRESHOLD) { Out.WriteLine("Timestamp for incoming writeEvent is outside of threshold [" + (writeEvent.TimeStampRelativeMSec - correspondingReadEvent.eventTime).ToString() + "]. Disregarding: " + writeEvent.FileName); return; } ////////////////////////////////////// // at this point we know there has been a Read and a write to the same file, from the same process // and it was within the timing threshold. All that's left is to check the size of the read first // the file write. ////////////////////////////////////// // Check if previous event exist WriteEventTracker tempWE = null; foreach (WriteEventTracker wet in writeEvents) { if (writeEvent.FileName == wet.fileName) { tempWE = wet; break; } } //if it's new if (tempWE == null) { //update time stamps firstWriteTime = writeEvent.TimeStampRelativeMSec; lastWriteTime = writeEvent.TimeStampRelativeMSec; bool suspicious = false; if (writeEvent.IoSize - correspondingReadEvent.fileSize >= 0 && writeEvent.IoSize - correspondingReadEvent.fileSize <= READ_WRITE_SIZE_DIFF_THRESHOLD) { suspicious = true; Out.WriteLine("[!] Suspicious write event detected! " + writeEvent.FileName); Out.WriteLine("\tSize of file write(s): " + writeEvent.IoSize.ToString() + " Size of file read(s): " + correspondingReadEvent.fileSize.ToString() + ". PID: " + writeEvent.ProcessID.ToString() + ". Process name: " + writeEvent.ProcessName); //if we encounter a certain number of suspicious events we call it ransomware! if (suspiciousWriteEvents.Count >= SUSPICOUS_EVENTS_THRESHOLD) { Out.WriteLine("[!!] Ransomware detected! - PID[" + writeEvent.ProcessID.ToString() + "] Process Name: " + writeEvent.ProcessName); } //don't add duplicates bool dup = false; foreach (WriteEventTracker swe in suspiciousWriteEvents) { if (swe.fileName == writeEvent.FileName) { dup = true; Out.WriteLine("\t Already detected entry, not added"); } } if (!dup) { suspiciousWriteEvents.Add(new WriteEventTracker(writeEvent, false)); } } WriteEventTracker wet = new WriteEventTracker(writeEvent, suspicious); writeEvents.Add(wet); } //update existing write event else { //remove old before we add in our updated version writeEvents.Remove(tempWE); //update time stamps firstWriteTime = writeEvent.TimeStampRelativeMSec; lastWriteTime = writeEvent.TimeStampRelativeMSec; //update time, file size with current time then check tempWE.updateEvent(writeEvent); if (tempWE.fileSize - correspondingReadEvent.fileSize >= 0 && tempWE.fileSize - correspondingReadEvent.fileSize <= READ_WRITE_SIZE_DIFF_THRESHOLD) { Out.WriteLine("[!] Suspicious write event on existing file: " + writeEvent.FileName); Out.WriteLine("\tSize of file write(s): " + tempWE.fileSize.ToString() + " Size of file read(s): " + correspondingReadEvent.fileSize.ToString() + ". PID: " + correspondingReadEvent.pid.ToString() + ". Process name: " + writeEvent.ProcessName); //if we encounter a certain number of suspicious events we call it cryptolocker if (suspiciousWriteEvents.Count >= SUSPICOUS_EVENTS_THRESHOLD) { Out.WriteLine("[!!] Ransomware detected! - PID[" + writeEvent.ProcessID.ToString() + "] Process Name: " + writeEvent.ProcessName); } //don't add duplicates bool dup = false; foreach (WriteEventTracker swe in suspiciousWriteEvents) { if (swe.fileName == tempWE.fileName) { dup = true; Out.WriteLine("\tAlready detected entry, not added"); } } if (!dup) { suspiciousWriteEvents.Add(tempWE); } } writeEvents.Add(tempWE); } }