1、每个Windows进程都是由一个执行体进程EPROCESS结构来表示的,EPROCESS和相关数据结构位于系统空间,但是进程环境控制块PEB是个例外,它位于进程空间地址中(因为它包含了一些需要由用户模式代码来修改的信息)。对于每一个执行了Win32程序的进程,WIn32子系统进程Crss为它维护了一个平行的结构CSR_PROCESS。最后,Windows子系统的内核模式部分(Win32.sys)有一个针对每个进程的数据结构W32PROCESS,当一个线程第一次调用Windows的USR或GDI函数(它们是在内核模式中实现的)时,W32PROCESS结构就会被创建。除空闲进程外,每个EPROCESS结构会被执行体对象管理器封装为一个进程对象。一个进程句柄通过进程相关的API提供EPROCESS结构中部分数据以及它的相关结构中数据的访问。一个简化版的关于进程和线程数据结构的框图如下:
下图显示了EPROCESS结构中的关键域:
执行体进程结构的第一个字段称作PCB,代表进程控制块,它是一个KPROCESS类型的结构,代表内核进程。虽然执行体的例程往EPROCESS中保存数据,但是分发器、调度器和终端/时间记账代码——作为操作系统内核的一部分——使用KPROCESS。这使得执行体的高层功能和下面的底层特定功能实现之间能有一层抽象,避免二者之间不必要的依赖。
2、PEB:位于它所描述的进程的用户模式地址空间,包含了映像加载器、堆管理器以及其他需要从用户模式访问它的Windows组件所需的信息。EPROCESS和KPROCESS结构只能从内核模式访问。EPB的字段如下图所示:
3、CSR_PROCSS结构包含专用于Windows子系统(Crsss)的进程信息。这样,只有Windows应用程序才有CSR_PROCESS结构关联到它们。另外,因为每个会话都有它自己的Windows子系统,所以CSR_PROCESS结构会有它自己的Windows子系统,所以CSR_PROCESS结构由每个会化的Crss来维护。CRSS_PROCESS的基本结构如下图所示:
4、WIN32PROCESS:该结构包含内核(Win32k)中的Windows图像和窗口管理代码需要维护的有关GUI进程的状态信息,其基本结构如下图所示:
5、受保护进程:在哪Windows安全模型中,任何一个进程的令牌只要有调试权限就能对机器上其他任何进程请求任意的访问权限(如读写任意进程的内存、注入代码,挂起和恢复线程)。但有时候有些进程需要避免被拥有调试权限的进程随意修改和访问,因此Windows引入了受保护进程(这类进程大多与多媒体相关)。受保护进程与普通进程并存,但是它们对系统其他进程(即以管理员特权运行)可申请的访问权限上增加了重要的限制。受保护进程可以由任何应用程序创建,然而操作系统仅在以下条件允许一个进程被保护:它的映像已经被一个特殊的Windows Media证书数字签名过。
在内核层面上对受保护进程的支持分为两块,首先,进程创建过程完全在内核模式进行以避免注入攻击;其次,受保护进程会在PROCESS结构中设置一个特殊的位,它修饰了进程管理器中安全方面例程的行为,会拒绝某些通常授予管理员的访问权。事实上,对受保护进程仅有的访问权是PROCESS_QUERY、SET_LIMIT_INFORMATION、PROCCESS_TERMINATE和PROCESS_SUSPEND_RESUME。某些特定的访问权对于受保护进程内的线程也是禁用的。
由于Process Explorer使用普通的用户模式Windows API来查询进程内部的信息,它对于受保护进程无法进行某些操作。另一方面,Windbg这样的工具运行于内核调试模式下,使用内核模式基础设施来获取这些信息,得到的信息会更加完整。
6、线程的局部原理:在操作系统层次上,Windows线程是一个由执行体线程对象来表示的。执行体线程对象封装了一个ETHREAD结构体,而ETHREAD结构又含有一个KTHREAD结构作为它的第一个成员,如下图所示:
ETHREAD结构和它指向的结构都位于系统地址空间,唯一的例外是线程环境快TEB,它位于进程地址空间中(同样地,也是因为用户模式组件需要访问它)。并且Windows子系统Crss为Windows进程中创建的每个线程维护了一个平行的结构称为CSR_THREAD。另外,对于那些已经调用了任一Windows子系统USER或者GDI函数的线程,Windows子系统的内核模式部分(Win32.sys)为每个这样的线程维护了一个数据结构,称为W32THREAD结构,线程的KTHREAD结构指向了W32THREAD结构。
ETHRED的第一个字段是Tcb,也称为线程控制块,其类型是KTHREAD。KTHREAD结构包含了Windows内核为这些正在运行的线程执行线程调度、同步和计时而需要访问的信息。
TEB内部有一个称为TIB(线程信息块)的头,主要作用是为了保证OS/2和Win9X应用程序的兼容性。当通过一个初始TIB创建新线程的时候,它也允许异常和栈信息被保存进一个较小的TIB中。TEB存储了有关映像加载器和各种Windows DLL的环境信息。因为这些组件运行在用户模式下,所以它们需要一个在用户模式下可写的数据结构。
Windows实现了一个优先级驱动的、抢占式调度系统——具有最好有限的就绪线程运行,而该线程可能仅限于在允许它运行(或者设定为偏好的)的处理器上运行,这种现象称为处理器亲和性。
Windows调度代码是在内核中实现的,然而,内核中不存在单独的“调度器”模块或者例程——调度代码散步在内核中凡是会发生与调度相关的事件的各处,执行这些任务的例程合起来称为内核的“分发器”。
7、线程环境切换:一个线程的环境和用于环境切换的过程随处理器体系结构的不同而不尽相同。一个典型的环境切换需要保存和加载以下数据:指令指针EIP、内核栈的指针、指向该线程运行所在的地址空间(该进程的页表目录)的指针。内核把老线程的这些信息保存起来:将这些信息压入到老线程的内核栈中,更新站指针,然后将此栈指针保存到老线程的KTHREAD块中。然后内核栈指针被设置为新线程的内核栈,新线程的环境被加载进来。如果新线程位于另外一个进程中,那么,内核还会降新进程的页目录表加载到一个专门的处理器寄存器中,从而使用新进程的地址空间。如果一个需要被交付的内核APC正在等待处理器,则一个IRQL为1的中断就会产生。否则处理器的控制被传递给新线程中已经被恢复的指令指针,于是新线程开始运行。
一个线程可能会通过调用某个Windows等待函数来等待某个对象(如事件、互斥体、信号量、IO完成端口、进程、线程、窗口消息等)从而进入等待状态,主动放弃对处理器的使用。但是放弃处理器的线程并不是降低优先级了,该线程只是被内核移动到了它正在等待的对象的等待队列中。
8、理想处理器:一个线程的理想处理器是该线程被创建的时候,利用进程控制块中的一个种子来选定的。每当一个线程被创建时,该种子就会递增。所以,一个进程中的每个新线程的理想处理会循环经理当前系统上所有可用的处理器。但是这种分配方法假定了一个进程内的线程完成的是等量的工作。然而在现实中这个往往是不可能的,更常见的是,由一个或者多个线程做事务管理工作,其他另有一组工作者线程。因此,一个多线程程序想要充分利用底层平台的优势,使用SetThreadIdealProcessor函数来为它的线程指定理想的处理器编号是更有用的,或者使用SetThreadIdealProcessorEx函数为线程选择一个亲和处理器组号。