var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-333696-1']); _gaq.push(['_trackPageview']); _gaq.push(['_trackPageLoadTime']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();
  • 2008年03月18日

    PEB和TEB

    分类:

    TEBThread Environment Block,线程环境块)系统在此TEB中保存频繁使用的线程相关的数据。位于用户地址空间,在比 PEB 所在地址低的地方。进程中的每个线程都有自己的一个TEB。一个进程的所有TEB都以堆栈的方式,存放在从0x7FFDE000开始的线性内存中,每4KB为一个完整的TEB,不过该内存区域是向下扩展的。在用户模式下,当前线程的TEB位于独立的4KB段,可通过CPUFS寄存器来访问该段,一般存储在[FS:0]在用户态下WinDbg中可用命令$thread取得TEB地址

     

    PEBProcess Environment Block,进程环境块)存放进程信息,每个进程都有自己的PEB信息。位于用户地址空间。在Win 2000下,进程环境块的地址对于每个进程来说是固定的,在0x7FFDF000处,这是用户地址空间,所以程序能够直接访问。准确的PEB地址应从系统的EPROCESS结构的0x1b0偏移处获得,但由于EPROCESS在系统地址空间,访问这个结构需要有ring0的权限。还可以通过TEB结构的偏移0x30处获得PEB的位置,FS段寄存器指向当前的TEB结构:

    mov eax,fs:[0x30]

    mov PEB,eax

    在用户态下WinDbg中可用命令$proc取得PEB地址。

     

    见图1: PEBTEB

     

    见图2: 进程和线程

     

     

    KPCRKernel's Processor Control Region,内核进程控制区域)是一个不会随WINDOWS版本变动而改变的固定结构体,在它的末尾(偏移0x120)指向KPRCB结构。KPRCB同样是一个不会随WINDOWS版本变动而改变的固定结构体。它包含有指向当前KTHREAD的指针(偏移值0x004)。ETHREAD的第一项是KTHREAD,也就知道了当前的ETHREAD基地址。KTHREAD中的_KAPC_STATE结构包含当前KPROCESS的地址每个进程都有一个EPROCESS结构,里面保存着进程的各种信息,和相关结构的指针。EPROCESS结构位于系统地址空间,所以访问这个结构需要有ring0的权限。EPROCESS的第一项是KPROCESS

     

    CreateProcess创建进程的大致步骤:

    1.打开可执行文件[.exe],以FILE_EXECUTE存取方式打开。

    2.把可执行映像装载进RAM

    2.创建进程内核对象(EPROCESSKPROCESSPEB结构)

    4.为该新建进程分配地址空间。

    3.在该进程中创建主线程的线程执行对象(ETHREADKTHREADTEB结构),为主线程分配堆栈,建立该进程主线程的执行上下文。

    4.Kernel32.dll通知Win32子系统已经创建了一个新进程。

    5.如果标志不是CREATE_ SUSPENDED,那么就开始执行进程中的线程

    6.在进程和线程的context里,完成地址空间的初始化(比如,加载需要的DLL),开始执行程序。

     

    【附录】基础

    1.     主要组成

    用户模式的一些主要模块:

    l  系统支持进程(System Support Processes) -- Logon 进程 (位于\%SystemRoot%\System32\Winlogon.exe)

    l  服务进程(Service Processes) -- Spooler 进程 (位于\%SystemRoot%\System32\spoolsv.exe)

    l  用户应用程序(User Applications) -- 任何 Win32Windows 3.1DOSPOSIX 或者 OS/2 程序;

    l  子系统(Environment Subsystems) -- Windows 内置3个子系统:Win32 (位于\%SystemRoot%\System32\Csrss.exe) POSIX子系统 (位于\%SystemRoot%\System32\Psxss.exe) OS/2子系统 (位于\%SystemRoot%\System32\Os2ss.exe)

    注:Windows XP及后续的操作系统中, POSIXOS/2子系统已被去掉。

    内核模式的一些主要模块:

    l  运行模块(Executive) -- 内存管理、进程和线程的管理、安全机制等;

    l  内核(Kernel) -- 线程调度、中断、异常的分派等 (运行模块和内核位于\%SystemRoot%\System32\Ntoskrnl.exe)

    l  设备驱动程序(Device Drivers) -- 硬件设备驱动程序、文件系统和网络驱动程序;

    l  硬件抽象层 (Hardware Abstraction Layer HAL) -- 将内核、设备驱动程序和运行模块和具体的硬件平台隔离开 (位于\%SystemRoot%\System32\Hal.dll)

    l  窗口和图形系统(Windowing And Graphics System) -- 实现 GUI 函数, 如处理窗口、用户界面的控制和绘画等 (位于\%SystemRoot%\System32\Win32k.sys)

    详尽点的大图见NT_Structure 

     

    2.     线程上下文环境 (Thread Context)

    在大多数情况下, 我们的系统中只安装了一个 CPU,所以, 对于所有这些运行中的程序来说, 操作系统对每个进程中的线程所使用的 CPU 时间进行调度, 循环为每个线程分配时间片, 这就造成了多个程序同时执行的假象。如果系统中安装了多个 CPU 那么操作系统的调度算法将复杂得多, 因为它要将各 CPU 上的线程进行平衡。如果 Windows 检测到一个新线程要开始运行了, 它将进行一次上下文环境切换 (context switch) (注:上下文环境 (Content) 实际上就是线程运行的环境, 也就是运行时各寄存器和其他东东的状态, 更自然的理解就是 "线程状态") 。所谓上下文切换就是保存线程运行时的机器状态, 然后将另一个线程的状态恢复并重新开始执行。如果重新开始执行的线程属于另一个进程, 那么该进程的地址空间也将被同时切换过来 (通过在 CR3 寄存器中装入页表) 。上下文切换比较耗 CPU 时间。

     

    3.     系统内存堆

    系统内存堆表现为系统地址空间的两个所谓的内存池。

    l  不分页池(Nonpaged Pool)。不分页池不会分页到交换文件 (swap file) 自然也不需要分页回来。它们总是老老实实在物理内存里活动, 在你想访问它们的时候总能找到它们 (任何 IRQL 等级) 并且不会出现分页错误。这也正是它的优点, 任何访问都不会出现页面错误! 页面错误可是往往导致系统瘫掉( IRQL >= DISPATCH_LEVEL)!

    l  分页池(Paged Pool)。顾名思义, 就是可以分页 (分入和分出) 的了。你只能使用 (IRQL < DISPATCH_LEVEL) 的内存。

    以上两种池都位于系统地址空间,在进程上下文环境中可以使用它们。

     

    4.     注册表的结构

    注册表 (Registry) 是基本数据的中心, 在系统设置和管理方面扮演着重要的角色。注册表的内容随系统的工作进程而动态改变。注册表由 keys 构成,最上层的keys叫做root keyskeys本身就是一个容器,装着其它的keys,装在里面的这些keys叫做subkeys和数据入口 valuesvalues 保存着实际数据。对注册表的操作与管理由 Configuration Manager 负责。

    root keys有六个:

    HKEY_USER

    包含计算机上的所有以活动方式加载的用户配置文件;

    缩写为“HKU”。

    HKEY_CURRENT_USER

    保存着当前用户的注册信息;

    链接到子键HKEY_USER\<SID_当前用户>系统用户中对应于当前用户的注册信息;

    缩写为“HKCU”。

    HKEY_LOCAL_MACHINE

    保存着系统配置信息: 硬件设备支持记录, 安全策略, 用户口令, 应用程序设置和服务及驱动程序配置;

    缩写为“HKLM”。

    HKEY_CURRENT_CONFIG

    包含当前硬件配置信息;

    链接到子键HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current

    HKEY_CLASSES_ROOT

    保存着文件关联和 COM 类的注册数据;

    链接到子键HKEY_LOCAL_MACHINE\SOFTWARE\ClassesHKEY_CURRENT_USER\SOFTWARE\Classes

    缩写为“HKCR”。

    HKEY_PERFORMANCE_DATA

    包含着性能信息。

    在用户模式下, 关于性能统计的信息是通过Performance Data Helper库来访问,这个库实现在模块 pdh.dll(位于\%SystemRoot%\System32\pdh.dll)。标准程序Performance Monitor正是利用了这个库。除性能统计之外这个键还包含着许多补充信息,例如,用于枚举进程、线程和模块等等的Process Status函数 ( psapi.dll(位于\%SystemRoot%\System32\psapi.dll)实现)正是从HKEY_PERFORMANCE_DATA键中获得的信息。访问HKEY_PERFORMANCE_DATA需要有Administrators组的权限,注册表编辑器 Regedit Regedt32 并不能显示出这个键的内容,因此无法编辑,但RegOpenKeyRegConnectRegistry可以打开。

     

    【资源】

    Windows Internals---Processes,Threads(1)(2)

    JIURL玩玩Win2k进程线程篇EPROCESSPEBTEB

    关于进程PEB结构的修改实现

    高级用户的Windows注册表信息

    分享到:

    历史上的今天:

    Windows窗口生成过程 2008年03月18日