原文
窗口
上的系統調用通過,每個由系統調用(x64
)或sysenter(x86)CPU
指令調用的NTDLL.dll
,如NTDLL
的NtCreateFile
的以下輸出
所示:
這里
0:000> u
ntdll!NtCreateFile:
00007ffc`c07fcb50 4c8bd1 mov r10,rcx
00007ffc`c07fcb53 b855000000 mov eax,55h
00007ffc`c07fcb58 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
00007ffc`c07fcb60 7503 jne ntdll!NtCreateFile+0x15 (00007ffc`c07fcb65)
00007ffc`c07fcb62 0f05 syscall
00007ffc`c07fcb64 c3 ret
00007ffc`c07fcb65 cd2e int 2Eh
00007ffc`c07fcb67 c3 ret
EAX
的值是系統服務編號
(在本例中為0x55
).接著是系統調用指令
(測試的條件一般沒有分支).
系統調用(syscall)
導致內核傳輸到負責分發到執行器
中的實際系統調用實現
的系統服務分發器例程
.最終,必須將EAX寄存器
作為,每個系統服務編號
(索引)都指向實際例程
的系統服務分發表
(SSDT
)的查找索引
.
在x64
版本的窗口
上,SSDT
在內核調試器中的nt!KiServiceTable
符號中:
lkd> dd nt!KiServiceTable
fffff804`13c3ec20 fced7204 fcf77b00 02b94a02 04747400
fffff804`13c3ec30 01cef300 fda01f00 01c06005 01c3b506
fffff804`13c3ec40 02218b05 0289df01 028bd600 01a98d00
fffff804`13c3ec50 01e31b00 01c2a200 028b7200 01cca500
fffff804`13c3ec60 02229b01 01bf9901 0296d100 01fea002
你可能期望SSDT
中的值是,直接指向系統服務
(這是x86
系統上使用的方案)的64
位指針.在x64
上,這些值為32
位,它們是SSDT
自身開頭的偏移.
但是,偏移不包括最后十六進制數
字(4位):最后值
是系統調用的參數個數
.
來看看這是否適合NtCreateFile
.正如用戶模式
,它的服務編號是0x55
的,因此要取得實際的偏移
,需要簡單計算
:
kd> dd nt!KiServiceTable+55*4 L1
fffff804`13c3ed74 020b9207
現在,需要取(不帶最后十六進制數
字的)此偏移,在SSDT
中添加它,它應該指向NtCreateFile
:
lkd> u nt!KiServiceTable+020b920
nt!NtCreateFile:
fffff804`13e4a540 4881ec88000000 sub rsp,88h
fffff804`13e4a547 33c0 xor eax,eax
fffff804`13e4a549 4889442478 mov qword ptr [rsp+78h],rax
fffff804`13e4a54e c744247020000000 mov dword ptr [rsp+70h],20h
事實上,這是NtCreateFile
.參數個數呢?存儲的值
是7
.下面是NtCreateFile
的原型(在WDK
中記錄為ZwCreateFile
):
NTSTATUS NtCreateFile(PHANDLE FileHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PIO_STATUS_BLOCK IoStatusBlock,PLARGE_INTEGER AllocationSize,ULONG FileAttributes,ULONG ShareAccess,ULONG CreateDisposition,ULONG CreateOptions,PVOID EaBuffer,ULONG EaLength);
顯然,有11
個參數,而不僅是7個
.為什么會有差異?存儲的值
是使用棧傳遞的參數個數
.在x64
調用約定中,前4個參數
使用寄存器
傳遞:RCX,RDX,R8,R9
(按此順序).
現在回到文章標題
.下面是SSDT
中的前幾個項:
lkd> dd nt!KiServiceTable
fffff804`13c3ec20 fced7204 fcf77b00 02b94a02 04747400
fffff804`13c3ec30 01cef300 fda01f00 01c06005 01c3b506
前兩個項的數字
要大得多.試對第一個值
(索引0
)應用相同邏輯:
kd> u nt!KiServiceTable+fced720
fffff804`2392c340 ??
???^ Memory access error in 'u nt!KiServiceTable+fced720'
(按二進制
補碼)該值實際上是一個負值
,因此需要符號擴展
到64
位,然后加起來(如前省略最后十六進制數
字):
kd> u nt!KiServiceTable+ffffffff`ffced720
nt!NtAccessCheck:
fffff804`1392c340 4c8bdc mov r11,rsp
fffff804`1392c343 4883ec68 sub rsp,68h
fffff804`1392c347 488b8424a8000000 mov rax,qword ptr [rsp+0A8h]
這是NtAccessCheck
.該函數
的實現在比SSDT
自身更低的地址中.來試用1索引
執行相同練習:
kd> u nt!KiServiceTable+ffffffff`ffcf77b0
nt!NtWorkerFactoryWorkerReady:
fffff804`139363d0 4c8bdc mov r11,rsp
fffff804`139363d3 49895b08 mov qword ptr [r11+8],rbx
現在得到1
系統調用號:NtWorkerFactoryWorkerReady
.
對那些喜歡WinDbg
腳本的人,編寫一個腳本
來很好地顯示所有系統調用函數及其索引
.