PEB及其武器化
字数 1481 2025-08-10 08:28:52
Windows PEB 结构及其武器化应用
1. PEB 和 TEB 基础概念
1.1 PEB (Process Environment Block)
PEB (Process Environment Block) 是 Windows 操作系统中一个关键的数据结构,用于存储有关进程的信息。每个进程都有一个对应的 PEB 结构体,它提供了许多关于进程状态和环境的信息,是用户模式和内核模式之间的重要接口。
1.2 TEB (Thread Environment Block)
TEB (Thread Environment Block) 用于存储线程状态信息和线程所需的各种数据。每个线程都有一个对应的 TEB 结构体,其中包含指向 PEB 的指针。
2. TEB 和 PEB 结构分析
2.1 32位和64位系统的差异
-
32位系统:
- TEB 结构指针存储在 FS 寄存器中
- TEB 到 PEB 的偏移量为 0x30
-
64位系统:
- TEB 结构指针存储在 GS 寄存器中
- TEB 到 PEB 的偏移量为 0x60
2.2 PEB 关键成员
PEB 结构中最重要的成员之一是 Ldr (位于偏移 0x0c 处),它存储着有关模块加载的信息。Ldr 指向 _PEB_LDR_DATA 结构,该结构包含三个重要的双向链表:
- InLoadOrderModuleList: 模块加载顺序
- InMemoryOrderModuleList: 模块在内存加载顺序
- InInitializationOrderLinks: 模块初始化装载顺序
2.3 模块链表结构
这些链表都是双向链表,每个节点都是 _LDR_DATA_TABLE_ENTRY 结构,关键成员包括:
Flink: 指向下一个节点Blink: 指向上一个节点DllBase(偏移 0x18): 模块基地址dllName(偏移 0x30): 模块名称
3. 获取 PEB 的方法
3.1 汇编方式
32位系统:
__asm {
mov eax, dword ptr fs:[00000030h]
mov peb, eax
}
64位系统:
GetPEB PROC
mov rax, gs:[30h] ; TEB from gs in 64 bit only
mov rax, [rax + 60h] ; PEB
ret
GetPEB ENDP
3.2 使用 readfsdword/readgsqword
#ifndef _WIN64
PPEB pPeb = (PPEB)__readfsdword(0x30);
#else
PPEB pPeb = (PPEB)__readgsqword(0x60);
#endif
3.3 使用 NtQueryInformationProcess
#include <windows.h>
#include <winternl.h>
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef NTSTATUS(NTAPI* PNtQueryInformationProcess)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
int main() {
HANDLE hProcess = GetCurrentProcess();
PROCESS_BASIC_INFORMATION pbi;
HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
PNtQueryInformationProcess pNtQueryInformationProcess =
(PNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
NTSTATUS status = pNtQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&pbi,
sizeof(pbi),
NULL
);
if (NT_SUCCESS(status)) {
PPEB pebAddress = pbi.PebBaseAddress;
wprintf(L"PEB Address: %p\n", pebAddress);
}
CloseHandle(hProcess);
return 0;
}
4. PEB 的武器化应用
4.1 动态获取 API
通过遍历 PEB 中的模块链表和导出表,可以实现动态获取 API 地址的功能:
PVOID GetAddressFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName) {
PVOID get_address = 0;
DWORD ulFunctionIndex = 0;
// DOS头
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
// NT头
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
// 导出表
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader +
pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
ULONG NumberOfFunctions = pExportTable->NumberOfFunctions;
PULONG AddressOfNamesTable = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
PCHAR Name = NULL;
for (ULONG i = 0; i < NumberOfFunctions; i++) {
Name = (PCHAR)((PUCHAR)pDosHeader + AddressOfNamesTable[i]);
if (0 == _strnicmp(pszFunctionName, Name, strlen(pszFunctionName))) {
USHORT ordinal = *(USHORT*)((PUCHAR)pDosHeader +
pExportTable->AddressOfNameOrdinals + 2 * i);
ULONG FuncAddr = *(PULONG)((PUCHAR)pDosHeader +
pExportTable->AddressOfFunctions + 4 * ordinal);
get_address = (PVOID)((PUCHAR)pDosHeader + FuncAddr);
return get_address;
}
}
return 0;
}
4.2 进程伪装
通过修改 PEB 中的进程参数可以实现进程伪装:
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <winternl.h>
int main() {
// 获取TEB中PEB指针的偏移
#ifdef _M_IX86
PPEB PEB = (PPEB)__readfsdword(0x30);
#else
PPEB PEB = (PPEB)__readgsqword(0x60);
#endif
// 改变进程当前目录
int result = SetCurrentDirectoryW(L"C:\\Users\\James\\");
// 改变进程映像路径和命令行
WCHAR path[] = L"c:\\windows\\system32\\notepad.exe\0";
PEB->ProcessParameters->ImagePathName.Buffer = path;
PEB->ProcessParameters->CommandLine.Buffer = path;
getchar();
}
4.3 反调试技术
PEB 中包含多个可用于检测调试的标志:
- BeingDebugged: 当有调试器附加时该位被置为1
- NtGlobalFlag: 当有调试器附加时该位通常被置为 0x70
- Heap Flags:
ProcessHeap指向_HEAP结构体HeapFlags值大于2,或ForceFlags值大于0时,说明被调试
- 堆Magic标志:
- 0xABABABAB
- 0xFEEEFEEE
5. 实际调试示例
使用 WinDbg 调试 notepad 进程:
- 附加到 notepad 进程
- 查看 TEB 信息:
dt _TEB @$teb - 查看 PEB 信息
- 查看 Ldr 信息
- 遍历模块链表:
dt 0x1b678806dc0 _LDR_DATA_TABLE_ENTRY
6. 总结
PEB 是 Windows 系统中一个极其重要的数据结构,通过它可以:
- 动态获取 API 地址,实现无导入表的函数调用
- 修改进程信息,实现进程伪装
- 检测调试器存在,实现反调试
- 获取进程加载的模块信息
理解 PEB 结构及其应用对于 Windows 系统编程、安全研究和逆向工程都具有重要意义。