Windows本地操作系统服务API由一系列以Nt或Zw为前缀的函数实现的,这些函数以内核模式运行,内核驱动可以直接调用这些函数,而用户层程序只能通过系统进行调用。通常情况下用户层应用程序不会直接调用Nt和Zw系函数,更多的是通过直接调用Win32函数,这些Win32函数内部会调用Nt和Zw系函数,但也仅限于通常情况下,当Win32函数不支持一些操作时,用户层也会直接调用这些本地系统服务函数。
Nt前缀是Windows NT的缩写,但Zw前缀并没有任何意义,使用Zw只是避免跟其他已存在和未来可能出现的API有命名冲突而已。很多Windows驱动支持函数都以两到三个特定的简称字母为前缀进行命名,以此来表示这些例程都是由哪些内核系统组件实现的,比如CmRegisterCallbackEx中的Cm就表示配置管理器(Configuration manager)
每个本地系统服务例程都有两个有着不同前缀的相似名称的函数版本,比如NtCreateFile和ZwCreateFile,两者执行相同的操作,并且事实上两者也都服务于相同的内核模式系统例程。对于用户层的系统调用,Nt和Zw系函数是没有什么区别的,但对于来自于内核驱动的调用,Nt和Zw系函数对传入参数的处理方式有些不一样。
如果传入参数是来自于可信任的内核层,那么内核模式驱动则调用Zw版本的本地系统服务例程来通知其他例程,在这种情况下,例程都是不经过验证就直接使用这些参数。反而,如果这些参数可能来自用户层或者内核层,那么驱动则调用Nt版本的例程,这取决于调用线程的历程——这些参数是从用户层还是内核层发起的,线程对象中有个PreviousMode的属性可用于判断参数是否从用户层过来的,关于例程如何判断参数是来自用户层还是内核层,详细内容请参见
更多内容请关注个人微信公众号 物役记 (微信号:materialchains)
