1. 程式人生 > >堆溢位DWORD SHOOT原理

堆溢位DWORD SHOOT原理

1、雙向連結串列上有a、b、c一共3個連續的堆塊,a、b、c三者之間的實際實體地址可能相差很大,但是絕對不會三者之間無其他位元組,如果無其他位元組,那表示他們三個可以合併成一個物理連線起來的大塊,堆管理系統很快會讓他們三者搞基成一個大個子堆塊,拆下來重新按照其尺寸重新連結到該去的連結串列位置去。。。而不會放縱其在連結串列上實體地址緊密連結的同時還分成3個堆塊串聯在連結串列上。

2、返回正題,拆下其中一個堆塊b時,會產生a、c之間的空缺,導致a、c無法相互知曉。所以堆管理系統會在拆b時,把a和c縫縫補補,連在一起,成為新連結串列,等待下次拆分、合併等等。

  關鍵來了,

  【1】雙向連結串列上a與b之間有從左往右的一條線(這條線體現在:每個堆塊都在距離自身堆塊塊首的相對第9~12位元組儲存他前方那個堆塊(遠離連結串列頭的方向)的塊資料的地址)連起來.前邊8個位元組是堆首部記憶體

  【2】又有從右往左的一條線連起來(這條線體現在:每個堆塊都在距離自身堆塊塊首相對13~16位元組處儲存他屁股後面那個堆塊(當前堆塊屁股位置是靠近連結串列頭地址的那邊)的塊資料的地址);

  以此類推每2個相鄰堆塊之間由於雙向可循,由於每個堆塊上都記載著往該塊左邊或右邊方向走的下一個地址(即上述9~12、13~16位元組資料均為地址值),所以斷掉一個塊(暫稱為塊b)時,該斷掉的塊的左右兩邊欲形成新連線,必須知道彼此的地址。這個重新知曉相互地址的任務由即將被拆下來的堆塊去處理,因為它才同時熟悉兩邊的鄰居,知道他們地址,知道他們聯絡電話,QQ號,微訊號。。。於是該堆塊(又叫節點)把他身上距離頭頂第9~12位元組的4個位元組的資料(實際上是他右鄰居堆塊的門牌號地址,舉例0x001A0038)抄下來,給到左鄰居。怎麼給?在他身上距離頭頂第13~16位元組處的4個位元組,就是他左鄰居的門牌號地址(這個資料肯定比他右鄰居的門牌號地址小,假設0x001A000A),我們於是按照這個左鄰居地址,在堆管理系統幫助下,把0x001A0038這個數值給到左鄰居家去:mov [0x001A000A],0x001A0038    。。。。都知道[]方括號的意思吧。等右鄰居的地址給了左鄰居後,再把左鄰居的地址按此方法給到右鄰居,他此時也就從連結串列上斷下來了,因為空錶鏈表上已經沒有他存在的痕跡了。

  而這個斷掉塊b過程之前,我們先通過字串變數溢位,將字串從其他塊溢位到塊b中,即覆蓋了他的第9~16位元組資料,效果就是改了他身上所保管的左、右鄰居門牌號地址,一般就是右鄰門牌號覆蓋為shellcode入口地址,左鄰門牌號覆蓋為各種特殊地址,比如重要函式呼叫地址,棧幀中函式返回地址,棧幀中SEH的控制代碼。這樣,在塊b斷下來時,他會把shellcode地址賦值到某個經常呼叫的函式的地址上,或棧幀中當前函式返回地址上,或棧幀中距離當前棧最近的SEH異常處理最近的那個控制代碼。

  然後堆塊這邊就沒他們什麼事了,就等著某個函式被呼叫,錯誤跳轉到shellcode地址去執行我們構造的code;等著棧幀中當前函式返回時執行的卻是跳轉到shellcode地址去執行我們構造的code;溢位發生了導致系統啟動異常處理,執行了SEH異常處理相關函式,跳轉到shellcode地址去執行我們構造的code。。。。。。

  溢位並惡意執行了我們的程式碼。

  現在回頭去看,堆塊斷下來時,把錯誤的右鄰居門牌號(子彈,shellcode入口地址,共計4個位元組,即為DWORD雙字),抄給左鄰居時(左鄰居的地址已經被改為目標地址,任何能被呼叫的地址),就是發生了子彈射擊,DWORD Shoot是也。

   至於後面的把左鄰居地址給右鄰居地址的操作,會發生指標反射現象,從而改寫shellcode的4位元組,但很多情況下4個位元組的地址處理器會當做“無關痛癢”的指令安全執行過去。