ntdll.dll和ntoskrnl.exe的Nt和Zw系列函数区别

in ring3:
lkd> ? ntdll!ZwOpenProcess
Evaluate expression: 2089999739 = 7c92dd7b
lkd> ?ntdll!NtOpenProcess
Evaluate expression: 2089999739 = 7c92dd7b

可以看到,在ntdll中,ZwOpenProcess和NtOpenProcess其实是同一个函数,只不过拥有两个名称而已。
也就是说,在ring3环境中,Zw***系列函数和Nt***系列函数无区别。

in ring0:
lkd> u nt!ZwOpenProcess
nt!ZwOpenProcess:
804de044 b87a000000      mov     eax,7Ah
804de049 8d542404        lea     edx,[esp+4]
804de04d 9c              pushfd
804de04e 6a08            push    8
804de050 e8dc150000      call    nt!KiSystemService (804df631)
804de055 c21000          ret     10h

lkd> u nt!NtOpenProcess
nt!NtOpenProcess:
80573d06 68c4000000      push    0C4h
80573d0b 6810b44e80      push    offset nt!ObWatchHandles+0x25c (804eb410)
80573d10 e826f7f6ff      call    nt!_SEH_prolog (804e343b)
80573d15 33f6            xor     esi,esi
80573d17 8975d4          mov     dword ptr [ebp-2Ch],esi
80573d1a 33c0            xor     eax,eax
80573d1c 8d7dd8          lea     edi,[ebp-28h]
80573d1f ab              stos    dword ptr es:[edi]

可以看得出,ZwOpenProcess函数很短,首先把0x7a(NtOpenProcess的服务号)存入eax,然后做一些保存现场的工作即KiSystemService——这个函数根据eax中的service id在SSDT中查找相应的系统服务,然后调用之。

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

简单总结如下:
r3下无论如何调用,均无法绕过SSDT HOOK,r0下调用Nt***可以绕过SSDT HOOK。

这里先说明下2000和XP系统用户模式到内核模式是通过软中断的方式进入的。2000下通过"int 2e",而XP下通过"sysenter"进入。

这里用WINDBG工具来说明区别:

1.在用户模式下ntdll.dll的Nt和Zw的区别

0:005> u ntdll!ZwCreateFile
ntdll!ZwCreateFile:
7c92d0ae b825000000      mov     eax,25h
7c92d0b3 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d0b8 ff12            call    dword ptr [edx]
7c92d0ba c22c00          ret     2Ch

0:005> u ntdll!NtCreateFile
ntdll!ZwCreateFile:
7c92d0ae b825000000      mov     eax,25h
7c92d0b3 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d0b8 ff12            call    dword ptr [edx]
7c92d0ba c22c00          ret     2Ch

函数先将0x25号放入eax,再将函数地址的指针放入edx,可以查看函数地址在7FFE03000为7C92E510

7FFE0300 : 10 E5 92 7C

进入7C92E510可以发现调用了sysenter,从用户态进入内核态。

7C92E510 > 8BD4            mov     edx, esp
7C92E512    0F34            sysenter

纵观ntdll.dll里的Nt和Zw发现就是同一个函数,也就是ntdll.dll的Nt和Zw其实是一个函数的两个别名而已。

2.进入内核态查看:

lkd> u nt!ZwCreateFile
nt!ZwCreateFile:
80501020 b825000000      mov     eax,25h
80501025 8d542404        lea     edx,[esp+4]
80501029 9c              pushfd
8050102a 6a08            push    8
8050102c e860140400      call    nt!KiSystemService (80542491)
80501031 c22c00          ret     2Ch

lkd> u nt!NtCreateFile
nt!NtCreateFile:
8057a084 8bff            mov     edi,edi
8057a086 55              push    ebp
8057a087 8bec            mov     ebp,esp
8057a089 33c0            xor     eax,eax
8057a08b 50              push    eax
8057a08c 50              push    eax
8057a08d 50              push    eax
8057a08e ff7530          push    dword ptr [ebp+30h]
lkd> u
nt!NtCreateFile+0xd:
8057a091 ff752c          push    dword ptr [ebp+2Ch]
8057a094 ff7528          push    dword ptr [ebp+28h]
8057a097 ff7524          push    dword ptr [ebp+24h]
8057a09a ff7520          push    dword ptr [ebp+20h]
8057a09d ff751c          push    dword ptr [ebp+1Ch]
8057a0a0 ff7518          push    dword ptr [ebp+18h]
8057a0a3 ff7514          push    dword ptr [ebp+14h]
8057a0a6 ff7510          push    dword ptr [ebp+10h]
lkd> u
nt!NtCreateFile+0x25:
8057a0a9 ff750c          push    dword ptr [ebp+0Ch]
8057a0ac ff7508          push    dword ptr [ebp+8]
8057a0af e868d8ffff      call    nt!IoCreateFile (8057791c)
8057a0b4 5d              pop     ebp
8057a0b5 c22c00          ret     2Ch

可以发现Zw内核态下调用了nt!KiSystemService (80542491)  调用SSDT
而Nt内核态下直接调用了nt!IoCreateFile (8057791c) 此函数直接实现了功能

所以不管是否在用户或者内核态Zw函数都是要经过SSDT  而Nt用户态经过,内核态就可以绕过SSDT

附:

操作系统根据是否是多处理器平台和是否支持PAE(Physical Address Extension)来选择合适的系统:

ntoskrnl.exe

单x86处理器,使用不超过4GB的物理内存。

ntkrnlpa.exe

单x86处理器,支持PAE。

ntkrnlmp.exe

多处理器,使用不超过4GB的物理内存。

ntkrpamp.exe

多处理器,支持PAE。

以NtOpenProcess和ZwOpenProcess为例,结合Windbg的lkd调试来说明

1、Q:ntdll.dll中的Nt*和Zw*区别?

lkd> u ntdll!zwopenprocess l4
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

lkd> u ntdll!ntopenprocess l4
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
A:从反汇编代码来看,两者别无区别,都是通过SSDT服务表,通过系统服务调度程序KiSystemService调用ntoskrnl.exe中的中断处理程序Nt*函数。

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

lkd> u nt!zwopenprocess l6
nt!ZwOpenProcess:
804e4c0a b87a000000      mov     eax,7Ah
804e4c0f 8d542404            lea     edx,[esp+4]
804e4c13 9c                        pushfd
804e4c14 6a08                    push    8
804e4c16 e8b69bffff           call    nt!KiSystemService (804de7d1)
804e4c1b c21000               ret     10h

lkd> u nt!ntopenprocess l20
nt!NtOpenProcess:
80582702 68c4000000      push    0C4h
80582707 68e8524f80      push    offset nt!ObWatchHandles+0x25c (804f52e8)
8058270c e87217f6ff      call    nt!_SEH_prolog (804e3e83)
80582711 33f6            xor     esi,esi
80582713 8975d4          mov     dword ptr [ebp-2Ch],esi
80582716 33c0            xor     eax,eax
80582718 8d7dd8          lea     edi,[ebp-28h]
8058271b ab              stos    dword ptr es:[edi]
8058271c 64a124010000    mov     eax,dword ptr fs:[00000124h]
80582722 8a8040010000    mov     al,byte ptr [eax+140h]
80582728 8845cc          mov     byte ptr [ebp-34h],al
8058272b 84c0            test    al,al
8058272d 0f840e7b0100    je      nt!NtOpenProcess+0xc0 (8059a241)
80582733 8975fc          mov     dword ptr [ebp-4],esi
80582736 a1d48e5680      mov     eax,dword ptr [nt!MmUserProbeAddress (80568ed4)]
8058273b 8b4d08          mov     ecx,dword ptr [ebp+8]
8058273e 3bc8            cmp     ecx,eax
80582740 0f8315170800    jae     nt!NtOpenProcess+0x40 (80603e5b)
80582746 8b01            mov     eax,dword ptr [ecx]
80582748 8901            mov     dword ptr [ecx],eax
8058274a 8b5d10          mov     ebx,dword ptr [ebp+10h]
8058274d f6c303          test    bl,3
80582750 0f850c170800    jne     nt!NtOpenProcess+0x4e (80603e62)
80582756 a1d48e5680      mov     eax,dword ptr [nt!MmUserProbeAddress (80568ed4)]
8058275b 3bd8            cmp     ebx,eax
8058275d 0f8309170800    jae     nt!NtOpenProcess+0x5c (80603e6c)
80582763 397308              cmp     dword ptr [ebx+8],esi
80582766 0f9545e6        setne   byte ptr [ebp-1Ah]
8058276a 8b4b0c          mov     ecx,dword ptr [ebx+0Ch]
8058276d 894dc8          mov     dword ptr [ebp-38h],ecx
80582770 8b4d14          mov     ecx,dword ptr [ebp+14h]
80582773 3bce            cmp     ecx,esi

A:从反汇编代码可知NT*是实现函数具体过程,而ZW*函数是在ring 0下通过SSDT服务表,KiSystemService调用ntoskrnl.exe中的中断处理程序Nt*函数。

3、Q:ntdll.dll中的ZW*和ntoskrnl.exe中的ZW*有什么区别呢?

A:

从发汇编代码来看:ntdll.dll:传入服务号到eax——>调用SharedUserData!SystemCallStub (7ffe0300)函数->KiSystemService---->Nt*(ntoskrnl)
ntoskrnl.exe:传入服务号eax——>KiSystemService--->Nt*(ntoshrnl)

S:从用户模式调用Nt和Zw API,如NtReadFile和ZwReadFile,连接ntdll.lib:
二者没有任何区别,通过设置系统服务表中的索引和在堆栈中设置参数,经由SYSENTER指令进入内核态(而不是象w2k中通过int 0x2e中断),并最终由KiSystemService跳转到KiServiceTable对应的系统服务例程中。由于是从用户模式进入内核模式,因此代码会严格检查用户空间传入的参数。

从内核模式调用Nt和Zw API,连接nooskrnl.lib:
Nt系列API将直接调用对应的函数代码,而Zw系列API则通过KiSystemService,最终跳转到对应的函数代码。
重要的是两种不同的调用对内核中previous mode的改变,如果是从用户模式调用Native API则previous mode是用户态,如果从内核模式调用Native API则previous mode是内核态。previous为用户态时Native API将对传递的参数进行严格的检查,而为内核态时则不会。
调用用户模式Nt API时不会改变previous mode的状态,调用Zw API时会将previous mode改为内核态,因此在进行Kernel Mode Driver开发时可以使用Zw系列API可以避免额外的参数列表检查,提高效率。

Nt*和Zw*系列函数的区别相关推荐

  1. 本地系统服务例程:Nt和Zw系列函数

    Windows本地操作系统服务API由一系列以Nt或Zw为前缀的函数实现的,这些函数以内核模式运行,内核驱动可以直接调用这些函数,而用户层程序只能通过系统进行调用.通常情况下用户层应用程序不会直接调用 ...

  2. Nt系列函数与Zw系列函数的关系

    常有人搞不清这两组函数的关系,因为调用接口和实现功能一样,有些人就认为他们是同一个函数的不同名称.实际上他们是有区别的,借助windbg这个工具,我们就可以一探究竟. 在ring3层,这两组函数确实是 ...

  3. Nt**、Zw**和Rtl** 开头的函数介绍

    首先他们都是微软未公开的函数,之所以未公开主要是因为这些函数大部分功能太强大了,把他们公开会让一些别有用心的人利用.9x下的我不知道,NT(含2000/xp)下你可以参考<Windows NT ...

  4. ntdll.dll和ntoskrnl.exe中的NT*和ZW*函数区别

    以NtOpenProcess和ZwOpenProcess为例,结合Windbg的lkd调试来说明 1.Q:ntdll.dll中的Nt*和Zw*区别? lkd> u ntdll!zwopenpro ...

  5. zw函数和nt函数的区别

    内核解惑:zw函数和nt函数的区别 lkd> u ZwOpenProcess nt!ZwOpenProcess: 804de044 b87a000000 mov eax,7Ah 804de049 ...

  6. 内核解惑:zw函数和nt函数的区别

    转载自:http://hi.baidu.com/resoft007/item/eb510a0d0ae2ac03addc7019 http://bbs.pediy.com/showthread.php? ...

  7. Nt*和Zw*开头的函数

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

  8. 技术沙龙系列之:Scala method(方法) 和 functio(函数) 的区别

    下面来简单介绍一下如何来认识Scala method(方法) 和 functio(函数) 的区别,具体如下所示: 在我没有学习 scala 的时候,主要用 java 和 python 做日常工作开发, ...

  9. 【驱动之四】Nt和Zw

    Ring3中的NATIVE API,和Ring0的系统调用,都有同名的Zw和Nt系列函数,初次接触会感到很迷茫. 现在就以ZwOpenProcess和NtOpenProcess函数为例,详细阐述下他们 ...

最新文章

  1. 访问量最高超7百万的Stack Overflow问题竟然是...
  2. ICCV 2021 Workshop 盘点
  3. 软件系统架构师成长之路(一)
  4. 【C++ 语言】vector 容器 ( 容器分类 | vector 声明 | vector 初始化 | vector 容器元素增删查改 )
  5. 利用74LS161计数器芯片分别实现模12,模20的计数器,并在QuartusⅡ上进行仿真
  6. 关于数据准确性,精益求精,神策数据矢志不渝的坚持
  7. sql server 千万级大数据sql更新_医疗SQL每日实例6数据更新大法
  8. ARM的UART实验
  9. 转载:警惕!!骗人的“培训机构” “北大青鸟”事件
  10. 信息系统项目管理系列之二:项目生命期和组织
  11. MFC入门示例之组合框(CComboBox)、列表框(CListBox)
  12. 用python语言写一个简单的计算器
  13. Hadoop、Spark等5种大数据框架对比,你的项目该用哪种?
  14. php用什么打开_php文件怎么打开,用什么软件打开php文件
  15. 联想拯救者Y7000P拆机清灰学习
  16. Hyperic HQ产品功能列表
  17. 你以为你在利用碎片化时间,实际上你的时间被碎片化了
  18. 新兴基金经理凯瑟琳·伍德ARKK基金在 2022 年初遭受新的打击
  19. deepin系统引导_【转】deepin系统启动流程
  20. 微信小程序,学习笔记(三)微信小计算器

热门文章

  1. 机器学习非监督分类之主成分分析(PCA)
  2. 2021年全国大学生电子设计大赛每一个注意问题11.05
  3. Mac下载SQLServer
  4. [RockWell FTPC]随笔_PD更改字体大小
  5. 计算机无法识别新挂硬盘,意外:如果新购买的移动硬盘计算机无法识别该怎么办...
  6. vue实现悬浮广告飘窗组件
  7. Nor Flash的理论性能
  8. ISD系列语音芯片电路介绍及其应用
  9. 2020最全微服务:SpringBoot+Cloud+Docker
  10. redis持久化(万一redis突然宕机了咋办?数据会丢失吗?)