NetAnalyzer笔记 之 六 用C#打造自己的网络连接进程查看器(为进程抓包做准备)
[创建时间:2016-04-13 22:37:00]
起因
最近因为NetAnalyzer2016的发布,好多人都提出是否可以在NetAnalyzer中加入一个基于进程的抓包功能。所以最近研究了一下大概有这样一个想法:
获取系统打开端口的所有进程,并获取进程所开启的端口、IP地址以及使用的协议等信息,然后生成对应的过滤表达式,然后给NetAnalyzer设置该过滤表达式,然后开始抓包。
开始
虽然.Net中提供了进程信息查看的相关库,但是却没有提供相关网络端口查询的功能,所以也没有过多深入的研究,就把注意打到了Windows API 的头上。最后经过一番查找与总结,最后找到了两个方法,
在iphlpapi.dll 针对于TCP和UDP分别是
DWORD GetExtendedTcpTable(
_Out_ PVOID pTcpTable,
_Inout_ PDWORD pdwSize,
_In_ BOOL bOrder,
_In_ ULONG ulAf,
_In_ TCP_TABLE_CLASS TableClass,
_In_ ULONG Reserved
);
DWORD GetExtendedUdpTable(
_Out_ PVOID pUdpTable,
_Inout_ PDWORD pdwSize,
_In_ BOOL bOrder,
_In_ ULONG ulAf,
_In_ UDP_TABLE_CLASS TableClass,
_In_ ULONG Reserved
);
找到了对应的接口方法,那么接下来要做的就是对这个接口进行c#封装,因为这两个接口还带一些结构体,此处就不卖关子了,先看图,后面直接把可用的代码贴出来
以下是核心代码
1 using System; 2 using System.Collections.Generic; 3 using System.Diagnostics; 4 using System.Runtime.InteropServices; 5 using System.Text; 6 7 namespace ProcessViewer 8 { 9 public class NetProcessAPI 10 { 11 12 /// <summary> 13 /// 获取TCP连接对象 14 /// </summary> 15 /// <param name="pTcpTable"></param> 16 /// <param name="dwOutBufLen"></param> 17 /// <param name="sort"></param> 18 /// <param name="ipVersion"></param> 19 /// <param name="tblClass"></param> 20 /// <param name="reserved"></param> 21 /// <returns></returns> 22 [DllImport("iphlpapi.dll", SetLastError = true)] 23 private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwOutBufLen, bool sort, int ipVersion, TCP_TABLE_CLASS tblClass, uint reserved = 0); 24 25 26 /// <summary> 27 /// 获取UDP连接对象 28 /// </summary> 29 /// <param name="pTcpTable"></param> 30 /// <param name="dwOutBufLen"></param> 31 /// <param name="sort"></param> 32 /// <param name="ipVersion"></param> 33 /// <param name="tblClass"></param> 34 /// <param name="reserved"></param> 35 /// <returns></returns> 36 [DllImport("iphlpapi.dll", SetLastError = true)] 37 private static extern uint GetExtendedUdpTable(IntPtr pUdpTable, ref int dwOutBufLen, bool sort, int ipVersion, UDP_TABLE_CLASS tblClass, uint reserved = 0); 38 39 40 /// <summary> 41 ///获取TCP连接对象 42 /// </summary> 43 /// <returns></returns> 44 public static TcpRow[] GetAllTcpConnections() 45 { 46 TcpRow[] tTable; 47 int AF_INET = 2; // IP_v4 48 int buffSize = 0; 49 uint ret = GetExtendedTcpTable(IntPtr.Zero, ref buffSize, true, AF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL); 50 IntPtr buffTable = Marshal.AllocHGlobal(buffSize); 51 try 52 { 53 ret = GetExtendedTcpTable(buffTable, ref buffSize, true, AF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL); 54 if (ret != 0) 55 { 56 return null; 57 } 58 TcpTable tab = (TcpTable)Marshal.PtrToStructure(buffTable, typeof(TcpTable)); 59 IntPtr rowPtr = (IntPtr)((long)buffTable + Marshal.SizeOf(tab.dwNumEntries)); 60 tTable = new TcpRow[tab.dwNumEntries]; 61 62 for (int i = 0; i < tab.dwNumEntries; i++) 63 { 64 TcpRow tcpRow = (TcpRow)Marshal.PtrToStructure(rowPtr, typeof(TcpRow)); 65 tTable[i] = tcpRow; 66 rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(tcpRow)); // next entry 67 } 68 } 69 finally 70 { 71 Marshal.FreeHGlobal(buffTable); 72 } 73 return tTable; 74 } 75 76 77 /// <summary> 78 ///获取udp连接对象 79 /// </summary> 80 /// <returns></returns> 81 public static UdpRow[] GetAllUdpConnections() 82 { 83 UdpRow[] tTable; 84 int AF_INET = 2; // IP_v4 85 int buffSize = 0; 86 uint ret = GetExtendedUdpTable(IntPtr.Zero, ref buffSize, true, AF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID); 87 IntPtr buffTable = Marshal.AllocHGlobal(buffSize); 88 try 89 { 90 ret = GetExtendedUdpTable(buffTable, ref buffSize, true, AF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID); 91 if (ret != 0) 92 { 93 return null; 94 } 95 UdpTable tab = (UdpTable)Marshal.PtrToStructure(buffTable, typeof(UdpTable)); 96 IntPtr rowPtr = (IntPtr)((long)buffTable + Marshal.SizeOf(tab.dwNumEntries)); 97 tTable = new UdpRow[tab.dwNumEntries]; 98 99 for (int i = 0; i < tab.dwNumEntries; i++) 100 { 101 UdpRow udpRow = (UdpRow)Marshal.PtrToStructure(rowPtr, typeof(UdpRow)); 102 tTable[i] = udpRow; 103 rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(udpRow)); // next entry 104 } 105 } 106 finally 107 { 108 Marshal.FreeHGlobal(buffTable); 109 } 110 return tTable; 111 } 112 113 114 115 #region 针对于TCP管理 116 /** 由于该部分使用到了Linq查询 需要.Net版本较高(当前使用的是.Net2.0),再着该部分代码在现有功能点并不需要, 所以注释了(主要是我懒得改了 ^_^) 117 /// <summary> 118 /// 设置 119 /// </summary> 120 /// <param name="pRow"></param> 121 /// <returns></returns> 122 [DllImport("iphlpapi.dll", SetLastError = true)] 123 public static extern uint SetTcpEntry(IntPtr pRow); 124 public static void CloseConnByLocalPort(int port) 125 { 126 var tcpRows = GetAllTcpConnections(); 127 var tmpRows = from i in tcpRows 128 where i.LocalPort == port 129 select i; 130 TcpRow[] tcpArry = tmpRows.ToArray(); 131 for (int i = 0; i < tcpArry.Length; i++) 132 { 133 tcpArry[i].state = ConnectionState.Delete_TCB; 134 SetTcpEntry(GetPtrToNewObject(tcpArry[i])); 135 } 136 } 137 public static IntPtr GetPtrToNewObject(object obj) 138 { 139 IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(obj)); 140 Marshal.StructureToPtr(obj, ptr, false); 141 return ptr; 142 } 143 * */ 144 #endregion 145 } 146 147 148 149 #region TCP返回的数据结构 150 /// <summary> 151 /// TCP表类型 152 /// </summary> 153 public enum TCP_TABLE_CLASS 154 { 155 TCP_TABLE_BASIC_LISTENER, 156 TCP_TABLE_BASIC_CONNECTIONS, 157 TCP_TABLE_BASIC_ALL, 158 TCP_TABLE_OWNER_PID_LISTENER, 159 TCP_TABLE_OWNER_PID_CONNECTIONS, 160 TCP_TABLE_OWNER_PID_ALL, 161 TCP_TABLE_OWNER_MODULE_LISTENER, 162 TCP_TABLE_OWNER_MODULE_CONNECTIONS, 163 TCP_TABLE_OWNER_MODULE_ALL 164 } 165 /// <summary> 166 /// TCP当前状态 167 /// </summary> 168 public enum ConnectionState : int 169 { 170 /// <summary> All </summary> 171 All = 0, 172 /// <summary> Closed </summary> 173 Closed = 1, 174 /// <summary> Listen </summary> 175 Listen = 2, 176 /// <summary> Syn_Sent </summary> 177 Syn_Sent = 3, 178 /// <summary> Syn_Rcvd </summary> 179 Syn_Rcvd = 4, 180 /// <summary> Established </summary> 181 Established = 5, 182 /// <summary> Fin_Wait1 </summary> 183 Fin_Wait1 = 6, 184 /// <summary> Fin_Wait2 </summary> 185 Fin_Wait2 = 7, 186 /// <summary> Close_Wait </summary> 187 Close_Wait = 8, 188 /// <summary> Closing </summary> 189 Closing = 9, 190 /// <summary> Last_Ack </summary> 191 Last_Ack = 10, 192 /// <summary> Time_Wait </summary> 193 Time_Wait = 11, 194 /// <summary> Delete_TCB </summary> 195 Delete_TCB = 12 196 } 197 198 199 /// <summary> 200 /// TCP列结构(行) 201 /// </summary> 202 [StructLayout(LayoutKind.Sequential)] 203 public struct TcpRow 204 { 205 // DWORD is System.UInt32 in C# 206 public ConnectionState state; 207 public uint localAddr; 208 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 209 public byte[] localPort; 210 public uint remoteAddr; 211 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 212 public byte[] remotePort; 213 public int owningPid; 214 public System.Net.IPAddress LocalAddress 215 { 216 get 217 { 218 return new System.Net.IPAddress(localAddr); 219 } 220 } 221 public ushort LocalPort 222 { 223 get 224 { 225 return BitConverter.ToUInt16( 226 new byte[2] { localPort[1], localPort[0] }, 0); 227 } 228 } 229 public System.Net.IPAddress RemoteAddress 230 { 231 get 232 { 233 return new System.Net.IPAddress(remoteAddr); 234 } 235 } 236 public ushort RemotePort 237 { 238 get 239 { 240 return BitConverter.ToUInt16( 241 new byte[2] { remotePort[1], remotePort[0] }, 0); 242 } 243 } 244 } 245 246 /// <summary> 247 /// TCP表结构 248 /// </summary> 249 [StructLayout(LayoutKind.Sequential)] 250 public struct TcpTable 251 { 252 public uint dwNumEntries; 253 TcpRow table; 254 } 255 #endregion 256 257 258 259 260 #region UDP结构 261 262 /// <summary> 263 /// UDP表类型 264 /// </summary> 265 public enum UDP_TABLE_CLASS 266 { 267 UDP_TABLE_BASIC, 268 UDP_TABLE_OWNER_PID, 269 UDP_TABLE_OWNER_MODULE 270 } 271 272 273 274 /// <summary> 275 /// TCP列结构(行) 276 /// </summary> 277 [StructLayout(LayoutKind.Sequential)] 278 public struct UdpRow 279 { 280 public uint localAddr; 281 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 282 public byte[] localPort; 283 public int owningPid; 284 public System.Net.IPAddress LocalAddress 285 { 286 get 287 { 288 return new System.Net.IPAddress(localAddr); 289 } 290 } 291 public ushort LocalPort 292 { 293 get 294 { 295 return BitConverter.ToUInt16( 296 new byte[2] { localPort[1], localPort[0] }, 0); 297 } 298 } 299 } 300 301 302 /// <summary> 303 /// UDP表结构 304 /// </summary> 305 [StructLayout(LayoutKind.Sequential)] 306 public struct UdpTable 307 { 308 public uint dwNumEntries; 309 UdpRow table; 310 } 311 #endregion 312 313 314 }
分别通过上面的GetAllTcpConnections()方法和GetAllUdpConnections() 可获得TCP和UDP的所有当前在线的进程,
额外给一段通过进程号获取应用图标的代码
1 using System; 2 using System.Collections.Generic; 3 using System.Diagnostics; 4 using System.Drawing; 5 using System.Runtime.InteropServices; 6 using System.Text; 7 8 namespace ProcessViewer 9 { 10 11 /// <summary> 12 /// 通过API获取进程图标 13 /// </summary> 14 public class ProcessAPI 15 { 16 [DllImport("Shell32.dll")] 17 private static extern int SHGetFileInfo 18 ( 19 string pszPath, 20 uint dwFileAttributes, 21 out SHFILEINFO psfi, 22 uint cbfileInfo, 23 SHGFI uFlags 24 ); 25 26 [StructLayout(LayoutKind.Sequential)] 27 private struct SHFILEINFO 28 { 29 public SHFILEINFO(bool b) 30 { 31 hIcon = IntPtr.Zero; iIcon = 0; dwAttributes = 0; szDisplayName = ""; szTypeName = ""; 32 } 33 public IntPtr hIcon; 34 public int iIcon; 35 public uint dwAttributes; 36 [MarshalAs(UnmanagedType.LPStr, SizeConst = 260)] 37 public string szDisplayName; 38 [MarshalAs(UnmanagedType.LPStr, SizeConst = 80)] 39 public string szTypeName; 40 }; 41 42 private enum SHGFI 43 { 44 SmallIcon = 0x00000001, 45 LargeIcon = 0x00000000, 46 Icon = 0x00000100, 47 DisplayName = 0x00000200, 48 Typename = 0x00000400, 49 SysIconIndex = 0x00004000, 50 UseFileAttributes = 0x00000010 51 } 52 //获取进程图标 53 public static Icon GetIcon(string strPath, bool bSmall) 54 { 55 SHFILEINFO info = new SHFILEINFO(true); 56 int cbFileInfo = Marshal.SizeOf(info); 57 SHGFI flags; 58 if (bSmall) 59 flags = SHGFI.Icon | SHGFI.SmallIcon | SHGFI.UseFileAttributes; 60 else 61 flags = SHGFI.Icon | SHGFI.LargeIcon | SHGFI.UseFileAttributes; 62 63 SHGetFileInfo(strPath, 256, out info, (uint)cbFileInfo, flags); 64 return Icon.FromHandle(info.hIcon); 65 } 66 67 68 //获取进程图标 69 public static Icon GetIcon(int pid, bool bSmall) 70 { 71 72 try 73 { 74 var p = System.Diagnostics.Process.GetProcessById(pid); 75 76 return GetIcon(p.MainModule.FileName, bSmall); 77 } 78 catch (Exception ex) 79 { 80 return null; 81 } 82 } 83 84 //获取进程名称 85 public static string GetProcessNameByPID(int processID) 86 { 87 //could be an error here if the process die before we can get his name 88 try 89 { 90 Process p = Process.GetProcessById((int)processID); 91 return p.ProcessName; 92 } 93 catch (Exception ex) 94 { 95 return "Unknown"; 96 } 97 } 98 } 99 }
我们已经完成了进程信息的获取
那么接下来就是使用了,其实使用起来还是非常容易的
1 private void loadProcess() 2 { 3 dataGridProcess.Rows.Clear(); 4 //tcp 5 foreach (var p in NetProcessAPI.GetAllTcpConnections()) 6 { 7 var icon=ProcessAPI.GetIcon(p.owningPid, true); 8 dataGridProcess.Rows.Add(new object[] { icon==null?Properties.Resources.app:icon, ProcessAPI.GetProcessNameByPID(p.owningPid), "TCP", p.LocalAddress.ToString(), p.LocalPort.ToString(), p.RemoteAddress.ToString(), p.RemotePort.ToString() }); 9 } 10 //udp 11 foreach (var p in NetProcessAPI.GetAllUdpConnections()) 12 { 13 var icon = ProcessAPI.GetIcon(p.owningPid, true); 14 dataGridProcess.Rows.Add(new object[] { icon == null ? Properties.Resources.app : icon, ProcessAPI.GetProcessNameByPID(p.owningPid), "UDP", p.LocalAddress.ToString(), p.LocalPort.ToString(), "-", "-" }); 15 } 16 }
好了就写到这里了
欢迎关注NetAnalyzer公众平台,感谢使用NetAnalyzer2016
示例代码下载:https://files.cnblogs.com/files/twzy/MyTcpView.zip