Ring3中的NATIVE API,和Ring0的系统调用,都有同名的Zw和Nt系列函数,一度让初学者感到迷糊。N久前的我,也是相当的迷糊。现在就以ZwOpenProcess和NtOpenProcess函数为例,详细阐述下他们的分别和联系。
ntdll.dll导出了NtOpenProcess和ZwOpenProcess两个函数,我们记为ntdll!NtOpenProcess和ntdll!ZwOpenProcess。仔细看一下,会发现他们的入口点实际上都是一样的,这就是说,ntdll!ZwOpenProcess仅仅是ntdll!NtOpenProcess函数的别名而已,实现如下:
ZwOpenProcess  
.text:7C92D5FE                 mov     eax, 7Ah         ; NtOpenProcess
.text:7C92D603                 mov     edx, 7FFE0300h
.text:7C92D608                 call     dword ptr [edx]
.text:7C92D60A                 retn     10h
  7FFE0300h处是ntdll!KiFastSystemCall的入口,ntdll!KiFastSystemCall会保存起当前的栈指针,然后通过引发0x2e中断,陷入内核。
  当触发0x2e中断后,CPU将执行环境切换到Ring0状态,然后去调用内核模块的0x2e处理例程nt!KiSystemService。nt!KiSystemService会在参数检查、栈拷贝等操作之后,根据Ring3代码传递过来的调用号0x7A,在SSDT中查找相应的函数地址,然后调用找到的函数。对于我们的例子来说,这个函数就是内核模块的导出函数nt!NtOpenProcess。nt!NtOpenProcess才是真正的打开进程实现函数。但是内核模块也导出了nt!ZwOpenProcess,这个nt!ZwOpenProcess,有什么用处呢?会不会像ntdll!ZwOpenProcess一样,也仅仅是ntdll!NtOpenProcess的一个别名?实际上,nt!ZwOpenProcess并不仅仅是nt!NtOpenProcess一个别名,我们可以看一下nt!ZwOpenProcess的实现:
kd> u nt!ZwOpenProcess
nt!ZwOpenProcess:
804fede8   mov     eax,7Ah
804feded   lea       edx,[esp+4]
804fedf1   pushfd
804fedf2   push     8
804fedf4   call       nt!KiSystemService (8053d891)
804fedf9   ret       10h
  与ntdll.ZwOpenProcess是不是很接近?nt!ZwOpenProcess也只是让nt!KiSystemService调用SSDT中的第0x7A号函数,他自己本身没有进行任何打开进程的实现。
  到这儿,就可以总结一下了:用户空间中的Zw***和Nt***的实现都是一样的,比如ntdll!ZwOpenProcess和ntdll!NtOpenProcess的入口都是0x7C92D5FE,ntdll!ZwOpenFile和ntdll!NtOpenFile的入口都是0f7C92D59E。内核空间中的Zw函数,是Nt函数的一个Stup,只是mov系统调用号到eax中,转而直接调用(注意,没有像ntdll!ZwOpenProcess)nt!KiSystemService去从SSDT中找到相应号码的函数再调用之,真正的实现都在Nt***函数中。

什么是“未公开”函数呢?微软为了某种目的。对于一些封装在系统中的函数没有在任何开发文档提供任何函数说明和定义。而这些函数有很多都是很有用的。所幸的是一些有心之人对Windows系统动态连接库做了十分详细的分析,从而将这些未公开函数公开以供广大开发人员共享(我对他们的感激之情就象滔滔江水,绵绵不绝…)

  首先他们都是微软未公开的函数,之所以未公开主要是因为这些函数大部分功能太强大了,把他们公开会让一些别有用心的人利用。9x下的我不知道,NT(含2000/xp)下你可以参考《Windows NT Native API》,他们中的大部分函数几乎就从来没有变过。而几乎所有从Kenerl.dll中引出的Win32API,都是通过调用的Native API(NTDLL.DLL中导出)实现系统调用的。举一个例子:NtQuerySystemInformation 这个函数就强大到可以查询所有的系统信息,使用时需要用户拥有相当高的访问权限。

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。

Zw函数与Nt函数的分别与联系的更多相关文章

  1. 《zw版·Halcon-delphi系列原创教程》 zw版-Halcon常用函数Top100中文速查手册

    <zw版·Halcon-delphi系列原创教程> zw版-Halcon常用函数Top100中文速查手册 Halcon函数库非常庞大,v11版有1900多个算子(函数). 这个Top版,对 ...

  2. 《zw版·Halcon-delphi系列原创教程》 Halcon分类函数001·3D函数

    <zw版·Halcon-delphi系列原创教程> Halcon分类函数001·3D函数 为方便阅读,在不影响说明的前提下,笔者对函数进行了简化: :: 用符号“**”,替换:“proce ...

  3. C++如何在r3静态调用NT函数

    原文最早发表于百度空间2010-02-22. 1.把ntapi.h.ntdll.lib放在一个目录,然后设置工具——选项——项目和解决方案——VC++目录——包含文件,把刚刚的目录设置在改包 含文件中 ...

  4. 调用Nt函数内核模式切换问题

    很久不写博客了,笔记大多记在电脑上在,以后整理好了再搬运上来吧. 今天记一下“进程内存管理器”这个小程序上遇到的一个问题——内核模式调用Nt*函数. 使用的是内核中的NtQueryVirtualMem ...

  5. map函数和filter函数 zip函数

    1.map函数 接收一个函数f和一个可迭代对象(列表,字典等),并通过把函数f依次作用在li每个元素上,得到一个新的list并返回 # -*-coding:utf8 -*- import reques ...

  6. 消息循环中的TranslateMessage函数和DispatchMessage函数,特别注意WM_TIMER消息

    原文:http://www.cnblogs.com/xingrun/p/3583357.html TranslateMessage函数 函数功能描述:将虚拟键消息转换为字符消息.字符消息被送到调用线程 ...

  7. 深入理解javascript函数定义与函数作用域

    最近在学习javascript的函数,函数是javascript的一等对象,想要学好javascript,就必须深刻理解函数.本人把思路整理成文章,一是为了加深自己函数的理解,二是给读者提供学习的途径 ...

  8. JavaScript 函数节流和函数去抖应用场景辨析

    概述 也是好久没更新 源码解读,看着房价蹭蹭暴涨,心里也是五味杂陈,对未来充满恐惧和迷茫 ...(敢问一句你们上岸了吗) 言归正传,今天要介绍的是 underscore 中两个重要的方法,函数节流和函 ...

  9. 如果你也会C#,那不妨了解下F#(4):了解函数及常用函数

    函数式编程其实就是按照数学上的函数运算思想来实现计算机上的运算.虽然我们不需要深入了解数学函数的知识,但应该清楚函数式编程的基础是来自于数学. 例如数学函数\(f(x) = x^2+x\),并没有指定 ...

随机推荐

  1. Prime Number(CodeForces-359C)【快速幂/思维】

    题意:已知X,数组arr[n],求一个分式的分子与分母的最大公因数.分子为ΣX^arr[i],分母为X^Σarr[i],数组为不递减序列. 思路:比赛的时候以为想出了正确思路,WA掉了很多发,看了别人 ...

  2. k8s之dashboard认证、资源需求、资源限制及HeapSter

    1.部署dashboard kubernetes-dashboard运行时需要有sa账号提供权限 Dashboard官方地址:https://github.com/kubernetes/dashboa ...

  3. ES6入门十一:Generator生成器、async+await、Promisify

    生成器的基本使用 生成器 + Promise async+await Promise化之Promisify工具方法 一.生成器的基本使用 在介绍生成器的使用之前,可以简单理解生成器实质上生成的就是一个 ...

  4. JS-闭包练习

    首先,第一个输出,因为前置运算,i要先参与输出,然后再自增,所以输出为0 第二个输出,因为f1和f2是不同的函数,不共享i变量,所以输出也为0 第三个输出,因为是f1,共享i,所以i加了1,输出为1 ...

  5. 微信小程序手动实现select下拉框选择

    在小程序中没有像h5中的下拉 标签的 picker又满足部了,那就自己动手写 <view class='list-msg'> <view class='list-msg1'> ...

  6. github 提交和更新代码

    …or create a new repository on the command line   echo "# flutterPluginsWorks" >> RE ...

  7. LED点阵显示

    /*********************************************************** 8*8LED点阵---显示数字实验 实现现象:下载程序后点阵上显示数字0 注意 ...

  8. vue项目前端限制页面长时间未操作超时退出到登录页

    之前项目超时判断是后台根据token判断的,这样判断需要请求接口才能得到返回结果,这样就出现页面没有接口请求时还可以点击,有接口请求时才会退出 现在需要做到的效果是:页面超过30分钟未操作时,无论点击 ...

  9. linux程序对比

  10. 【异常】 Could not find Linker 'g++' in system path.

    1 详细异常 FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':az-ex ...