进程管理程序大家都不陌生,通过CreateToolhelp32Snapshot/Process32First/Process32Next系列函数或者PSAPI库不难探出
其中的信息,但对进程是否有网络操作,监听的端口,远程地址,远程端口却力不从心了。然而这种监视对于分析某些恶意软
又十分必要,所以我们的目标就是打操,具有网络监视功能的最终梦幻版本。实现效果如图1所示。
实现方法
NETSTAT -A -N 这条命令可以打印出本地的TCP和UDP连接信息,在06年的杂志上古开元在《解析网络执法官》系列文章中实现
了NETSTAT的功能,方法是使用GetTcpTable和GetUdpTable两个函数得到信息列表,但它却无法实现连接信息与进程的对照,
所以我们还要找其它方法。不能用你还说,给你一顿暴K,当然我也没是没事找刺激,因为在它的基础上MS提供了住处另外的
函数可以达到我们的目得。他们是AllocateAndGetTcpExTableFromStack和AllocateAndGetUdpExTableFromStack,与
GetTcpTable和GetUdpTable相比,扩展函数包含了正在使用当前连接进程的ID号,有了进程ID我们就可以做事了。
版本要求
在开始之前还有些事情要做,请确认一下自己操作系统的版本,因为扩展函数是在WINDOWS XP 和更高版本中所提供的
IP帮助函数,而在WINDOWS2000中是无法使用的。不过如果你的WIN2000上安装了VS2003或VS20005那么就可以使用了(包括编写和运行)。
此扩展函数的原形定义在Iphipapi.h文件中,在使用时,必须链接到Iphlpapi.lib库。
函数原型和结构
因为函数所需的结构是没有公开的,使用时要自己定义。我们从函数本身开始介绍
AllocateAndGetTcpExTableFromStack和AllocateAndGetUdpExTableFromStack函数在使用时要用iphlpapi.dll中
动态获取扩展函数的入口地址,其示例代码如下:
细节实现
跟据上文所返回的结构我们可以从中提取需要的信息,包括本地/远程IP,端口状态,进程名称,进程路径等等
各个信息定义如下
与TCP进程相比UDP是无连接的协议,所以它只有本地IP/端口/进程ID三项,比TCP简单很多,实现上也相差无几,在里就不
再详细说明了,详细实现可以看原代码。
这样整个程序就完工了,因为关注重点是对网络进程的监视,所没有添加结束进程,或查看进程模快的部分,不过有兴趣
的话可以自己进行扩展,来打操真正的梦幻版本。本文参考了张越著的《VC网络程序设计》中的实例,如果有问题可以到
客黑防线的论坛或我的BLOG Http://blog.youkuaiyun.com/chinafe上讨论不论是鼓励还是暴K我都很高兴......。
其中的信息,但对进程是否有网络操作,监听的端口,远程地址,远程端口却力不从心了。然而这种监视对于分析某些恶意软
又十分必要,所以我们的目标就是打操,具有网络监视功能的最终梦幻版本。实现效果如图1所示。
实现方法
NETSTAT -A -N 这条命令可以打印出本地的TCP和UDP连接信息,在06年的杂志上古开元在《解析网络执法官》系列文章中实现
了NETSTAT的功能,方法是使用GetTcpTable和GetUdpTable两个函数得到信息列表,但它却无法实现连接信息与进程的对照,
所以我们还要找其它方法。不能用你还说,给你一顿暴K,当然我也没是没事找刺激,因为在它的基础上MS提供了住处另外的
函数可以达到我们的目得。他们是AllocateAndGetTcpExTableFromStack和AllocateAndGetUdpExTableFromStack,与
GetTcpTable和GetUdpTable相比,扩展函数包含了正在使用当前连接进程的ID号,有了进程ID我们就可以做事了。
版本要求
在开始之前还有些事情要做,请确认一下自己操作系统的版本,因为扩展函数是在WINDOWS XP 和更高版本中所提供的
IP帮助函数,而在WINDOWS2000中是无法使用的。不过如果你的WIN2000上安装了VS2003或VS20005那么就可以使用了(包括编写和运行)。
此扩展函数的原形定义在Iphipapi.h文件中,在使用时,必须链接到Iphlpapi.lib库。
函数原型和结构
因为函数所需的结构是没有公开的,使用时要自己定义。我们从函数本身开始介绍
AllocateAndGetTcpExTableFromStack和AllocateAndGetUdpExTableFromStack函数在使用时要用iphlpapi.dll中
动态获取扩展函数的入口地址,其示例代码如下:
复制内容到剪贴板
在成功得到函数入口后就可以获取TCP/UDP进程和网络信息列表了其代码如下
代码:
HMODULE hModule = ::LoadLibrary("iphlpapi.dll");
//获取TCP列表
pAllocateAndGetTcpExTableFromStack =
(PFNAllocateAndGetTcpExTableFromStack)::GetProcAddress(hModule,
"AllocateAndGetTcpExTableFromStack");
//获取UDP列表
pAllocateAndGetUdpExTableFromStack =
(PFNAllocateAndGetUdpExTableFromStack)::GetProcAddress(hModule,
"AllocateAndGetUdpExTableFromStack");
其中pAllocateAndGetTcpExTableFromStack 和pAllocateAndGetUdpExTableFromStack 是扩展函数指针如下
PFNAllocateAndGetTcpExTableFromStack pAllocateAndGetTcpExTableFromStack;
PFNAllocateAndGetUdpExTableFromStack pAllocateAndGetUdpExTableFromStack;
而PFNAllocateAndGetTcpExTableFromStack和PFNAllocateAndGetUdpExTableFromStack则是
由我们自己定义扩展函数原型代码如下:
typedef DWORD (WINAPI *PFNAllocateAndGetTcpExTableFromStack)(
PMIB_TCPEXTABLE *pTcpTable,
BOOL bOrder,
HANDLE heap,
DWORD zero,
DWORD flags
);
typedef DWORD (WINAPI *PFNAllocateAndGetUdpExTableFromStack)(
PMIB_UDPEXTABLE *pUdpTable,
BOOL bOrder,
HANDLE heap,
DWORD zero,
DWORD flags
);
复制内容到剪贴板
其中 PMIB_TCPEXTABLE和PMIB_UDPEXTABLE是自己定义的结构,用来接受列表信息,它们的原形如下
代码:
PMIB_TCPEXTABLE pTcpExTable;
PMIB_UDPEXTABLE pUdpExTable;
if(pAllocateAndGetTcpExTableFromStack(&pTcpExTable, TRUE, GetProcessHeap(), 2, 2) != 0)
{
MessageBox(" TCP列表失败/n");
}
if(pAllocateAndGetUdpExTableFromStack(&pUdpExTable, TRUE, GetProcessHeap(), 2, 2) != 0)
{
MessageBox(" UPD列表失败/n");
}
复制内容到剪贴板
上面的结构信息的说明十分详细,也是程序的核心,这样子我们就可以得进程的ID和其它信息了,下面我再
讨论其具体实现.
代码:
typedef struct
{
DWORD dwState; // 连接状态
DWORD dwLocalAddr; // 本地地址
DWORD dwLocalPort; // 本地端口
DWORD dwRemoteAddr; // 远程地址
DWORD dwRemotePort; // 远程端口
DWORD dwProcessId; // 进程ID号
} MIB_TCPEXROW, *PMIB_TCPEXROW;
typedef struct
{
DWORD dwNumEntries;
MIB_TCPEXROW table[ANY_SIZE];
} MIB_TCPEXTABLE, *PMIB_TCPEXTABLE;
typedef struct
{
DWORD dwLocalAddr; // 本地地址
DWORD dwLocalPort; // 本地端口
DWORD dwProcessId; // 进程ID号
} MIB_UDPEXROW, *PMIB_UDPEXROW;
typedef struct
{
DWORD dwNumEntries;
MIB_UDPEXROW table[ANY_SIZE];
} MIB_UDPEXTABLE, *PMIB_UDPEXTABLE;
细节实现
跟据上文所返回的结构我们可以从中提取需要的信息,包括本地/远程IP,端口状态,进程名称,进程路径等等
各个信息定义如下
复制内容到剪贴板
本地IP地址
代码:
char szLocalAddr[128];
char szRemoteAddr[128];
char szProcessName[128];
in_addr inadLocal;
in_addr inadRemote;
char strState[128];
DWORD dwRemotePort = 0;
复制内容到剪贴板
远程端口
代码:
inadLocal.s_addr = pTcpExTable->table[i].dwLocalAddr;
复制内容到剪贴板
远程IP地址
代码:
if(strcmp(strState, "LISTEN") != 0)
{
dwRemotePort = pTcpExTable->table[i].dwRemotePort;
}
else
dwRemotePort = 0;
复制内容到剪贴板
格式化地址+端口
代码:
inadRemote.s_addr = pTcpExTable->table[i].dwRemoteAddr;
复制内容到剪贴板
连接状态
代码:
sprintf(szLocalAddr, "%s:%u", inet_ntoa(inadLocal),
ntohs((unsigned short)(0x0000FFFF & pTcpExTable->table[i].dwLocalPort)));
sprintf(szRemoteAddr, "%s:%u", inet_ntoa(inadRemote),
ntohs((unsigned short)(0x0000FFFF & dwRemotePort)));
复制内容到剪贴板
进程名称/路径
代码:
switch (pTcpExTable->table[i].dwState)
{
case MIB_TCP_STATE_CLOSED:
strcpy(strState, "CLOSED");
break;
case MIB_TCP_STATE_TIME_WAIT:
strcpy(strState, "TIME_WAIT");
break;
case MIB_TCP_STATE_LAST_ACK:
strcpy(strState, "LAST_ACK");
break;
case MIB_TCP_STATE_CLOSING:
strcpy(strState, "CLOSING");
break;
case MIB_TCP_STATE_CLOSE_WAIT:
strcpy(strState, "CLOSE_WAIT");
break;
case MIB_TCP_STATE_FIN_WAIT1:
strcpy(strState, "FIN_WAIT1");
break;
case MIB_TCP_STATE_ESTAB:
strcpy(strState, "ESTAB");
break;
case MIB_TCP_STATE_SYN_RCVD:
strcpy(strState, "SYN_RCVD");
break;
case MIB_TCP_STATE_SYN_SENT:
strcpy(strState, "SYN_SENT");
break;
case MIB_TCP_STATE_LISTEN:
strcpy(strState, "LISTEN");
break;
case MIB_TCP_STATE_DELETE_TCB:
strcpy(strState, "DELETE");
break;
default:
printf("Error: unknown state!/n");
break;
}
复制内容到剪贴板
UDP的进程信息
代码:
hProcess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,pTcpExTable->table[i].dwProcessId);
EnumProcessModules(hProcess, &hModule, sizeof(hModule), &needed); //枚举进程模块
GetModuleFileNameEx(hProcess, hModule, Path, sizeof(Path)); //得到进程路径
GetModuleBaseName (hProcess, hModule, Name, sizeof(Name)); //得到进程名称
在上的实现都应该在以下的循环内进行
for(UINT i = 0; i < pTcpExTable->dwNumEntries; ++i)
{
.........//实现代码
}
与TCP进程相比UDP是无连接的协议,所以它只有本地IP/端口/进程ID三项,比TCP简单很多,实现上也相差无几,在里就不
再详细说明了,详细实现可以看原代码。
这样整个程序就完工了,因为关注重点是对网络进程的监视,所没有添加结束进程,或查看进程模快的部分,不过有兴趣
的话可以自己进行扩展,来打操真正的梦幻版本。本文参考了张越著的《VC网络程序设计》中的实例,如果有问题可以到
客黑防线的论坛或我的BLOG Http://blog.youkuaiyun.com/chinafe上讨论不论是鼓励还是暴K我都很高兴......。