[笔记]Windows核心编程《番外篇》常用的NT API及使用示例

1,929 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

@[toc]

前言

NTAPI:泛指ntdll.dll模块不对外提供的API接口,大多是提供给内核层开发人员使用的。

一般通过动态载入库的方式(LoadLibrary + GetProcAddress)调用

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.h

#pragma once		
#include <windows.h>
#include <iostream>
using namespace std;
//宏,结构体定义,函数声明;
//#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)


//要自己定义PEB结构:

//PEB结构中的查找进程完整路径的结构体
typedef struct _UNICODE_STRING
{
	UINT16 Length;//short型
	UINT16 MaximumLength;
	PWCHAR Buffer;//WCHAR*型(四字节大小的指针)
}UNICODE_STRING, PUNICODE_STRING;
//UNICODE_STRING在Ring3层不公开,(在驱动层才公开)
typedef struct _RTL_USER_PROCESS_PARAMETERS_X86
{
	UINT32 MaximumLength;
	UINT32 Length;
	UINT32 Flags;
	UINT32 DebugFlags;
	PVOID  ConsoleHandle;
	UINT32 ConsoleFlags;//UINT 4B
	PVOID  StandardInput;
	PVOID  StandardOutput;
	PVOID  StandardError;
	ULONG32 CurrentDirectory[3];//原来是十二字节的结构体CURDIR
	UNICODE_STRING DllPath;
	UNICODE_STRING ImagePathName;//完整路径
	UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS_X86, *PRTL_USER_PROCESS_PARAMETERS_X86;
typedef struct _PEB_X86
{
	UINT8 InheritedAddressSpace;
	UINT8 ReadImageFileExecOptions;
	UINT8 BeingDebugged;
	UINT8 BitField;//联合体(位域第一位的成员)
	PVOID Mutant;//互斥体
	PVOID ImageBaseAddress;//模块加载基地址
	PVOID Ldr;//结构体(Ldr实际上为结构体类型指针)
	PRTL_USER_PROCESS_PARAMETERS_X86 ProcessParameters;
}PEB_X86, *PPEB_X86;

#ifdef _WIN32
#define RTL_USER_PROCESS_PARAMETERS RTL_USER_PROCESS_PARAMETERS_X86
#define PPEB PPEB_X86
#define PEB  PEB_X86
#else
#define PPEB PPEB_X64
#define PEB  PEB_X64
#endif 



//有关查找PEB地址的属于进程内存的结构体
typedef struct _PROCESS_BASIC_INFORMATION
{
	NTSTATUS ExitStatus;
	PPEB     PebBaseAddress;   //地址
	ULONG    AffinityMask;
	LONG     BasePriority;
	ULONG    UniqueProcessId;
	ULONG    InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;
typedef PROCESS_BASIC_INFORMATION *PPROCESS_BASIC_INFORMATION;


//函数指针原型定义:
typedef enum _PROCESSINFOCLASS {
	ProcessBasicInformation,
	ProcessQuotaLimits,
	ProcessIoCounters,
	ProcessVmCounters,
	ProcessTimes,
	ProcessBasePriority,
	ProcessRaisePriority,
	ProcessDebugPort,
	ProcessExceptionPort,
	ProcessAccessToken,
	ProcessLdtInformation,
	ProcessLdtSize,
	ProcessDefaultHardErrorMode,
	ProcessIoPortHandlers,          // Note: this is kernel mode only
	ProcessPooledUsageAndLimits,
	ProcessWorkingSetWatch,
	ProcessUserModeIOPL,
	ProcessEnableAlignmentFaultFixup,
	ProcessPriorityClass,
	ProcessWx86Information,
	ProcessHandleCount,
	ProcessAffinityMask,
	ProcessPriorityBoost,
	ProcessDeviceMap,
	ProcessSessionInformation,
	ProcessForegroundInformation,
	ProcessWow64Information,
	ProcessImageFileName,
	ProcessLUIDDeviceMapsEnabled,
	ProcessBreakOnTermination,
	ProcessDebugObjectHandle,
	ProcessDebugFlags,
	ProcessHandleTracing,
	ProcessIoPriority,
	ProcessExecuteFlags,
	ProcessResourceManagement,
	ProcessCookie,
	ProcessImageInformation,
	MaxProcessInfoClass
} PROCESSINFOCLASS;

typedef
NTSTATUS(NTAPI *pfnNtQueryInformationProcess)(
IN HANDLE ProcessHandle,//,进程句柄,查谁
IN PROCESSINFOCLASS ProcessInformationClass,//枚举类型结构体,查什么信息
OUT PVOID ProcessInformation,//结构体首地址,查出来的东西放在哪里
IN UINT32 ProcessInformationLength,//结构体大小
OUT PUINT32 ReturnLength);//校验值
//#define NTAPI __stdcall,指调用约定
//定义函数指针
//
BOOL GetProcessFullPathByProcessID(ULONG32 ProcessID, WCHAR* BufferData, ULONG BufferLegnth);

main.cpp

// PEB.cpp : 定义控制台应用程序的入口点。
//

#include "PEB.h"

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
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,完整路径(存放的数组名),数组长度)

	cout << bOk << endl;
	if (bOk == TRUE)
	{
		printf("%S\r\n", BufferData);
		//BufferData双字,故用大S输出字符串;
	}
	return 0;
}

BOOL GetProcessFullPathByProcessID(ULONG32 ProcessID, WCHAR* BufferData, ULONG BufferLegnth)
//先找到peb结构在进程中的地址,再从peb结构中找到完整路径所在的地址;
//GetPebByProcessID,GetProcessFullPathByPeb,
{
	BOOL						bOk = FALSE;
	NTSTATUS					Status = 0;
	//一种int型返回值
	PEB	                        Peb = { 0 };
	//PEB结构体初始化
	HANDLE						ProcessHandle = NULL;

	//*打开目标进程空间
	ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessID);
	//ProcessHandle值是目标进程的进程句柄,是一个正数(-1是GetCurrentProcess函数,代表自己进程的伪句柄);
	//OpenProcess为Windows库函数,“打开(对方)进程空间”(想要行使的权限(查询|读),BOOL型,目标进程ID)

	if (ProcessHandle == NULL)
	{
		return FALSE;
	}
	pfnNtQueryInformationProcess	NtQueryInformationProcess =
		(pfnNtQueryInformationProcess)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");
	//GetModuleHandle为Windows库函数(GetModuleHandleW),“返回加载模块的基地址”(所以模块名字传为双字!)
	//GetProcAddress为Windows库函数,“从当前进程的导出表中获得目标函数地址”(实际上就是遍历导出表来搜索这个函数)
	//								本语句意思是从ntdll.dll的导出表中搜索NtQueryInformationProcess函数!
	//此时函数地址得到的是自己的,(1自己的基地址,2自己的函数)//没有用目标函数进程
	//	
	//GetProcAddress从当前函数的导出表搜索函数	//从当前进程空间的ntdll模块的导出表中获得一个函数NtQueryInformationProcess的地址
	//而不从导入表中获得(直接调用)原因是:
	//有可能就没有导入!(涉及到VS编译未公开函数等原因)GetProcAddress返回的是一个泛型,

	//得到函数地址以后,发生强制类型转换,
	if (NtQueryInformationProcess == NULL)
	{
		CloseHandle(ProcessHandle);
		ProcessHandle = NULL;
		return FALSE;
	}

	//**通过 NtQueryInformationProcess 获得 ProcessBasicInformation
	PROCESS_BASIC_INFORMATION	pbi = { 0 };
	ULONG32						ReturnLength = 0;
	//开始查进程的ProcessBasicInformation
	Status = NtQueryInformationProcess(ProcessHandle,
		ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION),
		(PUINT32)&ReturnLength);
	//参数:查谁,查什么,

	//Status=0
	//NT_SUCCESS(Status)=1
	if (!NT_SUCCESS(Status))
	{
		CloseHandle(ProcessHandle);
		ProcessHandle = NULL;
		return FALSE;
	}

	//***通过ReadProcessMemory 从进程里面 PebBaseAddress 内存数据读取出来
	bOk = ReadProcessMemory(ProcessHandle, pbi.PebBaseAddress, &Peb, sizeof(PEB), (SIZE_T*)&ReturnLength);
	//ReadProcessMemory是Windows库函数,“读进程空间的内存”,
	//(目标进程句柄,目标地址,读到peb这个结构体指针里,结构体大小,校验值)
	//SIZE_T相当于ULONG_PTR;
	if (bOk == FALSE)
	{
		CloseHandle(ProcessHandle);
		ProcessHandle = NULL;
		return FALSE;
	}

	RTL_USER_PROCESS_PARAMETERS RtlUserProcessParameters = { 0 };
	bOk = ReadProcessMemory(ProcessHandle, Peb.ProcessParameters, &RtlUserProcessParameters,
		sizeof(RTL_USER_PROCESS_PARAMETERS), (SIZE_T*)&ReturnLength);

	if (RtlUserProcessParameters.ImagePathName.Buffer != NULL)
	{
		ULONG v1 = 0;
		if (RtlUserProcessParameters.ImagePathName.Length<BufferLegnth)
		{
			v1 = RtlUserProcessParameters.ImagePathName.Length;
		}
		else
		{
			v1 = BufferLegnth - 10;
		}
		bOk = ReadProcessMemory(ProcessHandle, RtlUserProcessParameters.ImagePathName.Buffer,
			BufferData, v1, (SIZE_T*)&ReturnLength);
		if (bOk == FALSE)
		{
			CloseHandle(ProcessHandle);
			ProcessHandle = NULL;
			return FALSE;
		}
	}
	CloseHandle(ProcessHandle);
	return TRUE;
}

在这里插入图片描述

NtSetInformationProcess

参考 SetProcessInformation function msdn

设置指定进程的信息

函数原型

BOOL SetProcessInformation(
  [in] HANDLE                    hProcess,
  [in] PROCESS_INFORMATION_CLASS ProcessInformationClass,
       LPVOID                    ProcessInformation,
  [in] DWORD                     ProcessInformationSize
);

用例 使进程跳过DEP检测 关闭DEP

blog.csdn.net/dongyewolon…

总结