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

来源:互联网 发布:淘宝卖家真实姓名隐藏 编辑:程序博客网 时间:2024/05/23 11:40


来自:http://blog.csdn.net/sysprogram/article/details/5805265


以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可以避免额外的参数列表检查,提高效率。


0 0
原创粉丝点击