进程环境块PEB笔记

      The operating system allocates a structure for every running process that can always be found at fs:[0x30] from within the process.The PEB structure holds information about the process's heaps,binary image information and ,most importantly,three linked lists regarding loaded modules that have been mapped into process space.The linked lists themseleves differ in purpose from showing the order in which the modules were loaded to the order in which the modules were initialized.The initialization order linked list is of most interest as the order in which kernel32.dll is initialized is always constant as the second module to be initialized.By walking the list to the second entry,one can deterministically extract the base address for kernel32.dll.
      Declarations for PEB:
ContractedBlock.gifExpandedBlockStart.gifCode
 1ExpandedBlockStart.gifContractedBlock.giftypedef struct _PEB {
 2 BOOLEAN InheritedAddressSpace;
 3 BOOLEAN ReadImageFileExecOptions;
 4 BOOLEAN BeingDebugged;
 5 BOOLEAN Spare;
 6 HANDLE Mutant;
 7 PVOID ImageBaseAddress;
 8 PPEB_LDR_DATA LoaderData;
 9 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
10 PVOID SubSystemData;
11 PVOID ProcessHeap;
12 PVOID FastPebLock;
13 PPEBLOCKROUTINE FastPebLockRoutine;
14 PPEBLOCKROUTINE FastPebUnlockRoutine;
15 ULONG EnvironmentUpdateCount;
16 PVOID *KernelCallbackTable;
17 PVOID EventLogSection;
18 PVOID EventLog;
19 PPEB_FREE_BLOCK FreeList;
20 ULONG TlsExpansionCounter;
21 PVOID TlsBitmap;
22 ULONG TlsBitmapBits[0x2];
23 PVOID ReadOnlySharedMemoryBase;
24 PVOID ReadOnlySharedMemoryHeap;
25 PVOID *ReadOnlyStaticServerData;
26 PVOID AnsiCodePageData;
27 PVOID OemCodePageData;
28 PVOID UnicodeCaseTableData;
29 ULONG NumberOfProcessors;
30 ULONG NtGlobalFlag;
31 BYTE Spare2[0x4];
32 LARGE_INTEGER CriticalSectionTimeout;
33 ULONG HeapSegmentReserve;
34 ULONG HeapSegmentCommit;
35 ULONG HeapDeCommitTotalFreeThreshold;
36 ULONG HeapDeCommitFreeBlockThreshold;
37 ULONG NumberOfHeaps;
38 ULONG MaximumNumberOfHeaps;
39 PVOID **ProcessHeaps;
40 PVOID GdiSharedHandleTable;
41 PVOID ProcessStarterHelper;
42 PVOID GdiDCAttributeList;
43 PVOID LoaderLock;
44 ULONG OSMajorVersion;
45 ULONG OSMinorVersion;
46 ULONG OSBuildNumber;
47 ULONG OSPlatformId;
48 ULONG ImageSubSystem;
49 ULONG ImageSubSystemMajorVersion;
50 ULONG ImageSubSystemMinorVersion;
51 ULONG GdiHandleBuffer[0x22];
52 ULONG PostProcessInitRoutine;
53 ULONG TlsExpansionBitmap;
54 BYTE TlsExpansionBitmapBits[0x80];
55 ULONG SessionId;
56}
 PEB, *PPEB;
      The LoaderData member of PEB structure is of type PEB_LDR_DATA,as you can see,it's at the 0x0c offset from the head of PEB,and it is defined as below:

ContractedBlock.gifExpandedBlockStart.gifCode
1ExpandedBlockStart.gifContractedBlock.giftypedef struct _PEB_LDR_DATA {
2 ULONG Length;
3 BOOLEAN Initialized;
4 PVOID SsHandle;
5 LIST_ENTRY InLoadOrderModuleList;
6 LIST_ENTRY InMemoryOrderModuleList;
7 LIST_ENTRY InInitializationOrderModuleList;
8}
 PEB_LDR_DATA, *PPEB_LDR_DATA;
9
      Declaration for LIST_ENTRY:
1 typedef struct _LIST_ENTRY 
2ExpandedBlockStart.gifContractedBlock.gif{
3       struct _LIST_ENTRY *Flink; 
4       struct _LIST_ENTRY *Blink; 
5}
 LIST_ENTRY, *PLIST_ENTRY; 
      All the modules loaded by the process is cascaded by a list member InInitializationOrderModuleList,and "Kernel32.dll" is always the second item.
The element type of InInitializationOrderModuleList is defined like this:
ContractedBlock.gifExpandedBlockStart.gifCode
 1ExpandedBlockStart.gifContractedBlock.giftypedef struct _LDR_MODULE {
 2 LIST_ENTRY InLoadOrderModuleList;
 3 LIST_ENTRY InMemoryOrderModuleList;
 4 LIST_ENTRY InInitializationOrderModuleList;
 5 PVOID BaseAddress;
 6 PVOID EntryPoint;
 7 ULONG SizeOfImage;
 8 UNICODE_STRING FullDllName;
 9 UNICODE_STRING BaseDllName;
10 ULONG Flags;
11 SHORT LoadCount;
12 SHORT TlsIndex;
13 LIST_ENTRY HashTableEntry;
14 ULONG TimeDateStamp;
15}
 LDR_MODULE, *PLDR_MODULE;
      So,to get the base address of "kernel32.dll",you can try this:
ContractedBlock.gifExpandedBlockStart.gifCode
 1FIND_KERNEL32:
 2PUSH ESI;Preserve the ESI register
 3XOR EAX,EAX;Zero the EAX register
 4MOV EAX,FS:[EAX+0X30];Store the address of PEB in EAX
 5TEST EAX,EAX;Bitwidth compare eax with itself
 6JS FIND_KERNEL32_9X;If SF is 1 then it is operating on Windows 9x system,other wise it's running on NT.
 7MOV EAX,[EAX+0X0C];Extract the pointer to  Load data structure.
 8MOV ESI,[EAX+0X1C];Extract the first entry in the initialization module list.
 9LODSD;Grab the next entry in the list which points to kernel32.dll
10MOV EAX,[EAX+0X08];Grab the module base address and store in EAX
11JMP FIND_KERNEL32_FINISHED;Jump the the end as kernel32.dll has been done.
12FIND_KERNEL32_9X:
13MOV EAX,[EAX+0X34];Stores the pointer at offset 0x34 in EAX
14LEA EAX,[EAX+0X7C];Load the effective address at EAX plus 0x7c to keep us in signed byte range in order to avoid nulls.
15MOV EAX,[EAX+0X3C];Extract the base address of kernel32.dll
16FIND_KERNEL32_FINISHED:
17POP ESI;Restore ESI register
18RET;Return the caller

转载于:https://www.cnblogs.com/cmleung/archive/2009/09/16/1567884.html

<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、付费专栏及课程。

余额充值