获得目标进程PEB,并获得进程各种信息

本文介绍了一种方法,通过OpenProcess、NtWow64QueryInformationProcess64和NtWow64ReadVirtualMemory64函数,获取x64和x86进程的PEB结构以及环境变量等详细信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本程序可完美获得x64和x86程序PEB,及环境变量等信息。

程序首先用OpenProcess打开目标进程,然后用Ntddl.dll导入表中微软未公开函数NtWow64QueryInformationProcess64(NtQueryInformationProcess)、NtWow64ReadVirtualMemory64(ReadProcessMemory)来获得目标进程信息。

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

#include "stdafx.h"
#include<Windows.h>
#include<iostream>
#include <Strsafe.h>
using namespace std;

#define NT_SUCCESS(x) ((x) >= 0)

#define ProcessBasicInformation 0
typedef
NTSTATUS(WINAPI *pfnNtWow64QueryInformationProcess64)
(HANDLE ProcessHandle, UINT32 ProcessInformationClass,
	PVOID ProcessInformation, UINT32 ProcessInformationLength,
	UINT32* ReturnLength);

typedef
NTSTATUS(WINAPI *pfnNtWow64ReadVirtualMemory64)
(HANDLE ProcessHandle, PVOID64 BaseAddress,
	PVOID BufferData, UINT64 BufferLength,
	PUINT64 ReturnLength);

typedef
NTSTATUS(WINAPI *pfnNtQueryInformationProcess)
(HANDLE ProcessHandle, ULONG ProcessInformationClass,
	PVOID ProcessInformation, UINT32 ProcessInformationLength,
	UINT32* ReturnLength);

template <typename T>
struct _UNICODE_STRING_T
{
	WORD Length;
	WORD MaximumLength;
	T Buffer;
};

template <typename T>
struct _LIST_ENTRY_T
{
	T Flink;
	T Blink;
};

template <typename T, typename NGF, int A>
struct _PEB_T
{
	typedef T type;

	union
	{
		struct
		{
			BYTE InheritedAddressSpace;
			BYTE ReadImageFileExecOptions;
			BYTE BeingDebugged;
			BYTE BitField;
		};
		T dummy01;
	};
	T Mutant;
	T ImageBaseAddress;     //进程加载基地址
	T Ldr;				    
	T ProcessParameters;    //各种信息,环境变量,命令行等等
	T SubSystemData;
	T ProcessHeap;
	T FastPebLock;
	T AtlThunkSListPtr;
	T IFEOKey;
	T CrossProcessFlags;
	T UserSharedInfoPtr;
	DWORD SystemReserved;
	DWORD AtlThunkSListPtr32;
	T ApiSetMap;
	T TlsExpansionCounter;
	T TlsBitmap;
	DWORD TlsBitmapBits[2];
	T ReadOnlySharedMemoryBase;
	T HotpatchInformation;
	T ReadOnlyStaticServerData;
	T AnsiCodePageData;
	T OemCodePageData;
	T UnicodeCaseTableData;
	DWORD NumberOfProcessors;
	union
	{
		DWORD NtGlobalFlag;
		NGF dummy02;
	};
	LARGE_INTEGER CriticalSectionTimeout;
	T HeapSegmentReserve;
	T HeapSegmentCommit;
	T HeapDeCommitTotalFreeThreshold;
	T HeapDeCommitFreeBlockThreshold;
	DWORD NumberOfHeaps;
	DWORD MaximumNumberOfHeaps;
	T ProcessHeaps;
	T GdiSharedHandleTable;
	T ProcessStarterHelper;
	T GdiDCAttributeList;
	T LoaderLock;
	DWORD OSMajorVersion;
	DWORD OSMinorVersion;
	WORD OSBuildNumber;
	WORD OSCSDVersion;
	DWORD OSPlatformId;
	DWORD ImageSubsystem;
	DWORD ImageSubsystemMajorVersion;
	T ImageSubsystemMinorVersi
<think>好的,我现在需要处理用户的问题:他想了解进程环境块(PEB)中可被修改的字段,以及如何在驱动程序中校验这些字段的值。用户之前的问题是关于修改EPROCESS中的字段在驱动中校验,现在转向了PEB,可能需要更详细的信息。 首先,我需要回忆PEB的结构。PEB是用户态可访问的结构,包含进程的许多信息,比如环境变量、命令行参数、加载的模块等。根据用户提供的引用[1],PEB中的Ldr字段指向PEB_LDR_DATA结构,这个结构包含已加载模块的信息。引用[2]提到PEB中的TlsBitmapBits字段,用于TLS(线程本地存储)的位图。这些信息可能对用户的问题有帮助。 用户的需求是找出PEB中可以修改的字段,说明如何在驱动中校验。我需要确定哪些字段是用户态可修改的。比如,命令行参数、环境变量、当前目录等,通常可以通过用户态函数修改,如SetEnvironmentVariable、SetCurrentDirectory等。这些修改会反映在PEB的相应字段中。 接下来,考虑如何在内核驱动中访问PEB。每个进程的EPROCESS结构中有一个指向PEB的指针(EPROCESS->Peb)。在驱动中,可以通过PsGetProcessPeb函数或手动偏移来获取PEB地址。但需要注意不同Windows版本的结构偏移可能不同,可能需要动态获取。 然后,校验这些字段的值。比如,用户修改了命令行参数,驱动需要读取PEB中的ProcessParameters.CommandLine字段来验证。需要注意的是,用户态和内核态访问内存的方式不同,驱动需要使用ProbeForRead等函数确保安全访问用户态内存。 另外,需要考虑权限和内存保护。直接修改内核内存可能引发稳定性问题,但PEB的某些字段位于用户态空间,用户态程序可以直接修改,而驱动需要从内核态读取这些用户态指针指向的数据。 用户提供的引用[3]关于中断的内容可能与当前问题关联不大,但可能用户想了解进程切换时的行为,不过这可能属于其他问题。暂时可以忽略,专注于PEB字段的修改和校验。 需要列举具体的可修改字段,如ImagePathName、CommandLine、Environment、CurrentDirectory、TlsBitmapBits等。每个字段的修改方法和驱动校验步骤需要详细说明。 最后,生成相关问题,帮助用户深入理解,比如如何通过PEB注入DLL,或者如何保护PEB字段不被篡改。</think>### 进程环境块(PEB)中可修改字段及驱动校验方法 进程环境块(Process Environment Block, PEB)是Windows用户态进程的核心数据结构,**部分字段允许用户态程序直接或间接修改**。以下是可修改字段的详细说明及驱动校验实现方案: --- ### **1. 用户态可修改的PEB字段** #### **(1) 进程参数(ProcessParameters)** - **命令行参数(CommandLine)** 通过`GetCommandLine`和`WriteProcessMemory`修改: ```c wchar_t newCmdLine[] = L"modified_command_line"; PEB* peb = NtCurrentTeb()->ProcessEnvironmentBlock; PRTL_USER_PROCESS_PARAMETERS params = peb->ProcessParameters; WriteProcessMemory(GetCurrentProcess(), params->CommandLine.Buffer, newCmdLine, sizeof(newCmdLine), NULL); ``` **驱动校验**:通过`EPROCESS->Peb->ProcessParameters->CommandLine`读取[^1]。 - **环境变量(Environment)** 使用`SetEnvironmentVariable`修改,影响`PEB->ProcessParameters->Environment`: ```c SetEnvironmentVariable(L"INJECTED", L"TRUE"); ``` **驱动校验**:遍历`PEB->ProcessParameters->Environment`键值对。 - **当前目录(CurrentDirectory)** 通过`SetCurrentDirectory`修改: ```c SetCurrentDirectory(L"C:\\Temp"); ``` **驱动校验**:访问`PEB->ProcessParameters->CurrentDirectory.DosPath`。 #### **(2) 加载模块信息(Ldr)** - **内存中模块列表** 用户态可注入DLL或卸载模块,修改`PEB->Ldr->InLoadOrderModuleList`: ```c // 示例:隐藏模块(需直接操作链表) PLIST_ENTRY moduleEntry = &peb->Ldr->InLoadOrderModuleList; RemoveEntryList(moduleEntry); // 从链表中移除自身模块 ``` **驱动校验**:遍历`PEB->Ldr->InLoadOrderModuleList`,检查模块完整性。 #### **(3) TLS位图(TlsBitmapBits)** - **线程本地存储(TLS)槽位分配** 用户态可通过`TlsAlloc`/`TlsFree`修改`PEB->TlsBitmapBits`(引用[2]): ```c DWORD tlsIndex = TlsAlloc(); // 分配TLS索引,对应位图置1 TlsFree(tlsIndex); // 释放索引,位图置0 ``` **驱动校验**:读取`PEB->TlsBitmapBits`检查位图状态。 #### **(4) 调试标志(BeingDebugged)** - **反调试绕过** 直接修改`PEB->BeingDebugged`欺骗调试器: ```c peb->BeingDebugged = 0; // 置0表示未被调试 ``` **驱动校验**:直接读取`PEB->BeingDebugged`字段。 --- ### **2. 驱动校验实现步骤** #### **(1) 获取PEB地址** 通过`EPROCESS`结构定位PEB(需适配不同Windows版本): ```c PEPROCESS GetProcessEProcess(HANDLE pid) { PEPROCESS eprocess; PsLookupProcessByProcessId(pid, &eprocess); return eprocess; } PPEB GetProcessPeb(PEPROCESS eprocess) { return (PPEB)(*(PUCHAR*)eprocess + 0x3f8); // Win10 21H2中PEB偏移为0x3f8 } ``` #### **(2) 读取用户态内存** 由于PEB部分字段指向用户态内存(如`CommandLine.Buffer`),需使用`ProbeForRead`安全访问: ```c NTSTATUS ReadUserModeString(PVOID userBuffer, ULONG length, WCHAR* output) { __try { ProbeForRead(userBuffer, length, 1); RtlCopyMemory(output, userBuffer, length); return STATUS_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } ``` #### **(3) 校验字段示例(以CommandLine为例)** ```c NTSTATUS VerifyCommandLine(HANDLE pid, const WCHAR* expectedCmd) { PEPROCESS eprocess = GetProcessEProcess(pid); PPEB peb = GetProcessPeb(eprocess); PRTL_USER_PROCESS_PARAMETERS params = peb->ProcessParameters; // 读取用户态命令行缓冲区 WCHAR cmdLine[256] = {0}; NTSTATUS status = ReadUserModeString(params->CommandLine.Buffer, params->CommandLine.Length, cmdLine); ObDereferenceObject(eprocess); if (NT_SUCCESS(status) && wcsstr(cmdLine, expectedCmd) != NULL) { return STATUS_SUCCESS; } return STATUS_UNSUCCESSFUL; } ``` --- ### **3. 注意事项** 1. **字段偏移适配** `PEB`和`RTL_USER_PROCESS_PARAMETERS`的偏移量随系统版本变化,需动态获取(如通过特征码或`PsGetProcessPeb`函数)。 2. **用户态内存访问** 直接读取用户态指针(如`CommandLine.Buffer`)需使用`__try/__except`块防止蓝屏。 3. **反篡改机制** 部分安全软件会监控`PEB->BeingDebugged`或`Ldr`链表,修改这些字段可能触发检测。 --- ### **4. 完整驱动校验示例** #### **(1) 用户态程序(修改命令行)** ```c #include <windows.h> int main() { PEB* peb = NtCurrentTeb()->ProcessEnvironmentBlock; PRTL_USER_PROCESS_PARAMETERS params = peb->ProcessParameters; wchar_t newCmd[] = L"modified_by_user"; WriteProcessMemory(GetCurrentProcess(), params->CommandLine.Buffer, newCmd, sizeof(newCmd), NULL); return 0; } ``` #### **(2) 内核驱动(校验命令行)** ```c NTSTATUS DriverEntry() { HANDLE pid = /* 目标进程PID */; WCHAR expectedCmd[] = L"modified_by_user"; return VerifyCommandLine(pid, expectedCmd); } ``` --- ### **相关问题** 1. 如何通过修改`PEB->Ldr`链表实现DLL隐藏? 2. 驱动中如何动态获取不同系统版本的`PEB`结构偏移? 3. 修改`PEB->BeingDebugged`能否绕过所有调试器的检测? 4. 如何保护进程的`PEB`字段不被恶意篡改? [^1]: `PEB->ProcessParameters`中的字段需通过`RtlQueryProcessDebugInformation`获取详细信息。 [^2]: `TlsBitmapBits`的修改需同步更新线程的TLS槽位,避免内存泄漏。 [^3]: 操作`PEB->Ldr`链表时需注意线程同步问题,防止链表断裂导致进程崩溃。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值