首先他们都是微软未公开的函数,之所以未公开主要是因为这些函数大部分功能太强大了,把他们公开会让一些别有用心的人利用。9x下的我不知道,NT(含2000/xp)下你可以参考《Windows NT Native API》,他们中的大部分函数几乎就从来没有变过。而几乎所有从Kenerl.dll中引出的Win32API,都是通过调用的Native API(NTDLL.DLL中导出)实现系统调用的。举一个例子:NtQuerySystemInformation 这个函数就强大到可以查询所有的系统信息,使用时需要用户拥有相当高的访问权限。
in ring3:
lkd> ? ntdll!ZwOpenProcess
Evaluate expression_r: 2089999739 = 7c92dd7b
lkd> ? ntdll!NtOpenProcess
Evaluate expression_r: 2089999739 = 7c92dd7b
用dependency也可看到。
可以看到,在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。rtl** 函数是windows ddk提供的编写驱动的函数。
我的总结:
由以上反汇编Zw***可知,Zw***代码内部是通过SSDT中的对应Nt***索引号查找到真正Nt***执行代码的入口地址。
大多数win32的api函数都是包装了这些zwxxx api和ntxxx api实现的。
在用户模式下,这两种形式的本机api是相同的,只是ntdll.dll中相同入口点的两个不同符号。
在内核模式下,代码依靠ntoskrnl.exe来连接,不再是ntdll.dll。这是,zwxxx的函数入口点含有来自于ntdll.dll的一份拷贝。ntxxx的函数入口点则含有系统服务的实际实现。