这个函数的功能很强大,可以用来查找进程的很多相关信息。
先看一下定义:
NTSTATUS WINAPI NtQueryInformationProcess(
_In_ HANDLE ProcessHandle,
_In_ PROCESSINFOCLASS ProcessInformationClass,
_Out_ PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
该函数并没有被微软公开,它在Ntdll.dll 里导出的,所以要想调用此函数,得用LoadLibrary和GetProcAddress来加载。
用的时候要#include <winternl.h>头文件
这里说一下参数介绍:
processHandle:查询进程的句柄
ProcessInformationClass:想要查找的信息,他是一个 PROCESSINFOCLASS 的枚举类型;可以取值:
ProcessBasicInformation 0
ProcessDebugPort 7
ProcessWow64Information 26
ProcessImageFileName 27
ProcessBreakOnTermination 29
ProcessInformation:要存放查询结果的缓冲区,这个结构要根据第二个参数来决定,
ProcessInformationLength:缓冲区大小
ReturnLength:实际返回的写入缓冲区的字节数
我们看一下 ProcessBasicInformation 这个结构:
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
这是官方的定义,它其实就是下面的结构:
typedef struct
{
DWORD ExitStatus; // 接收进程终止状态
DWORD PebBaseAddress; // 接收进程环境块地址
DWORD AffinityMask; // 接收进程关联掩码
DWORD BasePriority; // 接收进程的优先级类
ULONG UniqueProcessId; // 接收进程ID
ULONG InheritedFromUniqueProcessId; //接收父进程ID
} PROCESS_BASIC_INFORMATION;
这个结构里面有父进程的ID,对应的官方的 Reserved3字段,
还有进程的PEB,看一下进程环境块儿的定义:
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged; //该进程是否正在被调试,
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId; //会话ID
} PEB, *PPEB;
下面写一段程序来看一下:
#include <windows.h>
#include <winternl.h>
//先定义函数指针
typedef NTSTATUS (WINAPI *PFUN_NtQueryInformationProcess)(
_In_ HANDLE ProcessHandle,
_In_ PROCESSINFOCLASS ProcessInformationClass,
_Out_ PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
void main()
{
DWORD dwCurrentProcessID;
HANDLE hProcessThis;
DWORD dwParentID;
//如果随意申请一块儿内存的话,不管内存多大,调用结果死活不成功,比如:UCHAR pbi[3000] = {0};这样会导致失败,还有待继续探究
PROCESS_BASIC_INFORMATION pbi = {0};
ULONG dwReturnLen;
ULONG dwData = sizeof(PROCESS_BASIC_INFORMATION);
dwCurrentProcessID = GetCurrentProcessId();
//打开进程一定要有 PROCESS_QUERY_INFORMATION 权限
hProcessThis = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwCurrentProcessID);
HMODULE hModule = LoadLibraryA("Ntdll.dll");
PFUN_NtQueryInformationProcess pfun = (PFUNNtQueryInformationProcess)GetProcAddress(hModule, "NtQueryInformationProcess");
NTSTATUS status = pfun(hProcessThis, ProcessBasicInformation, (PVOID)&pbi, dwData, &dwReturnLen);
dwParentID = (DWORD)pbi.Reserved3; //dwParentID的值为devenv.exe 进程的句柄,即父进程的句柄
PPEB peb = pbi.PebBaseAddress;
}
执行完这些语句后可以查看内存,下面是我的环境下的内存:
![查找父进程,进程的PEB 进程是否被调试 NtQueryInformationProcess - Prairie - work labor and play](http://img0.ph.126.net/3aiQPv9ku8ZqLF7eBZ2ISQ==/6630403660677508395.png)
//说明:把Reserved3转化为DWORD后一定会得到devenv.exe 进程的ID,dwParentID也可以说明问题
![查找父进程,进程的PEB 进程是否被调试 NtQueryInformationProcess - Prairie - work labor and play](http://img1.ph.126.net/8V4WaszuQW_rJ3KXdpMAQQ==/6630881948236327918.png)
//说明:这是peb字段,我们看到BeingDebugged字段已经被置为1,说明正在被调试,
SessionId:字段也显示出了该进程的会话ID
其它字段可以在深入的研究,现在自己也不太熟悉。