private static void HeartBeat() { while (true) { var te = new TrackEventArgs(); var log = new SuncatLog(); log.DateTime = DateTime.Now; log.Event = SuncatLogEvent.HeartBeat; te.LogData = log; Track?.Invoke(null, te); Thread.Sleep(1000 * 60 * 5); // 5 minutes } }
private static void GetPublicIP() { while (true) { while (true) { try { var webRequest = new SuncatWebClient(); publicIP = webRequest.DownloadString("https://checkip.amazonaws.com").Trim(); var te = new TrackEventArgs(); var log = new SuncatLog(); log.DateTime = DateTime.Now; log.Event = SuncatLogEvent.GetPublicIP; log.Data1 = publicIP; te.LogData = log; Track?.Invoke(null, te); break; } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif Thread.Sleep(1000 * 60 * 5); // repeat every 5 minutes until public IP has been successfully retrieved } } Thread.Sleep(1000 * 60 * 30); // check every 30 minutes if public IP has changed } }
private static void CheckFirefoxHistory(string dataDir, string tempFileName) { var lastDatabaseMD5Hash = default(string); DateTime?firstUrlTime = null, lastUrlTime = null; var newUrls = new List <Tuple <string, string> >(); while (true) { try { var session = SuncatUtilities.GetActiveSession(); if (session != null && !string.IsNullOrEmpty(session.UserName)) { if (!lastActiveUsernames.ContainsKey(tempFileName) || lastActiveUsernames[tempFileName] == session.UserName) { var realDataDir = dataDir.Replace("[USERNAME]", session.UserName); var profile = GetFirefoxDefaultProfile(realDataDir); if (profile != null) { var database = $@"{realDataDir}\Profiles\{profile}\places.sqlite"; if (File.Exists(database) && File.Exists($"{database}-wal")) { var databaseMD5Hash = SuncatUtilities.GetMD5HashFromFile($"{database}-wal"); if (databaseMD5Hash != lastDatabaseMD5Hash) { Directory.CreateDirectory($@"{serviceAppData}\History"); File.Copy(database, $@"{serviceAppData}\History\{tempFileName}", true); File.Copy($"{database}-wal", $@"{serviceAppData}\History\{tempFileName}-wal", true); using (var connection = new SQLiteConnection($@"Data Source={serviceAppData}\History\{tempFileName};PRAGMA journal_mode=WAL")) { connection.Open(); using (var command = new SQLiteCommand("select mp.url, mp.title, strftime('%Y-%m-%d %H:%M:%f', substr(mhv.visit_date, 1, 17) / 1000000.0, 'unixepoch', 'localtime') as visit_date from moz_places mp join moz_historyvisits mhv on mhv.place_id = mp.id where mp.hidden = 0 order by visit_date desc, mhv.id desc", connection)) { using (var reader = command.ExecuteReader()) { newUrls.Clear(); if (reader.HasRows) { string lastUrl = null; while (reader.Read()) { var url = Convert.ToString(reader["url"]); var title = Convert.ToString(reader["title"]); var urlTime = Convert.ToDateTime(reader["visit_date"]); if (url != lastUrl) { if (lastUrlTime.HasValue) { if (urlTime >= lastUrlTime) { if (newUrls.Count == 0) { firstUrlTime = urlTime; } if (urlTime > lastUrlTime && url.StartsWith("http")) { var tuple = new Tuple <string, string>(url, string.IsNullOrWhiteSpace(title) ? null : title.Trim()); newUrls.Insert(0, tuple); } } else { lastUrlTime = firstUrlTime; break; } } else { lastUrlTime = urlTime; break; } } lastUrl = url; } } else { lastUrlTime = default(DateTime); } foreach (var url in newUrls) { var te = new TrackEventArgs(); var log = new SuncatLog(); log.DateTime = DateTime.Now; log.Event = SuncatLogEvent.OpenURL; log.Data1 = url.Item1; log.Data2 = url.Item2; log.Data3 = tempFileName; te.LogData = log; Track?.Invoke(null, te); } if (newUrls.Count != 0) { lastUrlTime = firstUrlTime; } } } } lastDatabaseMD5Hash = databaseMD5Hash; } } } else { lastUrlTime = default(DateTime); } } else { lastUrlTime = null; } lastActiveUsernames[tempFileName] = session.UserName; } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } Thread.Sleep(1000); } }
private static void CheckSafariWinHistory(string dataDir, string tempFileName) { var lastDatabaseMD5Hash = default(string); Double?firstUrlTime = null, lastUrlTime = null; var newUrls = new List <Tuple <string, string> >(); while (true) { try { var session = SuncatUtilities.GetActiveSession(); if (session != null && !string.IsNullOrEmpty(session.UserName)) { if (!lastActiveUsernames.ContainsKey(tempFileName) || lastActiveUsernames[tempFileName] == session.UserName) { var realDataDir = dataDir.Replace("[USERNAME]", session.UserName); var database = $@"{realDataDir}\History.plist"; if (File.Exists(database)) { var databaseMD5Hash = SuncatUtilities.GetMD5HashFromFile(database); if (databaseMD5Hash != lastDatabaseMD5Hash) { Directory.CreateDirectory($@"{serviceAppData}\History"); File.Copy(database, $@"{serviceAppData}\History\{tempFileName}", true); var rootNode = (DictionaryNode)PList.Load(File.Open($@"{serviceAppData}\History\{tempFileName}", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); var urlsNode = (ArrayNode)rootNode["WebHistoryDates"]; newUrls.Clear(); if (urlsNode.Count > 0) { string lastUrl = null; foreach (var urlNode in urlsNode.OfType <DictionaryNode>().Select( u => new { Url = ((StringNode)u[""]).Value, Title = (u.ContainsKey("title") ? ((StringNode)u["title"]).Value : string.Empty), LastVisitedDate = Convert.ToDouble(((StringNode)u["lastVisitedDate"]).Value, CultureInfo.InvariantCulture), }).OrderByDescending(u => u.LastVisitedDate)) { var url = urlNode.Url; var title = urlNode.Title; var urlTime = urlNode.LastVisitedDate; if (url != lastUrl) { if (lastUrlTime.HasValue) { if (urlTime >= lastUrlTime) { if (newUrls.Count == 0) { firstUrlTime = urlTime; } if (urlTime > lastUrlTime && url.StartsWith("http")) { var tuple = new Tuple <string, string>(url, string.IsNullOrWhiteSpace(title) ? null : title.Trim()); newUrls.Insert(0, tuple); } } else { lastUrlTime = firstUrlTime; break; } } else { lastUrlTime = urlTime; break; } } lastUrl = url; } } else { lastUrlTime = default(Double); } foreach (var url in newUrls) { var te = new TrackEventArgs(); var log = new SuncatLog(); log.DateTime = DateTime.Now; log.Event = SuncatLogEvent.OpenURL; log.Data1 = url.Item1; log.Data2 = url.Item2; log.Data3 = tempFileName; te.LogData = log; Track?.Invoke(null, te); } if (newUrls.Count != 0) { lastUrlTime = firstUrlTime; } lastDatabaseMD5Hash = databaseMD5Hash; } } else { lastUrlTime = default(Double); } } else { lastUrlTime = null; } lastActiveUsernames[tempFileName] = session.UserName; } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } Thread.Sleep(1000); } }
public static bool IgnoreEventCallback(SuncatLog log) { var ignored = false; Func <SuncatLogEvent, string, string, bool> ignoreFilePatterns = delegate(SuncatLogEvent logEvent, string path, string oldPath) { if (path != null && path.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { return(false); } if (oldPath != null && oldPath.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { return(false); } var session = SuncatUtilities.GetActiveSession(); if (!ignored) { ignored |= Regex.IsMatch(path, $@"^{rootDrive}Users\[^\]+\AppData\".Replace(@"\", @"\\"), RegexOptions.IgnoreCase); } if (!ignored) { ignored |= path.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.Windows), StringComparison.OrdinalIgnoreCase); } if (!ignored) { ignored |= path.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), StringComparison.OrdinalIgnoreCase); } if (!ignored) { ignored |= path.IndexOf("$RECYCLE.BIN", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.IndexOf("$WINDOWS", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.IndexOf("Config.Msi", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.IndexOf("System Volume Information", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.IndexOf("WindowsApps", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.IndexOf("SystemApps", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.IndexOf("MicrosoftEdgeBackups", StringComparison.OrdinalIgnoreCase) > -1; } if (!ignored) { ignored |= path.EndsWith("desktop.ini", StringComparison.OrdinalIgnoreCase); } if (!ignored) { ignored |= (Path.GetFileName(path).StartsWith("~") && logEvent != SuncatLogEvent.RenameFile); } if (!ignored) { ignored |= (Path.GetFileName(path).EndsWith("~") && logEvent != SuncatLogEvent.RenameFile); } if (!ignored) { ignored |= (Path.GetExtension(path).Equals(".tmp", StringComparison.OrdinalIgnoreCase) && logEvent != SuncatLogEvent.RenameFile); } if (!ignored) { ignored |= Path.GetExtension(path).Equals(".lnk", StringComparison.OrdinalIgnoreCase); } if (!ignored) { ignored |= (session != null && !string.IsNullOrEmpty(session.UserName) && path.StartsWith($@"{rootDrive}Users\") && !path.StartsWith($@"{rootDrive}Users\{session.UserName}\")); } if (!ignored) { ignored |= (path.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), StringComparison.OrdinalIgnoreCase) && !Path.GetExtension(path).Equals(".exe", StringComparison.OrdinalIgnoreCase)); } if (!ignored) { ignored |= (path.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), StringComparison.OrdinalIgnoreCase) && !Path.GetExtension(path).Equals(".exe", StringComparison.OrdinalIgnoreCase)); } if (!ignored) { ignored |= path.Contains(@"\."); // folder starting with dot } try { if (!ignored) { ignored |= new FileInfo(path).Attributes.HasFlag(FileAttributes.Hidden); } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } return(ignored); }; if (log.Event != SuncatLogEvent.RenameFile && log.Data1 != null) { ignored |= ignoreFilePatterns(log.Event, log.Data1, null); } if (log.Event != SuncatLogEvent.RenameFile && log.Data2 != null) { ignored |= ignoreFilePatterns(log.Event, log.Data2, null); } if (log.Event == SuncatLogEvent.RenameFile && log.Data1 != null && log.Data2 != null) { ignored |= ignoreFilePatterns(log.Event, log.Data2, log.Data1); } return(ignored); }
private static void FileSystemEventHandler(object sender, FileSystemEventArgs e) { var originalEvent = e.ChangeType.ToSuncatLogEvent(); // Only log files, not directories (don't check for files exist on delete) if (originalEvent == SuncatLogEvent.DeleteFile || System.IO.File.Exists(e.FullPath)) { var eArgs = e as SmartFileSystemEventArgs; var reArgs = e as SmartFileSystemRenamedEventArgs; var te = new TrackEventArgs(); var log = new SuncatLog(); log.Event = originalEvent; log.DateTime = DateTime.Now; switch (originalEvent) { case SuncatLogEvent.CreateFile: case SuncatLogEvent.ChangeFile: { string copiedFile = null; var isCopiedFile = false; if (HookActivityMonitor.LastCopiedFiles != null && HookActivityMonitor.LastCopiedFiles.Count > 0) { var currentFileInfo = new FileInfo(e.FullPath); foreach (var copiedFileInfo in HookActivityMonitor.LastCopiedFiles.OrderByDescending(f => f.FileInfo.Name.Length)) { if (copiedFileInfo.IsDirectory) { copiedFile = FindCopiedFile(new DirectoryInfo(copiedFileInfo.FileInfo.FullName), currentFileInfo, currentFileInfo.Directory); if (copiedFile != null) { isCopiedFile = true; break; } } else { if (currentFileInfo.Name.StartsWith(Path.GetFileNameWithoutExtension(copiedFileInfo.FileInfo.Name))) { isCopiedFile = true; copiedFile = copiedFileInfo.FileInfo.FullName; break; } } } } if (isCopiedFile) { log.Event = SuncatLogEvent.CopyFile; log.Data1 = copiedFile; log.Data2 = eArgs.FullPath; try { log.Data3 = volumeWatcher.DriveList[copiedFile.Substring(0, 1)].DriveType.ToString(); } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif log.Data3 = copiedFile.StartsWith(@"\\") ? DriveType.Network.ToString() : DriveType.Unknown.ToString(); } log.Data3 += ","; } else { log.Data1 = eArgs.FullPath; } } break; case SuncatLogEvent.RenameFile: { var isOldFileTypeAssociated = IsAssociatedFileType(reArgs.OldFullPath); var isNewFileTypeAssociated = IsAssociatedFileType(reArgs.FullPath); // Only 1 operation on the file (rename in this case), treat it as RenameFile, else treat is as ChangeFile if ((isOldFileTypeAssociated && isNewFileTypeAssociated && Path.GetExtension(reArgs.OldFullPath).Equals(Path.GetExtension(reArgs.FullPath), StringComparison.OrdinalIgnoreCase) && reArgs.SameFileEventCount() == 1) || fileTypeKeyNames == null) { log.Data1 = reArgs.OldFullPath; log.Data2 = reArgs.FullPath; } else if (!isOldFileTypeAssociated && isNewFileTypeAssociated) { log.Event = SuncatLogEvent.ChangeFile; log.Data1 = reArgs.FullPath; } else // Discard rename event if the file extension is unknown { log.Event = SuncatLogEvent.None; } } break; default: { log.Data1 = eArgs.FullPath; } break; } if (log.Event != SuncatLogEvent.None) { try { if (originalEvent == SuncatLogEvent.RenameFile) { log.Data3 += volumeWatcher.DriveList[reArgs.FullPath.Substring(0, 1)].DriveType.ToString(); } else { log.Data3 += volumeWatcher.DriveList[eArgs.FullPath.Substring(0, 1)].DriveType.ToString(); } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } te.LogData = log; // The ignore part of these events are processed in the custom FileSystemWatcher's core switch (log.Event) { case SuncatLogEvent.CreateFile: case SuncatLogEvent.ChangeFile: case SuncatLogEvent.RenameFile: { Track?.Invoke(null, te); } break; case SuncatLogEvent.DeleteFile: { // Discard deleted event if the same file is renamed right after if (!eArgs.HasEvent(WatcherChangeTypes.Renamed)) { Track?.Invoke(null, te); } } break; default: { if (!IgnoreEventCallback(log)) { Track?.Invoke(null, te); } } break; } } } }
private static async void CheckUserRecentFiles() { DateTime?firstRecentFileDate = null, lastRecentFileDate = null; var newRecentFiles = new List <string>(); var robocopyProcessStartInfo = new ProcessStartInfo(); while (true) { try { var session = SuncatUtilities.GetActiveSession(); if (session != null && !string.IsNullOrEmpty(session.UserName)) { var recentFolder = Path.Combine(serviceAppData, "Recent"); using (var process = Process.Start(new ProcessStartInfo() { FileName = "robocopy", Arguments = $"\"{rootDrive}Users\\{session.UserName}\\AppData\\Roaming\\Microsoft\\Windows\\Recent\" \"{recentFolder}\" /XF \"desktop.ini\" /MAX:1000000 /A-:SH /PURGE /NP", WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, })) { process.WaitForExit(); } newRecentFiles.Clear(); // don't use EnumerateFiles here as it is unreliable for us in the foreach, GetFiles is reliable (i think EnumerateFiles doesn't fetch all FileInfo data that we need at the time of execution) var recentFiles = new DirectoryInfo(recentFolder).GetFiles("*.lnk").OrderByDescending(f => f.LastAccessTime); foreach (var recentFile in recentFiles) { try { var recentFileDate = recentFile.LastAccessTime; if (lastRecentFileDate.HasValue) { if (recentFileDate >= lastRecentFileDate) { var shell = new WshShell(); var link = (IWshShortcut)shell.CreateShortcut(recentFile.FullName); if (newRecentFiles.Count == 0) { firstRecentFileDate = recentFileDate; } link.TargetPath = link.TargetPath.Replace(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), $@"{rootDrive}Users\{session.UserName}"); if (recentFileDate > lastRecentFileDate && System.IO.File.Exists(link.TargetPath)) { newRecentFiles.Insert(0, link.TargetPath); } } else { lastRecentFileDate = firstRecentFileDate; break; } } else { lastRecentFileDate = recentFileDate; break; } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } } foreach (var recentFile in newRecentFiles) { var te = new TrackEventArgs(); var log = new SuncatLog(); log.DateTime = DateTime.Now; log.Event = SuncatLogEvent.OpenFile; log.Data1 = recentFile; try { log.Data3 = volumeWatcher.DriveList[recentFile.Substring(0, 1)].DriveType.ToString(); } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif log.Data3 = recentFile.StartsWith(@"\\") ? DriveType.Network.ToString() : DriveType.Unknown.ToString(); } te.LogData = log; // Make the event wait a bit to let the Open event appear after a Create event if necessary. await Task.Delay(3000).ContinueWith(_ => { if (!IgnoreEventCallback(log)) { Track?.Invoke(null, te); } }); } if (newRecentFiles.Count != 0) { lastRecentFileDate = firstRecentFileDate; } } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } Thread.Sleep(1000); } }
private async void InsertToDatabase(ITerminalServicesSession session, SuncatLog log) { try { using (var connection = new SqlConnection("Data Source=server;Database=master;User ID=user;Password=password")) { await connection.OpenAsync(); //if (log.Event == SuncatLogEvent.OpenURL) //{ // connection.ChangeDatabase("ip2location"); // // speed up the query by forcing SQL Server to use the indexes // using (var command = new SqlCommand(@" // SELECT // country_code, // country_name, // region_name, // city_name, // latitude, // longitude, // zip_code, // time_zone // FROM ip2location_db11 // WHERE ip_from = ( // SELECT MAX(ip_from) // FROM ip2Location_db11 // WHERE ip_from <= @Ip // ) // AND ip_to = ( // SELECT MIN(ip_to) // FROM ip2Location_db11 // WHERE ip_to >= @Ip // ) // ", connection)) // { // try // { // var host = new Uri(log.Data1).DnsSafeHost; // var ip = Dns.GetHostAddresses(host).First(); // remoteIp = ip.ToString(); // var bytes = ip.GetAddressBytes(); // var ip2int = (uint)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(bytes, 0)); // var ipParam = new SqlParameter("@Ip", SqlDbType.BigInt); // ipParam.Value = ip2int; // command.Parameters.Add(ipParam); // using (var dataReader = await command.ExecuteReaderAsync()) // { // if (await dataReader.ReadAsync()) // { // countryCode = dataReader.GetString(0); // countryName = dataReader.GetString(1); // regionName = dataReader.GetString(2); // cityName = dataReader.GetString(3); // latitude = dataReader.GetDouble(4); // longitude = dataReader.GetDouble(5); // zipCode = dataReader.GetString(6); // timeZone = dataReader.GetString(7); // } // } // } // catch (Exception ex) // { // #if DEBUG // Debug.WriteLine(ex); // if (ex.InnerException != null) // Debug.WriteLine(ex.InnerException); // #else // Trace.WriteLine(ex); // if (ex.InnerException != null) // Trace.WriteLine(ex.InnerException); // #endif // } // } //} connection.ChangeDatabase("Suncat"); using (var command = new SqlCommand(@" INSERT INTO SuncatLogs ( DATETIME, EVENT, DATA1, DATA2, DATA3, COMPUTERNAME, USERNAME, LOCALIP, MACADDRESS ) VALUES ( @DateTime, @Event, @Data1, @Data2, @Data3, @ComputerName, @UserName, @LocalIp, @MacAddress ) ", connection)) { var data1 = log.Data1; var data2 = log.Data2; var data3 = log.Data3; var localIp = SystemInformation.GetIPv4Address(); var macAddress = SystemInformation.GetMACAddress(); command.Parameters.AddWithValue("@DateTime", log.DateTime); command.Parameters.AddWithValue("@Event", log.Event.ToString()); command.Parameters.AddWithValue("@Data1", string.IsNullOrWhiteSpace(data1) ? (object)DBNull.Value : data1); command.Parameters.AddWithValue("@Data2", string.IsNullOrWhiteSpace(data2) ? (object)DBNull.Value : data2); command.Parameters.AddWithValue("@Data3", string.IsNullOrWhiteSpace(data3) ? (object)DBNull.Value : data3); command.Parameters.AddWithValue("@ComputerName", Environment.MachineName ?? string.Empty); command.Parameters.AddWithValue("@UserName", session.UserName ?? string.Empty); command.Parameters.AddWithValue("@LocalIp", string.IsNullOrEmpty(localIp) ? (object)DBNull.Value : localIp); command.Parameters.AddWithValue("@MacAddress", string.IsNullOrEmpty(macAddress) ? (object)DBNull.Value : macAddress); await command.ExecuteNonQueryAsync(); } } } catch (Exception ex) { #if DEBUG Debug.WriteLine(ex); if (ex.InnerException != null) { Debug.WriteLine(ex.InnerException); } #else Trace.WriteLine(ex); if (ex.InnerException != null) { Trace.WriteLine(ex.InnerException); } #endif } }