Windows系統調用中的現場保存

 Windows內核分析索引目錄:https://www.cnblogs.com/onetrainee/p/11675224.htmlhtml

Windows系統調用中的現場保存windows

  咱們以前介紹過三環進零環的步驟,經過中斷或者快速調用來實現。函數

  可是咱們是否考慮過CPU從三環進入零環時,其三環的寄存器該如何保存。spa

  這一篇文件就來介紹其系統調用中的(三環)現場保存的問題。操作系統

 

1、幾個重要的結構體介紹線程

1. _Ktrap_frame3d

  

  該結構體簡單來講用於三環的寄存器保存,存儲於零環,由操做系統維護,每一個線程都有本身的 _Ktrap_frame 結構體(ethread+0x108處)。指針

  詳細信息能夠查看這篇文章:解析windows內核每日一講 陷阱調度調試

  咱們以前講過進入0環時獲取新的四個寄存器很是重要, SS\CS\EIP\ESPcode

  以下圖,當進入零環時,操做系統會獲取ESP值,該值指向_Ktrap_frame結構體,將舊的SS\CS\EIP\ESP\EFLAG依次壓入(0x78-0x68處),以後ESP +0x070 ErrCode處。

  以後便進入獲取的EIP來執行內核函數。

  

 2. _ETHREAD 結構體

  該結構體保存了和線程相關的信息,位於0環(其並不是三環的 TEB,線程環境塊)

  在_ETHREAD結構體第一個成員是 _KTHRAD,能夠看出其大小0x200,裏面保存了線程中的一些信息  

  kd > dt _ethread
            ntdll!_ETHREAD
            + 0x000 Tcb              : _KTHREAD
            + 0x200 CreateTime : _LARGE_INTEGER
          ····

        kd > dt _kthread
            ntdll!_KTHREAD
            + 0x000 Header           : _DISPATCHER_HEADER
            ···
    +0x128 TrapFrame        : Ptr32 _KTRAP_FRAME
 

3. KPCR結構體(kernel processor control region 內核線程控制區)

  有一篇文章,裏面大致介紹了該結構體 --> [Windows內核分析]KPCR結構體介紹 (CPU控制區 Processor Control Region)

  簡單來講,KPCR結構體中保存着 關於CPU 的信息,一個核有一個本身私有的KPCR結構體,八核則每一個核有本身的單獨的KPCR結構體

  咱們須要用到最後一個成員中的中的CurrentThread來獲取當前線程的_KTHREAD結構體。

   kd > dt _kpcr
            ntdll!_KPCR
            + 0x000 NtTib            : _NT_TIB
            + 0x000 Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
            ····
            +0x120 PrcbData         : _KPRCB

         kd > dt _KPRCB
            ntdll!_KPRCB
            + 0x000 MinorVersion     : Uint2B
            + 0x002 MajorVersion : Uint2B
            + 0x004 CurrentThread : Ptr32 _KTHREAD
            + 0x008 NextThread : Ptr32 _KTHREAD
            ···

 

2、分析 nt!KiSystemService 內核函數

  該函數位於ntkrnlpa.exe真正的內核中(並不是ntdll.dll),一開始但願使用IDA反彙編查看其代碼,可是沒法顯示。

  咱們只能採起"曲線救國"的方法,經過int 2eh中斷號查找GDT表,從表中獲取中斷描述符,將中斷描述符拼接拆分,獲取 函數的EIP 地址。

  以後,咱們使用 Windbg 的U指令,來查看該其該函數在內存中的反彙編代碼

 

  反彙編代碼可能有點長,咱們在正式分析以前須要明確幾個注意事項。

  0)這些反彙編代碼的目的就是將 _Ktrap_frame 結構體中的寄存器填滿,而後將[KTHREAD+0x128]處舊的TRAPFRAME切換爲這個新的KTRAPFRAME而後調用內核函數。

  1)函數開始時ESP位於_Ktrap_framec+0x070 ErrCode處。ErroCode這裏沒有,所以能夠看待彙編代碼中第一行使用 push 0。

  2)FS寄存器在0環時是指向本身的KPCR,而在3環時保存的是該線程的TEB結構體。(R3能夠查看:利用C++實現模塊隱藏)

    所以在反彙編代碼 83e8cff6 、83e8cffb 是手動將FS寄存器存儲KPCR。

    原理是以30h做爲段選擇子查找GDT這張表,找出段描述符,而後加載到fs段寄存器中。

    

  3) 0x83e8d007處 KPCR:[124] 爲當前線程的ETHREAD結構體(看一中的表,KTHREAD也即ETHREAD的頭部),將其存儲到寄存器esi中,以後要常用。

  4)0x83e8d026處修改esp,將其指向 _Ktrap_frame 結構體第一個成員,0x83e8d036 處也將ebp修改成 _Ktrap_frame 結構體第一個成員。

  5)由於 esi 指向ETHREAD, [esi+128h] 則表示當前線程的_Ktrap_frame,在進入內核時,其保存了一箇舊的frame。

    0x83e8d038將獲取舊的_Ktrap_frame

    0x83e8d03e將舊的Frame放入新的Frame的edx寄存器中

    0x83e8d049將新的Frame掛靠在ETHREAD+0x128處,這樣完成了新舊替換。

    下圖三個箭頭依次對應上面三個階段,這樣經過FS寄存器就能夠查找到該FRAME了,回去只須要找到這裏完成替換便可。

    

  6)Frame前部分紅員和調試有關,所以0x83e8d045這裏須要判斷是否在調試狀態,若是處於調試狀態,則jmp進一個地址,將寄存器入棧再回來。

    硬件調試,其實就是經過這個部分。對於反調試,這裏能夠作些文章...

  7)還有部分涉及權限切換,0x83e8d030 好比有些API可讓3環也可讓0環權限調用,但有的不讓(看保護模式調用門等知識),此時就會進行位運算判斷"先前模式"的權限級別。

  8)當這些工做所有完成以後,會執行 83e8d06d e9dd000000      jmp     nt!KiFastCallEntry+0x8f (83e8d14f)

    對,你沒看錯,就是快速調用時的函數,至關於中斷多走了一步,處理了上面的一些信息,而快速調用提早就能夠處理好直接調用   nt!KiFastCallEntry+0x8f函數。

 

3、nt!KiSystemService函數的反彙編解讀

 1 nt!KiSystemService:
 2 // 壓棧 按照 _Ktrap_frame 結構中寄存的值
 3 83e8cfee 6a00            push    0 // errorcode 填入零來進行對齊
 4 83e8cff0 55              push    ebp
 5 83e8cff1 53              push    ebx
 6 83e8cff2 56              push    esi
 7 83e8cff3 57              push    edi
 8 83e8cff4 0fa0            push    fs
 9 
10 // 根據30h這個值做爲段選擇子,查找gdt這張表,找出段描描述符,將其加載到fs段寄存器中
11 // 30h -> 0011 0000 -> index = 00110 | TI = 0 |00 -> TI=0查LDT表,查索引爲6查出來的是 834093f7`ac003748 這個值。
12 // 834093f7`ac003748 段描述符,根據段描述符屬性拼接起來的 83f7ac00
13 // 83f7ac00 指向的是 KPCR,FS在零環的時候,指向KPCR,再也不是三環時線程TEB這個結構體
14 83e8cff6 bb30000000      mov     ebx,30h
15 83e8cffb 668ee3          mov     fs,bx
16 83e8cffe bb23000000      mov     ebx,23h
17 83e8d003 8edb            mov     ds,bx
18 83e8d005 8ec3            mov     es,bx
19 
20 
21 // 有些API 0環和三環均可以調用,經過下面操做能夠查看原來調用的是0環仍是3環,再進行調用API的權限驗證 
22 // 驗證完該線程,若是是0環,則bl爲0;若是是3環,則bl=1
23 83e8d007 648b3524010000  mov     esi,dword ptr fs:[124h] // 將當前CPU正在跑的線程放到esi中
24 83e8d00e 64ff3500000000  push    dword ptr fs:[0] // 把老的EXCEPTION_LIST 存入 _Ktrap_frame 結構體中(fs上邊那部分)
25 83e8d015 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh // 將如今EXCPTION_LIST放入異常鏈表
26 83e8d020 ffb63a010000    push    dword ptr [esi+13Ah] // 將老的"先前模式"也保存到棧中
27 83e8d026 83ec48          sub     esp,48h // 將當前ESP提高到 _Ktrap_frame 第一個成員
28 83e8d029 8b5c246c        mov     ebx,dword ptr [esp+6Ch] // 取出3環壓入的參數CS _KTRAP_FRAME + 0x6c,指向三環原來的CS值
29 83e8d02d 83e301          and     ebx,1 // 將原來CS的值進行與運算, 0環最低爲爲0,3環最低爲爲1
30 83e8d030 889e3a010000    mov     byte ptr [esi+13Ah],bl // 新的"先前模式",原來是三環模式爲1;原來是零環模式爲0
31 83e8d036 8bec            mov     ebp,esp // ebp 一樣指向_Ktrap_frame第一個成員
32 83e8d038 8b9e28010000    mov     ebx,dword ptr [esi+128h] // esi經過0x83e8d007處[KPCR+124],指向Ethread                              // Ethread+128h 指向的是 _KTRAP_FRAME這個結構體指針            
33 83e8d03e 895d3c          mov     dword ptr [ebp+3Ch],ebx  // 將該 _KTRAP_FRAME地址暫時保存在 edx 中                             
34 83e8d041 83652c00        and     dword ptr [ebp+2Ch],0
35 83e8d045 f64603df        test    byte ptr [esi+3],0DFh      // 判斷是否屬於調試狀態 一個位 +0x003 DebugActive : UChar
36 83e8d049 89ae28010000    mov     dword ptr [esi+128h],ebp // 由於新的 trap_frame地址已經發生變化,因此要將新的trapFrame放到線程放到這個位置
37 
38 83e8d04f fc              cld
39 83e8d050 0f859afeffff    jne     nt!Dr_kss_a (83e8cef0)  // 在0x83e8d045處根據判斷結果,若是是調試狀態,則進行跳轉。
40                              // 若爲調試,則跳過去將調試相關的寄存器也存入_KTRAP_FRAME這個結構體
41                              // 不然不是調試器,則將中是-1。(硬件斷點使用這個,反調試很管用)
42 83e8d056 8b5d60          mov     ebx,dword ptr [ebp+60h] // 3環的EBP
43 83e8d059 8b7d68          mov     edi,dword ptr [ebp+68h] // 3環的EIP
44 83e8d05c 89550c          mov     dword ptr [ebp+0Ch],edx // edx存放着三環參數的指針
45                              // {mov edx,esp;sysenter}                    
46 83e8d05f c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h // 操做系統須要用的標誌
47 83e8d066 895d00          mov     dword ptr [ebp],ebx     // 3環的ebp存儲到DbgEbp的位置
48 83e8d069 897d04          mov     dword ptr [ebp+4],edi   // 3環的eip存放到 DbgEip
49 83e8d06c fb              sti     // 關閉中斷
50 83e8d06d e9dd000000      jmp     nt!KiFastCallEntry+0x8f (83e8d14f) // 取出系統調用號,3環傳進來的。
51                  // 注意,這個就是快速調用首先進入的函數,至關於中斷多走了這一步,系統調用直接調用。

 

4、nt!KiFastCallEntry的反彙編代碼

該反彙編代碼閱讀量一樣很大,找時間必定給讀出來,若是感興趣能夠自行百度相關解讀。

  1 nt!KiFastCallEntry:
  2 83e8d0c0 b923000000      mov     ecx,23h
  3 83e8d0c5 6a30            push    30h
  4 83e8d0c7 0fa1            pop     fs
  5 83e8d0c9 8ed9            mov     ds,cx
  6 83e8d0cb 8ec1            mov     es,cx
  7 83e8d0cd 648b0d40000000  mov     ecx,dword ptr fs:[40h]
  8 83e8d0d4 8b6104          mov     esp,dword ptr [ecx+4]
  9 83e8d0d7 6a23            push    23h
 10 83e8d0d9 52              push    edx
 11 83e8d0da 9c              pushfd
 12 83e8d0db 6a02            push    2
 13 83e8d0dd 83c208          add     edx,8
 14 83e8d0e0 9d              popfd
 15 83e8d0e1 804c240102      or      byte ptr [esp+1],2
 16 83e8d0e6 6a1b            push    1Bh
 17 83e8d0e8 ff350403dfff    push    dword ptr ds:[0FFDF0304h]
 18 83e8d0ee 6a00            push    0
 19 83e8d0f0 55              push    ebp
 20 83e8d0f1 53              push    ebx
 21 83e8d0f2 56              push    esi
 22 83e8d0f3 57              push    edi
 23 83e8d0f4 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]
 24 83e8d0fb 6a3b            push    3Bh
 25 83e8d0fd 8bb324010000    mov     esi,dword ptr [ebx+124h]
 26 83e8d103 ff33            push    dword ptr [ebx]
 27 83e8d105 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh
 28 83e8d10b 8b6e28          mov     ebp,dword ptr [esi+28h]
 29 83e8d10e 6a01            push    1
 30 83e8d110 83ec48          sub     esp,48h
 31 83e8d113 81ed9c020000    sub     ebp,29Ch
 32 83e8d119 c6863a01000001  mov     byte ptr [esi+13Ah],1
 33 83e8d120 3bec            cmp     ebp,esp
 34 83e8d122 7597            jne     nt!KiFastCallEntry2+0x49 (83e8d0bb)
 35 83e8d124 83652c00        and     dword ptr [ebp+2Ch],0
 36 83e8d128 f64603df        test    byte ptr [esi+3],0DFh
 37 83e8d12c 89ae28010000    mov     dword ptr [esi+128h],ebp
 38 83e8d132 0f8538feffff    jne     nt!Dr_FastCallDrSave (83e8cf70)
 39 83e8d138 8b5d60          mov     ebx,dword ptr [ebp+60h]
 40 83e8d13b 8b7d68          mov     edi,dword ptr [ebp+68h]
 41 83e8d13e 89550c          mov     dword ptr [ebp+0Ch],edx
 42 83e8d141 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h
 43 83e8d148 895d00          mov     dword ptr [ebp],ebx
 44 83e8d14b 897d04          mov     dword ptr [ebp+4],edi
 45 83e8d14e fb              sti
 46 83e8d14f 8bf8            mov     edi,eax
 47 83e8d151 c1ef08          shr     edi,8
 48 83e8d154 83e710          and     edi,10h
 49 83e8d157 8bcf            mov     ecx,edi
 50 83e8d159 03bebc000000    add     edi,dword ptr [esi+0BCh]
 51 83e8d15f 8bd8            mov     ebx,eax
 52 83e8d161 25ff0f0000      and     eax,0FFFh
 53 83e8d166 3b4708          cmp     eax,dword ptr [edi+8]
 54 83e8d169 0f8333fdffff    jae     nt!KiBBTUnexpectedRange (83e8cea2)
 55 83e8d16f 83f910          cmp     ecx,10h
 56 83e8d172 751a            jne     nt!KiFastCallEntry+0xce (83e8d18e)
 57 83e8d174 8b8e88000000    mov     ecx,dword ptr [esi+88h]
 58 83e8d17a 33f6            xor     esi,esi
 59 83e8d17c 0bb1700f0000    or      esi,dword ptr [ecx+0F70h]
 60 83e8d182 740a            je      nt!KiFastCallEntry+0xce (83e8d18e)
 61 83e8d184 52              push    edx
 62 83e8d185 50              push    eax
 63 83e8d186 ff154c99fb83    call    dword ptr [nt!KeGdiFlushUserBatch (83fb994c)]
 64 83e8d18c 58              pop     eax
 65 83e8d18d 5a              pop     edx
 66 83e8d18e 64ff05b0060000  inc     dword ptr fs:[6B0h]
 67 83e8d195 8bf2            mov     esi,edx
 68 83e8d197 33c9            xor     ecx,ecx
 69 83e8d199 8b570c          mov     edx,dword ptr [edi+0Ch]
 70 83e8d19c 8b3f            mov     edi,dword ptr [edi]
 71 83e8d19e 8a0c10          mov     cl,byte ptr [eax+edx]
 72 83e8d1a1 8b1487          mov     edx,dword ptr [edi+eax*4]
 73 83e8d1a4 2be1            sub     esp,ecx
 74 83e8d1a6 c1e902          shr     ecx,2
 75 83e8d1a9 8bfc            mov     edi,esp
 76 83e8d1ab 3b351c97fb83    cmp     esi,dword ptr [nt!MmUserProbeAddress (83fb971c)]
 77 83e8d1b1 0f832e020000    jae     nt!KiSystemCallExit2+0xa5 (83e8d3e5)
 78 83e8d1b7 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
 79 83e8d1b9 f6456c01        test    byte ptr [ebp+6Ch],1
 80 83e8d1bd 7416            je      nt!KiFastCallEntry+0x115 (83e8d1d5)
 81 83e8d1bf 648b0d24010000  mov     ecx,dword ptr fs:[124h]
 82 83e8d1c6 8b3c24          mov     edi,dword ptr [esp]
 83 83e8d1c9 89993c010000    mov     dword ptr [ecx+13Ch],ebx
 84 83e8d1cf 89b92c010000    mov     dword ptr [ecx+12Ch],edi
 85 83e8d1d5 8bda            mov     ebx,edx
 86 83e8d1d7 f6050869f88340  test    byte ptr [nt!PerfGlobalGroupMask+0x8 (83f86908)],40h
 87 83e8d1de 0f954512        setne   byte ptr [ebp+12h]
 88 83e8d1e2 0f858c030000    jne     nt!KiServiceExit2+0x17b (83e8d574)
 89 83e8d1e8 ffd3            call    ebx
 90 83e8d1ea f6456c01        test    byte ptr [ebp+6Ch],1
 91 83e8d1ee 7434            je      nt!KiFastCallEntry+0x164 (83e8d224)
 92 83e8d1f0 8bf0            mov     esi,eax
 93 83e8d1f2 ff156801e583    call    dword ptr [nt!_imp__KeGetCurrentIrql (83e50168)]
 94 83e8d1f8 0ac0            or      al,al
 95 83e8d1fa 0f853b030000    jne     nt!KiServiceExit2+0x142 (83e8d53b)
 96 83e8d200 8bc6            mov     eax,esi
 97 83e8d202 648b0d24010000  mov     ecx,dword ptr fs:[124h]
 98 83e8d209 f68134010000ff  test    byte ptr [ecx+134h],0FFh
 99 83e8d210 0f8543030000    jne     nt!KiServiceExit2+0x160 (83e8d559)
100 83e8d216 8b9184000000    mov     edx,dword ptr [ecx+84h]
101 83e8d21c 0bd2            or      edx,edx
102 83e8d21e 0f8535030000    jne     nt!KiServiceExit2+0x160 (83e8d559)
103 83e8d224 8be5            mov     esp,ebp
104 83e8d226 807d1200        cmp     byte ptr [ebp+12h],0
105 83e8d22a 0f8550030000    jne     nt!KiServiceExit2+0x187 (83e8d580)
106 83e8d230 648b0d24010000  mov     ecx,dword ptr fs:[124h]
107 83e8d237 8b553c          mov     edx,dword ptr [ebp+3Ch]
108 83e8d23a 899128010000    mov     dword ptr [ecx+128h],edx
相關文章
相關標籤/搜索