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#封装,因为这两个接口还带一些结构体,此处就不卖关子了,先看图,后面直接把可用的代码贴出来

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

以下是核心代码

 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text; namespace ProcessViewer
{
public class NetProcessAPI
{ /// <summary>
/// 获取TCP连接对象
/// </summary>
/// <param name="pTcpTable"></param>
/// <param name="dwOutBufLen"></param>
/// <param name="sort"></param>
/// <param name="ipVersion"></param>
/// <param name="tblClass"></param>
/// <param name="reserved"></param>
/// <returns></returns>
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwOutBufLen, bool sort, int ipVersion, TCP_TABLE_CLASS tblClass, uint reserved = ); /// <summary>
/// 获取UDP连接对象
/// </summary>
/// <param name="pTcpTable"></param>
/// <param name="dwOutBufLen"></param>
/// <param name="sort"></param>
/// <param name="ipVersion"></param>
/// <param name="tblClass"></param>
/// <param name="reserved"></param>
/// <returns></returns>
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern uint GetExtendedUdpTable(IntPtr pUdpTable, ref int dwOutBufLen, bool sort, int ipVersion, UDP_TABLE_CLASS tblClass, uint reserved = ); /// <summary>
///获取TCP连接对象
/// </summary>
/// <returns></returns>
public static TcpRow[] GetAllTcpConnections()
{
TcpRow[] tTable;
int AF_INET = ; // IP_v4
int buffSize = ;
uint ret = GetExtendedTcpTable(IntPtr.Zero, ref buffSize, true, AF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL);
IntPtr buffTable = Marshal.AllocHGlobal(buffSize);
try
{
ret = GetExtendedTcpTable(buffTable, ref buffSize, true, AF_INET, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL);
if (ret != )
{
return null;
}
TcpTable tab = (TcpTable)Marshal.PtrToStructure(buffTable, typeof(TcpTable));
IntPtr rowPtr = (IntPtr)((long)buffTable + Marshal.SizeOf(tab.dwNumEntries));
tTable = new TcpRow[tab.dwNumEntries]; for (int i = ; i < tab.dwNumEntries; i++)
{
TcpRow tcpRow = (TcpRow)Marshal.PtrToStructure(rowPtr, typeof(TcpRow));
tTable[i] = tcpRow;
rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(tcpRow)); // next entry
}
}
finally
{
Marshal.FreeHGlobal(buffTable);
}
return tTable;
} /// <summary>
///获取udp连接对象
/// </summary>
/// <returns></returns>
public static UdpRow[] GetAllUdpConnections()
{
UdpRow[] tTable;
int AF_INET = ; // IP_v4
int buffSize = ;
uint ret = GetExtendedUdpTable(IntPtr.Zero, ref buffSize, true, AF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID);
IntPtr buffTable = Marshal.AllocHGlobal(buffSize);
try
{
ret = GetExtendedUdpTable(buffTable, ref buffSize, true, AF_INET, UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID);
if (ret != )
{
return null;
}
UdpTable tab = (UdpTable)Marshal.PtrToStructure(buffTable, typeof(UdpTable));
IntPtr rowPtr = (IntPtr)((long)buffTable + Marshal.SizeOf(tab.dwNumEntries));
tTable = new UdpRow[tab.dwNumEntries]; for (int i = ; i < tab.dwNumEntries; i++)
{
UdpRow udpRow = (UdpRow)Marshal.PtrToStructure(rowPtr, typeof(UdpRow));
tTable[i] = udpRow;
rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(udpRow)); // next entry
}
}
finally
{
Marshal.FreeHGlobal(buffTable);
}
return tTable;
} #region 针对于TCP管理
/** 由于该部分使用到了Linq查询 需要.Net版本较高(当前使用的是.Net2.0),再着该部分代码在现有功能点并不需要, 所以注释了(主要是我懒得改了 ^_^)
/// <summary>
/// 设置
/// </summary>
/// <param name="pRow"></param>
/// <returns></returns>
[DllImport("iphlpapi.dll", SetLastError = true)]
public static extern uint SetTcpEntry(IntPtr pRow);
public static void CloseConnByLocalPort(int port)
{
var tcpRows = GetAllTcpConnections();
var tmpRows = from i in tcpRows
where i.LocalPort == port
select i;
TcpRow[] tcpArry = tmpRows.ToArray();
for (int i = 0; i < tcpArry.Length; i++)
{
tcpArry[i].state = ConnectionState.Delete_TCB;
SetTcpEntry(GetPtrToNewObject(tcpArry[i]));
}
}
public static IntPtr GetPtrToNewObject(object obj)
{
IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
* */
#endregion
} #region TCP返回的数据结构
/// <summary>
/// TCP表类型
/// </summary>
public enum TCP_TABLE_CLASS
{
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL,
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
}
/// <summary>
/// TCP当前状态
/// </summary>
public enum ConnectionState : int
{
/// <summary> All </summary>
All = ,
/// <summary> Closed </summary>
Closed = ,
/// <summary> Listen </summary>
Listen = ,
/// <summary> Syn_Sent </summary>
Syn_Sent = ,
/// <summary> Syn_Rcvd </summary>
Syn_Rcvd = ,
/// <summary> Established </summary>
Established = ,
/// <summary> Fin_Wait1 </summary>
Fin_Wait1 = ,
/// <summary> Fin_Wait2 </summary>
Fin_Wait2 = ,
/// <summary> Close_Wait </summary>
Close_Wait = ,
/// <summary> Closing </summary>
Closing = ,
/// <summary> Last_Ack </summary>
Last_Ack = ,
/// <summary> Time_Wait </summary>
Time_Wait = ,
/// <summary> Delete_TCB </summary>
Delete_TCB =
} /// <summary>
/// TCP列结构(行)
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TcpRow
{
// DWORD is System.UInt32 in C#
public ConnectionState state;
public uint localAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] localPort;
public uint remoteAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] remotePort;
public int owningPid;
public System.Net.IPAddress LocalAddress
{
get
{
return new System.Net.IPAddress(localAddr);
}
}
public ushort LocalPort
{
get
{
return BitConverter.ToUInt16(
new byte[] { localPort[], localPort[] }, );
}
}
public System.Net.IPAddress RemoteAddress
{
get
{
return new System.Net.IPAddress(remoteAddr);
}
}
public ushort RemotePort
{
get
{
return BitConverter.ToUInt16(
new byte[] { remotePort[], remotePort[] }, );
}
}
} /// <summary>
/// TCP表结构
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TcpTable
{
public uint dwNumEntries;
TcpRow table;
}
#endregion #region UDP结构 /// <summary>
/// UDP表类型
/// </summary>
public enum UDP_TABLE_CLASS
{
UDP_TABLE_BASIC,
UDP_TABLE_OWNER_PID,
UDP_TABLE_OWNER_MODULE
} /// <summary>
/// TCP列结构(行)
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct UdpRow
{
public uint localAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public byte[] localPort;
public int owningPid;
public System.Net.IPAddress LocalAddress
{
get
{
return new System.Net.IPAddress(localAddr);
}
}
public ushort LocalPort
{
get
{
return BitConverter.ToUInt16(
new byte[] { localPort[], localPort[] }, );
}
}
} /// <summary>
/// UDP表结构
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct UdpTable
{
public uint dwNumEntries;
UdpRow table;
}
#endregion }

分别通过上面的GetAllTcpConnections()方法和GetAllUdpConnections() 可获得TCP和UDP的所有当前在线的进程,

额外给一段通过进程号获取应用图标的代码

 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text; namespace ProcessViewer
{ /// <summary>
/// 通过API获取进程图标
/// </summary>
public class ProcessAPI
{
[DllImport("Shell32.dll")]
private static extern int SHGetFileInfo
(
string pszPath,
uint dwFileAttributes,
out SHFILEINFO psfi,
uint cbfileInfo,
SHGFI uFlags
); [StructLayout(LayoutKind.Sequential)]
private struct SHFILEINFO
{
public SHFILEINFO(bool b)
{
hIcon = IntPtr.Zero; iIcon = ; dwAttributes = ; szDisplayName = ""; szTypeName = "";
}
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.LPStr, SizeConst = )]
public string szDisplayName;
[MarshalAs(UnmanagedType.LPStr, SizeConst = )]
public string szTypeName;
}; private enum SHGFI
{
SmallIcon = 0x00000001,
LargeIcon = 0x00000000,
Icon = 0x00000100,
DisplayName = 0x00000200,
Typename = 0x00000400,
SysIconIndex = 0x00004000,
UseFileAttributes = 0x00000010
}
//获取进程图标
public static Icon GetIcon(string strPath, bool bSmall)
{
SHFILEINFO info = new SHFILEINFO(true);
int cbFileInfo = Marshal.SizeOf(info);
SHGFI flags;
if (bSmall)
flags = SHGFI.Icon | SHGFI.SmallIcon | SHGFI.UseFileAttributes;
else
flags = SHGFI.Icon | SHGFI.LargeIcon | SHGFI.UseFileAttributes; SHGetFileInfo(strPath, , out info, (uint)cbFileInfo, flags);
return Icon.FromHandle(info.hIcon);
} //获取进程图标
public static Icon GetIcon(int pid, bool bSmall)
{ try
{
var p = System.Diagnostics.Process.GetProcessById(pid); return GetIcon(p.MainModule.FileName, bSmall);
}
catch (Exception ex)
{
return null;
}
} //获取进程名称
public static string GetProcessNameByPID(int processID)
{
//could be an error here if the process die before we can get his name
try
{
Process p = Process.GetProcessById((int)processID);
return p.ProcessName;
}
catch (Exception ex)
{
return "Unknown";
}
}
}
}

我们已经完成了进程信息的获取

那么接下来就是使用了,其实使用起来还是非常容易的

         private void loadProcess()
{
dataGridProcess.Rows.Clear();
//tcp
foreach (var p in NetProcessAPI.GetAllTcpConnections())
{
var icon=ProcessAPI.GetIcon(p.owningPid, true);
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() });
}
//udp
foreach (var p in NetProcessAPI.GetAllUdpConnections())
{
var icon = ProcessAPI.GetIcon(p.owningPid, true);
dataGridProcess.Rows.Add(new object[] { icon == null ? Properties.Resources.app : icon, ProcessAPI.GetProcessNameByPID(p.owningPid), "UDP", p.LocalAddress.ToString(), p.LocalPort.ToString(), "-", "-" });
}
}

好了就写到这里了

欢迎关注NetAnalyzer公众平台,感谢使用NetAnalyzer2016

示例代码下载:http://files.cnblogs.com/files/twzy/MyTcpView.zip

上一篇:字典_特点_4种创建方式_普通-dict


下一篇:NBA为什么29号没人敢穿?