端口与系统进程关联代码2

来源:互联网 发布:看港澳台直播软件 编辑:程序博客网 时间:2024/06/02 21:20
这两天想系统的看一下N API,所以就找了一段代码读了一下。这段代码实现了端口与系统关联的作用。里面用了3个N API

NtQuerySystemInformation

NtQueryObject

NtDeviceIoControlFile

【2】

代码如下:

//
//
//Coded By Napalm ,
//Modified By ZwelL ,
//Note By Gxter             BLOG : gxter.bokee.com


//实现的功能:可以看做是端口与进程关联。

#include "windows.h"
#include "stdio.h"
#include "string.h"
#include <psapi.h>
#include <shlwapi.h>

#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "shlwapi.lib")


typedef LONG NTSTATUS;
typedef VOID *POBJECT;
#define SystemHandleInformation  16

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING;

typedef UNICODE_STRING OBJECT_NAME_INFORMATION;
typedef UNICODE_STRING *POBJECT_NAME_INFORMATION;

#define STATUS_SUCCESS                ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH       ((NTSTATUS)0xC0000004L)


typedef
struct
_SYSTEM_HANDLE
{
    ULONG       uIdProcess;
    UCHAR       ObjectType;    // OB_TYPE_* (OB_TYPE_TYPE, etc.)
    UCHAR       Flags;        // HANDLE_FLAG_* (HANDLE_FLAG_INHERIT, etc.)
    USHORT         Handle;
    POBJECT         pObject;
    ACCESS_MASK    GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef
struct
_SYSTEM_HANDLE_INFORMATION
{
    ULONG           uCount;
    SYSTEM_HANDLE     Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;


//----------------------------------------------------------------------------------
typedef LONG TDI_STATUS;
typedef PVOID CONNECTION_CONTEXT;        // connection context

#define IOCTL_TDI_QUERY_INFORMATION      CTL_CODE(FILE_DEVICE_TRANSPORT, 4, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

#define TDI_QUERY_ADDRESS_INFO           0x00000003

//IRP 的 IO_STATUS_BLOCK   结构
typedef struct _IO_STATUS_BLOCK {
    union
{
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef void (WINAPI * PIO_APC_ROUTINE)(PVOID, PIO_STATUS_BLOCK, DWORD);


//下面这3个结构构造了一个TDI的信息结构
typedef struct _TDI_REQUEST
{
    union
{
        HANDLE AddressHandle;
        CONNECTION_CONTEXT ConnectionContext;
        HANDLE ControlChannel;
    } Handle;

    PVOID RequestNotifyObject;
    PVOID RequestContext;
    TDI_STATUS TdiStatus;
} TDI_REQUEST, *PTDI_REQUEST;

typedef struct _TDI_CONNECTION_INFORMATION
{
    LONG UserDataLength;        // length of user data buffer
    PVOID UserData;            // pointer to user data buffer
    LONG OptionsLength;        // length of following buffer
    PVOID Options;             // pointer to buffer containing options
    LONG RemoteAddressLength;   // length of following buffer
    PVOID RemoteAddress;        // buffer containing the remote address
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;

typedef struct _TDI_REQUEST_QUERY_INFORMATION
{
    TDI_REQUEST Request;
    ULONG QueryType;             // class of information to be queried.
    PTDI_CONNECTION_INFORMATION RequestConnectionInformation;
} TDI_REQUEST_QUERY_INFORMATION, *PTDI_REQUEST_QUERY_INFORMATION;
//-----------------------------------NtDeviceIoControlFile
typedef
NTSTATUS
(WINAPI *tNTQSI)(DWORD SystemInformationClass,
     PVOID SystemInformation,
                 DWORD SystemInformationLength,
     PDWORD ReturnLength);

typedef
NTSTATUS
(WINAPI *tNTQO)(HANDLE ObjectHandle,
    DWORD ObjectInformationClass,
    PVOID ObjectInformation,
                DWORD Length,
    PDWORD ResultLength);

typedef
NTSTATUS
(WINAPI *tNTDIOCF)(HANDLE FileHandle,
       HANDLE Event,
       PIO_APC_ROUTINE ApcRoutine,
       PVOID ApcContext,
                   PIO_STATUS_BLOCK IoStatusBlock,
       DWORD IoControlCode,
                   PVOID InputBuffer,
       DWORD InputBufferLength,
                   PVOID OutputBuffer,
       DWORD OutputBufferLength);


//-----------------------------------NtQuerySystemInformation

#define ObjectNameInformation           1
#define STATUS_BUFFER_OVERFLOW           ((NTSTATUS)0x80000005L)

//-----------------------------------NtQueryObject


void EnableDebugPrivilege();
LPWSTR GetObjectName(HANDLE hObject);
void OutputConnectionDetails(HANDLE hObject, in_addr *ip, DWORD *port);

int main()
{
unsigned long pid = 0, newpid = 0;
EnableDebugPrivilege();

printf("Coded By Napalm , Modified By ZwelL , note by Gxter/n/n");
printf("Process   ,PID   ,HANDLE   ,DEVICE     ,IP ADDR   ,Port /n/n");

tNTQSI pNTQSI = (tNTQSI)GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtQuerySystemInformation");
if(pNTQSI == NULL)
{
  printf("error  GetProcAddress !/n");
  getchar();
}

DWORD dwSize = sizeof(SYSTEM_HANDLE_INFORMATION);
PSYSTEM_HANDLE_INFORMATION  pSHinfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[dwSize];
NTSTATUS ntReturn = pNTQSI(SystemHandleInformation, pSHinfo, dwSize, &dwSize);

if(ntReturn == STATUS_INFO_LENGTH_MISMATCH)
{
         delete pSHinfo;
         pSHinfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[dwSize];

         ntReturn = pNTQSI(SystemHandleInformation, pSHinfo, dwSize, &dwSize);
    }
else
  printf("error pNTQSI !/n");

if(ntReturn == STATUS_SUCCESS)
{
  for(DWORD dwIdx = 0; dwIdx < pSHinfo->uCount; dwIdx++)
        {
   //printf("pid : %d", pSHinfo->Handles[dwIdx].uIdProcess);  //进程ID
   //printf("   handle:%d", pSHinfo->Handles[dwIdx].Handle);  //句柄
   //printf("   TYPE:%d", pSHinfo->Handles[dwIdx].ObjectType); //句柄的类型
   //printf("   access:%x/n", pSHinfo->Handles[dwIdx].pObject);
   
   //根据进程ID,打开进程
   HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                    FALSE, pSHinfo->Handles[dwIdx].uIdProcess);
   if(hProcess != INVALID_HANDLE_VALUE)
   {
    HANDLE hObject = NULL;
    //这个函数用处很大,大概的作用就是,复制一个个内核对象的句柄
    //从目标进程中复制一个句柄出来
    if(DuplicateHandle(hProcess, (HANDLE)pSHinfo->Handles[dwIdx].Handle,
     GetCurrentProcess(), &hObject, STANDARD_RIGHTS_REQUIRED, FALSE, 0) != FALSE)
                {
     //根据复制出来的句柄,得到句柄的类型名
     LPWSTR lpwsName = GetObjectName(hObject);
     if(lpwsName != NULL)
     {
      //printf("%S/n", lpwsName);
      //getchar();
      //过滤出用语网络通信的句柄
      
      if(!wcscmp(lpwsName, L"//Device//Tcp") || !wcscmp(lpwsName, L"//Device//Udp") || !wcscmp(lpwsName, L"//Device//RawIp"))
                        {
       LPSTR lpszProcess = new CHAR[MAX_PATH];
       struct in_addr ipaddr;
       DWORD port;
      
       OutputConnectionDetails(hObject, &ipaddr, &port);
       ZeroMemory(lpszProcess, MAX_PATH);
       //通过一个进程的句柄,来得出程序的完整路径 + 程序名
       GetModuleFileNameEx(hProcess, NULL, lpszProcess, MAX_PATH);

       //显示信息部分
       if(lpszProcess[0] == '?')
        printf("[SYSTEM]");
       else
        printf("%s/n", lpszProcess);
       printf("%6d", pSHinfo->Handles[dwIdx].uIdProcess);
       printf("%9d", pSHinfo->Handles[dwIdx].Handle);
       printf("%15S", lpwsName);
       printf("%18s", inet_ntoa(ipaddr));
       printf("%6d/n", port);
      
       delete lpszProcess;
                        }
      
      //printf("%15S/n", lpwsName);
                        delete lpwsName;
     }
     CloseHandle(hObject);
    }
    CloseHandle(hProcess);
   }
  }

  printf("当前共有 %d 个句柄/n",pSHinfo->uCount);
}
else
  printf("error for() !/n");

getchar();
return 0;
}

//
void EnableDebugPrivilege()
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tokenPriv;
    LUID luidDebug;
    if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != FALSE) {
        if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug) != FALSE)
        {
             tokenPriv.PrivilegeCount            = 1;
             tokenPriv.Privileges [0].Luid       = luidDebug;
             tokenPriv.Privileges [0].Attributes = SE_PRIVILEGE_ENABLED;
             AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(tokenPriv), NULL, NULL);
        }
    }
}

//
LPWSTR GetObjectName(HANDLE hObject)
{
    LPWSTR lpwsReturn = NULL;
//get  NtQueryObject  address
    tNTQO pNTQO = (tNTQO)GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtQueryObject");
    if(pNTQO != NULL)
{
        DWORD dwSize = sizeof(OBJECT_NAME_INFORMATION);
  //其实就是UNICODE 类型的指针
        POBJECT_NAME_INFORMATION pObjectInfo = (POBJECT_NAME_INFORMATION) new BYTE[dwSize];
        //调用  NtQueryObject    句柄      函数功能选择         是UNICODE格式的
  NTSTATUS ntReturn = pNTQO(hObject, ObjectNameInformation, pObjectInfo, dwSize, &dwSize);
        if(ntReturn == STATUS_BUFFER_OVERFLOW)
  {
             delete pObjectInfo;
             pObjectInfo = (POBJECT_NAME_INFORMATION) new BYTE[dwSize];
             //调用 NtQueryObject
    ntReturn = pNTQO(hObject, ObjectNameInformation, pObjectInfo, dwSize, &dwSize);
        }
        if((ntReturn >= STATUS_SUCCESS) && (pObjectInfo->Buffer != NULL))
        {
   //对UNICODE的处理
            lpwsReturn = (LPWSTR) new BYTE[pObjectInfo->Length + sizeof(WCHAR)];
            ZeroMemory(lpwsReturn, pObjectInfo->Length + sizeof(WCHAR));
            CopyMemory(lpwsReturn, pObjectInfo->Buffer, pObjectInfo->Length);
        }
        delete pObjectInfo;
    }
    return lpwsReturn;
}

//
void OutputConnectionDetails(HANDLE hObject, in_addr *ip, DWORD *port)
{
//得到  NtDeviceIoControlFile 地址
    tNTDIOCF pNTDIOCF = (tNTDIOCF)GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtDeviceIoControlFile");
    if(pNTDIOCF != NULL)
{
  //这是一个IRP头的一部分,IO_STATUS_BLOCK 结构
        IO_STATUS_BLOCK IoStatusBlock;
        TDI_REQUEST_QUERY_INFORMATION  tdiRequestAddress = {{0}, TDI_QUERY_ADDRESS_INFO};
        BYTE tdiAddress[128];

        HANDLE hEvent2 = CreateEvent(NULL, TRUE, FALSE, NULL);
        NTSTATUS ntReturn2 = pNTDIOCF(hObject,  //一个复制出来的进程句柄
          hEvent2, //事件
          NULL,
          NULL,
          &IoStatusBlock,  //OUT 接受返回信息
          IOCTL_TDI_QUERY_INFORMATION, //TDI结构
          &tdiRequestAddress,
          sizeof(tdiRequestAddress),
          &tdiAddress, //OUT
          sizeof(tdiAddress));
        if(hEvent2)
   CloseHandle(hEvent2);

        if(ntReturn2 == STATUS_SUCCESS)
  {
   //读取  返回的信息
             struct in_addr *pAddr = (struct in_addr *)&tdiAddress[14];
             *ip = *pAddr;
             *port = ntohs(*(PUSHORT)&tdiAddress[12]);
        }
    }
}


/*

这个程序基本读完了,可是最后的疑问就是:  NtDeviceIoControlFile这个函数的作用和其参数的作用

也想知道从什么地方可以有每个 N API的介绍?????

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 );

我们感兴趣的成员变量有这几个:
FileHandle标明了要通信的设备的句柄,
IoStatusBlock指向接收最后完成状态和请求操作信息的变量,
IoControlCode是指定要完成的特定的I/O控制操作的数字,
InputBuffer包含了输入的数据,
长度为按字节计算的InputBufferLength,
相似的还有OutputBuffer和OutputBufferLength。



//-------------------------------------------------------------------------------

NTSYSAPI
NTSTATUS
NTAPI
NtQueryObject(

  IN HANDLE               ObjectHandle OPTIONAL,  //对象句柄
  IN OBJECT_INFORMATION_CLASS ObjectInformationClass, // *
  OUT PVOID               ObjectInformation,   // *
  IN ULONG                Length,
  OUT PULONG              ResultLength );

这是第2个参数的信息,每一个代表一个种类型的信息,也代表了一种信息结构
(也就是说,第2个参数,和第3个参数是,对应关系的)

typedef enum _OBJECT_INFORMATION_CLASS
{
  ObjectBasicInformation,   // Result is OBJECT_BASIC_INFORMATION structure
  ObjectNameInformation,   // Result is OBJECT_NAME_INFORMATION structure
  ObjectTypeInformation,   // Result is OBJECT_TYPE_INFORMATION structure
  ObjectAllInformation,   // Result is OBJECT_ALL_INFORMATION structure
  ObjectDataInformation   // Result is OBJECT_DATA_INFORMATION structure
  
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;


这上函数是查询系统(内核)对象的,(在WIN系统中,有两类对象,一个是内核对象,一个是用户对象)

*/


/*
NTSYSAPI
NTSTATUS
NTAPI
NtQuerySystemInformation(

  IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
  OUT PVOID               SystemInformation,
  IN ULONG                SystemInformationLength,
  OUT PULONG              ReturnLength OPTIONAL );


//------------------------------------------------------------------------------

BOOL DuplicateHandle(
  HANDLE hSourceProcessHandle,  // handle to the source process  源进程句柄
  HANDLE hSourceHandle,         // handle to duplicate   
  HANDLE hTargetProcessHandle,  // handle to process to duplicate to
  LPHANDLE lpTargetHandle,  // pointer to duplicate handle
  DWORD dwDesiredAccess,    // access for duplicate handle
  BOOL bInheritHandle,      // handle inheritance flag
  DWORD dwOptions           // optional actions
);

我想,你大概是想知道DuplicateHandle()该如何用.

在系统中,对象分两类:核心对象和用户对象.如进程对象,线程对象,文件映射
对象等就是核心对象;而向窗口,菜单等都是用户对象.

   两者是有差别的,用于标示用户对象的句柄是系统唯一的,也就是说,一个进程
完全可以对另外一个进程中的用户对象进行操作,比如两个进程间通信的方法之一,
就是发送消息.正是由于窗口是用户对象,所以句柄是系统唯一,通过FindWindow(),
得到另外一个进程的窗口句柄,然后用SendMessage(),让hWnd的窗口过程来处理消
息,实现了进程间的通信.因此,对于用户对象,你根本不用DuplicateHandle(),直接
把句柄拿来用就行了.

   而核心对象则不一样.核心对象是为了加强系统的稳定性,因此,核心对象句柄是
进程相关的,在每一个进程中都有一个核心对象表,每一个对象的索引(不完全是)作为
内核对象的句柄,从而实现进程相关.同一个对象在不同的进程中可能有不同的索引,即句柄.
对核心对象进行操作时,系统还要进行安全检验,看一下你是否有权来操作这个对象.
因此你不能同用户对象一样,直接把句柄拿过来用.比方说,你想操作另一个进程中的文件映射对象,
这个文件映射对象句柄在那个进程中假设是0x000001,但在你的进程中,很有可能0x00000001时表示
另一个核心对象,此时的操作就永远不会成功,甚至会产生灾难性的后果.此时,就有必要用DuplicateHandle().

DuplicateHandle(),要涉及到三个进程,(一般很少有这种情况,最多的是两个进程).
第一个是你调用DuplicateHandle()函数的线程.第二个是你的源进程,第三个是目的进程.
hSourceHandle,是你要复制的核心对象句柄.调用这个函数后,系统将检索对象名空间,
找到内核对象,增加计数,然后在你的目的进程中的核心对象表中,为这个对象分配一个
索引,这个索引作为目的进程中该内核对象的句柄.然后你还要通知(发消息)目的进程说
"喂,你现在可以用这个核心对象了",目的进程才可以操作该对象.
  
不知道,我回答的清不清楚?

一句话,用于复制进程或线程句柄