PEB结构的获取

本文介绍了如何在32位和64位系统中获取PEB(Process Environment Block)结构,包括通过CreateProcess创建新进程获取PEB地址,以及在X64系统下利用GS寄存器找到PEB和TEB(Thread Environment Block)。通过枚举PEB的InInitializationOrderModuleList,可以得到Kernel32的基址。同时,文章提到了X64环境下内联汇编的限制和C语言实现搜索过程。

32位获取KERNEL32地址汇编代码PEB结构----枚举用户模块列表。

PEB地址的取得:

1:通过CreateProcess()创建新的被挂起的进程,此时其初始化线程上下文中,ebx 指向其PEB结构, EAX指向其EIP(代码执行地址)

demo:

CreateProcess(NULL, TARGETPROC,
                 NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi))    
  {
    ctx->ContextFlags=CONTEXT_FULL;
    GetThreadContext(pi->hThread, ctx); //获得线程的所有重要的寄存器CTX

    DWORD *pebInfo = (DWORD *)ctx->Ebx; //ctx->Ebx = points to PEB

2:如果线程没被挂起, 通过FS寄存器指向当前TEB结构 , 再TEB偏移0x30处是PEB指针 ,通过这个指针可以取得PEB结构的地址

demo:

__asm
{
mov eax,fs:[0x30]
mov PEB,eax
}


3:X64程序下的FS寄存器角色已经换成了gs

暂时发现的一些东西:

gs:[0x30] TEB

gs:[0x40] Pid

gs:[0x48] Tid

gs:[0x60]  PEB

gs:[0x68]  LastError.

虽然gs:[0x60]直接存放的PEB,但是由于vista/7后的地址随机化机制,还是从TEB获取比较靠谱。

0:009> dt 000007fffff98000 _TEB
ntdll!_TEB
+0×000 NtTib            : _NT_TIB
+0×038 EnvironmentPointer : (null)
+0×040 ClientId         : _CLIENT_ID
+0×050 ActiveRpcHandle  : (null)
+0×058 ThreadLocalStoragePointer : (null)
+0×060 ProcessEnvironmentBlock : 0x000007ff`fffd5000 _PEB    //这里即是PEB
//用c语言描述就是
#define x64_GetPeb()                    ( (LONG64*)(*((LONG64*)((BYTE*)x64_GetTeb()+0×060))) )
得到了PEB,剩下的就和x86下一样了.只是偏移不一样了

0:009> dt 0x000007ff`fffd5000 _PEB
ntdll!_PEB
+0×000 InheritedAddressSpace : 0 ”
+0×001 ReadImageFileExecOptions : 0 ”
+0×002 BeingDebugged    : 0×1 ”
+0×003 BitField         : 0×8 ”
+0×003 ImageUsesLargePages : 0y0
+0×003 IsProtectedProcess : 0y0
+0×003 IsLegacyProcess  : 0y0
+0×003 IsImageDynamicallyRelocated : 0y1
+0×003 SkipPatchingUser32Forwarders : 0y0
+0×003 SpareBits        : 0y000
+0×008 Mutant           : 0xffffffff`ffffffff Void
+0×010 ImageBaseAddress : 0×00000000`ff310000 Void
+0×018 Ldr              : 0×00000000`77222640 _PEB_LDR_DATA

0:009> dt 0×00000000`77222640 _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0×000 Length           : 0×58
+0×004 Initialized      : 0×1 ”
+0×008 SsHandle         : (null) //length 8 ,32位系统length 4
+0×010 InLoadOrderModuleList : _LIST_ENTRY [ 0x00000000`00202780 - 0x2421b0 ]   //length 0x10h , x86 length 0x8h .结构多8字节
+0×020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x00000000`00202790 - 0x2421c0 ]  //同上
+0×030 InInitializationOrderModuleList : _LIST_ENTRY [ 0x00000000`00202890 - 0x2421d0 ]  //同上
同样的,搜索InInitializationOrderModuleList 即可得到Kernel32的基址.

由于x64下vs2005没法直接使用内联汇编,所以只把必须使用汇编来做的事情写成单独的asm

x64下.指针的长度已经是8个字节,所以偏移不一样了.

0:009> dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0×000 InLoadOrderLinks : _LIST_ENTRY
+0×010 InMemoryOrderLinks : _LIST_ENTRY
+0×020 InInitializationOrderLinks : _LIST_ENTRY
+0×030 DllBase          : Ptr64 Void
+0×038 EntryPoint       : Ptr64 Void
+0×040 SizeOfImage      : Uint4B
+0×048 FullDllName      : _UNICODE_STRING

C语言表示x64搜索过程:

HMODULE x64_GetKernel32(void)
{
	HMODULE	hKernel32 = NULL;
	UNICODE_STRING * pBaseName = NULL;
	LIST_ENTRY * pNode = NULL;
	pNode = X64_GetPebInitOrderList();
	while{1}
	{
		pBaseName = (UNICODE_STRING *)((BYTE *)pNode + 0x038);
		if (*(pBaseName->Buffer)+12=='\0')
		{
			/* code */
			hKernel32 = (HMODULE)(*((LONG64*)((BYTE*)pNode+0x010)));
			break;
		}
		pNode = pNode->Flink;
	}
	return hKernel32;
}


win7 x64下测试通过win7 x64下测试通过

32位程序的通用Kernel32地址获取方法

 

 

### PEB 结构与 PE 结构是否为同一概念 PEB(Process Environment Block)和 PE(Portable Executable)结构并非同一概念,尽管它们都与 Windows 操作系统的进程和可执行文件相关。 PEB 是 Windows 操作系统中用于存储进程级别信息的数据结构。它包含与进程运行环境相关的信息,如加载的模块列表、堆信息、命令行参数、环境变量等。每个进程都有一个唯一的 PEB,位于用户模式地址空间中,可以通过 TEB(线程环境块)的偏移 0x30 处获取其地址。此外,还可以通过未公开的系统调用 `NtQueryInformationProcess` 获取 PEB 的地址[^2]。 PE 结构则是指 Windows 可执行文件(如 EXE 或 DLL)的文件格式标准。它定义了可执行文件在磁盘上的布局,包括文件头、节区表、导入表、导出表、资源数据等信息。PE 文件结构是操作系统加载器用来将程序加载到内存并执行的基础。当一个进程被创建时,其主模块(通常是 EXE 文件)会以 PE 格式被映射到内存中,而 PEB 中的 `ImageBaseAddress` 字段就指向该模块的基地址[^1]。 虽然 PEB 和 PE 结构密切相关,但它们的功能和作用不同:PEB 是运行时的进程信息容器,而 PE 是静态文件格式的描述。例如,PEB 中的 `Ldr` 成员指向一个包含进程已加载模块的链表,每个模块的基地址可以通过 PE 文件结构中的 `ImageBaseAddress` 字段获取。在逆向工程或系统调试中,分析 PEB 和 PE 结构可以帮助理解进程的加载行为、模块依赖和内存布局。 ### 示例:通过 PEB 获取主模块的 PE 结构 ```asm ; 假设使用 MASM 汇编器,以下代码演示如何通过 TEB 获取 PEB,再获取主模块基地址 mov eax, fs:[30h] ; 获取 PEB 地址(TEB + 0x30) mov eax, [eax + 0Ch] ; 获取 Ldr 成员(指向 PEB_LDR_DATA 结构) mov eax, [eax + 14h] ; 获取 InMemoryOrderModuleList(第一个模块) mov eax, [eax] ; 获取下一个模块(即主模块) mov eax, [eax + 18h] ; 获取主模块的基地址(即 PE 文件的加载地址) ``` 上述代码展示了如何通过 PEB 结构定位到主模块的 PE 文件基地址,从而进一步解析 PE 文件头和节区信息。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值