调用NtQueryInformationProcess部分进程触发AV问题
问题描述
调试器视图显示:返回码正常,UniqueProcessId为请求的进程ID,PebBaseAddress非空,但读取该地址时触发AV(访问违例)
我正在枚举所有进程,这段代码大多数时候可以正常运行,但在某些特定进程上会失败(比如iexplore.exe、vcpkgsrv.exe、rdpclip.exe等),系统环境为Win10 22H2。
相关代码
// using PROCESS_ALL_ACCESS nor MAXIMUM_ALLOWED doesn't help AutoHandleNull hProcess{ ::OpenProcess(ProcessQueryRight/*PROCESS_QUERY_LIMITED_INFORMATION*/, FALSE, procEntry.th32ProcessID) }; if (hProcess) { ::PROCESS_BASIC_INFORMATION pbi{}; ULONG returnLength; const NTSTATUS st = pNtQueryInformationProcess(hProcess.get(), ProcessBasicInformation, &pbi, sizeof(pbi), &returnLength); if (NT_SUCCESS(st) && pbi.PebBaseAddress && pbi.PebBaseAddress->SessionId == sessionID) { return procEntry.th32ProcessID; } }
解决方案
核心问题在于:PebBaseAddress是目标进程虚拟地址空间中的地址,直接在当前进程解引用这个指针,会访问当前进程地址空间中不存在或无权限的内存,触发访问违例。
正确处理方式
用
ReadProcessMemory跨进程读取PEB数据
必须通过ReadProcessMemory将目标进程的PEB内容读取到当前进程的内存缓冲区,再访问SessionId字段,不能直接跨进程解引用指针。补充进程权限
OpenProcess需要同时申请PROCESS_VM_READ权限,仅PROCESS_QUERY_LIMITED_INFORMATION只能获取进程基本信息,无法读取目标进程内存。
修改后的代码
// 添加PROCESS_VM_READ权限 AutoHandleNull hProcess{ ::OpenProcess(ProcessQueryRight | PROCESS_VM_READ, FALSE, procEntry.th32ProcessID) }; if (hProcess) { ::PROCESS_BASIC_INFORMATION pbi{}; ULONG returnLength; const NTSTATUS st = pNtQueryInformationProcess(hProcess.get(), ProcessBasicInformation, &pbi, sizeof(pbi), &returnLength); if (NT_SUCCESS(st) && pbi.PebBaseAddress) { // 将目标进程的PEB读取到本地缓冲区 PEB localPeb{}; SIZE_T bytesRead; if (::ReadProcessMemory(hProcess.get(), pbi.PebBaseAddress, &localPeb, sizeof(localPeb), &bytesRead) && bytesRead == sizeof(localPeb)) { if (localPeb.SessionId == sessionID) { return procEntry.th32ProcessID; } } } }
额外注意事项
- 部分受保护的系统进程、UAC隔离进程,即使拥有
PROCESS_VM_READ权限也可能读取失败,需提前处理这类异常情况。 PEB结构体定义随Windows版本变化,要确保使用对应系统版本的正确定义,避免结构体大小不匹配导致读取错误。
内容的提问来源于stack exchange,提问作者OwnageIsMagic
相关产品推荐
相关产品推荐

