Windows系統(tǒng)調(diào)用學(xué)習(xí)筆記(三)—— 保存現(xiàn)場
- 要點回顧
- 基本概念
- Trap Frame 結(jié)構(gòu)
- 線程相關(guān)的結(jié)構(gòu)體
- CPU相關(guān)的結(jié)構(gòu)體
- 實驗一:分析 KiSystemService
- 實驗二:分析 KiFastCallEntry
要點回顧
API進入0環(huán)后調(diào)用的函數(shù):
中斷門 – KiSystemService快速調(diào)用 – KiFastCallEntry
上一篇留了幾個練習(xí):
進0環(huán)后,原來的寄存器存在哪里?如何根據(jù)系統(tǒng)服務(wù)號(eax中存儲)找到要執(zhí)行的內(nèi)核函數(shù)?調(diào)用時參數(shù)是存儲到3環(huán)的堆棧,如何傳遞給內(nèi)核函數(shù)?2種調(diào)用方式是如何返回到3環(huán)的?
本篇將對第一個練習(xí)進行說明
基本概念
Trap Frame 結(jié)構(gòu)
描述:
無論是通過中斷門進入0環(huán),還是通過快速調(diào)用進入0環(huán),進入0環(huán)前(3環(huán))的所有寄存器都會存到這個結(jié)構(gòu)體中這個結(jié)構(gòu)體本身處于0環(huán),由windows操作系統(tǒng)進行維護當(dāng)程序通過中斷門從3環(huán)進入0環(huán)時,ESP指向TrapFrame+0x64的位置當(dāng)程序通過快速調(diào)用從3環(huán)進入0環(huán)時,ESP指向TrapFrame+0x78的位置
結(jié)構(gòu)體:
在WinDbg中查看:
kd> dt _Ktrap_frame
注意:
5. 在保護模式下,最后四個成員(0x7C~0x88)并沒有被使用,因此無需考慮;只有在虛擬8086模式下,才會用到
6. 當(dāng)中斷門執(zhí)行時,3環(huán)的SS、ESP、EFLAGS、CS、EIP會被存儲到結(jié)構(gòu)體的0x68~0x78中,而執(zhí)行快速調(diào)用時不會
線程相關(guān)的結(jié)構(gòu)體
ETHREAD
結(jié)構(gòu)體:
KTHREAD
結(jié)構(gòu)體:
kd> dt _KTHREAD
CPU相關(guān)的結(jié)構(gòu)體
KPCR
描述:
全稱為CPU控制區(qū)(Processor Control Region)每一個CPU都有一個CPU控制區(qū),一核一個KPCR
結(jié)構(gòu)體:
查看CPU數(shù)量:
kd>dd KeNumBerProcessors
查看KPCR:
kd>dd KiProcessorBlock L2
ffdff120 00000000
若第二個成員有值,說明當(dāng)前CPU有兩個核
_NT_TIB
描述:
_NT_TIB是KPCR結(jié)構(gòu)體的成員之一
結(jié)構(gòu)體:
KPRCB
描述:
KPRCB是KPCR結(jié)構(gòu)體的成員之一
結(jié)構(gòu)體:
kd> dt _KPRCB
實驗一:分析 KiSystemService
注意:當(dāng)進入KiSystemService時,3環(huán)的SS、ESP、EFLAGS、CS、EIP就已經(jīng)被存儲到 Trap Frame 結(jié)構(gòu)體中
IDA反匯編:
.text:004067D1 push 0 ; nt!_KTRAP_FRAME; +0x064 ErrCode : Uint4B; 中斷門產(chǎn)生權(quán)限切換時一般往堆棧中壓入5個值,但有些情況會壓入6個值,第六個值為Error Code; 具體細節(jié)可以參考Intel白皮書第三卷,章節(jié)名:Input and Exception Handling; 其中有一小節(jié)叫做 Error Code;; 當(dāng)通過 INT 2E 進入0環(huán)時,并沒有壓入Error Code; 操作系統(tǒng)為了對齊,自己補了個0
.text:004067D3 push ebp ; nt!_KTRAP_FRAME; +0x060 Ebp : Uint4B
.text:004067D4 push ebx ; +0x05c Ebx : Uint4B
.text:004067D5 push esi ; +0x058 Esi : Uint4B
.text:004067D6 push edi ; +0x054 Edi : Uint4B
.text:004067D7 push fs ; +0x050 SegFs : Uint4B
.text:004067D9 mov ebx, 30h ; 為FS寄存器賦值,指向KPCR結(jié)構(gòu)體
.text:004067DE mov fs, ebx ; 加載下標(biāo)為6的段描述符到fs
在WinDbg中查看GDT表中下標(biāo)為6的段描述符:
段描述符:ffc093df`f0000001
fs.Base:0xffdff000(KPCR)
.text:004067E0 push large dword ptr fs:0 ; 保存老的ExceptionList(異常列表); nt!_KPCR; +0x000 NtTib : _NT_TIB; nt!_NT_TIB; +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD;; nt!_KTRAP_FRAME; +0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
.text:004067E7 mov large dword ptr fs:0, 0FFFFFFFFh ; 新的ExceptionList為空白
.text:004067F2 mov esi, large fs:124h ; 得到當(dāng)前正在執(zhí)行的線程信息; nt!_KPCR; +0x120 +0x4 CurrentThread : Ptr32 _KTHREAD; 存儲了當(dāng)前正在跑的線程的信息,為 KTHREAD 結(jié)構(gòu)體
在WinDbg中查看 KPCR + 0x120 + 0x4:
.text:004067F9 push dword ptr [esi+140h] ; 保存老的"先前模式"到堆棧; nt!_KTHREAD; +0x140 PreviousMode : Char
.text:004067FF sub esp, 48h ; 執(zhí)行前,ESP位于_KTRAP_FRAME + 0x48 = PreviousPreviousMode; 執(zhí)行后,ESP 等于 _KTRAP_FRAME 結(jié)構(gòu)指針
.text:00406802 mov ebx, [esp+68h+arg_0] ; arg_0 = 4; 取出三環(huán)壓入的參數(shù)CS(_KTRAP_FRAME + 0x6C)
.text:00406806 and ebx, 1 ; 權(quán)限檢查:0環(huán)最低位為0,3環(huán)最低位為1
.text:00406809 mov [esi+140h], bl ; 新的"先前模式"; 將權(quán)限檢查的結(jié)果存儲到 PreviousMode 中; 目的是檢測調(diào)用該代碼前,程序處于幾環(huán)
.text:0040680F mov ebp, esp ; ebp = esp = _KTRAP_FRAME 結(jié)構(gòu)指針
.text:00406811 mov ebx, [esi+134h] ; _KTHREAD 的成員 TrapFrame
.text:00406817 mov [ebp+3Ch], ebx ; 將 _KTHREAD 中的 TrapFrame 暫時存放在這個位置; 之后會將這個值重新取出來,賦值給 _KTHREAD 的 TrapFrame
.text:0040681A mov [esi+134h], ebp ; 將堆棧中形成的 _KTRAP_FRAME 結(jié)構(gòu)指針賦值給 _KTHREAD 的 TrapFrame
.text:00406820 cld
.text:00406821 mov ebx, [ebp+60h] ; 將原來3環(huán)的ebp賦值給ebx
.text:00406824 mov edi, [ebp+68h] ; 將原來3環(huán)的eip賦值給edi
.text:00406827 mov [ebp+0Ch], edx ; edx存儲的是3環(huán)參數(shù)的指針:;; _KiFasSystemCall函數(shù):; mov edx, esp; sysenter;
.text:0040682A mov dword ptr [ebp+8], 0BADB0D00h ; 給操作系統(tǒng)用的標(biāo)志
.text:00406831 mov [ebp+0], ebx ; 原來3環(huán)的ebp存儲到 _KTRAP_FRAME; + 0x000 DbgEbp 的位置
.text:00406834 mov [ebp+4], edi ; 原來3環(huán)的eip存儲到 _KTRAP_FRAME; + 0x004 DbgEbp 的位置
.text:00406837 test byte ptr [esi+2Ch], 0FFh ; 判斷 _KTHREAD + 0x02c DebugActive 是否為 -1; 若為 -1, 即當(dāng)前線程 未 處于調(diào)試狀態(tài)
.text:0040683B jnz Dr_kss_a ; 若處于調(diào)試狀態(tài),則跳轉(zhuǎn); 功能是對TrapFrame的Dr0~Dr7進行賦值; 也就是TrapFrame+0x18 ~ TrapFrame+0x2c的位置進行賦值; 若未處于調(diào)試狀態(tài),則繼續(xù)向下執(zhí)行(loc_406841)
在WinDbg中查看KTHREAD + 0x02c:
.text:00406841 sti ; 關(guān)閉中斷
.text:00406842 jmp loc_406932 ; KiSystemService 與 KiFastCallEntry 函數(shù)的共同代碼片段; 下篇學(xué)習(xí)系統(tǒng)服務(wù)表時再進行分析
實驗二:分析 KiFastCallEntry
IDA反匯編:
.text:0040689F mov ecx, 23h ; ECX = 0x23
.text:004068A4 push 30h ; 通過堆棧的入棧和出棧加載fs
.text:004068A6 pop fs ; 加載fs段寄存器:GDT表下標(biāo)為6的段描述符
在WinDbg中查看GDT表下標(biāo)為6的段描述符:
段描述符:ffc093df`f0000001
fs.Base:0xffdff000(KPCR)
.text:004068A8 mov ds, ecx ; RPL=3;TI=0;INDEX=4; 加載GDT表下標(biāo)為4的段描述符給ds
.text:004068AA mov es, ecx ; 加載GDT表下標(biāo)為4的段描述符給es
在WinDbg中查看GDT表下標(biāo)為4的段描述符:
.text:004068AC mov ecx, large fs:40h ; ECX = TSS指針; nt!_KPCR; +0x040 TSS : Ptr32 _KTSS
.text:004068B3 mov esp, [ecx+4] ; nt!_KTSS; +0x004 Esp0 : Uint4B
.text:004068B6 push 23h ; nt!_KTRAP_FRAME; +0x078 HardwareSegSs : Uint4B
.text:004068B8 push edx ; edx保存的是3環(huán)參數(shù)的指針; nt!_KTRAP_FRAME; +0x074 HardwareEsp : Uint4B
.text:004068B9 pushf ; 舊的標(biāo)志寄存器入棧
.text:004068BA
.text:004068BA loc_4068BA: ; CODE XREF: _KiFastCallEntry2+23↑j
.text:004068BA push 2 ; 新的標(biāo)志寄存器的值入棧
.text:004068BC add edx, 8
.text:004068BF popf ; 新的標(biāo)志寄存器的值出棧
; EFlags = 2,即第二位置1,其它位清零
.text:004068C0 or [esp+0Ch+var_B], 2
.text:004068C5 push 1Bh ; nt!_KTRAP_FRAME; +0x06c SegCs : Uint4B
.text:004068C7 push dword ptr ds:0FFDF0304h ; +0x068 Eip : Uint4B
.text:004068CD push 0 ; +0x064 ErrCode : Uint4B
.text:004068CF push ebp ; +0x060 Ebp : Uint4B
.text:004068D0 push ebx ; +0x05c Ebx : Uint4B
.text:004068D1 push esi ; +0x058 Esi : Uint4B
.text:004068D2 push edi ; +0x054 Edi : Uint4B
.text:004068D3 mov ebx, large fs:1Ch ; nt!_KPCR; +0x01c SelfPcr : Ptr32 _KPCR; 指向當(dāng)前 KPCR 結(jié)構(gòu)體本身,目的是方便查找
.text:004068DA push 3Bh ; nt!_KTRAP_FRAME; +0x050 SegFs : Uint4B
.text:004068DC mov esi, [ebx+124h] ; nt!_KPCR; +0x120 +0x4 CurrentThread : Ptr32 _KTHREAD; 存儲了當(dāng)前正在跑的線程的信息,為 KTHREAD 結(jié)構(gòu)體
.text:004068E2 push dword ptr [ebx] ; ebx 保存的是KPCR結(jié)構(gòu)體的地址; KPCR 第一個成員為結(jié)構(gòu)體 NT_TIB 的指針; NT_TIB 的第一個值為 ExceptionList(異常列表); 這句話的目的是將異常列表保存到TrapFrame結(jié)構(gòu)體中; nt!_KPCR; +0x000 NtTib : _NT_TIB; nt!_NT_TIB; +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD;; nt!_KTRAP_FRAME; +0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
.text:004068E4 mov dword ptr [ebx], 0FFFFFFFFh ; 將 ExceptionList(異常列表)置為 -1
.text:004068EA mov ebp, [esi+18h] ; nt!_KTHREAD; +0x018 InitialStack : Ptr32 Void
.text:004068ED push 1 ; nt!_KTRAP_FRAME; +0x048 PreviousPreviousMode : Uint4B; 往棧中壓入老的先前模式,1表示先前模式為3環(huán)
.text:004068EF sub esp, 48h ; 執(zhí)行前,ESP位于_KTRAP_FRAME + 0x48 = PreviousPreviousMode; 執(zhí)行后,ESP 等于 _KTRAP_FRAME 結(jié)構(gòu)指針
.text:004068F2 sub ebp, 29Ch
.text:004068F8 mov byte ptr [esi+140h], 1 ; 新的先前模式; nt!_KTHREAD; +0x140 PreviousMode : Char
.text:004068FF cmp ebp, esp ; 檢查 ebp 是否等于 esp,也就是 _KTRAP_FRAME 結(jié)構(gòu)指針
.text:00406901 jnz loc_40686C ; 若不等于,則跳轉(zhuǎn),進行異常處理
.text:00406907 and dword ptr [ebp+2Ch], 0 ; 修改 TrapFrame 結(jié)構(gòu)體中 Dr7 的值; nt!_KTRAP_FRAME; +0x02c Dr7 : Uint4B
.text:0040690B test byte ptr [esi+2Ch], 0FFh ; 檢測當(dāng)前進程是否處于調(diào)試狀態(tài); nt!_KTHREAD; +0x02c DebugActive : UChar; 若不處于調(diào)試狀態(tài),則 DebugActive 的值為FF
.text:0040690F mov [esi+134h], ebp ; 將 TrapFrame 結(jié)構(gòu)指針寫入當(dāng)前線程信息中; nt!_KTHREAD; +0x134 TrapFrame : Ptr32 _KTRAP_FRAME
.text:00406915 jnz Dr_FastCallDrSave ; 若當(dāng)前進程處于被調(diào)試狀態(tài),則跳轉(zhuǎn),為 Dr0 ~ Dr7 進行賦值; 若當(dāng)前進程不處于被調(diào)試狀態(tài),則繼續(xù)向下執(zhí)行
.text:0040691B
.text:0040691B loc_40691B: ; CODE XREF: Dr_FastCallDrSave+10↑j
.text:0040691B ; Dr_FastCallDrSave+7C↑j
.text:0040691B mov ebx, [ebp+60h] ; 從 TrapFrame 結(jié)構(gòu)體中取出 Ebp 到 ebx 寄存器
.text:0040691E mov edi, [ebp+68h] ; 從 TrapFrame 結(jié)構(gòu)體中取出 Eip 到 edi 寄存器
.text:00406921 mov [ebp+0Ch], edx ; nt!_KTRAP_FRAME; +0x000 DbgEbp : Uint4B
.text:00406924 mov dword ptr [ebp+8], 0BADB0D00h; +0x008 DbgArgMark : Uint4B
.text:0040692B mov [ebp+0], ebx ; +0x000 DbgEbp : Uint4B
.text:0040692E mov [ebp+4], edi ; +0x004 DbgEip : Uint4B
.text:00406931 sti ; 關(guān)閉中斷
.text:00406932
.text:00406932 loc_406932: ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:00406932 ; _KiSystemService+71↑j; KiSystemService 與 KiFastCallEntry 函數(shù)的共同代碼部分; 下篇學(xué)習(xí)系統(tǒng)服務(wù)表時再進行分析
總結(jié)
當(dāng)程序通過中斷門從3環(huán)進入0環(huán)時,ESP指向TrapFrame+0x64的位置當(dāng)程序通過快速調(diào)用從3環(huán)進入0環(huán)時,ESP指向TrapFrame+0x78的位置若通過中斷門進入0環(huán),在KiSystemService函數(shù)開始執(zhí)行時,3環(huán)的SS、ESP、EFLAGS、CS、EIP就已經(jīng)被存儲到 TrapFrame 結(jié)構(gòu)體中了TrapFrame 結(jié)構(gòu)體的其它成員通過 KiSystemService 和 KiFastCallEntry 進行賦值不管是 KiSystemService 還是 KiFastCallEntry,最終都要執(zhí)行一部分相同的代碼,分為兩個函數(shù)是因為進入0環(huán)時,堆棧里的值不一樣,走同一條函數(shù)會出問題
總結(jié)
以上是生活随笔為你收集整理的Windows系统调用学习笔记(三)—— 保存现场的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。