如何用C#查找指定网络端口占用进程并监控AD登录请求状态
基于C#的AD登录请求监控实现方案
实现思路
AD登录请求通常走LDAP(默认389端口)或LDAPS(636端口),要实现监控需完成三个核心动作:捕获本地到AD服务器的网络连接并关联进程PID、记录请求时间戳、通过Windows事件日志判断登录成败状态。
具体实现步骤
1. 捕获网络连接并关联PID
利用Windows原生的IP Helper API获取TCP连接的进程映射,过滤目标端口为389/636的连接(AD服务端口),拿到发起请求的进程PID。
代码示例:
using System; using System.Runtime.InteropServices; public class TcpConnectionTracker { [DllImport("iphlpapi.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder, int ulAf, TcpTableClass tblClass, uint dwReserved); private enum TcpTableClass { TCP_TABLE_OWNER_PID_CONNECTIONS = 4 } [StructLayout(LayoutKind.Sequential)] private struct MIB_TCPROW_OWNER_PID { public uint state; public uint localAddr; public uint localPort; public uint remoteAddr; public uint remotePort; public int owningPid; } [StructLayout(LayoutKind.Sequential)] private struct MIB_TCPTABLE_OWNER_PID { public uint dwNumEntries; public MIB_TCPROW_OWNER_PID table; } public static void TrackAdConnections() { int bufferSize = 0; GetExtendedTcpTable(IntPtr.Zero, ref bufferSize, true, 2, TcpTableClass.TCP_TABLE_OWNER_PID_CONNECTIONS, 0); IntPtr tableBuffer = Marshal.AllocHGlobal(bufferSize); try { if (GetExtendedTcpTable(tableBuffer, ref bufferSize, true, 2, TcpTableClass.TCP_TABLE_OWNER_PID_CONNECTIONS, 0) == 0) { MIB_TCPTABLE_OWNER_PID tcpTable = Marshal.PtrToStructure<MIB_TCPTABLE_OWNER_PID>(tableBuffer); IntPtr rowPtr = (IntPtr)((long)tableBuffer + Marshal.SizeOf(tcpTable.dwNumEntries)); for (int i = 0; i < tcpTable.dwNumEntries; i++) { MIB_TCPROW_OWNER_PID row = Marshal.PtrToStructure<MIB_TCPROW_OWNER_PID>(rowPtr); ushort remotePort = (ushort)((row.remotePort >> 8) | ((row.remotePort & 0xFF) << 8)); if (remotePort == 389 || remotePort == 636) { int pid = row.owningPid; string timestamp = DateTime.Now.ToString("HH:mm:ss:ffff"); Console.WriteLine($"捕获到AD请求 - PID: {pid}, 时间: {timestamp}"); } rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf<MIB_TCPROW_OWNER_PID>()); } } } finally { Marshal.FreeHGlobal(tableBuffer); } } }
2. 获取AD登录状态
Windows安全日志会记录AD登录事件:事件ID4624表示登录成功,4625表示失败。通过读取这些日志,结合PID关联到之前捕获的请求,就能得到登录状态。
代码示例:
using System; using System.Diagnostics.Eventing.Reader; using System.Diagnostics; public class AdLoginStatusChecker { public static void MonitorAdLoginLogs(string domainName) { string query = $"*[System[EventID=4624 or EventID=4625]] and *[EventData[Data[@Name='TargetDomainName']='{domainName}']]"; EventLogQuery logQuery = new EventLogQuery("Security", PathType.LogName, query); using (EventLogReader logReader = new EventLogReader(logQuery)) { EventRecord logEntry; while ((logEntry = logReader.ReadEvent()) != null) { try { int pid = int.Parse(logEntry.Properties[10].Value.ToString()); string status = logEntry.Id == 4624 ? "Success" : "Failed"; string timestamp = logEntry.TimeCreated.Value.ToString("HH:mm:ss:ffff"); Process process = Process.GetProcessById(pid); string appInfo = $"{process.ProcessName}_{pid}"; Console.WriteLine($"{appInfo}, {timestamp} , ({status})"); } catch (ArgumentException) { continue; } } } } }
3. 整合监控逻辑
将上述两部分结合,比如每隔一段时间扫描TCP连接,同时实时监听事件日志,通过PID和时间窗口(比如连接发生后5分钟内的日志)匹配,输出最终结果。
关键注意事项
- 程序必须以管理员权限运行,否则无法访问TCP连接信息和安全事件日志。
- 事件日志中的PID可能存在延迟,建议设置合理的时间窗口进行匹配。
- 如果AD使用非标准端口,需要调整代码中过滤的端口号。
内容的提问来源于stack exchange,提问作者Ken
相关产品推荐
相关产品推荐

