注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

陷阱调度--END  

2009-07-26 23:59:05|  分类: Win32 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

http://hi.baidu.com/l_wait/blog/item/cab8b051e300818b8d543040.html

系统服务调度
       内核的陷阱处理程序调度中断、异常以及系统服务调用。前面的部分向你展示了中断和异常处理是如何工作的;在这一部分,你将了解系统服务。一个系统服务调度是因为执行了配给系统服务调度的指令而被触发的。Windows所使用的系统服务调度指令取决于它所使用的处理器。
32位系统服务调度
       在Pentium II之前的0x86处理器中,Windows使用指令int 0x2e,0x2e是十进制的46,制造一个陷阱。Windows将IDT的第46项指向系统服务调度程序。陷阱使执行线程转到内核模式并进入系统服务调度程序。处理器寄存器EAX中的数字参数表示被调用的系统服务号。寄存器EBX则指向调用者传给系统服务的参数列表。
   在0x86 Pentium II以及其后的处理器中,Windows使用了一个专门的指令sysenter,这个指令是特别为快速系统范围调度而定义的。为了支持这个指令,Windows在启动时将内核的系统服务调度程序的地址储蓄在了与该指令相关的寄存器中。执行这个指令的结果是进入内核模式并执行系统服务调度程序。系统服务号会被传入处理器寄存器EAX中,而寄存器EDX则指向调用者参数列表。要转回用户模式,系统服务调度程序一般会执行指令sysexit。(但在某些情况下,比如处理器的单步标志为1时,系统服务调度程序就会使用指令iretd了。)
   在K6以及其后的32位AMD处理器中,Windows使用了专门的指令syscall,该指令的功能与x86的类似,Windows也要设置一个syscall相关处理器寄存器为内核的系统服务调度程序的地址。系统服务号会传给寄存器EAX,而栈中则存储了调用者传递的参数。在完成调度之后,内核会执行指令sysret。
   在启动时,Windows会检测执行它的处理器的类型并且构造适当的系统调用代码备用。用户模式下NtReadFile的系统服务代码是这样的:

ntdll!NtReadFile:

77f5bfa8 b8b7000000        mov     eax,0xb7

77f5bfad ba0003fe7f        mov     edx,0x7ffe0300

77f5bfb2 ffd2              call    edx

77f5bfb4 c22400            ret     0x24

   系统服务号是0xb7(十进制的183)而指令负责执行由系统建立的系统服务调度代码,在此例中其地址为0x7ffe0300。因为这个是取自Pentium M,它用的是sysenter:

SharedUserData!SystemCallStub:

7ffe0300 8bd4             mov     edx,esp

7ffe0302 0f34             sysenter

7ffe0304 c3               ret

64位系统服务调度
       在x64体系结构中,Windows使用了指令syscall,该指令的功能和AMD K6的syscall指令相同,系统服务调度,传送系统调用号给EAX寄存器,前4个参数放入寄存器,这4个以外的参数放到栈里:

ntdll!NtReadFile:

00000000'77f9fc60 4c8bd1          mov     r10,rcx

00000000'77f9fc63 b8bf000000      mov     eax,0xbf

00000000'77f9fc68 0f05            syscall

00000000'77f9fc6a c3              ret

       在IA64体系结构中,Windows使用了epc(进入特权模式)指令。前8个系统调用参数传入寄存器,其余的传入栈中。

内核模式系统服务调度
   内核用系统调用参数在系统服务调度表(system service dispatch table)中定位系统服务信息。这个表和IDT类似,除了每一项包含的是一个指向系统服务而不是指向中断处理例程的指针。
   系统服务调度程序,KiSystemService,从线程的用户模式栈复制调用者的参数到它的内核模式栈(如此用户就不可能在内核访问这些参数时改变它们了),然后执行系统服务。如果传给系统服务的参数是指向用户空间的缓存区的,那么就必须在内核模式代码读写它们之前检查它们是否是可访问的。
       每一个线程都有一个指针指向它的系统服务表。Windows有两个内部的系统服务表,最高可以有四个。系统服务调度程序通过将32位系统服务号中的2位译为表索引决定了哪个表包含了被请求的服务。系统服务号的低12位被作为前述表索引所指定的表的索引。
服务描述符表
       一个主要的向量表,KeServiceDescriptorTable,定义了在Ntoskrnl.exe中实现的核心的可执行系统服务。另一个向量表,KeServiceDescriptorTableShadow,包括了在内核模式的部分Windows子系统Win32k.sys中实现的Windows USER和GDI。一个Windows线程第一次调用Windows USER或GDI服务,该线程的系统服务表地址即被变为指向包含了Windows USER和GDI 服务的表的地址。函数KeAddSystemServiceTable允许Win32k.sys及其他设备驱动添加系统服务表。如果你在Windows 2000上安装了Internet Information Services (IIS),它的支持驱动在加载的时候会定义一个附加服务表,leaving only one left for definition by third parties。除了Win32k.sys服务表,用KeAddSystemServiceTable添加的服务表会被复制到向量表KeServiceDescriptorTable和KeServiceDescriptorTableShadow中。除了核心的和Win32表以外Windows ……
注意
    Windows Server 2003 sp1及其后版本除了由Win32k.sys添加的以外,不支持添加额外的系统服务表,所以添加服务表不能够扩展这些系统的功能。
   
   Windows可执行服务的系统服务调度指令存在于系统库Ntdll.dll中。子系统DLLs调用Ntdll中的函数来实现它们定义的功能。Windows USER和GDI函数例外,它们的系统服务调度指令直接实现在User32.dll和Gdi32.dll中了——没有调用Ntdll.dll。
   Kernel32.dll中的Windows函数WriteFile调用Ntdll.dll中的函数NtWriteFile,后者再执行某个适当的指令制造一个系统服务陷阱,传递表示NtWriteFile的系统服务号。系统服务调度程序(Ntoskrnl.exe中的函数KiSystemService)接着调用真正的NtWriteFile处理I/O请求。对于Windows USER和GDI函数来说,系统服务调度调用可加载的内核模式部分Windows子系统,Win32k.sys中的函数。

  评论这张
 
阅读(316)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017