天天看點

7- 代碼段權限檢查與 jmp

概述

這一篇 hin 重要。

一般來說,我們在 Windows 中寫的代碼,都運作在 3 環(應用層)。隻有在調用一些系統接口的時候,或者中斷等情況的時候,才會進入 0 環(核心)。

為什麼 CPU 要給代碼賦予不同的權限?這是為了防止你任意妄為。在 Windows 中,如果你随意更改了核心的重要資料,作業系統必然面臨着危險——藍屏。

為了防止這種情況發生,CPU 把執行權限分成了4個等級,0,1,2,3. 其中 0 表示最進階,可以執行任意代碼,而執行權限為 3 的程式,隻能執行普通的指令。Windows 和 Linux 隻使用了 0 和 3 這兩種。

而 CPU 的有些指令,隻能在 0 環執行。有些記憶體的通路,也隻能在 0 環。這就是所謂的保護。

之前已經學過,代碼段描述符中,有 DPL 字段,它是專門用來描述代碼段級别的。前面分析過 Windows 的GDT 表中段描述符,就發現有 0 環的代碼段和 3 環代碼段。這裡的 DPL 表示,隻允許相同級别的下的程式跳過來執行,除非被我同意,低特權級的程式才能跳進來執行。

所謂的特定級别下的程式,是指的目前 CPL 的級别。見後文。

CPU 是不允許 CPL = 3 的程式直接跳轉到 DPL=0 的代碼中去執行。

目前特權級

為了防止意外,有必要再次重複下 CPL。

這個值可以始終儲存在 cs 或者 ss 段寄存器的低 2 位。在OD裡打開一個程式,如果你細心觀察,你總會發現,cs 的最低2位一定是2進制 11,也就是3. 你絕對不可能看到這個值變成 0. 因為 OD 本身就是運作在 3 環的調試器。

這是不是意味着,目前特權級永遠不會變成 0?

不會的,後面的實驗将驗證這一點。

如果你想在 VC6.0 中寫程式,直接去讀取高 2G 位址的資料,一定會報錯。如果你目前的特權級被提升為 0 環(簡稱提權),這時候再去讀取高 2G 位址資料,就沒有問題了。然而提權并不是這麼簡單。後文會陸續介紹。

跨段執行——就是改變 CS 段寄存器

跨段執行,就是指改變目前的 cs 段寄存器,把另一個代碼段的描述符加載到 cs 段寄存器。千萬不要想當然的使用 ​

​mov ax, 0x08; mov cs, ax​

​​,編譯器都不會讓你通過。前面你也發現,也不存在​

​lcs​

​這樣的指令加載段寄存器。

改變 cs 段寄存器,可以使用 ​

​jmp far​

​​ 和 ​

​call far​

​ 等等。注意,除了這兩個指令,還有别的,這裡不能講太多。本篇隻介紹 jmp,原因還是那樣,因為它簡單。

指令 jmp 可以實作跨段執行代碼,但是它并不能提權(無法改變當權特權級),也就是說,即便你跨到了 DPL = 0 的段,你的 CPL 也不會發生任何改變。 除非你原來就是 0.

使用 jmp 跨到 0 環代碼段,也是有要求的,除非這個0環代碼段描述符同意(這就是所謂的一緻代碼段)。

一緻代碼段與非一緻代碼段

當段描述符描述代碼段時,TYPE 字段的 c 位置 1 說明該段是一緻代碼段,否則是非一緻代碼段。

  • 隻有得到段描述符的同意,才允許低權限的程式跳轉進去執行。這種段稱為一緻代碼段。
  • 而有些代碼段描述符,絕對不允許低權限的程式跳轉進去執行,這種段稱為非一緻代碼段。

實作跨段:一緻代碼段(比目前權限高的)

要求:CPL >= DPL

步驟:

1. 在8003f048 處添加描述符 00cf9f00`0000ffff,該描述符描述的段為一緻代碼段,DPL = 0
    指令 eq 8003f048 00cf9f00`0000ffff
2.  打開 OD,修改目前指令為 jmp 48:0044420c
3.  執行指令後跳轉到了 0044420c 處,且 cs 變為 0x4b      
7- 代碼段權限檢查與 jmp

圖1 安裝描述符

7- 代碼段權限檢查與 jmp

圖2 跨段跳轉

實作跨段:非一緻代碼段(與目前權限一緻)

要求:CPL == DPL 并且 RPL <= DPL

步驟:

1. 在8003f048 處添加描述符 00cffb00`0000ffff,該描述符描述的段為非一緻代碼段,DPL = 3
    指令 eq 8003f048 00cffb00`0000ffff
2.  打開 OD,修改目前指令為 jmp 48:0044420c
3.  執行指令後跳轉到了 0044420c 處,且 cs 變為 0x4b      
7- 代碼段權限檢查與 jmp

圖3 安裝段描述符

7- 代碼段權限檢查與 jmp

圖4 跨段跳轉

總結

繼續閱讀