- xp _NtReadFile
- 0xFFE0300h
- 系統呼叫
- xp _KiIntSystemCall
- int 2Eh
- xp _KiSystemService 原始碼asm
- ENTER_SYSCALL macro
- EXIT_ALL macro
- xp _KiSystemService 原始碼asm
- SSDT結構
- xp _KiSystemService 反編譯asm
- xp _KiIntSystemCall
- 快速系統呼叫
- 入口方式不同 xp _KiFastSystemCall 反編譯ASM
- 使用者空間資訊儲存不同 xp _KiFastCallEntry 原始碼asm
- 執行流程
- 系統呼叫
- 快速系統呼叫
系統呼叫就是作業系統為R3和R0(或R0與R0(僅限windows))提供函式呼叫的一種機制
xp _NtReadFile
ntdll.dll
中追蹤NTSTATUS __stdcall NtReadFile(x,x,x,x,x,x,x,x,x)
函式如下
.text:77F062B8 ; NTSTATUS __stdcall NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
.text:77F062B8 public _NtReadFile@36
.text:77F062B8 _NtReadFile@36 proc near ; CODE XREF: RtlGetSetBootStatusData(x,x,x,x,x,x)+72↑p
.text:77F062B8 ; RtlGetSetBootStatusData(x,x,x,x,x,x):loc_77F4E893↓p ...
.text:77F062B8
.text:77F062B8 FileHandle = dword ptr 4
.text:77F062B8 Event = dword ptr 8
.text:77F062B8 ApcRoutine = dword ptr 0Ch
.text:77F062B8 ApcContext = dword ptr 10h
.text:77F062B8 IoStatusBlock = dword ptr 14h
.text:77F062B8 Buffer = dword ptr 18h
.text:77F062B8 Length = dword ptr 1Ch
.text:77F062B8 ByteOffset = dword ptr 20h
.text:77F062B8 Key = dword ptr 24h
.text:77F062B8
.text:77F062B8 mov eax, 111h ; NtReadFile系統呼叫號
.text:77F062BD mov edx, 7FFE0300h ;系統呼叫入口
.text:77F062C2 call dword ptr [edx] ;執行系統呼叫
.text:77F062C4 retn 24h ;堆疊平衡
.text:77F062C4 _NtReadFile@36 endp
.text:77F062C4
.text:77F062C4 ; ---------------------------------------------------------------------------
111
為預定義的核心函式系統呼叫號,實際為SSDT(SSDT擴充套件)表索引0xFFE0300h
為系統呼叫入口
0xFFE0300h
0x7ffe0000
(低2GB)與0xffdf0000
(高2GB)為預定義資料共享段,內容完全相同,windbg如下:
kd> dd 7ffe0000
7ffe0000 00000000 0f99a027 32c8a556 00000677
7ffe0010 00000677 5d00846f 01db0fc0 01db0fc0
7ffe0020 f1dcc000 ffffffbc ffffffbc 014c014c
7ffe0030 003a0043 0057005c 006e0069 006f0064
7ffe0040 00730077 00000000 00000000 00000000
7ffe0050 00000000 00000000 00000000 00000000
7ffe0060 00000000 00000000 00000000 00000000
7ffe0070 00000000 00000000 00000000 00000000
kd> dd ffdf0000
ffdf0000 00000000 0f99a027 32c8a556 00000677
ffdf0010 00000677 5d00846f 01db0fc0 01db0fc0
ffdf0020 f1dcc000 ffffffbc ffffffbc 014c014c
ffdf0030 003a0043 0057005c 006e0069 006f0064
ffdf0040 00730077 00000000 00000000 00000000
ffdf0050 00000000 00000000 00000000 00000000
ffdf0060 00000000 00000000 00000000 00000000
ffdf0070 00000000 00000000 00000000 00000000
共享資料段定義為_KUSER_SHARED_DATA
結構體,windbg如下:
kd> dt _KUSER_SHARED_DATA
nt!_KUSER_SHARED_DATA
+0x000 TickCountLowDeprecated : Uint4B
+0x004 TickCountMultiplier : Uint4B
+0x008 InterruptTime : _KSYSTEM_TIME
+0x014 SystemTime : _KSYSTEM_TIME
+0x020 TimeZoneBias : _KSYSTEM_TIME
+0x02c ImageNumberLow : Uint2B
+0x02e ImageNumberHigh : Uint2B
+0x030 NtSystemRoot : [260] Wchar
+0x238 MaxStackTraceDepth : Uint4B
+0x23c CryptoExponent : Uint4B
+0x240 TimeZoneId : Uint4B
+0x244 LargePageMinimum : Uint4B
+0x248 Reserved2 : [7] Uint4B
+0x264 NtProductType : _NT_PRODUCT_TYPE
+0x268 ProductTypeIsValid : UChar
+0x26c NtMajorVersion : Uint4B
+0x270 NtMinorVersion : Uint4B
+0x274 ProcessorFeatures : [64] UChar
+0x2b4 Reserved1 : Uint4B
+0x2b8 Reserved3 : Uint4B
+0x2bc TimeSlip : Uint4B
+0x2c0 AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+0x2c4 AltArchitecturePad : [1] Uint4B
+0x2c8 SystemExpirationDate : _LARGE_INTEGER
+0x2d0 SuiteMask : Uint4B
+0x2d4 KdDebuggerEnabled : UChar
+0x2d5 NXSupportPolicy : UChar
+0x2d8 ActiveConsoleId : Uint4B
+0x2dc DismountCount : Uint4B
+0x2e0 ComPlusPackage : Uint4B
+0x2e4 LastSystemRITEventTickCount : Uint4B
+0x2e8 NumberOfPhysicalPages : Uint4B
+0x2ec SafeBootMode : UChar
+0x2ed TscQpcData : UChar
+0x2ed TscQpcEnabled : Pos 0, 1 Bit
+0x2ed TscQpcSpareFlag : Pos 1, 1 Bit
+0x2ed TscQpcShift : Pos 2, 6 Bits
+0x2ee TscQpcPad : [2] UChar
+0x2f0 SharedDataFlags : Uint4B
+0x2f0 DbgErrorPortPresent : Pos 0, 1 Bit
+0x2f0 DbgElevationEnabled : Pos 1, 1 Bit
+0x2f0 DbgVirtEnabled : Pos 2, 1 Bit
+0x2f0 DbgInstallerDetectEnabled : Pos 3, 1 Bit
+0x2f0 DbgSystemDllRelocated : Pos 4, 1 Bit
+0x2f0 DbgDynProcessorEnabled : Pos 5, 1 Bit
+0x2f0 DbgSEHValidationEnabled : Pos 6, 1 Bit
+0x2f0 SpareBits : Pos 7, 25 Bits
+0x2f4 DataFlagsPad : [1] Uint4B
+0x2f8 TestRetInstruction : Uint8B
+0x300 SystemCall : Uint4B // 系統呼叫
+0x304 SystemCallReturn : Uint4B
+0x308 SystemCallPad : [3] Uint8B
+0x320 TickCount : _KSYSTEM_TIME
+0x320 TickCountQuad : Uint8B
+0x320 ReservedTickCountOverlay : [3] Uint4B
+0x32c TickCountPad : [1] Uint4B
+0x330 Cookie : Uint4B
+0x334 CookiePad : [1] Uint4B
+0x338 ConsoleSessionForegroundProcessId : Int8B
+0x340 Wow64SharedInformation : [16] Uint4B
+0x380 UserModeGlobalLogger : [16] Uint2B
+0x3a0 ImageFileExecutionOptions : Uint4B
+0x3a4 LangGenerationCount : Uint4B
+0x3a8 Reserved5 : Uint8B
+0x3b0 InterruptTimeBias : Uint8B
+0x3b8 TscQpcBias : Uint8B
+0x3c0 ActiveProcessorCount : Uint4B
+0x3c4 ActiveGroupCount : Uint2B
+0x3c6 Reserved4 : Uint2B
+0x3c8 AitSamplingValue : Uint4B
+0x3cc AppCompatFlag : Uint4B
+0x3d0 SystemDllNativeRelocation : Uint8B
+0x3d8 SystemDllWowRelocation : Uint4B
+0x3dc XStatePad : [1] Uint4B
+0x3e0 XState : _XSTATE_CONFIGURATION
其中0x300
偏移處儲存系統呼叫入口,windbg如下:
kd> dd 7ffe0300
7ffe0300 778b70b0 778b70b4 00000000 00000000
7ffe0310 00000000 00000000 00000000 00000000
7ffe0320 02b7593f 00000000 00000000 00000000
7ffe0330 af2059b8 00000000 0000052c 00000000
7ffe0340 00000000 00000000 00000000 00000000
7ffe0350 00000000 00000000 00000000 00000000
7ffe0360 00000000 00000000 00000000 00000000
7ffe0370 00000000 00000000 00000000 00000000
0x7ffe0300
處值為778b70b0
,解析後得出為快速系統呼叫函式地址
,因為此處解析需要涉及分頁機制,所以沒有展示解析過程,下面先解析系統呼叫過程而後再解析快速系統呼叫過程
系統呼叫
xp _KiIntSystemCall
反編譯 xp C:\Windows\System32\ntdll.dll _KiIntSystemCall
函式如下
.text:77F070C0 ; Exported entry 108. KiIntSystemCall
.text:77F070C0
.text:77F070C0 ; =============== S U B R O U T I N E =======================================
.text:77F070C0
.text:77F070C0
.text:77F070C0 ; _DWORD __stdcall KiIntSystemCall()
.text:77F070C0 public _KiIntSystemCall@0
.text:77F070C0 _KiIntSystemCall@0 proc near ; DATA XREF: .text:off_77EF61B8↑o
.text:77F070C0
.text:77F070C0 arg_4 = byte ptr 8
.text:77F070C0
.text:77F070C0 lea edx, [esp+arg_4]
.text:77F070C4 int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
.text:77F070C4 ; DS:SI -> counted CR-terminated command string
.text:77F070C6 retn
.text:77F070C6 _KiIntSystemCall@0 endp
.text:77F070C6
.text:77F070C6 ; ---------------------------------------------------------------------------
.text:77F070C7 align 4
.text:77F070C8 ; Exported entry 1103. RtlRaiseException
.text:77F070C8
- ESP+8:esp棧頂指標,壓入第一個引數的地址。
lea
:esp+arg_4
的地址放入到edx
中_NtReadFile
和_KiIntSystemCall
都為__stdcall
呼叫約定,傳參方式為從右向左的順序傳遞引數,因為棧是從高地址往低地址增長,+4是EIP,+8是壓入堆疊的第一個引數
int 2Eh
自陷指令,通用系統服務入口點,int 2eh
代表呼叫中斷向量表中第47箇中斷:83e7ee00 0008ffee
,解析後函式地址為:83e7ffee
。windbg如下:
kd> !pcr
KPCR for Processor 0 at 83f6dc00:
Major 1 Minor 1
NtTib.ExceptionList: 83f6a0ac
NtTib.StackBase: 00000000
NtTib.StackLimit: 00000000
NtTib.SubSystemTib: 801e4000
NtTib.Version: 4cf55ad2
NtTib.UserPointer: 00000001
NtTib.SelfTib: 00000000
SelfPcr: 83f6dc00
Prcb: 83f6dd20
Irql: 0000001f
IRR: 00000000
IDR: ffffffff
InterruptMode: 00000000
IDT: 80b99400 // 中斷向量表
GDT: 80b99000
TSS: 801e4000
CurrentThread: 83f77380
NextThread: 00000000
IdleThread: 83f77380
DpcQueue:
kd> dq 80b99400 l50
80b99400 83e88e00`00080fc0 83e88e00`00081150
80b99410 00008500`00580000 83e8ee00`000815c0
80b99420 83e8ee00`00081748 83e88e00`000818a8
80b99430 83e88e00`00081a1c 83e88e00`00082018
80b99440 00008500`00500000 83e88e00`00082478
80b99450 83e88e00`0008259c 83e88e00`000826dc
80b99460 83e88e00`0008293c 83e88e00`00082c2c
80b99470 83e88e00`000832fc 83e88e00`000836b0
80b99480 83e88e00`000837d4 83e88e00`00083914
80b99490 00008500`00a00000 83e88e00`00083a80
80b994a0 83e88e00`000836b0 83e88e00`000836b0
80b994b0 83e88e00`000836b0 83e88e00`000836b0
80b994c0 83e88e00`000836b0 83e88e00`000836b0
80b994d0 83e88e00`000836b0 83e88e00`000836b0
80b994e0 83e88e00`000836b0 83e88e00`000836b0
80b994f0 83e88e00`000836b0 83e28e00`00085af8
80b99500 00000000`00080000 00000000`00080000
80b99510 00000000`00080000 00000000`00080000
80b99520 00000000`00080000 00000000`00080000
80b99530 00000000`00080000 00000000`00080000
80b99540 00000000`00080000 00000000`00080000
80b99550 83e8ee00`0008063a 83e8ee00`000807c0
80b99560 83e8ee00`000808fc 83e8ee00`00081498
80b99570 83e7ee00`0008ffee 83e88e00`000836b0
kd> u 83e7ffee
nt!KiSystemService:
83e7ffee 6a00 push 0
83e7fff0 55 push ebp
83e7fff1 53 push ebx
83e7fff2 56 push esi
83e7fff3 57 push edi
83e7fff4 0fa0 push fs
83e7fff6 bb30000000 mov ebx,30h
83e7fffb 668ee3 mov fs,bx
下面分析_KiSystemService
函式
xp _KiSystemService 原始碼asm
ENTER_SYSCALL macro
NT\base\ntos\ke\i386\kimacro.inc
ENTER_SYSCALL macro AssistLabel, TargetLabel, NoFSLoad
.FPO ( FPO_LOCALS, FPO_PARAMS, FPO_PROLOG, FPO_REGS, FPO_USE_EBP, FPO_TRAPFRAME )
ifdef KERNELONLY
;
; 構造陷阱幀 (Trap Frame)。
;
; 注意:陷阱幀的初始部分是透過在堆疊上推送值來構造的。
; 如果陷阱幀的格式發生更改,則下面的程式碼也必須進行更改。
;
push 0 ; 在堆疊上放置錯誤佔位符
push ebp ; 儲存不可變暫存器
push ebx ;
push esi ;
push edi ;
ifb <NoFSLoad>
push fs ; 儲存FS並將FS設定為PCR
mov ebx,KGDT_R0_PCR ; 設定PCR段號
mov fs,bx ;
else
; FS已經包含KGDT_R0_PCR(透過PentiumPro快速系統呼叫進入)
push KGDT_R3_TEB OR RPL_MASK ;
endif ; NoFSLoad
;
; 在陷阱幀中儲存舊的異常連結串列並初始化一個新的空異常連結串列。
;
push PCR[PcExceptionList] ; 儲存舊的異常連結串列
mov PCR[PcExceptionList],EXCEPTION_CHAIN_END ; 設定新的空連結串列
;
; 在陷阱幀中儲存舊的previous mode(以前的模式),
; 分配陷阱幀的其餘部分,並設定新的previous mode。
;
mov esi,PCR[PcPrcbData+PbCurrentThread] ; 獲取當前執行緒地址
push [esi]+ThPreviousMode ; 儲存舊的previous mode
sub esp,TsPreviousPreviousMode ; 分配陷阱幀的其餘部分
mov ebx,[esp+TsSegCS] ; 計算新的previous mode
and ebx,MODE_MASK ;
mov [esi]+ThPreviousMode,bl ; 設定新的previous mode
;
; 儲存舊的陷阱幀地址並設定新的陷阱幀地址。
;
mov ebp,esp ; 設定陷阱幀地址
mov ebx,[esi].ThTrapFrame ; 儲存當前陷阱幀地址
mov [ebp].TsEdx,ebx ;
mov [esi].ThTrapFrame,ebp ; 設定新的陷阱幀地址
cld ; 確保方向為前向
SET_DEBUG_DATA ; 注意:這將銷燬edi
test byte ptr [esi]+ThDebugActive,-1 ; 檢查除錯是否啟用
jnz Dr_&AssistLabel ; 如果不為零,執行緒上啟用除錯
Dr_&TargetLabel: ;
sti ; 啟用中斷
else
%out ENTER_SYSCAL outside of kernel
.err
endif
endm
ENTER_SYSCALL
宏用於進入系統呼叫,填充系統呼叫框架,為後續真正的系統呼叫儲存現場提供資訊
- 儲存暫存器狀態:儲存重要的暫存器(如
ebp
,ebx
,esi
,edi
等),這些暫存器的值在陷阱幀中會被恢復。 - 處理FS段暫存器:條件地儲存FS暫存器並設定為PCR(Processor Control Region)段。
- 處理異常連結串列:儲存當前異常連結串列並初始化一個新的空連結串列,用於異常處理。
- 處理previous mode(先前模式):儲存並設定新的previous mode,用於區分核心模式和使用者模式。
- 設定陷阱幀:儲存當前陷阱幀地址並將新的陷阱幀地址儲存在當前執行緒控制塊中(TSS)。
- 處理除錯資訊:如果偵錯程式處於活動狀態,會跳轉到處理偵錯程式的程式碼路徑。
- 啟用中斷:最後啟用中斷,使得系統呼叫可以處理中斷。執行系統呼叫時不用發生執行緒切換
EXIT_ALL macro
NT\base\ntos\ke\i386\kimacro.inc
EXIT_ALL macro NoRestoreSegs, NoRestoreVolatiles, NoPreviousMode
local a, b, f, x
local Dr_ExitHelp, Dr_ExitHelp_Target
local Db_NotATrapFrame, Db_A, Db_NotValidEntry, NonFlatPm_Target
;
; 檢查某些值並設定宏的全域性變數
;
?adjesp = TsSegGs
?RestoreAll = 1
ifnb <NoRestoreSegs>
; 如果不恢復段暫存器,不恢復所有暫存器
?RestoreAll = 0
?adjesp = ?adjesp + 12
endif
ifnb <NoRestoreVolatiles>
if ?RestoreAll eq 1
%out "EXIT_ALL NoRestoreVolatiles requires NoRestoreSegs"
.err
endif
?adjesp = ?adjesp + 12
endif
ifb <NoPreviousMode>
ifndef KERNELONLY
%out EXIT_ALL 不能在核心外恢復先前模式
.err
endif
endif
; 所有呼叫者都必須確保在中斷禁用的情況下到達此處。
if DBG
pushfd
pop edx
test edx, EFLAGS_INTERRUPT_MASK ; 檢查中斷標誌
jnz Db_NotValidEntry ; 如果中斷未禁用,跳轉到無效入口處理
cmp esp, ebp ; 確保 esp 等於 ebp
jne Db_NotValidEntry
; 確保 BADB0D00 標記存在。如果沒有,這不是一個陷阱幀!
Db_A: sub [esp]+TsDbgArgMark,0BADB0D00h
jne Db_NotATrapFrame
endif
ASSERT_FS ; 確保 FS 暫存器有效
mov edx, [esp]+TsExceptionList ; 讀取異常連結串列
if DBG
or edx, edx
jnz short @f
int 3
@@:
endif
mov ebx, fs:[PcDebugActive] ; (ebx) = DebugActive 標誌
mov fs:[PcExceptionList], edx ; 恢復異常連結串列
ifb <NoPreviousMode>
mov ecx, [esp]+TsPreviousPreviousMode ; 恢復先前模式
if DBG
cmp ecx, -1 ; 臨時程式碼,確保沒有恢復不正確的模式
jne @f ; 確保沒有人彈出 ThPreviousMode
int 3
@@:
endif
mov esi,fs:[PcPrcbData+PbCurrentThread]
mov [esi]+ThPreviousMode,cl
else
if DBG
mov ecx, [esp]+TsPreviousPreviousMode
cmp ecx, -1 ; 臨時程式碼,確保沒有推送 ThPreviousMode 並
je @f ; 現在退出時不恢復它
int 3 ; 如果沒有正確恢復,觸發斷點
@@:
endif
endif
test ebx, 0fh
jnz Dr_ExitHelp
Dr_ExitHelp_Target:
test dword ptr [esp].TsEflags,EFLAGS_V86_MASK
jnz V86ExitHelp ; 如果在虛擬8086模式下,跳轉到處理程式碼
test word ptr [esp]+TsSegCs,FRAME_EDITED
jz b ; 如果幀被編輯,跳轉到相應處理。
if ?RestoreAll eq 0
.errnz MODE_MASK-1
cmp word ptr [esp]+TsSegCs,KGDT_R3_CODE OR RPL_MASK ; 設定/清除 ZF
bt word ptr [esp]+TsSegCs,0 ; 測試 MODE_MASK,設定/清除 CF
cmc ; 反轉 CF 標誌
ja f ; 如果 CF=0 且 ZF=0,跳轉
endif
ifb <NoRestoreVolatiles>
mov edx, [esp]+TsEdx ; 恢復易失性暫存器
mov ecx, [esp]+TsEcx
; 在恢復段暫存器之前,必須先恢復 eax
mov eax, [esp].TsEax ; 參見 trap0e 處理程式
endif
cmp word ptr [ebp]+TsSegCs, KGDT_R0_CODE
jz short @f
ifb <NoRestoreSegs>
lea esp, [ebp]+TsSegGs
pop gs ; 恢復段暫存器
pop es
pop ds
endif
NonFlatPm_Target:
lea esp, [ebp]+TsSegFs
pop fs
@@:
lea esp, [ebp]+TsEdi ; 跳過 PreMode, ExceptList 和 fs
pop edi ; 恢復不可變暫存器
pop esi
pop ebx
pop ebp
;
; Esp 必須指向堆疊上的錯誤碼。因為我們使用它來儲存進入的 esp。
;
cmp word ptr [esp+8], 80h ; 檢查是否是 abios 程式碼段?
ja AbiosExitHelp
add esp, 4 ; 從陷阱幀中移除錯誤碼
ifnb <NoRestoreVolatiles>
public _KiSystemCallExitBranch
public _KiSystemCallExit
public _KiSystemCallExit2
public _KiSystemCallExit3
; NoRestoreVolatiles 僅用於從系統服務返回。
; 如果返回到核心模式,則處理器狀態不需要更改(CS, CPL 保持不變),
; 因此可以簡單地展開核心幀並跳轉到儲存的 EIP。
test dword ptr [esp+4], MODE_MASK
; 如果以下分支被執行,我們將返回到使用者模式。
; 如果處理器支援 SYSEXIT 指令,分支將在引導時調整以使用適當的程式碼序列。
_KiSystemCallExitBranch:
jnz short _KiSystemCallExit
; 從系統呼叫返回到核心模式,比 IRETD 更快,
; 展開核心幀並跳轉到返回地址。
pop edx ; 獲取 eip
pop ecx ; 從堆疊中移除 CS
popfd ; 恢復 eflags
jmp edx
if 0
; 有一天我們應該測試看看以下程式碼是否比上面的更快
; 並且仍然有效。
sti ; 重新啟用中斷
ret 8 ; 返回到 @esp 並彈出 CS 和 EFLAGs
endif
_KiSystemCallExit:
iretd ; 返回
_KiSystemCallExit2:
pop edx ; 彈出 EIP
add esp, 8 ; 移除 CS 和 EFLAGS
pop ecx ; 彈出 ESP
sti ; SYSEXIT 不重新載入標誌
iSYSEXIT
_KiSystemCallExit3:
; AMD
pop ecx ; 彈出 EIP
add esp, 8
pop esp
; mov esp, [esp+8] ; 移除 CS 和 EFLAGS,獲取 ESP
iSYSRET
endif ;; <NoRestoreVolatiles>
iretd ; 返回
if DBG
Db_NotATrapFrame:
add [esp]+TsDbgArgMark,0BADB0D00h ; 還原原始值
Db_NotValidEntry:
int 3
jmp Db_A
endif
;
; EXIT_HELPER
;
; if (PreviousMode == UserMode) {
; DR* 暫存器 = TF.Dr* 暫存器
; }
;
; 入口條件:
;
; DebugActive == TRUE
; (ebp)->TrapFrame
;
;--
align dword
Dr_ExitHelp:
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
jnz short x
test dword ptr [ebp]+TsSegCs,MODE_MASK
jz Dr_ExitHelp_Target
x: mov ebx,0
mov esi,[ebp]+TsDr0
mov edi,[ebp]+TsDr1
mov dr7,ebx
mov dr0,esi
mov ebx,[ebp]+TsDr2
mov dr1,edi
mov dr2,ebx
mov esi,[ebp]+TsDr3
mov edi,[ebp]+TsDr6
mov ebx,[ebp]+TsDr7
mov dr3,esi
mov dr6,edi
mov dr7,ebx
jmp Dr_ExitHelp_Target
endm
EXIT_ALL
宏主要用於恢復系統呼叫框架,退出系統呼叫或異常處理程式,並恢復現場。
- 引數:
NoRestoreSegs
:控制是否恢復段暫存器(gs
、fs
)。NoRestoreVolatiles
:控制是否恢復通用暫存器(eax
、ecx
、edx
)。NoPreviousMode
:控制是否恢復先前模式。
- 全域性變數設定:
?adjesp
:初始化為TsSegGs
,並根據條件調整。?RestoreAll
:預設為1,表示恢復所有暫存器。如果NoRestoreSegs
或NoRestoreVolatiles
被指定,則調整恢復行為。
- 入口檢查:
- 檢查中斷標誌和堆疊指標,確保它們符合預期,以保證正確的陷阱幀格式。
- 除錯檢查:
- 檢查除錯資訊是否啟用。如果除錯啟用,會跳轉到對應的除錯處理程式碼。
- 恢復暫存器和處理器狀態:
- 根據宏引數條件,恢復段暫存器(
fs
,gs
,es
,ds
)和通用暫存器(如eax
,ecx
,edx
)。 - 恢復先前模式,如果指定了
NoPreviousMode
,則不進行恢復。 - 恢復異常連結串列(
ExceptionList
)和呼叫框架其他欄位。
- 根據宏引數條件,恢復段暫存器(
- 處理特殊情況:
- 檢查是否是在虛擬8086模式下執行,並進行相應處理。
- 針對特定模式(如平面記憶體模式)進行不同的恢復操作。
- 最終返回:
- 使用
iret
或iretd
指令將控制權返回給呼叫者,恢復執行流。
- 使用
xp _KiSystemService 原始碼asm
\NT\base\ntos\ke\i386\trap.asm
;
; 通用系統服務入口點
;
PUBLIC _KiSystemService
_KiSystemService proc
ENTER_SYSCALL kss_a, kss_t ; 設定陷阱幀並儲存狀態
;
; (eax) = 服務號
; (edx) = 呼叫者的堆疊指標
; (esi) = 當前執行緒地址
;
; 所有其他暫存器已儲存並可用。
;
; 檢查服務號是否在有效範圍內
;
_KiSystemServiceRepeat:
mov edi, eax ; 複製系統服務號
shr edi, SERVICE_TABLE_SHIFT ;隔離服務表號,(shr edi,8)整除256=0×100*0×10=0×1000
;基本的SSDT表小於0x1000
;擴充套件的SSDT表大於0x1000
;透過SSDT表查詢3環API對應的核心函式,要判斷系統呼叫號對應的核心函式在哪張表
;方法就是將系統呼叫號右移8位
and edi, SERVICE_TABLE_MASK ;再和掩碼0x0010做個與運算,就可得出在哪張表
mov ecx, edi ;ECX變成0×00(SSDT表)或0×10(擴充套件SSDT表呼叫號大於0×1000)
add edi, [esi]+ThServiceTable ;計算服務描述符地址
;esi指向當前執行緒結構
;TIKTHREAD_SERVICE_TABLE(_KTHREAD結構的ServiceTable欄位)
;EDI指向描述塊KeServiceDescriptorTable[0]或[1]
;KeServiceDescriptorTable是全域性變數
;0x10=16個位元組
;edi=KeServiceDescriptorTable+0x10或者KeServiceDescriptorTable+0x00
;kd> dd KeServiceDescriptorTable
;83fac9c0 83ec0d9c 00000000 00000191 83ec13e4 -> 基本SSDT表
;83fac9d0 00000000 00000000 00000000 00000000 -> 擴充套件SSDT表
;擴充套件SSDT表為什麼為空呢?因為擴充套件SSDT表不是全域性變數,要單獨去查
;kd> dd KeServiceDescriptorTableShadow
;地址表 計數器(當前執行緒引用次數) 函式個數 參數列(位元組數)
;83faca00 83ec0d9c 00000000 00000191 83ec13e4
;83faca10 95db6000 00000000 00000339 95db702c
mov ebx, eax ; 儲存系統服務號
and eax, SERVICE_NUMBER_MASK ; 隔離服務表偏移
;SERVICE_NUMBER_MASK定義為0XOFFF(取低12為Limit欄位)
;
; 如果指定的系統服務號不在範圍內,則嘗試將執行緒轉換為GUI執行緒並重試服務排程。
;
cmp eax, [edi]+SdLimit ; 檢查是否有效服務
;檢查系統呼叫號是否越界
;偏移SERVICE_DESCRIPTOR_LIMIT=8
jae Kss_ErrorHandler ; 如果超出範圍,嘗試轉換為GUI執行緒
;
; 如果服務是GUI服務且GDI使用者批處理佇列不為空,
; 則呼叫適當的服務以重新整理使用者批處理。
;
cmp ecx, SERVICE_TABLE_TEST ; 檢查是否為GUI服務
jne short Kss40 ; 如果不相等,則不是GUI服務
mov ecx, PCR[PcTeb] ; 獲取當前執行緒TEB地址
xor ebx, ebx ; 獲取批處理GDI呼叫的數量
KiSystemServiceAccessTeb:
or ebx, [ecx]+TbGdiBatchCount ; 可能導致頁面異常
jz short Kss40 ; 如果為零,則沒有批處理呼叫
push edx ; 儲存使用者引數的地址
push eax ; 儲存服務號
call [_KeGdiFlushUserBatch] ; 重新整理GDI使用者批處理
pop eax ; 恢復服務號
pop edx ; 恢復使用者引數的地址
;
; 引數透過堆疊傳遞。因此它們總是需要被複制,因為為機器狀態幀在堆疊上分配了額外的空間。
; 注意我們不檢查零引數的情況 - 複製總是進行,因為零引數的情況非常少見。
;
Kss40: inc dword ptr PCR[PcPrcbData+PbSystemCalls] ; 系統呼叫計數+1
;DBG不用看---------------------------------------------------------------------------
...
;DBG不用看---------------------------------------------------------------------------
mov esi, edx ; (esi)->使用者引數 使ESI指向使用者空間堆疊上的引數塊
mov ebx, [edi]+SdNumber ; 獲取參數列地址,引數個數(位元組為單位)EDI指向具體的系統呼叫表
xor ecx, ecx
mov cl, byte ptr [ebx+eax] ; (ecx) = 引數大小,相應的陣列元素裝入暫存器ECX,eax為系統呼叫號,ebx為引數個數表
mov edi, [edi]+SdBase ; 獲取服務表地址,EDI指向具體的系統呼叫表
mov ebx, [edi+eax*4] ; (ebx)->服務例程,函式指標(eax=系統呼叫號)為下標,ebx為對應的核心函式
sub esp, ecx ; 為引數在系統棧上分配空間,ECX為引數位元組數
shr ecx, 2 ; (ecx) = 引數DWORD數量,右移2位,即除以4=引數的個數
mov edi, esp ; (es:edi)->接收第一個引數的位置,目標在系統空間堆找上
cmp esi, _MmUserProbeAddress ; 檢查是否為使用者地址,引數塊的位置不得高於MmSystemRangeStart-0x10000
jae kss80 ; 如果大於等於,則不是使用者地址
KiSystemServiceCopyArguments:
rep movsd ; 將引數複製到堆疊頂部。複製引數,以ESI為源、EDI為目標,ECX為迴圈次數
; 由於我們通常複製超過3個引數,
; rep movsd比mov指令更快。
;DBG不用看---------------------------------------------------------------------------
...
;DBG不用看---------------------------------------------------------------------------
;
; ================================== 實際呼叫系統服務 ================================
;
kssdoit:
;CAPSTARTX macro ArgList
; push eax
; stdCall __CAP_ThreadID
; pop eax
; stdCall __CAP_Start_Profiling, <ArgList>
;endm
;
;CAPENDX macro ArgList
; stdCall __CAP_End_Profiling, <ArgList>
; push eax
; stdCall __CAP_SetCPU
; pop eax
;endm
CAPSTARTX <_KiSystemService,ebx>
call ebx ; 呼叫系統服務,呼叫目標函式---ebx=函式指標
CAPENDX <_KiSystemService>
kss60:
;DBG不用看---------------------------------------------------------------------------
...
;DBG不用看---------------------------------------------------------------------------
kss61:
; ================================== 呼叫系統服務返回 ================================
; 返回時,(eax)= 狀態碼
;
mov esp, ebp ; 釋放引數的堆疊空間,回到系統呼叫框架
;
; 從當前陷阱幀恢復舊的陷阱幀地址。
;
kss70: mov ecx, PCR[PcPrcbData+PbCurrentThread] ; 獲取當前執行緒地址,使ECX指向當前執行緒的KTHREAD
; EDX儲存原系統呼叫框架指標,KTHREAD中儲存原系統呼叫框架
mov edx, [ebp].TsEdx ; 恢復之前的陷阱幀地址,從堆疊中取出儲存著的框架指標
mov [ecx].ThTrapFrame, edx ;恢復KTHREAD結構中的框架指標
;釋放當前系統呼叫框架,恢復前一個系統呼叫框架
;
; 系統服務的私有版本KiExceptionExit
; (也用於KiDebugService)
;
; 檢查是否有待處理的APC中斷,如果找到,則排程它們
; (先儲存eax在幀中)。
;
public _KiServiceExit
_KiServiceExit:
cli ; 禁用中斷,因為在系統呼叫時不允許執行緒切換
DISPATCH_USER_APC ebp, ReturnCurrentEax ;檢查是否有執行使用者空間“非同步過程呼叫”即APC請求,
;如果有則“遞交(Deliver)”請求,相當於由核心向使用者空間發出中斷請求。
;普通使用者執行緒優先順序為0,APC優先順序為1,dispatch執行緒優先順序為2
;在從R0 -> R3時會檢查是否有APC,有APC會先執行APC
;
; 從SystemService退出
;
EXIT_ALL NoRestoreSegs, NoRestoreVolatile ;退出宏,清理現場
;
; 引數列表的地址不是使用者地址。如果之前的模式是使用者,則返回訪問衝突作為系統服務的狀態。
; 否則,複製引數列表並執行系統服務。
;
kss80: test byte ptr [ebp].TsSegCs, MODE_MASK ; 測試之前的模式
jz KiSystemServiceCopyArguments ; 如果為零,之前的模式為核心
mov eax, STATUS_ACCESS_VIOLATION ; 設定服務狀態
jmp kss60 ;
;++
;
; _KiServiceExit2 - 與 _KiServiceExit 類似,但恢復完整的trap_frame(陷阱幀)上下文
;
;--
public _KiServiceExit2
_KiServiceExit2:
cli ; 禁用中斷
DISPATCH_USER_APC ebp
;
; 從 SystemService 退出
;
EXIT_ALL ; 退出宏
;DBG不用看---------------------------------------------------------------------------
...
;DBG不用看---------------------------------------------------------------------------
ret
;
; 如果在16位模式下執行sysenter指令,生成錯誤而不是嘗試處理系統呼叫。
; 沒有辦法返回到使用者模式下的正確程式碼。
;
Kfsc90:
push 0 ; 儲存VX86 Es, Ds, Fs, Gs暫存器
push 0
push 0
push 0
push 01bh ; 儲存轉換CS(程式碼段)
push 0 ; 無法知道使用者的ESP
push EFLAGS_INTERRUPT_MASK+EFLAGS_V86_MASK+2h; 帶有VX86設定的EFLAGS
push 01bh ; CS(程式碼段)
push 0 ; 不知道原始EIP(指令指標)
jmp _KiTrap06 ; 將異常轉換為非法操作。
_KiSystemService endp
SSDT結構
NT\base\ntos\inc\ke.h
//
// System Service Table Descriptor
//
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
PULONG_PTR Base; // 設定成指向MainSSDT--基本的系統呼叫函式表
PULONG Count; // 系統呼叫次數計數器
ULONG Limit; //系統呼叫函式的個數;Limit:存放引數位元組數/4=個數
#if defined(_IA64_)
LONG TableBaseGpOffset;// 系統服務參數列基址,8位元組大小。實際指向的陣列是以位元組為單位的記錄著對應服務函式的引數個數
#endif
PUCHAR Number; //指向另一個陣列MainSSPT](說明系統呼叫引數的個數,以位元組為單位)
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
win32/win64中SSDT結構相同
windbg如下:
;kd> dd KeServiceDescriptorTableShadow
;地址表 計數器(當前執行緒引用次數) 函式個數 參數列(位元組數)、引數格式=位元組數/4
;83faca00 83ec0d9c 00000000 00000191 83ec13e4
;83faca10 95db6000 00000000 00000339 95db702c
xp _KiSystemService 反編譯asm
原始碼狀態下,大量邏輯糅合,理解困難。以下反編譯程式碼,更易理解
C:\Windows\System32\ntoskrnl.exe
.text:00407EA6
.text:00407EA6 ; =============== S U B R O U T I N E =======================================
.text:00407EA6
.text:00407EA6
.text:00407EA6 _KiSystemService proc near ; CODE XREF: ZwAcceptConnectPort(x,x,x,x,x,x)+C↑p
.text:00407EA6 ; ZwAccessCheck(x,x,x,x,x,x,x,x)+C↑p ...
.text:00407EA6
.text:00407EA6 arg_0 = dword ptr 4
.text:00407EA6
.text:00407EA6 push 0 ; _KTRAP_FRAME +0x64 ErrCode,push 0 因為諸如0號異常等本身沒有返回錯誤程式碼,為了保證堆疊平衡,所以直接push 0
.text:00407EA6 ; KiSystemCall在R3的共享資料段中
.text:00407EA8 push ebp ; +0x60 EBP
.text:00407EA9 push ebx ; +0x5c ebx
.text:00407EAA push esi ; +0x58 esi
.text:00407EAB push edi ; +0x54 edi
.text:00407EAC push fs ; +0x50 SegFs
.text:00407EAE mov ebx, 30h ; 為FS暫存器賦值,指向KPCR結構體,KPCR裡存放的是CPU狀態資訊,KPCR結構體也在共享資料段中
.text:00407EB3 mov fs, bx ; windows核心中KPCR機構線性地址為0xffdff000
.text:00407EB3 ; fs = 0x30 (selector = 0011 0 000b)
.text:00407EB3 ; RPL=0, TI = 0(查GDT表); 索引 = 00110b = 6 (GDT表的第6項)
.text:00407EB3 ; KPCR所在的段描述符為: GDT表基址8003F000 + 0×30h(低3位清零)
.text:00407EB3 ;
.text:00407EB3 ; kd>dq 8003f000
.text:00407EB3 ; 8003F000 00000000`00000000 00cf9b00`0000FFFF
.text:00407EB3 ; 8003f010 00cf9300`0000FFFF 00cffb00`0000ffff
.text:00407EB3 ; 8003F020 30cff300`0000Ffff 80008b04`200020ab
.text:00407EB3 ; 8003F030 ffc093df`f0000001 0040F300`00000FFF
.text:00407EB3 ; 8003F040 0000F200`0400FFFF 00000000`00000000
.text:00407EB3 ; 8003F050 80008955`23800068 80008955`23e80068
.text:00407EB3 ; 8003F060 00009302`2F40FFFF 0000920b`80003fff
.text:00407EB3 ; 8003f070 FF0092ff`700003FF 80009a40`0000ffff
.text:00407EB3 ;
.text:00407EB3 ; ffc093df`f0000001: 段基址 = ffdff000 limit = 00001 c表示32位段20位
.text:00407EB6 push dword ptr ds:0FFDFF000h ; 儲存老的 ExceptionList -- 異常處理, 既KPRC[0] 地址處_NT_TIB[0]
.text:00407EBC mov dword ptr ds:0FFDFF000h, 0FFFFFFFFh ; 設定新的異常處理鏈-1(為空)
.text:00407EC6 mov esi, ds:0FFDFF124h ; 偏移在0x120 對應KPCR結構最後一個欄位KPRCB+4
.text:00407EC6 ; nt!_KPRCB
.text:00407EC6 ; +0x000 MinorVersion : Uint2B // 子版本
.text:00407EC6 ; +0x002 MajorVersion : Uint2B // 主版本
.text:00407EC6 ; +0x004 CurrentThread : Ptr32 _KTHREAD // 當前CPU所執行的執行緒
.text:00407ECC push dword ptr [esi+140h] ; 儲存老的先前模式;esi指向當前執行緒KTHREAD結構
.text:00407ED2 sub esp, 48h ; ESP指向KTRAP_FRAME框架0x000處
.text:00407ED5 mov ebx, [esp+68h+arg_0] ; 取出KTRAP_FRAME框架0x6c處存放使用者空間CS
.text:00407ED9 and ebx, 1 ; 取CS的CPU狀態,並儲存新 的先前模式
.text:00407EDC mov [esi+140h], bl
.text:00407EE2 mov ebp, esp
.text:00407EE4 mov ebx, [esi+134h] ; 取_KTREAD結構中的Trap_Frane,並儲存在下面的地址處備後面恢復時用
.text:00407EEA mov [ebp+3Ch], ebx
.text:00407EED mov [esi+134h], ebp ; 將新構建的_KTRAP_FRAME指標賦給Trap_frane欄位
.text:00407EF3 cld
.text:00407EF4 mov ebx, [ebp+60h] ; 3環的EBP
.text:00407EF7 mov edi, [ebp+68h] ; 3環的EIP
.text:00407EFA mov [ebp+0Ch], edx ; edx中儲存3環引數的指標
.text:00407EFA ; _KiIntSystemCall@0 proc near
.text:00407EFA ; lea edx,[esp+arg_4] ;User函式傳遞引數,eax中儲存系統呼叫號
.text:00407EFA ; int 2Eh
.text:00407EFD mov dword ptr [ebp+8], 0BADB0D00h
.text:00407F04 mov [ebp+0], ebx ; 3環的恩必普儲存到_KTHREAD_FRAME的0x000地址處(DbgEbp)
.text:00407F07 mov [ebp+4], edi ; 儲存3環的EIP
.text:00407F0A test byte ptr [esi+2Ch], 0FFh ; 判斷_KTHREAD 0x2c處 DebugeActive是否為-1
.text:00407F0E jnz Dr_kss_a ; 如果處於除錯狀態則跳轉
.text:00407F14
.text:00407F14 loc_407F14: ; CODE XREF: Dr_kss_a+10↑j
.text:00407F14 ; Dr_kss_a+7C↑j
.text:00407F14 sti ; 關中斷
.text:00407F15 jmp loc_408000
.text:00407F15 _KiSystemService endp
.text:00407F15
.text:00407F15 ; ---------------------------------------------------------------------------
.text:00407F1A db 5 dup(90h)
.text:00407F1F
.text:00407F1F ; =============== S U B R O U T I N E =======================================
.text:00407F1F
.text:00407F1F
.text:00407F1F _KiFastCallEntry2 proc near ; DATA XREF: _KiTrap01:loc_408CBB↓o
.text:00407F1F mov ecx, 30h
.text:00407F24 mov fs, ecx
.text:00407F26 mov ecx, 23h
.text:00407F2B mov ds, ecx
.text:00407F2D mov es, ecx
.text:00407F2F mov ecx, ds:0FFDFF040h
.text:00407F35 mov esp, [ecx+4]
.text:00407F38 push 23h
.text:00407F3A push edx
.text:00407F3B pushf
.text:00407F3C or byte ptr [esp+1], 1
.text:00407F41 jmp short loc_407F89
.text:00407F41 _KiFastCallEntry2 endp
.text:00407F41
.text:00407F43 ; ---------------------------------------------------------------------------
.text:00407F43 ; START OF FUNCTION CHUNK FOR _KiFastCallEntry
.text:00407F43
.text:00407F43 loc_407F43: ; CODE XREF: .text:00407F66↓j
.text:00407F43 ; _KiFastCallEntry+60↓j
.text:00407F43 mov ecx, ds:0FFDFF040h
.text:00407F49 mov esp, [ecx+4]
.text:00407F4C push 0
.text:00407F4E push 0
.text:00407F50 push 0
.text:00407F52 push 0
.text:00407F54 push 23h
.text:00407F56 push 0
.text:00407F58 push 20202h
.text:00407F5D push 1Bh
.text:00407F5F push 0
.text:00407F61 jmp _KiTrap06
.text:00407F61 ; END OF FUNCTION CHUNK FOR _KiFastCallEntry
.text:00407F66 ; ---------------------------------------------------------------------------
.text:00407F66 jmp short loc_407F43
.text:00407F66 ; ---------------------------------------------------------------------------
.text:00407F68 db 8Bh, 0FFh
.text:00407F6A db 5 dup(90h)
.text:00407F6F
.text:00407F6F ; =============== S U B R O U T I N E =======================================
.text:00407F6F
.text:00407F6F
.text:00407F6F _KiFastCallEntry proc near ; DATA XREF: _KiTrap01+72↓o
.text:00407F6F ; KiLoadFastSyscallMachineSpecificRegisters(x)+24↓o
.text:00407F6F
.text:00407F6F var_B = byte ptr -0Bh
.text:00407F6F
.text:00407F6F ; FUNCTION CHUNK AT .text:00407F43 SIZE 00000023 BYTES
.text:00407F6F ; FUNCTION CHUNK AT .text:00408210 SIZE 00000014 BYTES
.text:00407F6F
.text:00407F6F mov ecx, 23h ; KGDT_R3_DATA|RPL_MASK
.text:00407F74 push 30h ; KGDT_RO_PCR
.text:00407F76 pop fs ; 使FS指向KPCR(在WINDOWS核心地址為:0xffdff000)
.text:00407F78 mov ds, ecx ; 將暫存器DS和ES設定成 KGDT_R3_DATA | RPL_MASK
.text:00407F7A mov es, ecx
.text:00407F7C mov ecx, ds:0FFDFF040h ; mov ecx, PCR[KPCR_TSS] 從KPCR獲取TSS段的起點
.text:00407F82 mov esp, [ecx+4] ; mov esp,[ecx+KTSS_ESP0] //從TSS獲取系統空間堆疊指標
.text:00407F85 push 23h ; 使用者空間SS:ESP入棧
.text:00407F85 ; push KGDT_R3_DATA + RPL_MASK
.text:00407F85 ; push edx /*Ring 3 SS:ESP*/
.text:00407F87 push edx
.text:00407F88 pushf ; /* Ring 3 EFLAGS */
.text:00407F89
.text:00407F89 loc_407F89: ; CODE XREF: _KiFastCallEntry2+22↑j
.text:00407F89 push 2 ; push 2 /* Ring 0 EFLAGS */
.text:00407F8B add edx, 8 ; /* Skip 略過user parameter list */
.text:00407F8E popf ; /* EFLAGS暫存器的值改為2 */
.text:00407F8F or [esp+0Ch+var_B], 2 ; 在EFLAGS中重新啟用IRQs,以偽造INT
.text:00407F94 push 1Bh ; push 1Bh就是push cs。壓入cs
.text:00407F96 push dword ptr ds:0FFDF0304h ; 壓入返回地址,退出時 pop edx
.text:00407F96 ; ds:0FFDF0300對應KiInitSystemCall或KiFastSystemCall
.text:00407F96 ; ds:0FFDF0304對應KiFastSystemCallRet
.text:00407F96 ; 就是 PUSH EIP
.text:00407F9C push 0 ; 設定系統呼叫框架堆疊
.text:00407F9E push ebp
.text:00407F9F push ebx
.text:00407FA0 push esi
.text:00407FA1 push edi
.text:00407FA2 mov ebx, ds:0FFDFF01Ch ; 設定當前KPCRB地址
.text:00407FA8 push 3Bh ; push GDT_R3_TEB + RPL_MASK
.text:00407FAA mov esi, [ebx+124h] ; 在PCR中拿到當前執行緒指標_KTHREAD
.text:00407FB0 push dword ptr [ebx] ; 異常處理鏈入棧
.text:00407FB2 mov dword ptr [ebx], 0FFFFFFFFh
.text:00407FB8 mov ebp, [esi+18h] ; /* 使用當前執行緒堆疊 */
.text:00407FB8 ; mov ebp,[esi + KTHREAD_INITIAL_STACK]
.text:00407FB8 ; 當前ebp指向0環棧頂
.text:00407FBB push 1 ; 儲存前一個進入模式,因為在0環不需要使用快速系統呼叫,所以不需要判斷進入模式,直接設定
.text:00407FBD sub esp, 48h ; 跳過其他暫存器
.text:00407FC0 sub ebp, 29Ch ; 在堆疊上為我們騰出空間
.text:00407FC6 mov byte ptr [esi+140h], 1 ; 設定當前進入模式
.text:00407FCD cmp ebp, esp ; 合理性檢查,防止棧溢位
.text:00407FCF jnz loc_407F43
.text:00407FD5 and dword ptr [ebp+2Ch], 0 ; /* Flush DR7 */
.text:00407FD5 ; and dword ptr[cbp+KTRAP_FRAMEJDR7],0
.text:00407FD9 test byte ptr [esi+2Ch], 0FFh ; 檢查執行緒是否正在被除錯
.text:00407FD9 ; test byte ptr [esi+KTHREAD_DEBUG_ACTIUE],OxFF
.text:00407FDD mov [esi+134h], ebp ; 設定執行緒的自陷框架
.text:00407FDD ; mov [esi + KTHREAD_TRAP_FRAHE],ebp
.text:00407FE3 jnz Dr_FastCallDrSave
.text:00407FE9
.text:00407FE9 loc_407FE9: ; CODE XREF: Dr_FastCallDrSave+10↑j
.text:00407FE9 ; Dr_FastCallDrSave+7C↑j
.text:00407FE9 mov ebx, [ebp+60h] ; dbg除錯
.text:00407FE9 ; set the trap frane debug header除錯報頭
.text:00407FE9 ; Dr_&EndLabcl:
.text:00407FE9 ; SET_TF_DEBUG_HEADER /*Enable interrupts*/
.text:00407FEC mov edi, [ebp+68h]
.text:00407FEF mov [ebp+0Ch], edx
.text:00407FF2 mov dword ptr [ebp+8], 0BADB0D00h
.text:00407FF9 mov [ebp+0], ebx
.text:00407FFC mov [ebp+4], edi
.text:00407FFF sti
.text:00408000
.text:00408000 loc_408000: ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:00408000 ; _KiSystemService+6F↑j
.text:00408000 mov edi, eax ; 取出系統呼叫號
.text:00408002 shr edi, 8 ; 右移兩位
.text:00408005 and edi, 30h ; 檢測0x000的x位是否為1.如果為1表示大於0x1009,是新擴充套件的呼叫號,需要安裝win32k.sys模組
.text:00408008 mov ecx, edi ; ECX值為0x00或0x10(呼叫號大於0x1000)
.text:0040800A add edi, [esi+0E0h] ; _KTREAD->ServiceTable(0xe0)為SSDT表,如果+0x10即為擴充套件的SSDT表
.text:00408010 mov ebx, eax
.text:00408012 and eax, 0FFFh ; 系統呼叫號只需要後12位是函式地址表和函式參數列的索引
.text:00408017 cmp eax, [edi+8] ; 檢查系統呼叫號是否越界SERUICE_DESCRIPTOR_LIMIT定義為8
.text:00408017 ; 系統呼叫表描述符大小為0×10
.text:00408017 ; typedef struct _KSERUICE_TABLE_DESCRIPTOR {
.text:00408017 ; PULONG_PTRBase; //設定成指向MainSSDT--基本的系統呼叫函式表
.text:00408017 ; PLILONG Count; //SSDT中服務被呼叫次數計數器,8位元組大小
.text:00408017 ; ULONGLimit; //SSDT表中服務函式的總數,設定成常數NUMBER_OF_SYSCALLS(8)
.text:00408017 ; #ifdefined(_IA64)
.text:00408017 ; LONG TableBaseGpoffset;
.text:00408017 ; #endif
.text:00408017 ; PUCHAR Number //指向另一個陣列MainSSPT[](說明系統呼叫引數的個數,以位元組為單位)
.text:00408017 ; ) KSERUICE_TABLE_DESCRIPTOR , *PKSERUICE_TABLE_DESCRIPTOR;
.text:0040801A jnb _KiBBTUnexpectedRange ; 系統呼叫號越界,有可能是因為大於0x1000,裝入Win32.sys模組(擴充套件系統呼叫表)
.text:00408020 cmp ecx, 10h ; 如果ecx值為0x10則為擴充套件的SSDT表
.text:00408023 jnz short loc_40803F ; 沒有越界,不死擴充套件系統呼叫
.text:00408025 mov ecx, ds:0FFDFF018h
.text:0040802B xor ebx, ebx
.text:0040802D
.text:0040802D loc_40802D: ; DATA XREF: _KiTrap0E+113↓o
.text:0040802D or ebx, [ecx+0F70h]
.text:00408033 jz short loc_40803F
.text:00408035 push edx
.text:00408036 push eax
.text:00408037 call ds:_KeGdiFlushUserBatch
.text:0040803D pop eax
.text:0040803E pop edx
.text:0040803F
.text:0040803F loc_40803F: ; CODE XREF: _KiFastCallEntry+B4↑j
.text:0040803F ; _KiFastCallEntry+C4↑j
.text:0040803F inc dword ptr ds:0FFDFF638h
.text:00408045 mov esi, edx
.text:00408047 mov ebx, [edi+0Ch]
.text:0040804A xor ecx, ecx
.text:0040804C mov cl, [eax+ebx]
.text:0040804F mov edi, [edi]
.text:00408051 mov ebx, [edi+eax*4]
.text:00408054 sub esp, ecx
.text:00408056 shr ecx, 2
.text:00408059 mov edi, esp
.text:0040805B cmp esi, ds:_MmUserProbeAddress
.text:00408061 jnb loc_408210
.text:00408067
.text:00408067 loc_408067: ; CODE XREF: _KiFastCallEntry+2A5↓j
.text:00408067 ; DATA XREF: _KiTrap0E+109↓o
.text:00408067 rep movsd ;複製引數
.text:00408069 call ebx ;執行核心函式
.text:0040806B
.text:0040806B loc_40806B: ; CODE XREF: _KiFastCallEntry+2B0↓j
.text:0040806B ; DATA XREF: _KiTrap0E+129↓o ...
.text:0040806B mov esp, ebp
.text:0040806D
.text:0040806D loc_40806D: ; CODE XREF: _KiBBTUnexpectedRange+38↑j
.text:0040806D ; _KiBBTUnexpectedRange+43↑j
.text:0040806D mov ecx, ds:0FFDFF124h
.text:00408073 mov edx, [ebp+3Ch]
.text:00408076 mov [ecx+134h], edx
.text:00408076 _KiFastCallEntry endp
.text:00408076
.text:0040807C
.text:0040807C ; =============== S U B R O U T I N E =======================================
.text:0040807C
.text:0040807C
.text:0040807C _KiServiceExit proc near ; CODE XREF: _KiSetLowWaitHighThread+7D↓j
.text:0040807C ; NtContinue(x,x)+42↓j ...
.text:0040807C
.text:0040807C arg_C = dword ptr 10h
.text:0040807C arg_10 = dword ptr 14h
.text:0040807C arg_40 = dword ptr 44h
.text:0040807C arg_44 = dword ptr 48h
.text:0040807C arg_48 = dword ptr 4Ch
.text:0040807C arg_60 = dword ptr 64h
.text:0040807C arg_64 = dword ptr 68h
.text:0040807C arg_68 = dword ptr 6Ch
.text:0040807C arg_6C = dword ptr 70h
.text:0040807C
.text:0040807C ; FUNCTION CHUNK AT .text:00408188 SIZE 00000088 BYTES
.text:0040807C
.text:0040807C cli
.text:0040807D test dword ptr [ebp+70h], 20000h
.text:00408084 jnz short loc_40808C
.text:00408086 test byte ptr [ebp+6Ch], 1
.text:0040808A jz short loc_4080E4
.text:0040808C
.text:0040808C loc_40808C: ; CODE XREF: _KiServiceExit+8↑j
.text:0040808C ; _KiServiceExit+63↓j
.text:0040808C mov ebx, ds:0FFDFF124h
.text:00408092 mov byte ptr [ebx+2Eh], 0
.text:00408096 cmp byte ptr [ebx+4Ah], 0
.text:0040809A jz short loc_4080E4
.text:0040809C mov ebx, ebp
.text:0040809E mov [ebx+44h], eax
.text:004080A1 mov dword ptr [ebx+50h], 3Bh
.text:004080A8 mov dword ptr [ebx+38h], 23h
.text:004080AF mov dword ptr [ebx+34h], 23h
.text:004080B6 mov dword ptr [ebx+30h], 0
.text:004080BD mov ecx, 1 ; NewIrql
.text:004080C2 call ds:__imp_@KfRaiseIrql@4 ; KfRaiseIrql(x)
.text:004080C8 push eax
.text:004080C9 sti
.text:004080CA push ebx
.text:004080CB push 0
.text:004080CD push 1
.text:004080CF call _KiDeliverApc@12 ; KiDeliverApc(x,x,x)
.text:004080D4 pop ecx ; NewIrql
.text:004080D5 call ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
.text:004080DB mov eax, [ebx+44h]
.text:004080DE cli
.text:004080DF jmp short loc_40808C
.text:004080DF ; ---------------------------------------------------------------------------
.text:004080E1 align 4
.text:004080E4
.text:004080E4 loc_4080E4: ; CODE XREF: _KiServiceExit+E↑j
.text:004080E4 ; _KiServiceExit+1E↑j
.text:004080E4 mov edx, [esp+arg_48]
.text:004080E8 mov ebx, large fs:50h
.text:004080EF mov large fs:0, edx
.text:004080F6 mov ecx, [esp+arg_44]
.text:004080FA mov esi, large fs:124h
.text:00408101 mov [esi+140h], cl
.text:00408107 test ebx, 0FFh
.text:0040810D jnz short loc_408188
.text:0040810F
.text:0040810F loc_40810F: ; CODE XREF: _KiServiceExit+11C↓j
.text:0040810F ; _KiServiceExit+14B↓j
.text:0040810F test [esp+arg_6C], 20000h
.text:00408117 jnz loc_408A28
.text:0040811D test word ptr [esp+arg_68], 0FFF8h
.text:00408124 jz loc_4081DE
.text:0040812A cmp word ptr [esp+arg_68], 1Bh
.text:00408130 bt word ptr [esp+arg_68], 0
.text:00408137 cmc
.text:00408138 ja loc_4081CC
.text:0040813E cmp word ptr [ebp+6Ch], 8
.text:00408143 jz short loc_40814A
.text:00408145
.text:00408145 loc_408145: ; CODE XREF: _KiServiceExit+15D↓j
.text:00408145 lea esp, [ebp+50h]
.text:00408148 pop fs
.text:0040814A assume fs:nothing
.text:0040814A
.text:0040814A loc_40814A: ; CODE XREF: _KiServiceExit+C7↑j
.text:0040814A lea esp, [ebp+54h]
.text:0040814D pop edi
.text:0040814E pop esi
.text:0040814F pop ebx
.text:00408150 pop ebp
.text:00408151 cmp word ptr [esp-60h+arg_64], 80h
.text:00408158 ja loc_408A44
.text:0040815E add esp, 4
.text:00408161 test [esp-64h+arg_64], 1
.text:00408161 _KiServiceExit endp ; sp-analysis failed
快速系統呼叫
系統呼叫與快速系統呼叫僅入口方式與使用者態資訊獲取儲存有些許不同
入口方式不同 xp _KiFastSystemCall 反編譯ASM
C:\Windows\System32\ntdll.dll
.text:77F070B0
.text:77F070B0 ; _DWORD __stdcall KiFastSystemCall()
.text:77F070B0 public _KiFastSystemCall@0
.text:77F070B0 _KiFastSystemCall@0 proc near ; DATA XREF: .text:off_77EF61B8↑o
.text:77F070B0 mov edx, esp ;將堆疊指標儲存在暫存器EDX中
.text:77F070B2 sysenter ;進入核心
.text:77F070B2 _KiFastSystemCall@0 endp
.text:77F070B2
.text:77F070B4 ; Exported entry 107. KiFastSystemCallRet
.text:77F070B4
.text:77F070B4 ; =============== S U B R O U T I N E =======================================
.text:77F070B4
.text:77F070B4
.text:77F070B4 ; _DWORD __stdcall KiFastSystemCallRet()
.text:77F070B4 public _KiFastSystemCallRet@0
.text:77F070B4 _KiFastSystemCallRet@0 proc near ; DATA XREF: .text:off_77EF61B8↑o
.text:77F070B4 retn
.text:77F070B4 _KiFastSystemCallRet@0 endp
.text:77F070B4
.text:77F070B4 ; ---------------------------------------------------------------------------
-
系統呼叫:透過
INT 2EH
指令進入0環執行呼叫。進入0環時3環資訊(SS/ESP/EFLAGS/CS/EIP)儲存在棧空間,進行傳遞 -
快速系統呼叫:透過
sysenter
指令進入0環執行呼叫。進入0環所需的CS/ESP/EIP都已在系統初始化時預定義,SS = CS + 8
-
IA32_SYSENTER_CS (MSR 0x174)
:儲存核心程式碼段選擇子(CS)的值。IA32_SYSENTER_ESP (MSR 0x175)
:儲存在進入核心模式時要載入到ESP
的核心堆疊指標。IA32_SYSENTER_EIP (MSR 0x176)
:儲存sysenter
指令進入核心模式後跳轉的程式碼地址,既_KiFastCallEntry
。
-
winDbg如下:
kd> rdmsr 174
msr[174] = 00000000`00000008
kd> rdmsr 175
msr[175] = 00000000`80790000
kd> rdmsr 176
msr[176] = 00000000`83e800c0
使用者空間資訊儲存不同 xp _KiFastCallEntry 原始碼asm
\NT\base\ntos\ke\i386\trap.asm
_KiFastCallEntry proc
;
; 返回到緊接著 sysenter 指令之後的指令,該指令位於共享使用者資料結構中的已知位置
; (這是為了在系統初始化時根據處理器動態放置正確的程式碼)。
;
; 從 Tss.Esp0 載入 ESP。中斷已被禁用,ESP 尚未載入。
ifndef NT_UP
mov ecx, KGDT_R0_PCR ; 載入全域性描述符表(GDT)中的PCR
mov fs, ecx ; 將 fs 暫存器設定為 PCR
mov ecx, PCR[PcTss] ; 從 PCR 中獲取 TSS 的地址
else
mov ecx, ss:PCR[PcTss] ; 在單處理器系統上,從 ss 段暫存器獲取 TSS
endif ;; NT_UP
mov esp, ss:[ecx].TssEsp0 ; 將 ESP 設定為 TSS 的 Esp0
;
; 將 ecx 設定為使用者模式下的返回地址
;
mov ecx, MM_SHARED_USER_DATA_VA+UsSystemCall+fscrOffset ; 獲取使用者模式下系統呼叫返回地址
Kfsc10:
cmp esp, PCR[PcInitialStack] ; 檢查是否從 VDM 呼叫
je Kfsc90 ; 如果從 VDM 呼叫,則跳轉到 Kfsc90
push KGDT_R3_DATA OR RPL_MASK ; 壓入使用者堆疊段 SS
push edx ; 壓入 ESP
add edx, 8 ; edx 指向系統呼叫的引數
push EFLAGS_INTERRUPT_MASK+2 ; 壓入已清理的 EFLAGS
push 2 ; 清理後的核心 EFLAGS
popfd ; 從棧中彈出並載入到 EFLAGS
push KGDT_R3_CODE OR RPL_MASK ; 壓入使用者程式碼段 CS
push ecx ; 壓入返回地址
ifndef NT_UP
; 在多處理器(MP)系統中,FS 已經在上面載入
ENTER_SYSCALL kfce_a, kfce_t, NoFSLoad ; 進入系統呼叫處理
jmp _KiSystemServiceRepeat ; 跳轉到系統服務處理邏輯
endif ;; NT_UP
_KiFastCallEntry endp
- 系統呼叫R3跳轉到R0時,R3資訊(ss/esp/eflags/cs/eip)由int指令隱式執行儲存到堆疊中並複製到R0堆疊
- 快速系統呼叫R3跳轉R0時,R3資訊在
_KiFastCallEntry
顯示的儲存到了R0的堆疊中