在無法使用ESP定律時—EBP的妙用
互聯網 發(fā)布時間:2008-10-08 19:03:28 作者:佚名
我要評論

在寄存器里面有很多寄存器雖然他們的功能和使用沒有任何的區(qū)別,但是在長期的編程和使用中,在程序員習慣中已經默認的給每個寄存器賦上了特殊的含義,比如:EAX一般用來做返回值,ECX用于記數等等。在win32的環(huán)境下EBP寄存器用與存放在進入call以后的ESP的值,便于退出的
在寄存器里面有很多寄存器雖然他們的功能和使用沒有任何的區(qū)別,但是在長期的編程和使用中,在程序員習慣中已經默認的給每個寄存器賦上了特殊的含義,比如:EAX一般用來做返回值,ECX用于記數等等。在win32的環(huán)境下EBP寄存器用與存放在進入call以后的ESP的值,便于退出的時候回復ESP的值,達到堆棧平衡的目的。
應用以前說過的一段話:
原程序的OEP,通常是一開始以 Push EBP 和MOV Ebp,Esp這兩句開始的,不用我多說大家也知道這兩句的意思是以EBP代替ESP,作為訪問堆棧的指針。
為什么要這樣呢?為什么幾乎每個程序都是的開頭能?因為如果我們寫過C等函數的時候就應該清楚,程序的開始是以一個主函數main()為開始的,而函數在訪問的過程中最重要的事情就是要確保堆棧的平衡,而在win32的環(huán)境下保持平衡的辦法是這樣的:
1.讓EBP保存ESP的值;
2.在結束的時候調用
mov esp,ebp
pop ebp
retn
或者是
leave
retn
兩個形式是一個意思。
這樣做的好處是不用考慮ESP等于多少,PUSH了多少次,要POP多少次了,因為我們知道EBP里面放的是開始時候的ESP值。
2.推廣的ESP定律
在尋找OEP的時候,往往下斷HW ESP-4不成功,除了殼代碼將硬件斷點刪除了以外,很可能的情況就是因為殼代碼在運行到OEP的時候他的ESP已經不再是在EP時候的ESP(12FFC4)了,這樣我們下斷當然是不成功的。
那么如何找到在殼到達OEP的時候的堆棧的值將是關鍵。
在這里我們應用的關鍵是
Push EBP
MOV Ebp,Esp----》關鍵是這句
我來解釋一下,當程序到達OEP的時候Push EBP這句對于ESP的值來說就是ESP-4,然后是ESP-4賦給了EBP,而做為保存ESP值作用的EBP寄存器在這個“最上層的程序”中的值將始終不會改變。雖然他可能在進入子call里面以后會暫時的改變(用于子程序的堆棧平衡)但是在退出了以后依*pop ebp這一句將還原原來的EBP的值。
以這句做為突破口,就是說只要我們能斷在“最上層的程序”中,就能通過觀察EBP的值得到殼在JMP到OEP的時候的ESP的值了。
3.實戰(zhàn)
來看看pespin1.1的殼,在pespin1.0的殼中,我們使用HW 12FFC0能很容易的找到stolen code的地方,但是到pespin1.1的時候,我們就不行了。用HW 12FFC0根本斷不下來。
現在我們就使用這個推廣的ESP定律,載入程序后來到最后的一個異常
0040ED85 2BDB sub ebx,ebx //停在這里
0040ED87 64:8F03 pop dword ptr fs:[ebx]
0040ED8A 58 pop eax
0040ED8B 5D pop ebp
0040ED8C 2BFF sub edi,edi
0040ED8E EB 01 jmp short pespin1_.0040ED91
0040ED90 C466 81 les esp,fword ptr ds:[esi-7F]
我用使用內存斷點辦法來到FOEP處
004010D3 0000 add byte ptr ds:[eax],al
004010D5 0000 add byte ptr ds:[eax],al
004010D7 0000 add byte ptr ds:[eax],al
004010D9 0000 add byte ptr ds:[eax],al
004010DB 0000 add byte ptr ds:[eax],al
004010DD 0000 add byte ptr ds:[eax],al
004010DF 75 1B jnz short pespin1_.004010FC //這里是FOEP
004010E1 56 push esi
004010E2 FF15 99F44000 call dword ptr ds:[40F499]
004010E8 8BF0 mov esi,eax
004010EA 8A00 mov al,byte ptr ds:[eax]
好了,這里就是“最上層的程序”的地方了,看看寄存器
EAX 00141E22
ECX 0040C708 pespin1_.0040C708
EDX 0040C708 pespin1_.0040C708
EBX 0040C708 pespin1_.0040C708
ESP 0012F978
EBP 0012F9C0 //注意這里
ESI 00141EE0
EDI 0040E5CD pespin1_.0040E5CD
EIP 004010DF pespin1_.004010DF
看到了吧,EBP=0012F9C0,我們來想象一下這個值是怎么得到的。
首先肯定是通過MOV ESP,EBP這一句,也就是說ESP這時是0012F9C0的,然而上面還有一句PUSH EBP也就是說ESP在到達OEP的時候應該是0012F9C4的。好了得到這個結論我們就能很快的找到stolen code的所在了。
重來停在最后的異常
0040ED85 2BDB sub ebx,ebx //停在這里
0040ED87 64:8F03 pop dword ptr fs:[ebx]
0040ED8A 58 pop eax
0040ED8B 5D pop ebp
0040ED8C 2BFF sub edi,edi
0040ED8E EB 01 jmp short pespin1_.0040ED91
0040ED90 C466 81 les esp,fword ptr ds:[esi-7F]
然后下斷HW 0012F9C0 ,F9運行,來到這里
0040D8FB 61 popad
0040D8FC 55 push ebp
0040D8FD EB 01 jmp short pespin1_.0040D900 //停在這里
0040D8FF 318B ECEB01AC xor dword ptr ds:[ebx AC01EBEC],ecx
0040D905 83EC 44 sub esp,44
0040D908 EB 01 jmp short pespin1_.0040D90B
0040D90A 72 56 jb short pespin1_.0040D962
0040D90C EB 01 jmp short pespin1_.0040D90F
0040D90E 95 xchg eax,ebp
0040D90F FF15 6CF34000 call dword ptr ds:[40F36C]
0040D915 EB 01 jmp short pespin1_.0040D918
于是就很快的找到了stolen code的所在了。
4.總結
上面的這個辦法大概可以總結以下的步驟:
(1).直接或間接的斷在“最上層的程序”的地方。
(2).得到“最上層的程序”的EBP的值。
(3).利用程序初始化的兩個固定語句找到殼JMP到OEP的堆棧值。這個辦法有很大的局限性,因為只有VC和delphi程序使用這個初始化的開頭。
但是找到“最上層的程序”的辦法除了內存斷點還有很多辦法,例如對于VC來說使用 bp ExitProcess也是一個很好的斷點,可以直接得到EBP的數值。
5.后話
原來這個辦法有很強的前提條件,不是一個很具普遍性的辦法,我原來也不想單獨的提出來,但是對于jney2兄弟的anti-ESP定律來說這個辦法卻是一個解決之道。
當然還有更多的辦法,在這里我只想說很多事情有矛就有盾,沒有什么辦法是一定沒有漏洞的,只是希望這篇文章給大家闊寬思路,起到拋磚引玉的作用。
應用以前說過的一段話:
原程序的OEP,通常是一開始以 Push EBP 和MOV Ebp,Esp這兩句開始的,不用我多說大家也知道這兩句的意思是以EBP代替ESP,作為訪問堆棧的指針。
為什么要這樣呢?為什么幾乎每個程序都是的開頭能?因為如果我們寫過C等函數的時候就應該清楚,程序的開始是以一個主函數main()為開始的,而函數在訪問的過程中最重要的事情就是要確保堆棧的平衡,而在win32的環(huán)境下保持平衡的辦法是這樣的:
1.讓EBP保存ESP的值;
2.在結束的時候調用
mov esp,ebp
pop ebp
retn
或者是
leave
retn
兩個形式是一個意思。
這樣做的好處是不用考慮ESP等于多少,PUSH了多少次,要POP多少次了,因為我們知道EBP里面放的是開始時候的ESP值。
2.推廣的ESP定律
在尋找OEP的時候,往往下斷HW ESP-4不成功,除了殼代碼將硬件斷點刪除了以外,很可能的情況就是因為殼代碼在運行到OEP的時候他的ESP已經不再是在EP時候的ESP(12FFC4)了,這樣我們下斷當然是不成功的。
那么如何找到在殼到達OEP的時候的堆棧的值將是關鍵。
在這里我們應用的關鍵是
Push EBP
MOV Ebp,Esp----》關鍵是這句
我來解釋一下,當程序到達OEP的時候Push EBP這句對于ESP的值來說就是ESP-4,然后是ESP-4賦給了EBP,而做為保存ESP值作用的EBP寄存器在這個“最上層的程序”中的值將始終不會改變。雖然他可能在進入子call里面以后會暫時的改變(用于子程序的堆棧平衡)但是在退出了以后依*pop ebp這一句將還原原來的EBP的值。
以這句做為突破口,就是說只要我們能斷在“最上層的程序”中,就能通過觀察EBP的值得到殼在JMP到OEP的時候的ESP的值了。
3.實戰(zhàn)
來看看pespin1.1的殼,在pespin1.0的殼中,我們使用HW 12FFC0能很容易的找到stolen code的地方,但是到pespin1.1的時候,我們就不行了。用HW 12FFC0根本斷不下來。
現在我們就使用這個推廣的ESP定律,載入程序后來到最后的一個異常
0040ED85 2BDB sub ebx,ebx //停在這里
0040ED87 64:8F03 pop dword ptr fs:[ebx]
0040ED8A 58 pop eax
0040ED8B 5D pop ebp
0040ED8C 2BFF sub edi,edi
0040ED8E EB 01 jmp short pespin1_.0040ED91
0040ED90 C466 81 les esp,fword ptr ds:[esi-7F]
我用使用內存斷點辦法來到FOEP處
004010D3 0000 add byte ptr ds:[eax],al
004010D5 0000 add byte ptr ds:[eax],al
004010D7 0000 add byte ptr ds:[eax],al
004010D9 0000 add byte ptr ds:[eax],al
004010DB 0000 add byte ptr ds:[eax],al
004010DD 0000 add byte ptr ds:[eax],al
004010DF 75 1B jnz short pespin1_.004010FC //這里是FOEP
004010E1 56 push esi
004010E2 FF15 99F44000 call dword ptr ds:[40F499]
004010E8 8BF0 mov esi,eax
004010EA 8A00 mov al,byte ptr ds:[eax]
好了,這里就是“最上層的程序”的地方了,看看寄存器
EAX 00141E22
ECX 0040C708 pespin1_.0040C708
EDX 0040C708 pespin1_.0040C708
EBX 0040C708 pespin1_.0040C708
ESP 0012F978
EBP 0012F9C0 //注意這里
ESI 00141EE0
EDI 0040E5CD pespin1_.0040E5CD
EIP 004010DF pespin1_.004010DF
看到了吧,EBP=0012F9C0,我們來想象一下這個值是怎么得到的。
首先肯定是通過MOV ESP,EBP這一句,也就是說ESP這時是0012F9C0的,然而上面還有一句PUSH EBP也就是說ESP在到達OEP的時候應該是0012F9C4的。好了得到這個結論我們就能很快的找到stolen code的所在了。
重來停在最后的異常
0040ED85 2BDB sub ebx,ebx //停在這里
0040ED87 64:8F03 pop dword ptr fs:[ebx]
0040ED8A 58 pop eax
0040ED8B 5D pop ebp
0040ED8C 2BFF sub edi,edi
0040ED8E EB 01 jmp short pespin1_.0040ED91
0040ED90 C466 81 les esp,fword ptr ds:[esi-7F]
然后下斷HW 0012F9C0 ,F9運行,來到這里
0040D8FB 61 popad
0040D8FC 55 push ebp
0040D8FD EB 01 jmp short pespin1_.0040D900 //停在這里
0040D8FF 318B ECEB01AC xor dword ptr ds:[ebx AC01EBEC],ecx
0040D905 83EC 44 sub esp,44
0040D908 EB 01 jmp short pespin1_.0040D90B
0040D90A 72 56 jb short pespin1_.0040D962
0040D90C EB 01 jmp short pespin1_.0040D90F
0040D90E 95 xchg eax,ebp
0040D90F FF15 6CF34000 call dword ptr ds:[40F36C]
0040D915 EB 01 jmp short pespin1_.0040D918
于是就很快的找到了stolen code的所在了。
4.總結
上面的這個辦法大概可以總結以下的步驟:
(1).直接或間接的斷在“最上層的程序”的地方。
(2).得到“最上層的程序”的EBP的值。
(3).利用程序初始化的兩個固定語句找到殼JMP到OEP的堆棧值。這個辦法有很大的局限性,因為只有VC和delphi程序使用這個初始化的開頭。
但是找到“最上層的程序”的辦法除了內存斷點還有很多辦法,例如對于VC來說使用 bp ExitProcess也是一個很好的斷點,可以直接得到EBP的數值。
5.后話
原來這個辦法有很強的前提條件,不是一個很具普遍性的辦法,我原來也不想單獨的提出來,但是對于jney2兄弟的anti-ESP定律來說這個辦法卻是一個解決之道。
當然還有更多的辦法,在這里我只想說很多事情有矛就有盾,沒有什么辦法是一定沒有漏洞的,只是希望這篇文章給大家闊寬思路,起到拋磚引玉的作用。
相關文章
- “CMOS密碼”就是通常所說的“開機密碼”,主要是為了防止別人使用自已的計算機,設置的一個屏障2023-08-01
QQScreenShot之逆向并提取QQ截圖--OCR和其他功能
上一篇文章逆向并提取QQ截圖沒有提取OCR功能, 再次逆向我發(fā)現是可以本地調用QQ的OCR的,但翻譯按鈕確實沒啥用, 于是Patch了翻譯按鈕事件, 改為了將截圖用百度以圖搜圖搜索.2023-02-04- QQ截圖是我用過的最好用的截圖工具, 由于基本不在電腦上登QQ了, 于是就想將其提取出獨立版目前除了屏幕錄制功能其他都逆出來了, 在此分享一下2023-02-04
非系統分區(qū)使用BitLocker加密導致軟件無法安裝的解決方法
很多電腦用戶在考慮自己電腦磁盤分區(qū)安全時會采用 Windows 自帶的 BitLocker 加密工具對電腦磁盤分區(qū)進行加密。但有些人加密后就會忘記自己設置的密碼從而導致在安裝其它軟2020-11-25防止離職員工帶走客戶、防止內部員工泄密、避免華為員工泄密事件的發(fā)生
這篇文章為大家詳細介紹了如何才能防止離職員工帶走客戶、防止內部員工泄密、避免華為員工泄密事件的發(fā)生,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-27徹底防止計算機泄密、重要涉密人員離職泄密、涉密人員離崗離職前防范舉
近些年企業(yè)商業(yè)機密泄漏的事件屢有發(fā)生,這篇文章主要教大家如何徹底防止計算機泄密、重要涉密人員離職泄密、告訴大家涉密人員離崗離職前的防范舉措,具有一定的參考價值,2017-06-27- 最近有電腦用戶反應量子計算機可以破解下載的所有的加密算法嗎?其實也不是不可以,下面虛擬就為大家講解買臺量子計算機,如何分分鐘破解加密算法2016-09-26
怎么破解Webshell密碼 Burpsuite破解Webshell密碼圖文教程
webshell是以asp、php、jsp或者cgi等網頁文件形式存在的一種命令執(zhí)行環(huán)境,一種網頁后門。黑客通常會通過它控制別人網絡服務器,那么怎么破解webshell密碼呢?一起來看看吧2016-09-19- 本文討論了針對Linux系統全盤加密的冷啟動攻擊,大家都認為這種攻擊是可行的,但執(zhí)行這么一次攻擊有多難?攻擊的可行性有多少呢?需要的朋友可以參考下2015-12-28
防止泄露公司機密、企業(yè)數據防泄密軟件排名、電腦文件加密軟件排行
面對日漸嚴重的內部泄密事件,我們如何守護企業(yè)的核心信息,如何防止內部泄密也就成了擺在各個企業(yè)領導面前的一大問題。其實,針對內網安全,防止內部信息泄漏早已有了比較2015-12-17