浅尝辄止谈系统服务分发

    欢迎转载,转载请注明出处:http://www.cnblogs.com/uAreKongqi/p/6597701.html

0x00.说在前边

  就我们所知晓,Windows操作系统内核的钩处理器会分发中断、异常和体系服务调用,这里我们虽其中的系统服务分发简单解析一下。

 

0x01.粗看不同电脑进入系统调用

  (1).在PentiumII
之前的x86处理器上,Windows使用int2e指令发出一个圈套,导致执行线程转到根本模式,进入系统服务分发器,eax保存体系服务号,edx指为参数列表。最后经过iret指令回到用户模式;

    
  我们查阅IDT的2e分子,得知该成员保存的地点是系统调用分发器的地址,紧接着u一下KiSystemService,会发现以保存了寄存器等状态后,他举手投足及了KiFastCallEntry里面!(在Win7
x86下测试)

      图片 1

  (2).在x86Pentium II
处理器上,Windows使用了sysenter指令,内核的系服务分发器例程的地点保存在和该令相关联的一个MSR中,eax,edx保存和int2e相同的内容。最后经过sysexit指令返回用户模式;

     这里读取MSR的0x176高居,其中蕴含了系统服务分发器地址,发现实际调用的虽是KiFastCallEntry(入口)!(在Win7
x86下测试)

      图片 2

  (3).在x64体系架构上,Windows使用syscall指令,将系统调用号保存于eax中,前四独参数放在寄存器(rcx/rdx/r8/r9)中,剩下的参数在栈中。

    64各类平台读取MSR的0xC0000082介乎,里面保存之是64各的syscall,当我们u一下这个地点,发现这就算是x64系统调用分发的进口KiSystemCall64(在Win7
x64下蛋测试)

    
 图片 3

    Ps:通过KiSystemCall64的地址可以经硬编码得到SSDT、SSSDT地址

 ……

图片 4

 

   我们发现,32员生,系统调用分发操作都见面动至KiFastCallEntry里面,而64号生,系统调用分发操作会走至KiSystemCall64,然后去好相应的系服务调用。那么我们有只问题,系统是怎么上及这些系统调用的吧?

 

0x02.举例查看系统调用如何来

  这里为Win7 x86 平台下的
NtOpenProcess为例,切换至一个经过内(如explorer.exe),u一下NtOpenProcess,这里显得的是ntdll里的NtOpenProcess的相反汇编:

  图片 5

  我们发半点个获,一个是来看了系统服务号放在了eax里了,另一个凡她呼叫了一个地方,call指令将尽由基本建立起的网服务分发代码,该地址保存在ntdll!_KUSER_SHARED_DATA+0x300高居,我们随后进这地点看看:

  图片 6

  我们似乎产生了点儿眉目了,系统调用在ntdll里面来了,也就是说,在ntdll里面完成了从ring3届ring0的切换,其中eax保存服务号,edx保存参数列表首地址,通过服务号可以以SSDT中恒目标服务例程

  32号生的KeServiceDescriptorTable每个成员即使目标体系服务之绝对化地址,64各项生的靶子体系服务真地址是KeServiceDescriptorTable每个成员保存之偏移量(右变4个后的)+KeServiceDescriptorTable基地址;

  同开始线程的系服务表地址指向Ntoskrnl.exe中的SSDT表,但当调用了一个USER或GDI服务时,服务表地址为修改成对win32k.sys中之系服务表。 

 

0x03.从用户层至内核层完整的调用过程

  (1).
当一个Windows应用程序调用Kernel32.dll中的OpenProcess时,其导入并调用了API-MS-Win-Core-File-L1-1-0.dll(一个MinWin重定向Dll)中的NtOpenProcess函数;

  (2).
接着上述的NtOpenProcess函数又会调用KernelBase.dll中之OpenProcess函数,这里是函数的真正实现,它会对系统有关的参数做了反省;

  (3).
然后KernelBase!OpenProcess就会见调用ntdll.dll中的NtOpenProcess函数,在这就见面硌系统调用(ntdll!KiFastSystemCall),传递NtOpenProcess的体系服务号和参数列表;

  (4).
系统服务分发器(Ntoskrnl.exe中之KiSystemService函数)就会调用真正的NtOpenProcess函数来拍卖该I/O请求。

 图片 7

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0x04.本模式下的系统分发

  在系统调用中,如果原本模式为用户模式,在为系统服务传递的参数指为了用户空间缓冲区时,内核模式代码在操作该缓冲区前会检查是不是好拜该缓冲区,而原先模式就是是水源模式的当儿,默认参数有效,则不会见指向参数进行反省。而既然已经当基础模式了,那就是未需要int2e中断或sysenter之类的操作了,但要直接像调用API一般直接调用NtOpenProcess之类的体系服务函数时,内核保存之本原模式值仍然是用户模式(进基本之前当然是用户模式了~),但同时检测到传递来的地址是一个根本模式地址(因为当手上本模式下调用),于是会造成调用失败(STATUS_ACCESS_VIOLATION)。

  这里要介绍本的Zw系列函数了,他们非但是Nt版本函数的别名或卷入,而是对应Nt系列系统调用的翻版,使用了一样的系统调用分发机制。他们会成立一个假的刹车栈(CPU以刹车后变的库),并一直调用KiSystemService例程,这个进程即以模仿CPU中断,仿佛调用来自用户模式相似,而于检测及拖欠调用的实际特权级后拿原本模式修改也基石模式,这样为节省了参数校验,成功调用到NtOpenProcess!

  图片 8

 

 0x05.简单小结

   Ring3 —> Ring0 的系调用:
Kernel32.dll(API)—>ntdll.dll(Nt/Zw)—>用户模式转内核模式—>Ntoskrnl.exe(Nt)—>完成I/O请求(原行程返回)

   Ring0 —> Ring0
的体系调用:Ntoskrnl.exe(Zw)—>Ntoskrnl.exe(Nt)

   以上知情参考自《深入解析Windows操作系统6》第三章节,如果出免正确的地方还恳请指出,我以谦虚请教!

相关文章