ntdll.dll和ntoskrnl.exe中的NT*和ZW*函数区别
以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可以避免額外的參數列表檢查,提高效率。
總結
以上是生活随笔為你收集整理的ntdll.dll和ntoskrnl.exe中的NT*和ZW*函数区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字符数据类型转换代码
- 下一篇: MFC 获取命令行参数