文章目录
前言
NTAPI:泛指ntdll.dll模块不对外提供的API接口,大多是提供给内核层开发人员使用的。
一般通过动态载入库的方式(LoadLibrary + GetProcAddress)调用
注意:本文主要使用phlib库作为调用NTAPI的库
NtQueryInformationProcess函数
NtQueryInformationProcess
NtQueryInformationProcess用法
函数原型
作用:
通过ProcessInformationClass参数可以查找进程的不同信息,包括PEB信息、WOW64信息、子系统信息、imageFileName映像文件名信息等。
NTSYSCALLAPI
NTSTATUS
NTAPI
NtQueryInformationProcess(
_In_ HANDLE ProcessHandle,
_In_ PROCESSINFOCLASS ProcessInformationClass,
_Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
ProcessHandle
:进程句柄
ProcessInformationClass
:需要检索的进程信息类型,具体参数类型,见本节结尾“进程信息类型表”。
如果第二个参数是ProcessBasicInformation的话,则第三个参数必须为一个指针指向结构PROCESS_BASIC_INFORMATION:
ProcessInformation
: 缓冲指针,保存进程信息,大小取决于进程信息类型。
ProcessInformationLength
:以字节为单位的缓冲大小
ReturnLength
:实际写入到缓冲的字节数
返回值
:
返回一个NTSTATUS成功或错误代码
附录
进程信息类型表
值 | 含义 |
---|---|
ProcessBasicInformation 0 | 返回PEB结构指针,检索判断特定进程是否正在被调试 |
ProcessDebugPort 7 | 返回DWORD指针,检索获得当前进程的调试端口号 |
ProcessWow64Information 26 | 判断进程是否运行在WOW64环境(WOW64指基于Win32的程序运行在x64系统上) |
ProcessImageFileName 27 | 返回Unicode字符串,包含进程的映像文件名 |
ProcessBreakOnTermination 29 | 返回ULONG值, 判断是否这个进程被认为是重要进程的。(一般系统级别的exe都是重要进程) |
ProcessSubsystemInformation 75 | 返回SUBSYSTEM_INFORMATION_TYPE,指出进程的子系统类型。 |
当ProcessInformationClass为ProcessBasicInformation时:
缓冲区指针 应该指向 _PROCESS_BASIC_INFORMATION
typedef struct
{
DWORD ExitStatus; // 接收进程终止状态
DWORD PebBaseAddress; // 接收PEB进程环境块地址
DWORD AffinityMask; // 接收进程关联掩码
DWORD BasePriority; // 接收进程的优先级类
ULONG UniqueProcessId; // 接收进程ID
ULONG InheritedFromUniqueProcessId; //接收父进程ID
} PROCESS_BASIC_INFORMATION;
示例:从PEB32获得进程路径
代码参考:
CSDN博主「MailSloter」的原创文章
/**
*
* 获得PEB的进程路径
*
*/
#include <phnt_windows.h>
#include <phnt.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
BOOL GetProcessFullPathByProcessID(ULONG32 ProcessID, WCHAR* BufferData, ULONG BufferLegnth) {
HANDLE ProcessHandle = NULL;
ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessID);
if (ProcessHandle == NULL) {
return FALSE;
}
PROCESS_BASIC_INFORMATION pbi = { 0 };
SIZE_T ReturnLength = 0;
NTSTATUS status = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION),
(PULONG)&ReturnLength);
if (!NT_SUCCESS(status)) {
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}
PEB Peb = { 0 };
status = NtReadVirtualMemory(ProcessHandle, pbi.PebBaseAddress, &Peb, sizeof(PEB32), (SIZE_T*)&ReturnLength);
if (!NT_SUCCESS(status)) {
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}
RTL_USER_PROCESS_PARAMETERS RtlUserProcessParameters = { 0 };
status = NtReadVirtualMemory(ProcessHandle, Peb.ProcessParameters, &RtlUserProcessParameters,
sizeof(RTL_USER_PROCESS_PARAMETERS), (SIZE_T*)&ReturnLength);
if (!NT_SUCCESS(status)) {
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}
if (RtlUserProcessParameters.ImagePathName.Buffer != NULL)
{
ULONG v1 = 0;
if (RtlUserProcessParameters.ImagePathName.Length < BufferLegnth)
{
v1 = RtlUserProcessParameters.ImagePathName.Length;
}
else
{
v1 = BufferLegnth - 10;
}
status = ReadProcessMemory(ProcessHandle, RtlUserProcessParameters.ImagePathName.Buffer,
BufferData, v1, (SIZE_T*)&ReturnLength);
if (!NT_SUCCESS(status))
{
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
return FALSE;
}
}
CloseHandle(ProcessHandle);
return TRUE;
}
int main() {
BOOL bOk = FALSE;
ULONG32 ProcessID = 0;
WCHAR BufferData[MAX_PATH] = { 0 };
//定义完整路径数组,
//windows规定存放完整路径的数组最大为260个字节;
printf("Input Process ID\r\n");
scanf_s("%d", &ProcessID);
bOk = GetProcessFullPathByProcessID(ProcessID, BufferData, MAX_PATH);
//用自定义函数实现从进程ID得到进程完整路径的过程(进程ID,完整路径(存放的数组名),数组长度)
std::cout << bOk << std::endl;
if (bOk == TRUE)
{
printf("%S\r\n", BufferData);
//BufferData双字,故用大S输出字符串;
}
system("pause");
return 0;
}
NtSetInformationProcess函数
参考 SetProcessInformation function msdn
设置指定进程的信息
函数原型
BOOL SetProcessInformation(
[in] HANDLE hProcess,
[in] PROCESS_INFORMATION_CLASS ProcessInformationClass,
LPVOID ProcessInformation,
[in] DWORD ProcessInformationSize
);
示例:使进程跳过DEP检测 关闭DEP
ZwCreateThreadEx函数
函数原型
NtQueryVirtualMemory
解密NtQueryVirtualMemory
msdn NtQueryVirtualMemor
查询指定进程的某个虚拟地址控件所在的内存对象的一些信息。
函数原型
NTSTATUS NTAPI NtQueryVirtualMemory(
IN HANDLE ProcessHandle, //目标进程句柄
IN PVOID BaseAddress, //目标内存地址
IN MEMORY_INFORMATION_CLASS MemoryInformationClass, //查询内存信息的类别
OUT PVOID Buffer, //用于存储获取到的内存信息的结构地址
IN ULONG Length, //Buffer的最大长度
OUT PULONG ResultLength OPTIONAL); //存储该函数处理返回的信息的长度的ULONG的地址
);
第一个参数
是目标进程的句柄;
第二个参数
是要查询的内存地址;
第四个参数
是根据第三个参数选用不同的结构去接收内存信息的地址。
第五个和第六个参数
为Buffer长度,和函数处理结果返回的长度。
第三个参数
是MEMORY_INFORMATION_CLASS 表示需要获取内存的信息的类型
类型有以下几种:
//MEMORY_INFORMATION_CLASS定义
typedef enum _MEMORY_INFORMATION_CLASS
{
MemoryBasicInformation, //内存基本信息
MemoryWorkingSetInformation, //工作集信息
MemoryMappedFilenameInformation //内存映射文件名信息
} MEMORY_INFORMATION_CLASS;
MemoryBasicInformation
内存基本信息
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
代码使用可参考 DllFinder Process::ListModulesVQ
MemoryWorkingSetInformation
工作集信息
typedef struct _MEMORY_WORKING_SET_INFORMATION {
ULONG SizeOfWorkingSet;
DWORD WsEntries[ANYSIZE_ARRAY];
} MEMORY_WORKING_SET_INFORMATION, *PMEMORY_WORKING_SET_INFORMATION;
MemoryMappedFilenameInformation
内存映射文件名信息
#define _MAX_OBJECT_NAME 1024/sizeof(WCHAR)
typedef struct _MEMORY_MAPPED_FILE_NAME_INFORMATION {
UNICODE_STRING Name;
WCHAR Buffer[_MAX_OBJECT_NAME];
} MEMORY_MAPPED_FILE_NAME_INFORMATION, *PMEMORY_MAPPED_FILE_NAME_INFORMATION;
示例:获取进程映像文件名
示例:查询内存保护模式类型 PAGE_EXECUTE_READWRITE
int main() {
DWORD dwProcessId = 33700;
HANDLE hProcess;
NTSTATUS status = PhNtOpenProcess(&hProcess,
PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ, dwProcessId);
if (!NT_SUCCESS(status)) {
status = PhNtOpenProcess(&hProcess,
PROCESS_QUERY_INFORMATION, dwProcessId);
if (!NT_SUCCESS(status))
return -1;
}
void* pBaseAddres = NULL;
MEMORY_BASIC_INFORMATION basicInfo;
while (NT_SUCCESS(NtQueryVirtualMemory(
hProcess, pBaseAddres, MemoryBasicInformation, &basicInfo,
sizeof(MEMORY_BASIC_INFORMATION), NULL))) {
ULONG dwState = basicInfo.State;
DWORD protectStatus = basicInfo.Protect;
if (protectStatus == PAGE_EXECUTE_READWRITE) {
printf("memery PAGE_EXECUTE_READWRITE exist! \n");
break;
}
pBaseAddres = PTR_ADD_OFFSET(pBaseAddres, basicInfo.RegionSize);
}
return 0;
}
NtReadVirtualMemory
函数原型
读取进程内存内容
NTSTATUS
NtReadVirtualMemory (
IN HANDLE ProcessHandle,//进程句柄
IN PVOID BaseAddress,//基地址
OUT PVOID Buffer,//输出的内容
IN SIZE_T BufferSize,//输出大小
OUT PSIZE_T NumberOfBytesRead OPTIONAL//读取字节数
)
示例:简单用法
int main() {
int adrnum = 0;
DWORD dwPid = 26392;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);
NtReadVirtualMemory(hProcess, (PVOID)0x90000, (LPVOID)&adrnum, 4, 0);
CloseHandle(hProcess);
printf("%d\n", adrnum);
system("pause");
return 0;
}
NtQuerySystemInformation
查询到特定的系统信息
函数原型
NTSYSCALLAPI
NTSTATUS
NTAPI
NtQuerySystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
第一个参数 SystemInformationClass
: 所要查询的系统信息的类型
第二个参数 SystemInformation
:输出的系统信息内容的指针
第三个参数 SystemInformationLength
:接受长度
第四个参数 ReturnLength
:实际返回长度
示例:查询系统基本信息
SYSTEM_BASIC_INFORMATION systemBasicInformation = {};
NTSTATUS status = NtQuerySystemInformation(
SystemBasicInformation, &systemBasicInformation, sizeof(SYSTEM_BASIC_INFORMATION), NULL);
NtQueryInformationThread
检索指定的线程信息。
函数原型
NTSYSCALLAPI
NTSTATUS
NTAPI
NtQueryInformationThread(
_In_ HANDLE ThreadHandle,//线程句柄
_In_ THREADINFOCLASS ThreadInformationClass, //查询线程信息的类型
_Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, //接受线程信息的指针
_In_ ULONG ThreadInformationLength,//线程信息长度
_Out_opt_ PULONG ReturnLength//返回长度
);
示例:获得线程起始地址
#include <phnt_windows.h>
#include <phnt.h>
#include <stdio.h>
int main()
{
DWORD dwThreadId = GetCurrentThreadId();
HANDLE hThread = NULL;
hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, dwThreadId);
if (!hThread)
{
return -1;
}
DWORD dwStaAddr = NULL;
DWORD dwReturnLength = 0;
NTSTATUS status = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress,
&dwStaAddr, sizeof(dwStaAddr), &dwReturnLength);
if (!NT_SUCCESS(status))
{
return -1;
}
printf("0x%p", dwStaAddr);
return 0;
}
示例:通过线程获得进程ID
THREAD_BASIC_INFORMATION threadBasicInfo;
NtQueryInformationThread(hThread, ThreadBasicInformation, &threadBasicInfo, sizeof(threadBasicInfo), &dwReturnLength);
printf("processId:%d", threadBasicInfo.ClientId.UniqueProcess);