Nt*和Zw*开头的函数

原文链接:http://blog.csdn.net/tianzhhy/article/details/6184265

http://blog.csdn.net/evi10r/article/details/6742052


Ring3中的NATIVE API,和Ring0的系统调用,都有同名的Zw和Nt系列函数,这些Zw*和Nt*函数既在ntdll.dll(Ring3)中导出又在ntoskrnl.exe(Ring0)中导出,他们有什么区别呢?

我们先来看看ntdll.dll和ntoskrnl.exe的关系
Win32 API中的所有调用最终都转向了ntdll.dll,再由它转发至ntoskrnl.exe。ntdll.dll是本机API用户模式的终端,真正的接口在ntoskrnl.exe里完成。
Ntdll.dll的主要作用就是让内核函数的特定子集可以被用户模式下运行的程序调用。Ntdll.dll通过软件中断int 2Eh进入ntoskrnl.exe,就是通过中断门切换CPU特权级。

 

下面以ZwOpenProcess和NtOpenProcess函数为例,详细阐述下他们的分别和联系。

 

1.ntdll.dll中的Zw*和Nt*有什么区别?

用dependency查看ntdll.dll中的ZwOpenProcess和NtOpenProcess,如下图,可见两者的入口点是一样的,这就是说,ntdll!ZwOpenProcess仅仅是ntdll!NtOpenProcess函数的别名而已。

两者实现如下:
0:000> u ntdll!zwopenprocess
ntdll!ZwOpenProcess:
7c92d5fe b87a000000      mov     eax,7Ah
7c92d603 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d608 ff12            call    dword ptr [edx]
7c92d60a c21000          ret     10h
7c92d60d 90              nop

0:000> u ntdll!ntopenprocess
ntdll!ZwOpenProcess:
7c92d5fe b87a000000      mov     eax,7Ah
7c92d603 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d608 ff12            call    dword ptr [edx]
7c92d60a c21000          ret     10h
7c92d60d 90              nop
从反汇编代码来看,两者别无区别,都是通过SSDT服务表,通过系统服务调度程序KiSystemService调用ntoskrnl.exe中的中断处理程序Nt*函数。

7FFE0300h处是ntdll!KiFastSystemCall的入口,ntdll!KiFastSystemCall会保存起当前的栈指针,然后通过引发0x2e中断,陷入内核。 
当触发0x2e中断后,CPU将执行环境切换到Ring0状态,然后去调用内核模块的0x2e处理例程nt!KiSystemService。nt!KiSystemService会在参数检查、栈拷贝等操作之后,根据Ring3代码传递过来的调用号0x7A,在SSDT中查找相应的函数地址,然后调用找到的函数。对于我们的例子来说,这个函数就是内核模块的导出函数nt!NtOpenProcess。nt!NtOpenProcess才是真正的打开进程实现函数。

 

2.ntoskrnl.exe中的Zw*和Nt*有什么区别?

用dependency查看ntdll.dll中的ZwOpenProcess和NtOpenProcess,如下图。两者入口点不同,显然不是简单的别名关系了。

两者实现如下:
kd> u nt!ZwOpenProcess
nt!ZwOpenProcess:
804febfc b87a000000      mov     eax,7Ah
804fec01 8d542404        lea     edx,[esp+4]
804fec05 9c              pushfd
804fec06 6a08            push    8
804fec08 e844ea0300      call    nt!KiSystemService (8053d651)
804fec0d c21000          ret     10h

kd> u nt!ntOpenProcess
nt!NtOpenProcess:
805c0b56 68c4000000      push    0C4h
805c0b5b 6888aa4d80      push    offset nt!ObWatchHandles+0x25c (804daa88)
805c0b60 e87b75f7ff      call    nt!_SEH_prolog (805380e0)
805c0b65 33f6            xor     esi,esi
805c0b67 8975d4          mov     dword ptr [ebp-2Ch],esi
805c0b6a 33c0            xor     eax,eax
805c0b6c 8d7dd8          lea     edi,[ebp-28h]
805c0b6f ab              stos    dword ptr es:[edi]

……………………代码未完
ZwOpenProcess函数很短,首先把0x7a(NtOpenProcess的系统服务号)存入eax,然后做一些保存现场的工作,之后调用KiSystemService函数,KiSystemService内部会根据eax中的service id(系统服务号)在SSDT中查找相应的系统服务,然后调用之。

NtOpenProcess函数很长(反汇编结果只是一部分),事实上,NtOpenProcess是真正执行打开进程操作的函数(在Ring0中通常称为服务或例程)。所以若在驱动中直接调用Nt系列函数,是不会经过SSDT的,也就不会被SSDT HOOK所拦截。

可见,ZwOpenProcess通过中断来实现功能,2E软中断的7Ah子中断号的处理程序是NtOpenProcess。那这么一说他们是没区别了?错!NtOpenProcess是在Ring0下;而ZwOpenProcess是通过int 7Ah进入Ring0的,不管ZwOpenProcess处于什么模式下。

 

总结如下:
1.
用户空间,即Ring3(ntdll.dll)中的Zw*和Nt*的实现都是一样的;
内核空间,即Ring0(ntoskrnl.exe)中Nt*是真正的函数实现,而Zw*函数是Nt*的一个stub函数,其内部通过SSDT来找到对应的Nt*函数。

2.
ntdll.dll中ZwOpenProcess与ntoskrnl.exe中ZwOpenProcess的区别是:
前者在ring3下工作,后者在ring0下工作。

ntdll.dll中NtOpenProcess与ntoskrnl.exe中NtOpenProcess区别是:
前者在ring3下工作,后者在ring0下工作;前者通过中断实现,后者是前者的中断处理程序。


3.
由以上对Zw*反汇编可知,Zw*代码内部是通过SSDT中的对应Nt*索引号查找到真正Nt*执行代码的入口地址。
ntdll.dll:        传入服务号到eax--->调用ntdll!KiFastSystemCall (7ffe0300)函数--->KiSystemService--->Nt*(ntoskrnl)
ntoskrnl.exe:传入服务号到eax--->KiSystemService--->Nt*(ntoshrnl)

4.
R3下无论如何调用,均无法绕过SSDT HOOK,R0下调用Nt*可以绕过SSDT HOOK。

5.
从用户模式调用Nt和Zw API,连接ntdll.lib。由于是从用户模式进入内核模式,因此代码会严格检查用户空间传入的参数。

从内核模式调用Nt和Zw API,连接nooskrnl.lib。Nt系列API将直接调用对应的函数代码,而Zw系列API则通过KiSystemService,最终跳转到对应的函数代码。
在进行Kernel Mode Driver开发时可以使用Zw系列API可以避免额外的参数列表检查,提高效率。

 

参考文章:

http://blog.csdn.net/yushiqiang1688/archive/2010/03/19/5393286.aspx

http://hi.baidu.com/ligh0721/blog/item/123c99fa4808b6839f514668.html

http://blog.csdn.net/syf442/archive/2009/09/15/4554927.aspx

http://blog.csdn.net/bobohack/archive/2009/10/24/4724140.aspx

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值