├── Program.cs ├── README.md └── SQLiteHandler.cs /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.Eventing.Reader; 3 | using System.Xml; 4 | using System.Collections; 5 | using System.Globalization; 6 | using System.Collections.Generic; 7 | using winlogparser; 8 | using System.Text; 9 | using System.Linq; 10 | 11 | namespace winlogparser 12 | { 13 | public class LoginLog 14 | { 15 | public string IpAddress { get; set; } 16 | public DateTime SystemTime { get; set; } 17 | // 你可以添加其他的属性,比如 EventRecordID, TargetDomainName, TargetUserName, EventID, LogonType 18 | } 19 | class winlogParser 20 | { 21 | static Hashtable logtypename = new Hashtable(){ 22 | {2, "type = 2|Interactive|交互式登录"}, 23 | {3, "type = 3|Network|网络登录"}, 24 | {4, "type = 4|Batch|批处理登录"}, 25 | {5, "type = 5|Service|服务登录"}, 26 | {7, "type = 7|Unlock|解锁登录"}, 27 | {8, "type = 8|NetworkCleartext|网络明文方式登录"}, 28 | {10, "type = 10|Remotelnteractive|远程桌面方式登录"}, 29 | {11, "type = 11|CachedUnlock|缓存域证书登录"}, 30 | }; 31 | 32 | public List Queries { get; private set; } 33 | 34 | public winlogParser() 35 | { 36 | Queries = new List(); 37 | } 38 | 39 | public void ProcessEventLog(string logName, string queryPath, Action action) 40 | { 41 | EventLogQuery eventLogQuery = new EventLogQuery(logName, PathType.LogName, queryPath) 42 | { 43 | TolerateQueryErrors = true, 44 | ReverseDirection = true 45 | }; 46 | 47 | using (EventLogReader eventLogReader = new EventLogReader(eventLogQuery)) 48 | { 49 | do 50 | { 51 | EventRecord eventData = eventLogReader.ReadEvent(); 52 | if (eventData == null) 53 | break; 54 | 55 | XmlDocument xmldoc = new XmlDocument(); 56 | xmldoc.LoadXml(eventData.ToXml()); 57 | 58 | action(eventData, xmldoc); 59 | 60 | eventData.Dispose(); 61 | 62 | } while (true); 63 | } 64 | } 65 | 66 | public void ProcessLoginLog(EventRecord eventData, XmlDocument xmldoc) 67 | { 68 | XmlNodeList recordid = xmldoc.GetElementsByTagName("EventRecordID"); 69 | XmlNodeList eventid = xmldoc.GetElementsByTagName("EventID"); 70 | XmlNodeList data = xmldoc.GetElementsByTagName("Data"); 71 | 72 | int Ieventid; 73 | int.TryParse(eventid[0].InnerText, out Ieventid); 74 | 75 | if (Ieventid == 4624) 76 | { 77 | String targetUserSid = data[4].InnerText; 78 | String targetDomainName = data[6].InnerText; 79 | String targetUserName = data[5].InnerText; 80 | int Logtype = Convert.ToInt16(data[8].InnerText); 81 | 82 | String ipAddress = data[18].InnerText; 83 | if (targetUserSid.Length > 9 && ipAddress.Length > 8) 84 | { 85 | string query = "INSERT INTO loginlog (EventRecordID, SystemTime, IpAddress, TargetDomainName, TargetUserName, EventID, LogonType) VALUES ('" + recordid[0].InnerText + "', '" + 86 | eventData.TimeCreated.Value.ToString("yyyy-MM-dd HH:mm:ss") + "', '" + 87 | ipAddress + "', '" + 88 | targetDomainName + "', '" + 89 | targetDomainName + "\\" + targetUserName + "', '" + 90 | eventid[0].InnerText + "', '" + 91 | logtypename[Logtype] + "');"; 92 | 93 | Queries.Add(query); 94 | 95 | Console.WriteLine("[+] EventRecordID: " + recordid[0].InnerText); 96 | Console.WriteLine(" EventID : " + eventid[0].InnerText); 97 | Console.WriteLine(" TimeCreated : " + eventData.TimeCreated); 98 | Console.WriteLine(" Logtype: " + logtypename[Logtype]); 99 | Console.WriteLine(" UserName: " + targetDomainName + "\\" + targetUserName); 100 | Console.WriteLine(" IpAddress: " + ipAddress); 101 | Console.WriteLine("\r\n"); 102 | } 103 | } 104 | 105 | if (Ieventid == 4625) 106 | { 107 | String targetDomainName = data[6].InnerText; 108 | String targetUserName = data[5].InnerText; 109 | String processname = data[18].InnerText; 110 | String ipAddress = data[19].InnerText; 111 | String processid = data[17].InnerText; 112 | int Logtype = Convert.ToInt16(data[10].InnerText); 113 | String Tusername = null; 114 | int pid = Convert.ToInt32(processid, 16); 115 | 116 | if (!string.IsNullOrEmpty(targetDomainName)) 117 | { 118 | Tusername = targetDomainName + "\\" + targetUserName; 119 | } 120 | else 121 | { 122 | Tusername = targetUserName; 123 | } 124 | 125 | string query = "INSERT INTO loginlog (EventRecordID, SystemTime, IpAddress, TargetDomainName, TargetUserName, EventID, LogonType) VALUES ('" + recordid[0].InnerText + "', '" + 126 | eventData.TimeCreated.Value.ToString("yyyy-MM-dd HH:mm:ss") + "', '" + 127 | ipAddress + "', '" + 128 | targetDomainName + "', '" + 129 | targetDomainName + "\\" + targetUserName + "', '" + 130 | eventid[0].InnerText + "', '" + 131 | logtypename[Logtype] + "');"; 132 | 133 | Queries.Add(query); 134 | 135 | Console.WriteLine("[+] EventRecordID: " + recordid[0].InnerText); 136 | Console.WriteLine(" EventID : " + eventid[0].InnerText); 137 | Console.WriteLine(" TimeCreated : " + eventData.TimeCreated); 138 | Console.WriteLine(" Logtype: " + logtypename[Logtype]); 139 | Console.WriteLine(" IpAddress: " + ipAddress); 140 | Console.WriteLine(" UserName: " + Tusername); 141 | Console.WriteLine(" ProcessName: " + processname); 142 | Console.WriteLine(" ProcessId: " + pid); 143 | Console.WriteLine("\r\n"); 144 | } 145 | } 146 | 147 | public void loginlog() 148 | { 149 | Console.WriteLine("#######################################################"); 150 | Console.WriteLine("[+] 正在获取登陆事件...\r\n"); 151 | string queryPath = "*[System[(EventID=4624 or EventID=4625)]]"; 152 | ProcessEventLog("Security", queryPath, ProcessLoginLog); 153 | } 154 | 155 | 156 | } 157 | 158 | 159 | 160 | class Program 161 | { 162 | 163 | private static List> DetectBruteForceAttempts(Dictionary> logs, int threshold, int intervalMinutes) 164 | { 165 | List> bruteForceAttempts = new List>(); 166 | 167 | foreach (var kvp in logs) 168 | { 169 | var ipLogs = kvp.Value; 170 | var sortedLogs = ipLogs.OrderBy(log => log.SystemTime).ToList(); 171 | 172 | int startIndex = 0; 173 | int endIndex = 0; 174 | int count = 0; 175 | 176 | for (int i = 0; i < sortedLogs.Count; i++) 177 | { 178 | if (i > 0 && (sortedLogs[i].SystemTime - sortedLogs[i - 1].SystemTime).TotalMinutes > intervalMinutes) 179 | { 180 | startIndex = i; 181 | count = 0; 182 | } 183 | 184 | count++; 185 | 186 | if (count >= threshold) 187 | { 188 | endIndex = i; 189 | var bruteForceAttempt = sortedLogs.GetRange(startIndex, endIndex - startIndex + 1); 190 | bruteForceAttempts.Add(bruteForceAttempt); 191 | count = 0; 192 | } 193 | } 194 | } 195 | 196 | return bruteForceAttempts; 197 | } 198 | 199 | 200 | 201 | static void Main(string[] args) 202 | { 203 | winlogParser parser = new winlogParser(); 204 | parser.loginlog(); 205 | 206 | List queries = parser.Queries; 207 | StringBuilder sb = new StringBuilder(); 208 | 209 | foreach (string query in queries) 210 | { 211 | sb.AppendLine(query); 212 | } 213 | 214 | string queriesString = sb.ToString(); 215 | // Console.WriteLine(queriesString); 216 | 217 | string databaseName = "loginlog"; // 请将此处的 YourDatabaseName 更换为你的数据库名称 218 | SQLiteHandler handler = new SQLiteHandler(databaseName); 219 | 220 | string tableName = "loginlog"; // 请在此处插入你的表名 221 | handler.CreateNewTable(tableName); 222 | 223 | //string sql = "..."; // 请在此处插入你的 SQL 语句 224 | long result = handler.ExecuteSQL(queriesString); 225 | 226 | Console.WriteLine("SQL command executed. Rows affected: " + result); 227 | 228 | 229 | 230 | // 获取登录日志 231 | List logs = handler.GetLoginLogs(); 232 | 233 | // 检测爆破事件 234 | int threshold = 10; // 阈值 235 | int intervalMinutes = 5; // 时间间隔(分钟) 236 | // 获取登录日志 237 | 238 | // 获取登录日志 239 | Dictionary> logsByIp = logs.GroupBy(log => log.IpAddress).ToDictionary(group => group.Key, group => group.ToList()); 240 | 241 | // 检测爆破事件 242 | 243 | List> bruteForceAttempts = DetectBruteForceAttempts(logsByIp, threshold, intervalMinutes); 244 | 245 | // 输出检测结果 246 | foreach (var attempt in bruteForceAttempts) 247 | { 248 | Console.WriteLine("Brute Force Attempt:"); 249 | foreach (var log in attempt) 250 | { 251 | Console.WriteLine("IpAddress: "+log.IpAddress+", SystemTime: "+log.SystemTime); 252 | } 253 | Console.WriteLine(); 254 | } 255 | 256 | 257 | 258 | /* 统计ip登陆情况 259 | SELECT IpAddress, COUNT(*) as Count 260 | FROM LoginLog 261 | WHERE IpAddress != '-' AND IpAddress != '127.0.0.1' And IpAddress !='::1' 262 | GROUP BY IpAddress; 263 | 264 | */ 265 | 266 | /* 267 | 268 | foreach (string query in queries) 269 | { 270 | Console.WriteLine(query); 271 | } 272 | */ 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **已实现功能:** 2 | - 检测用户操作日志 3 | - 日志清除日志 4 | - 爆破 5 | - 删除日志检测 6 | - 服务安装 7 | 8 | **待实现功能:** 9 | - 合并为单文件 10 | - dcsync 11 | - 统计功能 12 | - 导出excel 文件 13 | - 输出优化 14 | 15 | ![image](https://github.com/mabangde/winlogparser/assets/6219246/f873b6a6-1146-4c34-800e-a2df589ab25c) 16 | ![image](https://github.com/mabangde/winlogparser/assets/6219246/a8de0812-2cb5-4d53-a8d8-e40fdf29507c) 17 | 18 | -------------------------------------------------------------------------------- /SQLiteHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Data.SQLite; 6 | using System.IO; 7 | 8 | namespace winlogparser 9 | { 10 | 11 | 12 | public class SQLiteHandler 13 | { 14 | private string _connectionString; 15 | private string _databaseFilePath; 16 | 17 | public SQLiteHandler(string databaseName) 18 | { 19 | _databaseFilePath = databaseName + ".db"; 20 | _connectionString = String.Format("Data Source={0};Version=3;", _databaseFilePath); 21 | 22 | // 初始化 23 | CreateDatabase(); 24 | 25 | // 设置数据库参数 26 | ExecutePragmaSQL(@" 27 | PRAGMA temp_store = memory; 28 | PRAGMA locking_mode = EXCLUSIVE; 29 | PRAGMA synchronous = OFF; 30 | PRAGMA cache_size = 400000; 31 | PRAGMA page_size = 4096; 32 | PRAGMA auto_vacuum = NONE; 33 | PRAGMA count_changes = OFF; 34 | PRAGMA journal_mode = OFF; 35 | "); 36 | } 37 | 38 | public void ExecutePragmaSQL(string sql) 39 | { 40 | using (SQLiteConnection conn = new SQLiteConnection(_connectionString)) 41 | { 42 | conn.Open(); 43 | 44 | using (SQLiteCommand cmd = new SQLiteCommand(sql, conn)) 45 | { 46 | cmd.ExecuteNonQuery(); 47 | } 48 | } 49 | } 50 | public List GetLoginLogs() 51 | { 52 | var query = "SELECT * FROM LoginLog WHERE IpAddress != '-' AND IpAddress != '127.0.0.1' And EventID != 4624 ORDER BY SystemTime"; 53 | var logs = new List(); 54 | using (SQLiteConnection conn = new SQLiteConnection(_connectionString)) 55 | { 56 | conn.Open(); 57 | using (SQLiteCommand cmd = new SQLiteCommand(query, conn)) 58 | { 59 | using (SQLiteDataReader reader = cmd.ExecuteReader()) 60 | { 61 | while (reader.Read()) 62 | { 63 | logs.Add(new LoginLog 64 | { 65 | IpAddress = reader["IpAddress"].ToString(), 66 | SystemTime = DateTime.Parse(reader["SystemTime"].ToString()), 67 | // 你可以添加其他的属性,比如 EventRecordID, TargetDomainName, TargetUserName, EventID, LogonType 68 | }); 69 | } 70 | } 71 | } 72 | } 73 | return logs; 74 | } 75 | 76 | private void CreateDatabase() 77 | { 78 | if (!File.Exists(_databaseFilePath)) 79 | { 80 | SQLiteConnection.CreateFile(_databaseFilePath); 81 | Console.WriteLine("Database " + _databaseFilePath + " created"); 82 | } 83 | else 84 | { 85 | Console.WriteLine("Database " + _databaseFilePath + " already exists"); 86 | } 87 | } 88 | 89 | public void CreateNewTable(string tableName) 90 | { 91 | string sql = String.Format(@" 92 | DROP TABLE IF EXISTS {0}; 93 | CREATE TABLE IF NOT EXISTS {0} ( 94 | EventRecordID INTEGER PRIMARY KEY, 95 | SystemTime TEXT, 96 | IpAddress TEXT, 97 | TargetDomainName TEXT, 98 | TargetUserName TEXT, 99 | EventID INTEGER, 100 | LogonType TEXT 101 | ); 102 | 103 | CREATE VIRTUAL TABLE IF NOT EXISTS idx_{0} 104 | USING fts4(EventRecordID,IpAddress ,LogonType); 105 | ", tableName); 106 | 107 | ExecutePragmaSQL(sql); 108 | } 109 | 110 | public long ExecuteSQL(string sql) 111 | { 112 | using (SQLiteConnection conn = new SQLiteConnection(_connectionString)) 113 | { 114 | conn.Open(); 115 | 116 | using (SQLiteTransaction transaction = conn.BeginTransaction()) 117 | { 118 | using (SQLiteCommand cmd = new SQLiteCommand(sql, conn, transaction)) 119 | { 120 | var result = cmd.ExecuteNonQuery(); 121 | transaction.Commit(); 122 | return result; 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | 130 | 131 | /* 132 | class Program 133 | { 134 | static void Main(string[] args) 135 | { 136 | string databaseName = "YourDatabaseName"; // 请将此处的 YourDatabaseName 更换为你的数据库名称 137 | SQLiteHandler handler = new SQLiteHandler(databaseName); 138 | 139 | string tableName = "YourTableName"; // 请在此处插入你的表名 140 | handler.CreateNewTable(tableName); 141 | 142 | string sql = "..."; // 请在此处插入你的 SQL 语句 143 | long result = handler.ExecuteSQL(sql); 144 | 145 | Console.WriteLine("SQL command executed. Rows affected: " + result); 146 | } 147 | } 148 | */ 149 | } 150 | --------------------------------------------------------------------------------