MIB_UDPEXROWtable[ANY_SIZE];
}MIB_UDPEXTABLE,*PMIB_UDPEXTABLE; //函数声明:
typedefDWORD(WINAPI*PALLOCATE_AND_GET_TCPEXTABLE_FROM_STACK)( PMIB_TCPEXTABLE*pTcpTable, BOOLbOrder, HANDLEheap, DWORDzero, DWORDflags );
typedefDWORD(WINAPI*PALLOCATE_AND_GET_UDPEXTABLE_FROM_STACK)( PMIB_UDPEXTABLE*pUdpTable, BOOLbOrder,HANDLEheap, DWORDzero, DWORDflags );
//定义函数事例入口指针,初始化为NULL
staticPALLOCATE_AND_GET_TCPEXTABLE_FROM_STACK pAllocateAndGetTcpExTableFromStack=NULL;
staticPALLOCATE_AND_GET_UDPEXTABLE_FROM_STACK pAllocateAndGetUdpExTableFromStack=NULL;
staticcharTcpState[][32]={\\
\\
//辅助函数
PCHARGetPort(unsignedintport,char*pPort) {
sprintf(pPort,\returnpPort; }
PCHARGetIp(unsignedintipaddr,char*pIP) {
unsignedintnipaddr; nipaddr=htonl(ipaddr);
sprintf(pIP,\(nipaddr>>16)&0xFF,(nipaddr>>8)&0xFF, (nipaddr)&0xFF); returnpIP; }
//加载API函数 BOOLLoadAPI() {
pAllocateAndGetTcpExTableFromStack=(PALLOCATE_AND_GET_TCPEXTABLE_
FROM_STACK)GetProcAddress(LoadLibrary(\, \if(!pAllocateAndGetTcpExTableFromStack) returnFALSE;
pAllocateAndGetUdpExTableFromStack=
(PALLOCATE_AND_GET_UDPEXTABLE_FROM_STACK) GetProcAddress(LoadLibrary(\, \if(!pAllocateAndGetUdpExTableFromStack) returnFALSE; }
intmain(intargc,char*argv[]) {
intnRetCode; DWORDi;
WSADATAWSAData; HANDLEhProcessSnap;
PMIB_TCPEXTABLETCPExTable; PMIB_UDPEXTABLEUDPExTable; charszProcessName[MAX_PATH];
charszLocalName[HOSTNAMELEN],szRemoteName[HOSTNAMELEN]; charszRemotePort[PORTNAMELEN],szLocalPort[PORTNAMELEN]; charszLocalAddress[ADDRESSLEN],szRemoteAddress[ADDRESSLEN]; nRetCode=LoadAPI(); if(nRetCode==FALSE) {
printf(\return0; }
if(WSAStartup(MAKEWORD(1,1),&WSAData)) {
printf(\return0; }
nRetCode=pAllocateAndGetTcpExTableFromStack(&TCPExTable,TRUE, GetProcessHeap(),2,2); if(nRetCode) {
printf(\return0; }
nRetCode=pAllocateAndGetUdpExTableFromStack(&UDPExTable,TRUE, GetProcessHeap(),2,2); if(nRetCode)
{
printf(\return-1; }
//GetTCPList
printf(\Address\
for(i=0;i
sprintf(szLocalAddress,\,
GetIp(TCPExTable->table[i].dwLocalAddr,szLocalName), GetPort(TCPExTable->table[i].dwLocalPort,szLocalPort) );
sprintf(szRemoteAddress,\
GetIp(TCPExTable->table[i].dwRemoteAddr,szRemoteName), GetPort(TCPExTable->table[i].dwRemotePort,szRemotePort) );
printf(\szLocalAddress,szRemoteAddress,
TcpState[TCPExTable->table[i].dwState],
GetProcessNameFromPID(TCPExTable->table[i].dwProcessId), TCPExTable->table[i].dwProcessId ); }
//GetUDPList
for(i=0;i
sprintf(szLocalAddress,\
GetIp(UDPExTable->table[i].dwLocalAddr,szLocalName), GetPort(UDPExTable->table[i].dwLocalPort,szLocalPort) );
sprintf(szRemoteAddress,\printf(\szLocalAddress,szRemoteAddress,
GetProcessNameFromPID(TCPExTable->table[i].dwProcessId), TCPExTable->table[i].dwProcessId ); }
WSACleanup(); return0; }
注意:
这段代码不能在WindowsNT/2000上运行,这是因为这两个版本的
IPHelpAPI.DLL文件没有输出上面的两个函数,采用动态加载得到的函数指针为
NULL。也许用户会想当然地说我把这个文件从XP复制到2000不就得了?值得注意 的是WindowsXP下的IPHelpAPI.DLL文件支持IPv6,这个潜在支持是借助于
NTDLL.DLL文件实现的。而Windows2000下的这个文件没有输出该库需要的IPv6 输出函数。
也许用户会问Fport是怎么实现的,可以这么说,这个程序调用了未公开的系统 接口。
还有另外一种方法是这样实现的:我们知道当一个程序创建一个socket,并开始
侦听的时候,它确定会创建一个进程句柄和打开端口的句柄。注意socket和文件句柄、 进程句柄一样也是一种系统对象。通过使用特殊的参数调用NtDeviceIoControlFile函 数,就会知道如何得知端口是哪一个进程句柄打开的。尽管系统中存在着大量的开放 句柄,但是这里只关心\\Device\\Tcp和\\Device\\Udp。
当我们对iphlpapi.dll反汇编的时候会发现,上面这些函数实际上是调用
NtDeviceIoControlFile实现的,这个函数会把系统中得到的所有开放端口列表发送到 一个特别的缓冲区中。
由于socket和窗口句柄、文件句柄、进程句柄等句柄一样都是系统对象,都被统 一保存在一个系统的内核结构定义里面,分别具有不同的句柄类型,因此可以通过调 用NtQuerySystemInformation函数遍历给定类型的所有句柄信息。这里我们只关心 OBJECT_TYPE_SOCKET类型和进程标识不为空的情况。对于得到每一个套接字句
柄,我们可以通过把它转化成套接字,然后调用getsockname和getsockopt函数反向 得到其端口协议和地址信息。对于状态信息,可以借助于调用上面的GetUdpTable和 GetTcpTable实现。
值得注意的是,上面得到的套接字(socket)句柄都属于其他的进程。根据NT内核
进程保护的原则,一个进程是不能直接得到其他进程的各种信息的,特别是句柄。因 为所谓的句柄只是一个相对于当前进程虚拟地址空间的地址偏移量,它只对当前进程 有效。不同进程中的同一句柄(数值相同)指向的是不同的内容,甚至是无效的,根本 就不是同样的东西。因此,必须进行进程的上下文切换,把其他进程句柄切换为当前 进程句柄,以便获得该进程的信息。切换工作只要调用DuplicateHandle函数就可以。 其实现思路是:
(1)得到当前进程的句柄,打开当前进程的令牌环,提升到调试权限。 (2)动态加载ntdll.dll的NtQuerySystemInformation函数获得系统信息。
(3)从得到的句柄列表中,查询ObjType类型为OBJECT_TYPE_SOCKET和进程 标识不为NULL的情况。
(4)打开遍历中的每一个进程句柄,调用DuplicateHandle函数实现进程上下文切换。 (5)当切换到套接字所在的进程后,调用getsockname和getsockopt函数得到映射 信息。
例3-8实现WindowsNT/2000下端口进程关联。 DWORDdwNumBytesRet=0;
iRet=(*NtQuerySystemInformation)(NT_HANDLE_LIST, pdwHandleList,dwNumBytes, &dwNumBytesRet); DWORDdwNumEntries; PHANDLEINFOpHandleInfo; if(iRet) {

