Loading... 首先总结2种切换到内核模式方法的各自流程,以Windows API WriteFile()调用为例: ##### 内存法(中断法) (用户模式)WriteFile() —>ntdll!NtWriteFile()—>ntdll!KiIntSystemCall()—>int 2Eh—>查找IDT(中断描述符)的内存地址,偏移0x2E处—>(内核模式)nt!KiSystemService()—>nt!KiFastCallEntry()—>nt!NtWriteFile(). 通过0x2E中断转移控制到内核模式后,系统服务分发/调度器为nt!KiFastCallEntry(),它负责调用内核空间中的同名异前缀函数nt!NtWriteFile(),后者有一个系统服务号;也叫做分发ID,该ID需要在执行int 2Eh前,加载到EAX寄存器,以便通知nt!KiSystemService()要它分发的系统调用(本机API),但是最终还是经由nt!KiFastCallEntry()来分发。 粗略地讲,INT指令在内部涉及如下几个操作: 1. 清空陷阱标志(TF),和中断允许标志(IF); 2. 依序把(E)FLAGS,CS,(E)IP寄存器中的值压入栈上; 3. 转移到IDT中的中断门描述符记载的相应ISR(中断服务例程)的起始地址; 4. 执行ISR,直至遇到IRET返回。 最关键的第三步涉及"段间"转移通过中断门描述符,能够引用一个ring0权限代码段, 该代码段对应的64位段描述符(存储在GDT中)中的DPL位,即特权级位等于0(0=ring3;3=ring3,即便由Intel规定的段描述符的DPL位有4种取值,但Windows仅使用了其中的最高特权级Ring3,总体而言,用户模式应用程序位于Ring3代码或数据段;内核与设备驱动则位于ring0代码或数据段),再结合段描述符中的"基址"与中断门描述符中的“偏移”,就能计算出ISR在Ring0代码段中的起始地址。下表是64位段描述符的格式,取自Intel文档,自行添加了注释: ![image.png](http://47.117.131.13/usr/uploads/2021/10/131090869.png) 待写........ https://blog.51cto.com/shayi1983/1710861 最后修改:2021 年 10 月 28 日 04 : 13 PM © 允许规范转载