Peb小结
字数 1658 2025-08-07 00:34:54
PE文件格式与进程内存管理深入解析
前言:进程内存空间基础
每个Windows进程都拥有自己独立的4GB虚拟内存空间(在32位系统中),这是现代操作系统内存管理的核心特性。这种隔离机制确保了进程间的安全性和稳定性。
进程内存访问的本质
当进程中的线程执行代码时,其能够访问的内存内容完全由所属进程决定。这一机制的关键在于:
- 线程执行上下文:线程在访问内存时,操作系统会根据当前进程的上下文进行地址转换和权限检查
- 进程隔离边界:不同进程的相同虚拟地址指向不同的物理内存位置
EPROCESS结构体详解
在Windows内核(0环)中,每个进程都由一个称为EPROCESS的结构体表示,这是Windows内核管理进程的核心数据结构:
EPROCESS关键字段
| 字段 | 描述 |
|---|---|
| UniqueProcessId | 进程ID (PID) |
| ActiveProcessLinks | 活动进程链表节点 |
| VadRoot | 虚拟地址描述符(VAD)树的根节点 |
| ObjectTable | 进程对象句柄表 |
| ImageFileName | 进程映像文件名 |
| Peb | 指向进程环境块(PEB)的指针 |
EPROCESS与进程创建
- 当调用
CreateProcess时,内核会:- 分配并初始化EPROCESS结构体
- 建立进程的虚拟地址空间
- 创建初始线程及其ETHREAD结构体
进程环境块(PEB)深入分析
PEB(Process Environment Block)是位于用户空间(3环)的重要数据结构,包含进程的全局信息:
PEB关键结构
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged; // 调试标志
HANDLE hProcess; // 进程句柄
PVOID lpImageBaseAddress; // 映像基址
PPEB_LDR_DATA Ldr; // 加载器数据
// ... 其他字段
} PEB, *PPEB;
PEB_LDR_DATA结构
typedef struct _PEB_LDR_DATA {
DWORD Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList; // 按加载顺序的模块列表
LIST_ENTRY InMemoryOrderModuleList; // 按内存顺序的模块列表
LIST_ENTRY InInitializationOrderModuleList; // 按初始化顺序的模块列表
} PEB_LDR_DATA, *PPEB_LDR_DATA;
LDR_DATA_TABLE_ENTRY结构
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase; // DLL基址
PVOID EntryPoint; // 入口点
ULONG SizeOfImage; // 映像大小
UNICODE_STRING FullDllName; // 完整DLL路径
UNICODE_STRING BaseDllName; // DLL基本名称
// ... 其他字段
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
进程内存管理技术
虚拟地址描述符(VAD)
VAD树是Windows内核用来管理进程虚拟内存空间的数据结构:
- VAD节点:每个节点描述一段虚拟地址范围及其属性
- 树结构:平衡二叉树结构,便于快速查找地址范围
- 内存属性:包含保护标志、内存类型等信息
内存访问流程
- 线程访问虚拟地址
- CPU触发页错误异常(若PTE无效)
- 操作系统检查VAD树:
- 地址是否在有效范围内
- 访问权限是否匹配
- 若检查通过,建立页表项(PTE)
进程注入与检测技术
常见的进程注入技术
-
DLL注入:
- 通过
CreateRemoteThread在目标进程创建线程 - 线程执行
LoadLibrary加载指定DLL
- 通过
-
代码注入:
- 在目标进程分配内存
- 写入shellcode
- 创建远程线程执行
-
APC注入:
- 向目标线程队列插入异步过程调用(APC)
- APC执行注入代码
检测注入的方法
-
PEB遍历检测:
- 枚举
InLoadOrderModuleList中的模块 - 检查异常模块路径或内存属性
- 枚举
-
VAD树分析:
- 检查异常内存区域
- 检测具有执行权限的非映像内存
-
线程分析:
- 检查线程起始地址是否在合法模块内
- 检测异常线程上下文
实战:PEB遍历代码示例
#include <windows.h>
#include <stdio.h>
#include <winternl.h>
// 声明未文档化API
typedef NTSTATUS (NTAPI *PNT_QUERY_PROCESS_INFORMATION)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
void TraversePEB(HANDLE hProcess) {
PROCESS_BASIC_INFORMATION pbi;
PNT_QUERY_PROCESS_INFORMATION NtQueryInformationProcess;
PEB peb;
PEB_LDR_DATA ldrData;
LDR_DATA_TABLE_ENTRY ldrEntry;
// 获取NtQueryInformationProcess地址
NtQueryInformationProcess = (PNT_QUERY_PROCESS_INFORMATION)
GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
// 查询进程基本信息
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
// 读取PEB
ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
// 读取PEB_LDR_DATA
ReadProcessMemory(hProcess, peb.Ldr, &ldrData, sizeof(ldrData), NULL);
// 遍历模块列表
LIST_ENTRY *head = ldrData.InLoadOrderModuleList.Flink;
LIST_ENTRY *current = head;
do {
// 读取当前条目
ReadProcessMemory(hProcess, current, &ldrEntry, sizeof(ldrEntry), NULL);
// 读取DLL名称
WCHAR dllName[MAX_PATH];
ReadProcessMemory(hProcess, ldrEntry.BaseDllName.Buffer,
dllName, ldrEntry.BaseDllName.Length, NULL);
dllName[ldrEntry.BaseDllName.Length / sizeof(WCHAR)] = L'\0';
// 输出模块信息
wprintf(L"Module: %s, Base: 0x%p, Size: 0x%X\n",
dllName, ldrEntry.DllBase, ldrEntry.SizeOfImage);
// 移动到下一个条目
current = ldrEntry.InLoadOrderLinks.Flink;
} while (current != head);
}
int main() {
DWORD pid;
printf("Enter PID: ");
scanf("%d", &pid);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess) {
TraversePEB(hProcess);
CloseHandle(hProcess);
} else {
printf("OpenProcess failed: %d\n", GetLastError());
}
return 0;
}
高级主题:PEB操纵与防御
PEB操纵技术
-
隐藏模块:
- 从PEB的模块链表中移除条目
- 修改LDR_DATA_TABLE_ENTRY结构
-
伪装信息:
- 修改BaseDllName和FullDllName
- 伪造内存属性信息
-
动态重建:
- 运行时重建PEB结构
- 使用异常处理绕过检测
防御措施
-
交叉验证:
- 对比VAD树与PEB模块列表
- 检查内存属性一致性
-
内核态检测:
- 从EPROCESS获取原始信息
- 与用户态PEB对比
-
行为监控:
- 监控PEB修改操作
- 检测异常内存访问模式
总结
理解PEB和EPROCESS结构是Windows系统编程和安全分析的基础。通过深入掌握这些数据结构及其相互关系,可以:
- 开发更强大的进程监控工具
- 实现有效的恶意代码检测
- 设计更安全的应用程序
- 深入理解Windows内存管理机制
这些知识在逆向工程、安全防御和系统开发等多个领域都有重要应用价值。