3.API的调用过程(保存现场)
_KTrap_Frame 結構
kd> dt _KTrap_Frame ntdll!_KTRAP_FRAME//調試系統服務+0x000 DbgEbp : Uint4B+0x004 DbgEip : Uint4B+0x008 DbgArgMark : Uint4B+0x00c DbgArgPointer : Uint4B//當需要調整棧時以下作為臨時變量+0x010 TempSegCs : Uint4B+0x014 TempEsp : Uint4B//調試寄存器+0x018 Dr0 : Uint4B+0x01c Dr1 : Uint4B+0x020 Dr2 : Uint4B+0x024 Dr3 : Uint4B+0x028 Dr6 : Uint4B+0x02c Dr7 : Uint4B//段寄存器+0x030 SegGs : Uint4B+0x034 SegEs : Uint4B+0x038 SegDs : Uint4B//易失寄存器+0x03c Edx : Uint4B+0x040 Ecx : Uint4B+0x044 Eax : Uint4B//非易失性寄存器需要在中斷例程中先保存+0x048 PreviousPreviousMode : Uint4B+0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD+0x050 SegFs : Uint4B//非易失寄存器+0x054 Edi : Uint4B+0x058 Esi : Uint4B+0x05c Ebx : Uint4B+0x060 Ebp : Uint4B+0x064 ErrCode : Uint4B//硬件填充 (通過中斷門進入的,這個值為NULL)//中斷發生時保存被中斷的代碼段和地址,iret返回到此地址+0x068 Eip : Uint4B//硬件填充+0x06c SegCs : Uint4B//硬件填充+0x070 EFlags : Uint4B//硬件填充//中斷發生時,若發生權限變換,則要保存舊堆棧+0x074 HardwareEsp : Uint4B//硬件填充,僅當有模式切換時才會使用+0x078 HardwareSegSs : Uint4B//硬件填充,僅當有模式切換時才會使用//這4個在保護模式下沒有使用+0x07c V86Es : Uint4B//硬件填充+0x080 V86Ds : Uint4B//硬件填充+0x084 V86Fs : Uint4B//硬件填充+0x088 V86Gs : Uint4B//硬件填充無論是通過中斷門進入的0環,還是快速調用,3環所有的寄存器都會保存在這個結構體里。
通過快速調用68~78是沒有的
權限發生切換時堆棧也會改變,這里聽不懂的話去學習保護模式
內核層的ESP = TSS+4
Windows操作系統在每個處理器初始化時,會在GDT中為它構造一個TSS段,然后利用ltr指令設置處理器的任務環境段。(參考_KiSystemStartup函數)
另外,Windows每次切換線程時,總是會設置好TSS中Ring0的esp,使指向當前線程的內核棧。(參考SwapContext函數)
保存3環寄存器值到_KTrap_Frame的0x50~0x64
fs :0030 拆分 0000 0000 0011 0 0 00,RPL為0 ,查gdt,第六組
ffc093df`f0000001
ffdff000這個地址剛好指向的就是CUP的KPCR結構,fs在3環指向的是PEB結構,0環就是kpcr。
繼續上面
Exceptionlist是異常鏈表。
把老的Exceptionlist保存到_KTRAP_FRAME的+0x4c位置,然后把它置為空白。
將kpcr+0x124放到esi中,也就是CurrentThread。
將[esi+140]保存先前模式到_KTRAP_FRAME的+048位置,_KTHREAD.PreviousMode 。
提升堆棧0x48
取出3環的CS放到ebx,然后and 上1結果放到esi+0x140,也就是新的先前模式。
先前模式:當你調用這段代碼的時候,如果是0環的程序先前模式就存0,3環就存1。操作系統想知道是哪一環的程序調用我只需要查看調用者的先前模式即可
提升棧底ebp與esp指向同一個位置_KTRAP_FRAME最開始的位置
取出esi+0x134的位置_KTHREAD.TrapFrame (+0x134 當前線程的信息),放到ebp+3c_KTHREAD.Edx 。
_KTRAP_FRAME放到_KTHREAD.TrapFrame
把3環的ebp放到ebx
把3環的eip放到edi
把3環的參數指針放到_KTRAP_FRAME.DbgArgPointer
0x0dadb0d0(操作系統用到的一個標志)放到_KTRAP_FRAME.DbgArgMark
ebp+0 = _KTRAP_FRAME.DbgEbp
ebp+04 = _KTRAP_FRAME.DbgEip
比較_KTHREAD.DebugActive(當前線程是否處于調試狀態如果處于調試狀態這個值就不是0ff),如果你處于調試狀態他就會跳轉到下面的代碼。
就是將dr0~dr7存到_KTRAP_FRAME的+0x18到+0x2c。
如果不處于調試狀態跳轉到以下代碼
無論是從KiFastCallEntry還是kisystenService都會最終都會調用一下的代碼
兩空進來最中執行的代碼是一樣的,中斷進來和快速調用的他們填表(_KTrap_Frame)的方式不一樣但是最終調用的代碼都是一樣的
- kiSystenService:
進入0環后原來3環的寄存器保存在_KTrap_Frame的0x50~0x64
把3環的參數指針放到_KTRAP_FRAME.DbgArgPointer
以上都kiSystenService從0環進入3環的填表過程
KiFastCallEntry的填表過程
KPCR+40就是TSS,TSS+4就是esp0
push 到_KTrap_Frame
+0x078 HardwareSegSs : Uint4B
+0x074 HardwareEsp : Uint4B
+0x070 EFlags : Uint4B
直接貼ida分析代碼了
mov ecx, 23hpush 30hpop fs ; 修改fs寄存器為30mov ds, ecxmov es, ecxmov ecx, ds:0FFDFF040h ; 獲取當前TSSmov esp, [ecx+4] ; TSS中得到ESPpush 23h ; 原ss壓棧push edx ; 原esp壓棧pushf ; EFLAGS壓棧loc_40770A: ; CODE XREF: _KiFastCallEntry2+22jpush 2add edx, 8 ; 當前保存著sysentet進入前的ESP的值; +8 = 參數指針popfor [esp+0Ch+var_B], 2 ; KtrapFrame->Eflags.if = 1push 1Bh ; KtrapFrame->CS=0x1b 保存r3的cspush dword ptr ds:0FFDF0304h ; KtrapFrame->EIP =返回地址push 0 ; KtrapFrame->Error = 0push ebp ; KtrapFrame->ebp = ebppush ebx ; KtrapFrame->ebx = ebxpush esi ; KtrapFrame->esi = esipush edi ; KtrapFrame->edi = edimov ebx, ds:0FFDFF01Chpush 3Bh ; KtrapFrame->SegFs = 0x3b 保存r3的fsmov esi, [ebx+124h] ; 得到當前線程結構push dword ptr [ebx] ; KtrapFrame->0x4c 保存原異常鏈mov dword ptr [ebx], 0FFFFFFFFh ; 設置為空的異常鏈mov ebp, [esi+18h] ; 得到初始堆棧KtrapFrame->0x48push 1 ; KtrapFrame->PreviousPreviousMode = 1sub esp, 48h ; 提升棧頂指針到_Ktrap_Framesub ebp, 29Ch ; Ktrap_Framemov byte ptr [esi+140h], 1 ; 先前模式cmp ebp, espjnz loc_4076C8and dword ptr [ebp+2Ch], 0 ; 清零dr7test byte ptr [esi+2Ch], 0FFh ; 檢查是否處于調試狀態mov [esi+134h], ebp ; ;jnz Dr_FastCallDrSaveloc_40776A: ; CODE XREF: Dr_FastCallDrSave+10j; Dr_FastCallDrSave+7Cjmov ebx, [ebp+60h] ; ebp = KtrapFrame->ebpmov edi, [ebp+68h] ; edi = KtrapFrame->eipmov [ebp+0Ch], edx ; KtrapFrame->DbgArgPointer = 參數指針mov dword ptr [ebp+8], 0BADB0D00hmov [ebp+0], ebx ; KtrapFrame->DbgEbp = ebxmov [ebp+4], edi ; KtrapFrame->DbgEip = edisti總結
以上是生活随笔為你收集整理的3.API的调用过程(保存现场)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2.API的调用过程(3环进0环)
- 下一篇: 4.API的调用过程(系统服务表)