面朝大海,春暖花开

C++/C

[转载]总结进入RING0的方法

总结进入RING0的方法
by wowocock1/CVC.GB

关于进入RING0层的方法,大家一定听说过不少,我在复习保护模式编程中将一些进RING0
的方法;总结了一下,包括调用门,任务门,中断门,陷阱门等,这些方法都是直接利用
IA32的方法,所以和操作系统应该没有多大关系,当然由于NT内核对GDT,IDT,的保护所
以我们不能用这些方法,不过如果一旦突破了NT的保护,那么所有的方法就都可以使用了,
其他的还有SEH等方法,我在前面的文章中也有介绍。

-----------------Code---

;========================================
;      WOWOCOCK  编写      ;
;======================================== 
   .586p
   .model flat, stdcall
   option casemap :none  ; case sensitive
   include \masm32\include\windows.inc
   include \masm32\include\kernel32.inc
   include \masm32\include\user32.inc
   includelib \masm32\lib\kernel32.lib
   includelib \masm32\lib\user32.lib
;;--------------
TSS       STRUC
TRLink     dw   0   ;链接字段
        dw   0   ;不使用,置为0
TRESP0     dd   0   ;0级堆栈指针
TRSS0      dw   0   ;0级堆栈段寄存器
        dw   0   ;不使用,置为0
TRESP1     dd   0   ;1级堆栈指针
TRSS1      dw   0   ;1级堆栈段寄存器
        dw   0   ;不使用,置为0
TRESP2     dd   0   ;2级堆栈指针
TRSS2      dw   0   ;2级堆栈段寄存器
        dw   0   ;不使用,置为0
TRCR3      dd   0   ;CR3
TREIP      dd   0   ;EIP
TREFlag     dd   0   ;EFLAGS
TREAX      dd   0   ;eax
TRECX      dd   0   ;ecx
TREDX      dd   0   ;edx
TREBX      dd   0   ;ebx
TRESP      dd   0   ;esp
TREBP      dd   0   ;ebp
TRESI      dd   0   ;esi
TREDI      dd   0   ;edi
TRES      dw   0   ;ES
        dw   0   ;不使用,置为0
TRCS      dw   0   ;CS
        dw   0   ;不使用,置为0
TRSS      dw   0   ;ss
        dw   0   ;不使用,置为0
TRDS      dw   0   ;DS
        dw   0   ;不使用,置为0
TRFS      dw   0   ;FS
        dw   0   ;不使用,置为0
TRGS      dw   0   ;GS
        dw   0   ;不使用,置为0
TRLDTR     dw   0   ;LDTR
        dw   0   ;不使用,置为0
TRTrip     dw   0   ;调试陷阱标志(只用位0)
TRIOMap     dw   $+2  ;指向I/O许可位图区的段内偏移
TSS       ENDS
  .data
sztit   db "Gate Test",0
CTEXTCall db "call gate to Ring0!继续?",0
CTEXTInt  db "int gate to Ring0 By int 5 !继续?",0
CTEXTIntx db "int gate to Ring0 By int X !继续?",0
CTEXTTrap db "Trap gate to Ring0 By int 1!继续?",0
CTEXTFault db "Fault gate to Ring0!继续?",0
CTEXTTask db "Task gate to Ring0!继续?",0
temp1 db "Cr3的内容是:%8X",0
temp2 db 100 dup(?)
Freq db 08h    ;发声频率
gdtR df 0
idtR df 0
ldtR dw 0     
trR  dw 0     ;the contents of GDTR,IDTR,LDTR,TR

ldtDes dw 0    
    dw 0    ;LDT Limit  
    dd 0    ;LDT Base
Callgt dq 0    ;call gate's selff

TrDes dw 0    
    dw 0    ;TR Limit  
    dd 0    ;TR Base

Tss1Sel dw ?   ;TSS

Call32  dd 0
Tss1Gate dw ?   ;任务门

TSS1 TSS <>
Tss1Limit equ $-TSS1

TSS2 TSS <>
TestCR3 dd 4

MyCall MACRO Selector,Offsetv
 db 09ah
 dd Offsetv
 dw Selector
ENDM
;;-----------------------------------------
  .code
__Start:
  sgdt  fword ptr gdtR
  sidt  fword ptr idtR
  sldt  word ptr ldtR   
  str   word ptr trR  ;save them for later use

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

    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
    or  eax,ebx
    mov  dword ptr [ldtDes+4],eax    ;get ldt Base
    ;-----------------------
    ; get the tr mes
    ;-----------------------    
    movzx esi,trR
    add  esi,dword ptr [gdtR+2]

    mov  ax,word ptr [esi]
    mov  word ptr [TrDes],ax
    mov  ax,word ptr [esi+6]
    and  ax,0fh
    mov  word ptr [TrDes+2],ax     ;get tr Limit
    
    mov  eax,[esi+2]
    and  eax,0ffffffh
    mov  ebx,[esi+4]
    and  ebx,0ff000000h
    or  eax,ebx
    mov  dword ptr [TrDes+4],eax;get tr Base
    ;-------------------------------------
    ; 这里演示在GDT中寻找空白表项来制造调用门
    ;-------------------------------------
    mov  esi,dword ptr [gdtR+2] ;esi->gdt base
    movzx eax,word ptr [gdtR]  ;eax=gdt limit
    call  Search_XDT
                        ;esi==gdt Base
    mov  esi,dword ptr [gdtR+2]
    push  offset myring0_prc_callgt    ;set callgate in gdt
    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,dpl=3,and attribute ->386 call gate!

    and  dword ptr Callgt,0
    or   al,3h
    mov  word ptr [Callgt+4],ax
    call  fword ptr [Callgt]      ;use callgate to Ring0!

    ;--------------------------------------------
    ; 这里演示在Ldt中制造调用门
    ;--------------------------------------------
    invoke  MessageBoxA,0, addr CTEXTCall,addr sztit,MB_YESNO
    cmp  eax,IDNO
    jz   @xit000           ;继续演示?

    mov  esi,dword ptr [ldtDes+4]   ;esi->ldt base
    mov  eax,dword ptr [ldtDes]    ;eax=ldt limit

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

    push  offset myring0_prc_callgt  ;set callgate in ldt
    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,dpl=3,and attribute ->386 call gate!

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

; *通过中断门进入ring0,像在Dos下一样,我们只要替换中断向量表的地址以指向我们
; *自己的程序就可以了,不过在win下中断向量表变为IDT(中断描述符表),其第0~1保存
; *中断处理程序偏移的低16位,6~7字节保存偏移的高16位,我们必须使用描述符具有DPL=3
; *的中断门以便在ring3下转入中断程序,而int 03h,04h,05h,10h,13h,30h等本来就是
; *DPL=3,我们可以方便地利用之,注意中断处理程序返回用iretd
    ;---------------------------
    ; 下面利用int 5进入ring0
    ;---------------------------
    invoke  MessageBoxA,0,addr CTEXTInt,addr sztit,MB_YESNO
    cmp  eax,IDNO
    jz   @xit000           ;继续演示?

    mov  esi,dword ptr [idtR+2]    ;esi->idt base
    push  dword ptr [esi+8*5+0]
    push  dword ptr [esi+8*5+4]    ;保存INT 5,中断描述符

    push  offset myring0_prc_Intgt   ;替换原来INT5的入口地址
    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]    ;恢复,int 5,中断描述符
    pop  dword ptr [esi+8*5+0]

; *当然,上面使用的全部是DPL=3的int如1,3,5等,如果我们准备使用任意int 来达到
; *目的该怎么办?这就需要自己改int descriptor 的属性值,使DPL=3,sel=28h
; *如下面使用int 255
; *__________________________________________
    invoke  MessageBoxA,0,addr CTEXTIntx,addr sztit,MB_YESNO
    cmp  eax,IDNO
    jz   @xit000           ;继续演示?

    movzx ebx,word ptr [idtR] ;ebx=idt limit
    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 ;P=1,386中断门,DPL=3
    pop word ptr [esi+ebx+6]
    
    ;mov eax,ebx
    ;shl eax,5
    ;add eax,90C300CDh

    ;push eax
    ;call ss:esp ; 在堆栈中形成指令 int 5Fh ret直接转入执行!
    int 5fh
    ;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  MessageBoxA,0,addr CTEXTTrap,addr sztit,MB_YESNO
    cmp  eax,IDNO
    jz   @xit001           ;继续演示?
    ;---------------------------------
    ; 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     ; set TF=1

    nop      ; ring0!

    pop dword ptr [esi+(8*1)+4]; restore IDT entry 
    pop dword ptr [esi+(8*1)+0]
    ;--------------------------------------------
    ; 这里演示故障门,除法错误
    ;--------------------------------------------
    @xit001:invoke  MessageBoxA,0,addr CTEXTFault,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!
    ;-----------------------------------------
    invoke  MessageBoxA,0,addr CTEXTTask,addr sztit,MB_YESNO
    cmp  eax,IDNO
    jz   @xit000
    ;-------------------------------------
    ; 这里演示在GDT中寻找空白表项来制造TSS
    ;-------------------------------------
    mov  esi,dword ptr [gdtR+2]
    movzx eax,word ptr [gdtR]
    call  Search_XDT
    and  ax,0fff8h
    mov  Tss1Sel,ax   ;save Tss1 selector ,esi==gdt Base
    mov  esi,dword ptr [gdtR+2]
    mov  ebx,offset TSS1
    mov  word ptr [esi+eax+0],Tss1Limit    
    mov  dword ptr [esi+eax+2],ebx    ;offset

    mov  word ptr [esi+eax+5],89h
    shr  ebx,24
    mov  byte ptr [esi+eax+7],bl ;set mytss

    ;--------------------------------------------
    ; 这里演示在Ldt中制造任务门
    ;--------------------------------------------
    mov  esi,dword ptr [ldtDes+4]
    mov  eax,dword ptr [ldtDes]

    call  Search_XDT          ;eax返回找到的空白选择子
    push  eax
    or   ax,7h
    mov  Tss1Gate,ax
    pop  eax
    mov  esi,dword ptr [ldtDes+4]

    mov  word ptr [esi+eax+0],0    
    mov  word ptr [esi+eax+6],0    ;offset
    push  word ptr Tss1Sel
    pop  word ptr [esi+eax+2]
    mov  word ptr [esi+eax+4],0E500h ;Tss Gate

    mov esi,dword ptr [TrDes+4]
    assume esi:ptr TSS
    push word ptr ldtR
    pop word ptr[esi].TRLDTR ;设置LDT SELECTOR(WINDOWS98的TSS中LDT 为0???)

    lea edi,TSS1
    assume edi:ptr TSS
    push word ptr trR
    pop word ptr [edi].TRLink  ;返回TSS选择子,设置联接字

    push dword ptr[esi].TRESP0  ;设置SP0
    pop dword ptr[edi].TRESP0
  
    push word ptr[esi].TRSS0   ;设置SS0
    pop word ptr[edi].TRSS0

    push dword ptr[esi].TRCR3  
       ;设置CR3寄存器,即设置好转换以后所有的段及页转换相关寄存器
    pop dword ptr[edi].TRCR3

    push offset Ring0
    pop dword ptr[edi].TREIP

    mov word ptr[edi].TRCS,28h  ;CS=28
    mov word ptr[edi].TRSS,30h  ;ss=30

    push word ptr ldtR      ;设置LDTR
    pop word ptr[edi].TRLDTR

    push ds
    pop dword ptr[edi].TRDS
    mov word ptr[edi+54h+2],0

    call fword ptr Call32
    mov ebx,dword ptr [TestCR3]
   @xit000:
    invoke wsprintf,addr temp2,addr temp1,TestCR3
    invoke MessageBoxA,0,addr temp2,addr sztit,0
    mov eax,dword ptr [ldtDes+4];恢复GDT,LDT中的空选择子。
    movzx esi,Tss1Gate
    and  esi,0fffffff8h
    add eax,esi
    mov dword ptr [eax],0
    mov dword ptr [eax+4],0
    mov eax,dword ptr [gdtR+2]
    movzx esi,Tss1Sel
    add eax,esi
    mov dword ptr [eax],0
    mov dword ptr [eax+4],0
    invoke  ExitProcess,0
    ;-----------------------------------------
Ring0Code_div proc far                            
                                       
    pushad                                  
    mov  ecx,10     ;EIP
   ambalance002:         ;cs
    push  ecx      ;EFLAGS
    call  Beeps
    pop  ecx
    loop  ambalance002                                
    popad                                   
                                       
    add dword ptr [esp],2 ; 修改Eip,略过除错指令(div eax)2个字节长,继续执行             
                                       
    iretd                                   
                                       
Ring0Code_div endp                              

myring0_prc_Trapgt  proc  far
    pushad         ;注意压栈结构为
    mov  ecx,10      ;esp->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
    pushfd
    pop eax 
    or eax,3000h 
    push eax
    popfd
    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    ;ebx=limit
    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         ; eax=free GDT entry selector
    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

  Ring0:
  mov ebx,cr3
  mov TestCR3,ebx
  iretd
END  __Start

posted on 2007-10-23 14:54 随风只幻 阅读(542) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理