端口关联进程-在核心态的实现方法

来源:互联网 发布:淘宝掌柜名字怎么改 编辑:程序博客网 时间:2024/06/11 04:49
很多关于端口关联进程的方法都是在用户态实现的,如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,这种方法不是很好,以后再找更好的方法
原创粉丝点击