这两天想系统的看一下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,是你要复制的核心对象句柄.调用这个函数后,系统将检索对象名空间,
找到内核对象,增加计数,然后在你的目的进程中的核心对象表中,为这个对象分配一个
索引,这个索引作为目的进程中该内核对象的句柄.然后你还要通知(发消息)目的进程说
"喂,你现在可以用这个核心对象了",目的进程才可以操作该对象.
不知道,我回答的清不清楚?
一句话,用于复制进程或线程句柄
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,是你要复制的核心对象句柄.调用这个函数后,系统将检索对象名空间,
找到内核对象,增加计数,然后在你的目的进程中的核心对象表中,为这个对象分配一个
索引,这个索引作为目的进程中该内核对象的句柄.然后你还要通知(发消息)目的进程说
"喂,你现在可以用这个核心对象了",目的进程才可以操作该对象.
不知道,我回答的清不清楚?
一句话,用于复制进程或线程句柄