很多关于端口关联进程的方法都是在用户态实现的,如fport等,结合大虾们的方法,这里给出一种在核心态实现的方法,方法可能比较笨 ^_^
大概是
1.用ZwQuerySystemInformation列出系统所有的句柄
2.找出类型为SOCKET的句柄
3.根据SYSTEM_HANDLE_INFORMATION.object的一些数据,用NtDeviceIoControlFile得到端口相关信息
这种方法在用户态已经实现过了,正好是shotgun的方法加上isly的方法,这里主要是注意一些API的转换。
在WINDOWSXP下可以用,如果是2k,需要修改WINXP_SOCKET_FLAG和WINXP_EPROCESS_NAMEOFFSET,WINXP_SOCKET_FLAG是SOCKET句柄的类型值,2K下是0x1a,WINXP_EPROCESS_NAMEOFFSET是EPROCESS的进程名偏移值,2k下是0x1fc
代码如下
////////////////////////////////////////////////
/* Lport.sys */
/* list ports with processes in kernel */
/* Writen by Leven */
/* 2004-6-29 */
////////////////////////////////////////////////
#include <ntddk.h>
#include <string.h>
#include "Port.h"
#include "tdiinfo.h"
#include "tdistat.h"
#define SystemHandleInformation 16
#define TCPUDP_FLAG 100
#define WINXP_SOCKET_FLAG 0x1c
#define WINXP_EPROCESS_NAMEOFFSET 0x174
#define ntohs(s) /
( ( ((s) >> 8) & 0x00FF ) | /
( ((s) << 8) & 0xFF00 ) )
typedef struct _TDI_CONNECTION_INFO {
ULONG State;
ULONG Event;
ULONG TransmittedTsdus;
ULONG ReceivedTsdus;
ULONG TransmissionErrors;
ULONG ReceiveErrors;
LARGE_INTEGER Throughput;
LARGE_INTEGER Delay;
ULONG SendBufferSize;
ULONG ReceiveBufferSize;
BOOLEAN Unreliable;
} TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO;
typedef struct _TDI_CONNECTION_INFORMATION {
LONG UserDataLength;
PVOID UserData;
LONG OptionsLength;
PVOID Options;
LONG RemoteAddressLength;
PVOID RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessID; //进程的标识ID
UCHAR ObjectTypeNumber; //对象类型
UCHAR Flags; //0x01 = PROTECT_FROM_CLOSE,0x02 = INHERIT
USHORT Handle; //对象句柄的数值
PVOID Object; //对象句柄所指的内核对象地址
ACCESS_MASK GrantedAccess; //创建句柄时所准许的对象的访问权
}SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTSYSAPI
NTSTATUS
NTAPI
NtDeviceIoControlFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
);
NTSYSAPI
BOOLEAN
NTAPI
NtDuplicateObject(
IN HANDLE hSourceProcessHandle,
IN HANDLE hSourceHandle,
IN HANDLE hTargetProcessHandle,
OUT HANDLE * lpTargetHandle,
IN ULONG dwDesiredAccess,
IN BOOLEAN bInheritHandle,
IN ULONG dwOptions
);
NTSYSAPI
NTSTATUS
NTAPI
PsLookupProcessByProcessId(
IN ULONG ulProcId,
OUT PEPROCESS * pEProcess
);
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
void DriverUnload(IN PDRIVER_OBJECT DriverObject);
//几个全局变量,记录端口相关信息,最后列印出来
ULONG g_pid[1000];
ULONG g_port[1000];
ULONG g_handle[1000];
ULONG g_tcpudp[1000];
ULONG g_num =0 ;
//获得所有句柄
ULONG GetHandleList()
{
ULONG n;
ULONG pBuffer;
NTSTATUS status;
pBuffer =(ULONG)ExAllocatePool(PagedPool,0x1000);
status = ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuffer,0x1000,&n);
ExFreePool((PVOID)pBuffer);
if(STATUS_INFO_LENGTH_MISMATCH == status)
{
pBuffer =(ULONG)ExAllocatePool(NonPagedPool,n);
ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuffer,n,NULL);
return pBuffer;
}
else
return 0;
}
//根据句柄得到端口信息
void GetOpenPort(ULONG dwProcessesID,ULONG Handle,int NoCache,ULONG tcpudp)
{
HANDLE hProc,DupHandle=NULL;
USHORT openport;
ULONG i=0;
NTSTATUS status;
TDI_CONNECTION_INFO TdiConnInfo={0};
TDI_CONNECTION_INFORMATION TdiConnInformation={0};
ULONG dwRetu=0;
IO_STATUS_BLOCK IoStatusBlock={0};
CLIENT_ID id;
OBJECT_ATTRIBUTES objatt = {0};
id.UniqueProcess = (HANDLE)dwProcessesID;
id.UniqueThread = 0;
//打开对方进程
NtOpenProcess(&hProc,PROCESS_DUP_HANDLE,&objatt,&id);
//复制句柄
NtDuplicateObject(hProc,
(HANDLE)Handle,
(HANDLE)0xffffffff,
&DupHandle,
0,
FALSE,
2);
//根据object的数据得到端口信息
if(NoCache==0x2)
{
TdiConnInformation.RemoteAddressLength= 4;
status = NtDeviceIoControlFile((HANDLE)DupHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
0x210012, // Command code
&TdiConnInformation,
sizeof(TdiConnInformation),
&TdiConnInfo,
sizeof(TdiConnInfo));
//进行TDI查询,得到连接的相关信息
if(status == 0)
{
openport = ntohs((USHORT)TdiConnInfo.ReceivedTsdus);
if(openport == 0)
return;
for(i=0;i<g_num;i++)
{
if(g_pid[i] == dwProcessesID && g_port[i] == openport)
if(tcpudp >= TCPUDP_FLAG && g_tcpudp[i] >= TCPUDP_FLAG || tcpudp < TCPUDP_FLAG && g_tcpudp[i] < TCPUDP_FLAG)
return;
}
g_pid[i] = dwProcessesID;
g_port[i] = openport;
g_handle[i] = Handle;
g_tcpudp[i] = tcpudp;
g_num++;
}
}
if(NoCache==0x1)
{
TdiConnInformation.RemoteAddressLength= 3;
status = NtDeviceIoControlFile((HANDLE)DupHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
0x210012, // Command code
&TdiConnInformation,
sizeof(TdiConnInformation),
&TdiConnInfo,
sizeof(TdiConnInfo));
//进行TDI查询,得到连接的相关信息
if(status == 0)
{
openport = ntohs((USHORT)TdiConnInfo.ReceivedTsdus);
if(openport == 0)
return;
for(i=0;i<g_num;i++)
{
if(g_pid[i] == dwProcessesID && g_port[i] == openport)
if(tcpudp >= TCPUDP_FLAG && g_tcpudp[i] >= TCPUDP_FLAG || tcpudp < TCPUDP_FLAG && g_tcpudp[i] < TCPUDP_FLAG)
return;
}
g_pid[i] = dwProcessesID;
g_port[i] = openport;
g_handle[i] = Handle;
g_tcpudp[i] = tcpudp;
g_num++;
}
}
}
void Start(ULONG pBuffer)
{
ULONG i;
PSYSTEM_HANDLE_INFORMATION pProcesses = (PSYSTEM_HANDLE_INFORMATION)(pBuffer+4);
ULONG nocache;
ULONG tcpudp;
PEPROCESS epro;
char *p;
for (i=0;i<((ULONG)(*(ULONG*)pBuffer));i++)
{
if(pProcesses[i].ObjectTypeNumber == WINXP_SOCKET_FLAG)
{
//得到SYSTEM_HANDLE_INFORMATION.object的相关数据
//这里要密切注意内存情况,一不小心就蓝屏。因为句柄经常变化,有些可能已经被销毁了
nocache = (ULONG)pProcesses[i].Object;
if(!MmIsAddressValid((VOID*)nocache))
continue;
nocache = (ULONG)(*((ULONG*)(nocache)+4));
tcpudp = (ULONG)(*((ULONG*)(pProcesses[i].Object)+1));
if(!MmIsAddressValid((VOID*)tcpudp))
continue;
tcpudp = (ULONG)(*((ULONG*)(tcpudp)+1));
if(nocache == 2 || nocache == 1)
{
GetOpenPort(pProcesses[i].ProcessID,pProcesses[i].Handle,nocache,tcpudp);
}
}
}
for(i=0;i<g_num;i++)
{
//大于TCPUDP_FLAG是TCP,小于是UDP,后面有说明
if(g_tcpudp[i] >= TCPUDP_FLAG)
DbgPrint("TCP:/t");
if(g_tcpudp[i] < TCPUDP_FLAG)
DbgPrint("UDP:/t");
//根据PID得到进程名
PsLookupProcessByProcessId(g_pid[i],&epro);
p = (char*)epro + WINXP_EPROCESS_NAMEOFFSET;
DbgPrint("ProcName=%s/tPID=%d/tport=%d/t%d/n",p,g_pid[i],g_port[i],g_tcpudp[i]);
}
return;
}
//////////////////////////////////
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
ULONG pbuf;
DbgPrint("DriverEntry/n");
DriverObject->DriverUnload = DriverUnload;
pbuf = GetHandleList();
Start(pbuf);
return STATUS_SUCCESS;
}
void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload/n");
}
///////////////////////////////////////////
///////////////////////////////////////////
有个问题没有解决,就是不能知道端口是TCP还是UDP,这里用了一个TCPUDP_FLAG临时解决,值为100,SYSTEM_HANDLE_INFORMATION.object的某个数据大于它就是TCP,小于就是UDP,这种方法不是很好,以后再找更好的方法