Windows系統調用中API從3環到0環(上)

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

 

Windows系統調用中API從3環到0環(上)函數

若是對API在三環的部分不瞭解的,能夠查看 Windows系統調用中的API三環部分(依據分析重寫ReadProcessMemory函數
spa

這篇文章分爲上下兩篇,其中上篇初步講解大致輪廓,下篇着重經過實驗來探究其內部實現,最終分析兩個函數(快速調用與系統中斷),來實現經過系統中斷直接調用內核函數。操作系統

 

1、結構體 _KUSER_SHARED_DATA指針

  該結構體看名字可知是用於內核層與用戶層來共享數據所使用的結構體。htm

   kd > dt _KUSER_SHARED_DATA
          ntdll!_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
          ·······blog

   1)在User層和KerNel層分別定義了一個_KUSER_SHARED_DATA結構區域,用於User層和Kernel層共享某些數據。索引

   2)它們使用同一段頁,只是映射位置不一樣。雖然同一頁,但User只讀,Kernnel層可寫。ip

   3)它們使用固定的地址值映射,_KUSER_SHARED_DATA結構在User爲:0x7ffe0000,在Kernel層爲:0xffdf0000。內存

  

   經過windbg能夠查看其中兩塊內存徹底同樣(實質查看的是同一物理頁,掛在兩塊頁表PTT中。

    

 

2、分析 0X7FFE0300  這個地址

在 <&ntdll.NtReadVirtualMemory> 中調用 ntdll.KiFastSystemCall 函數 ,實質就是調用 0X7FFE0300 這個地址。
    77A162F8 >  B8 15010000  mov eax,0x115  // 對應操做系統內核中某一函數的編號。
    77A162FD    BA 0003FE7F  mov edx,0x7FFE0300  // 該地方是一個函數,該函數決定了什麼方式進零環。
    77A16302    FF12         call dword ptr ds:[edx]  ; ntdll.KiFastSystemCall

  1)_KUSER_SHARED_DATA 在用戶層的位置爲 0x7FFE0000,該地址爲其+0x300位置

     +0x300 SystemCall       : Uint4B

  2)該成員保存着系統調用的函數入口,若是當前CPU支持快速調用。

    則存儲着ntdll.dll!KiFastSystemCall()函數地址;

    若是不支持快速調用,則存儲着ntdll.dll!KiIntSystemCall()函數地址。

  3)經過實驗驗證當前CPU是否支持快速調用:

    當經過eax=1來執行cupid指令時,處理器特徵信息被存放在ecx和edx寄存器中,

    其中edx包含了SEP位(11位),該位指明瞭當前處理器是否支持sysenter/sysexit指令。

    

    以下圖,咱們執行cupid指令,獲取edx 178BFBFF,拆分 11-8位 B 1011,故其11位爲1,支持快速調用。

    這也驗證了咱們上一篇文章中的分析結果。(最後是快速調用並不是使用中斷門)

 

3、從3環進0環須要哪些寄存器改變

  1. CS的權限由3變爲0,意味着須要新的CS
  2. SS與CS的權限永遠一致,須要新的SS
  3. 權限發生切換的時候,堆棧也必定會改變,須要新的ESP
  4. 進0環後的代碼位置,須要EIP

 

4、ntdll.dll!KiIntSystemCall() 分析

  咱們使用ida來分析ntdll.dll!KiIntSystemCall()

  .text:77F070C0
  .text : 77F070C0                 public KiIntSystemCall
  .text : 77F070C0 KiIntSystemCall proc near; DATA XREF : .text : off_77EF61B8↑o
  .text : 77F070C0
  .text : 77F070C0 arg_4 = byte ptr  8
  .text : 77F070C0            // 以前調用該函數時 mov eax, 0x115,向eax傳入一個函數號
  .text : 77F070C0                 lea     edx, [esp + arg_4] // 當前參數的指針存儲在 edx中
  .text : 77F070C4                 int     2Eh; // 經過中斷門的形式進入到內核中
  .text:77F070C4; DS:SI->counted CR - terminated command string
  .text : 77F070C6                 retn
  .text : 77F070C6 KiIntSystemCall endp

  其在觸發 int 2eh中斷前用到兩個寄存器,一個是內核中調用函數的函數號,另一個就是傳入參數的指針。

 

五. ntdll.dll!KiFastSystemCall()函數分析
  當CPU支持快速調用,則使用這個函數。(咱們在上篇文章中已經用到了這個來重構WriteProcessMemory函數)
  .text:77F070B0                 public KiFastSystemCall
  .text:77F070B0 KiFastSystemCall proc near              ; DATA XREF: .text:off_77EF61B8↑o
  .text:77F070B0            // 以前調用該函數時 mov eax, 0x115,向eax傳入一個函數號
  .text:77F070B0                 mov     edx, esp // 將當前堆棧放入edx,用它來存儲參數
  .text:77F070B2                 sysenter
  .text:77F070B2 KiFastSystemCall endp

  觸發sysenter指令後,也用到兩個寄存器eax,edx,做用與使用中斷同樣。

 

  爲何叫快速調用?

    中斷門進入0環,須要的CS、EIP在IDT表中,須要查內存(SS與ESP由IDT表提供);

    而CPU若是支持sysenter指令時,操做系統會提早將CS/SS/ESP/EIP的值存儲在MSR寄存器中,

    sysenter指令執行時,CPU會將MSR寄存器中的值直接寫入寄存器中,沒有讀內存過程,本質時同樣的。

下一篇,咱們探究其中的詳細細節。

相關文章
相關標籤/搜索