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 结构,该结构包含三个重要的双向链表:

  1. InLoadOrderModuleList: 模块加载顺序
  2. InMemoryOrderModuleList: 模块在内存加载顺序
  3. 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 中包含多个可用于检测调试的标志:

  1. BeingDebugged: 当有调试器附加时该位被置为1
  2. NtGlobalFlag: 当有调试器附加时该位通常被置为 0x70
  3. Heap Flags:
    • ProcessHeap 指向 _HEAP 结构体
    • HeapFlags 值大于2,或 ForceFlags 值大于0时,说明被调试
  4. 堆Magic标志:
    • 0xABABABAB
    • 0xFEEEFEEE

5. 实际调试示例

使用 WinDbg 调试 notepad 进程:

  1. 附加到 notepad 进程
  2. 查看 TEB 信息:
    dt _TEB @$teb
    
  3. 查看 PEB 信息
  4. 查看 Ldr 信息
  5. 遍历模块链表:
    dt 0x1b678806dc0 _LDR_DATA_TABLE_ENTRY
    

6. 总结

PEB 是 Windows 系统中一个极其重要的数据结构,通过它可以:

  1. 动态获取 API 地址,实现无导入表的函数调用
  2. 修改进程信息,实现进程伪装
  3. 检测调试器存在,实现反调试
  4. 获取进程加载的模块信息

理解 PEB 结构及其应用对于 Windows 系统编程、安全研究和逆向工程都具有重要意义。

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位系统 : 64位系统 : 3.2 使用 readfsdword/readgsqword 3.3 使用 NtQueryInformationProcess 4. PEB 的武器化应用 4.1 动态获取 API 通过遍历 PEB 中的模块链表和导出表,可以实现动态获取 API 地址的功能: 4.2 进程伪装 通过修改 PEB 中的进程参数可以实现进程伪装: 4.3 反调试技术 PEB 中包含多个可用于检测调试的标志: BeingDebugged : 当有调试器附加时该位被置为1 NtGlobalFlag : 当有调试器附加时该位通常被置为 0x70 Heap Flags : ProcessHeap 指向 _HEAP 结构体 HeapFlags 值大于2,或 ForceFlags 值大于0时,说明被调试 堆Magic标志 : 0xABABABAB 0xFEEEFEEE 5. 实际调试示例 使用 WinDbg 调试 notepad 进程: 附加到 notepad 进程 查看 TEB 信息: 查看 PEB 信息 查看 Ldr 信息 遍历模块链表: 6. 总结 PEB 是 Windows 系统中一个极其重要的数据结构,通过它可以: 动态获取 API 地址,实现无导入表的函数调用 修改进程信息,实现进程伪装 检测调试器存在,实现反调试 获取进程加载的模块信息 理解 PEB 结构及其应用对于 Windows 系统编程、安全研究和逆向工程都具有重要意义。