NetAnalyzer笔记 之 六 用C#打造自己的网络连接进程查看器(为进程抓包做准备)

[创建时间:2016-04-13 22:37:00]

NetAnalyzer下载地址

起因

最近因为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

 

 

posted @ 2016-04-13 22:46  淡墨青云  阅读(4427)  评论(3编辑  收藏  举报