windows体系结构

Windwos  体系结构:
--------------------------------------
用户模式(ring3)
系统进程、服务进程、应用程序、环境子系统(向应用程序提供环境和应用程序编程接口  Appplication  Progra
mming  Interface-API。Windows  2000/XP  支持三种环境子系统:Win32、POSIX  和  OS/2,其中最重要的环境子
系统是  Win32  子系统,其他子系统都要通过  Win32  子系统  接收用户的输入和显示输出。环境子系统的作用是
将基本的执行体系统服务的某些子集提供给应用程序。  用户应用程序调用系统服务时必须通过一个或多个子
系统动态链接库作为中介才可以完成)、应用程序编程接口(API)、基于  NTDLL.DLL  的本地系统服务
--------------------------------------
内核模式(ring0)
系统服务调用(SSDT)、执行体(Executive)、系统内核和设备驱动(Kernel)、硬件抽象层(HAL)
一、Windows  系统服务调用机制
Windows  2000  的陷阱调度(Trap  Dispatching)机制包括了:中断(Interrupt),延迟过程调用(Deferred  Proc
edure  Call),异步过程调用(Asynchronous  Procedure  Call),异常调度(Exception  Dispatching)和系统服务
调用(System  Service  Call)。在  Intel  x86  平台的  Windows  2000  使用  int  0x2e  指令进入  Windows  系统服务调用;
Windows  XP  使用  sysenter  指令使系统陷入系统服务调用程序中;而  AMD  平台的  Windows  XP  系统使用  syscall
指令进入  Windows  系统服务调用。下面是  Intel  x86  平台的  Windows  2000  的系统服务调用模型。
mov  eax,  ServiceId
lea  edx,  ParameterTable
int  2eh
ret  ParamTableBytes
其中  ServiceId  是传递给系统服务调用程序的  ID  号,内核使用这个  ID  号来查找系统服务调度表(System  Service
Dispath  Table)中的对应系统服务信息。  系统服务调用也是一个接口,是面向  Windows  内核的接口。它实现
了将用户模式下的请求转发到内核模式下,并引发了处理器模式的切换。在用户看来,系统服务调用就是与  W
indows  内核通信的一个桥梁。
二、系统服务调用类型
在  Windows  2000  中默认存在两个系统服务调度表,它们对应了两类不同的系统服务。这两个系统服务调度表
分别是:KeServiceDescriptorTable   和  KeServiceDescriptorTable Shadow。  前者有  ntoskrnl.exe  导出,后者由  Win3
2k.sys  导出。在系统中,有三个  DLL  是最重要的:Kernel32.dll、  User32.dll  和  Gdi32.dll,这些  DLL  导出的函数,
都是通过某种类型的中断进入内核态,然后调用  ntoskrnl.exe  或  Win32k.sys  中的函数。函数  KeAddSystemServic
eTable  允许  Win32.sys  和其他设备驱动程序添加系统服务表。除了  Win32k.sys  服务表外,使用  KeAddSystemServ
iceTable  添加的服务表会被同时复制到  KeServiceDescriptorTable   和  KeServiceDescriptorTable Shadow  中去。
说明:
NTDLL..DLL  和  ntoskrnl.exe  的关系很“微妙”,用户态和内核态的调用也是有分别的,比如:参数检查。还有  N
ative  API  导出了  套函数:Zw***和  Nt***系列,要想彻底了解这些内容,推荐看  Sunwear  写的《浅析本机  API》
综上所述,Kernel32.dll/Advapi32.dll  进入  NTDLL.DLL  后,使用  int  0x2e  中断进入内核,最后在  ntoskrnl.exe  中实
现了真正的函数调用;User32.dll  和  Gdi32.dll  则在  Win32k.sys  中实现了真正的函数调用。
三、本机  API(Native  API)
本机  API  是除了  Win32  API,NT  平台开放了另一个基本接口。本机  API  也被很多人所熟悉,因为内核模式模块
位于更低的系统级别,在那个级别上环境子系统是不可见的。尽管如此,并不需要驱动级别去访问这个接口,
普通的  Win32  程序可以在任何时候向下调用本机  API。并没有任何技术上的限制,只不过微软不支持这种应用
开发方法。User32.dll,kernel32.dll,shell32.dll,gdi32.dll,rpcrt4.dll,comctl32.dll,advapi32.dll,version.dll  等  dll  代表了  Wi
n32  API  的基本提供者。Win32  API  中的所有调用最终都转向了  ntdll.dll,再由它转发至  ntoskrnl.exe。ntdll.dll 
本机  API  用户模式的终端。真正的接口在  ntoskrnl.exe  里完成。事实上,内核模式的驱动大部分时间用这个模
块,如果它们请求系统服务。Ntdll.dll  的主要作用就是让内核函数的特定子集可以被用户模式下运行的程序调
用。Ntdll.dll  通过软件中断  int  2Eh  进入  ntoskrnl.exe,就是通过中断门切换  CPU  特权级。比如  kernel32.dll  导出
的函数  DeviceIoControl()实际上调用  ntdll.dll  中导出的  NtDeviceIoControlFile(),反汇编一下这个函数可以看到,E
AX  载入  magic  数  0x38,实际上是系统调用号,然后  EDX  指向堆栈。目标地址是当前堆栈指针  ESP+4,所以  ED
指向返回地址后面一个,也就是指向在进入  NtDeviceIoControlFile()之前存入堆栈的东西。事实上就是函数的
参数。下一个指令是  int  2Eh,转到中断描述符表  IDT  位置  0x2E  处的中断处理程序。
反编汇这个函数得到:
mov  eax,  38h
lea  edx,  [esp+4]
int  2Eh
ret  28h
当然  int  2E  接口不仅仅是简单的  API  调用调度员,他是从用户模式进入内核模式的  main  gate。
W2k  Native  API  由  248  个这么处理的函数组成,比  NT  4.0  多了  37  个。可以从  ntdll.dll  的导出列表中很容易认出
来:前缀  Nt。Ntdll.dll  中导出了  249  个,原因在于  NtCurrentTeb()为一个纯用户模式函数,所以不需要传给内核。
令人惊奇的是,仅仅  Native  API  的一个子集能够从内核模式调用。而另一方面,ntoskrnl.exe  导出了两个  Nt*符
号,它们不存在于  ntdll.dll  中:  NtBuildNumber,  NtGlobalFlag。它们不指向函数,事实上,是指向  ntoskrnl.exe 
变量,可以被使用  编译器  extern  关键字的驱动模块导入。Ntdll.dll  和  ntoskrnl.exe  中都有两种前缀  Nt*,Zw*。
事实上  ntdll.dll  中反汇编结果两者是一样的。而在  ntoskrnl.exe  中,nt  前缀指向真正的代码,而  zw  还是一个  int
2Eh  的  stub。也就是说  zw*函数集通过用户模式到内核模式门传递的,而  Nt*符号直接指向模式切换以后的代码。
Ntdll.dll  中的  NtCurrentTeb()没有相对应的  zw  函数。Ntoskrnl  并不导出配对的  Nt/zw  函数。有些函数只以一种方
式出现。
四、系统服务调用示意图
------------------------------------
Win32  API  ->Ntdll.h  ->SSDT  (提供用户态到内核态的的转换)->ntoskrnl.exe
-------------------------------------
Win32  API  包括:User32.dll,kernel32.dll,shell32.dll,gdi32.dll,rpcrt4.dll,comctl32.dll,advapi32.dll,version.dll  等  dll
Ntdll.h  :ZW**和  NT**系列函数
ntoskrnl.exe:ZW**和  NT**系列函数
五、SSDT  说明
什么是  SSDT?
什么是  SSDT?自然,这个是我必须回答的问题。不过在此之前,请你打开命令行(cmd.exe)窗口,并输入“
dir”并回车——好了,列出了当前目录下的所有文件和子目录。
那么,以程序员的视角来看,整个过程应该是这样的:
1.由用户输入  dir  命令。
2.cmd.exe  获取用户输入的  dir  命令,在内部调用对应的  Win32  API  函数  FindFirstFile、FindNextFile  和  FindClose,
获取当前目录下的文件和子目录。
3.cmd.exe  将文件名和子目录输出至控制台窗口,也就是返回给用户。
到此为止我们可以看到,cmd.exe  扮演了一个非常至关重要的角色,也就是用户与  Win32  API  的交互。——你
大概已经可以猜到,我下面要说到的  SSDT  亦必将扮演这个角色,这实在是一点新意都没有。
没错,你猜对了。SSDT  的全称是  System  Services  Descriptor  Table,系统服务描述符表。这个表就是一个把  ring
的  Win32  API  和  ring0  的内核  API  联系起来的角色,下面我将以  API  函数  OpenProcess  为例说明这个联系的过
程。
你可以用任何反汇编工具来打开你的  kernel32.dll,然后你会发现在  OpenProcess  中有类似这样的汇编代码:
call  ds:NtOpenProcess
这就是说,OpenProcess  调用了  ntdll.dll  的  NtOpenProcess  函数。那么继续反汇编之,你会发现  ntdll.dll  中的这
个函数很短:
mov  eax,  7Ah
mov  edx,  7FFE0300h
call  dword  ptr  [edx]
retn  10h
另外,call  的一句实质是调用了  KiFastSystemCall:
mov  edx,  esp
sysenter
上面是我的  XP  Professional  sp2  中  ntdll.dll  的反汇编结果,如果你用的是  2000  系统,那么可能是这个样子:
mov  eax,  6Ah
lea  edx,  [esp+4]
int  2Eh
retn  10h
虽然它们存在着些许不同,但都可以这么来概括:
1.把一个数放入  eax(XP  是  0x7A,2000  是  0x6A),这个数值称作系统的服务号。
2.把参数堆栈指针(esp+4)放入  edx。
3.sysenter  或  int  2Eh。
好了,你在  ring3  能看到的东西就到此为止了。事实上,在  ntdll.dll  中的这些函数可以称作真正的  NT  系统服务
的存根(Stub)函数。分  隔  ring3  与  ring0  城里城外的这一道叹息之墙,也正是由它们打通的。接下来  SSDT 
要出场了,come  some  music。
站在城墙看城外
当程序的处理流程进入  ring0  之后,系统会根据服务号(eax)在  SSDT  这个系统服务描述符表中查找对应的表
项,这个找到的表项就是系统服务函  数  NtOpenProcess  的真正地址。之后,系统会根据这个地址调用相应的
系统服务函数,并把结果返回给  ntdll.dll  中的  NtOpenProcess。图中的“SSDT”所示即为系统服务描述符表的
各个表项;右侧的“ntoskrnl.exe”则为  Windows  系统内核服  务进程(ntoskrnl  即为  NT  OS  KerneL  的缩写),
它提供了相对应的各个系统服务函数。ntoskrnl.exe  这个文件位于  Windows  的  system32  目录下,有兴趣的朋友
可以反汇编一下。
附带说两点。根据你处理器的不同,系统内核服务进程可能也是不一样的。真正运行于系统上的内核服务进程
可能还有  ntkrnlmp.exe、ntkrnlpa.exe  这样的情况——不过为了统一起见,下文仍统称这个进程为  ntoskrnl.exe。
另外,SSDT  中  的各个表项也未必会全部指向  ntoskrnl.exe  中的服务函数,因为你机器上的杀毒监控或其它驱动
程序可能会改写  SSDT  中的某些表项——这也就是所  谓的“挂钩  SSDT”——以达到它们的“主动防御”式杀毒
方式或其它的特定目的。
KeServiceDescriptorTable
事实上,SSDT  并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基
地址、服务函数个数等等。  ntoskrnl.exe  中的一个导出项  KeServiceDescriptorTable   即是  SSDT  的真身,亦即它在
内核中的数据实体。SSDT  的数据结构定义如下:
typedef  struct  _tagSSDT  {
        PVOID  pvSSDTBase;
        PVOID  pvServiceCounterTable;
        ULONG  ulNumberOfServices;
          PVOID  pvParamTableBase;
SSDT,  *PSSDT;
其中,pvSSDTBase  就是上面所说的“系统服务描述符表”的基地址。pvServiceCounterTable  则指向另一个索引
表,该表包  含了每个服务表项被调用的次数;不过这个值只在  Checkd  Build  的内核中有效,在  Free  Build  的内
核中,这个值总为  NULL(注:Check/Free  是  DDK  的  Build  模式,如果你只使用  SDK,可以简单地把它们理解为
Debug/Release)。ulNumberOfServices  表示当前系统所支持的服务个数。pvParamTableBase  指向  SSPT  (Syste
Service  Parameter  Table,即系统服务参数表),该表格包含了每个服务所需的参数字节数。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值