.上節說的是單步跟蹤法,這節講的是利用堆棧平衡(ESP定律)來進行脫殼!想必大家都聽說過ESP定律這個大名吧!ESP定律運用的就是堆棧平衡原理!
一般的加殼軟件在執行時,首先要初始化,保存環境(保存各個寄存器的值),一般利用PUSHAD(相當於把eax,ecx,edx,ebx,esp,ebp,esi,edi都壓棧),當加殼程序的外殼執行完畢以后,再來恢復各個寄存器的內容,通常會用POPAD(相當與把eax,ecx,edx,ebx,esp,ebp,esi,edi都出棧),通過跨區段的轉移來跳到程序的OEP來執行原程序!
在脫殼的時候,我們可以根據堆棧平衡來對ESP進行下斷,進而快速到達OEP!
我們用OD來載入上節課加了UPX的殼的Delphi7.0的程序,當單步過pushad以后,會把各個寄存器的值壓入堆棧中!
004629D0 > 60 PUSHAD // 把所有的寄存器壓棧!
004629D1 BE 00F04300 MOV ESI,0043F000
004629D6 8DBE 0020FCFF LEA EDI,DWORD PTR DS:[ESI+FFFC2000]
這個為寄存器窗口各個寄存器的值:
這個為沒有步過pushad語句的堆棧窗口的值:
這個為步過pushad語句的堆棧窗口的值:
很明顯,經過pushad語句以后,所有的寄存器的值都進行了壓棧,也就是保存環境!
此時的ESP指向是 0012FF6C,我們來對它下硬件訪問斷點,我們在寄存器窗口,右鍵==》數據窗口跟隨,在數據窗口的前四個字節,下硬件訪問斷點 ==》 dword斷點!
按F9運行程序,外殼代碼處理結束以后,調用popad指令來恢復環境,在訪問這些堆棧的時候,會被OD捕獲並中斷下來,此時,已經離程序的OEP不再遙遠了!
00462B75 61 POPAD
00462B76 8D4424 80 LEA EAX,DWORD PTR SS:[ESP-80] ; 斷在了這里
00462B7A 6A 00 PUSH 0
00462B7C 39C4 CMP ESP,EAX
00462B7E ^ 75 FA JNZ SHORT 00462B7A
00462B80 83EC 80 SUB ESP,-80
00462B83 ^ E9 109FFEFF JMP 0044CA98 //經過上節的分析,得知這個跨區段的轉移是跳向OEP的!
ESP定律不一定非得在ESP的值為0012FFA4的時候才能運用,合理的運用會使脫殼變得很簡單!再告訴大家一個經驗吧!ESP定律不只是適用於壓縮殼,ESP定律靈活的運用,同樣的適用於加密殼(類似VMP等!)。下面我引用看雪論壇的Lenus在他的廣義ESP定律里說過的幾句話(順便PS下,我把堆棧平衡原理放到了附錄):
“ 首先,告訴你一條經驗也是事實---當PE文件運行開始的時候,也就是進入殼的第一行代碼的時候。寄存器的值總是上面的那些值,不信你自己去試試!而當到達OEP后,絕大多的程序都第一句都是壓棧!(除了BC編寫的程序,BC一般是在下面幾句壓棧)
現在,根據上面的ESP原理,我們知道多數殼在運行到OEP的時候ESP=0012FFC4。這就是說程序的第一句是對0012FFC0進行寫入操作!
最后我們得到了廣義的ESP定律,對只要在0012FFC0下,硬件寫入斷點,我們就能停在OEP的第二句處! ”
附下載版文章:
http://www.2cto.com/uploadfile/2012/1205/20121205071227412.zip