SCTF-2014 misc100 writeup(賽後分析)

wKiom1SL0sXh7uooAACSbf0skt8098.jpg

下載文件後,file命令看一下是ELF32程序,strings命令發現程序被UPX加殼了。

upx -d snake-final.exe

脫殼後扔到IDA裏面分析,主函數發現調用signal註冊了若干個回調函數:

wKiom1SL3JfiJCVHAAMVb8TCdSE916.jpg

特別是幾個38h、32h、34h、36h。實際上是定義了4個控制貪吃蛇行動的遊戲按鍵。但顯然就這個程序,按對應的鍵是產生不出對應的signal信號的。(有隊伍使用向進程發送對應signal的方式,間接操控貪吃蛇,遊戲成功可以獲得flag)。經過進一步分析,發現最重要的回調函數是handler,同時在handler中存在"int 3"反調試,正常執行的時候會產生signal==5的信號,這裏的處理函數爲nullsub_1。實際上就是忽略,所以我們也可以直接 nop 掉 int 3。當然完全按照本文的靜態分析方法,而不使用調試,完全可以忽略 int 3。

進一步分析handler,發現是一個極其複雜的函數。沒心思看,找找有沒有別的入口。

strings窗口發現"Mission Complete",xref發現這個字符串引用位置sub_80492E0+14C。

分析sub_80492E0:

wKioL1SL2c-RUcRwAAIQb2QwU8I103.jpg

這個函數確實是判斷遊戲成功與否的標誌,成功的話,還需要判斷一個ebx == 3,這裏的ebx實際上是函數的傳入參數。但問題是,找到成功的標誌,但是後面沒有跟着輸出flag的地方,而僅僅是調用settimer重置了新的信號量。這樣程序的執行流又回到handler裏面。

根據目前的信息,尋找帶參數3調用sub_80492E0的地方,xref只發現兩處8049941、8049FF1。實際上這兩處的代碼是一樣的(經過最後的分析實際上這裏往後的代碼就是輸出flag的地方,但我在這裏迷失了很久)。比較奇怪的是這兩處都不在IDA識別的handle函數的作用域中。原因是IDA識別出了handler函數的Canary保護機制,以此作爲handler函數的開始和結束。

進一步分析handler發現:

wKiom1SL4IrBG9WfAAFy171R1mE002.jpg

原來成功吃到30個食物成功後,是通過C++異常處理機制來調用sub_80492E0( 3 )的。

通過上面查找xref的兩個地方,隨便選取第二個,看到調用代碼:

wKioL1SL4naidfCiAAGgnOUVw3A868.jpg

由於sub_80492E0裏面沒有顯示flag的地方,只是重置settimer,那麼猜測很有可能flag也是通過異常處理鏈來打印的。上面的代碼發現,調用sub_80492E0後,重新拋出了一個異常。所以繼續觀察下面的代碼:

wKiom1SL4-rzzLQJAAKdjnlOFe0947.jpg

這裏注意804A039處的一個比較,這是在打印flag前的異常處理鏈中的最後一道門檻。也是調試時候爲什麼sub_80492E0已經運行到"Mission Complete",但還是沒有出現flag的原因。

wKiom1SL5DLDBRT2AAFSVJuwZnQ673.jpg

wKioL1SL5c_Sey2MAAPhaEUDdkg326.jpg

wKioL1SL5dyDo1A1AAGBv3nYrLg299.jpg

注意這裏的一個循環,實際上就是printf "[ebp-50+i] xor 2Ah"。(2Ah是ascii的'*')

import sys
a='\x7f\x1a\x64\7f\x78\x44\x5e\x50\x67\x7d\x4e\x5f'
for i in range(0, len(a)):
    sys.stdout.write(chr(ord(a[i]) ^ ord('*')))

得到:U0N-LRntzMWdu

這個還沒有完,繼續往下看:

wKioL1SL6PeA1UL-AAHIEkHq5kw587.jpg

wKiom1SL6G7BuZ1XAAHlx20assk918.jpg

可見flag還有兩部分,其中[ebp-84h]就是handler函數開始處的值(說明異常處理實際上還是應該在handler當中的,只是IDA分析的使用因爲canary的原因,被排除了):

wKioL1SL6bqzUhrlAAEmr9_0vDI437.jpg

最後一部分的數據是804C0C0處的全局數據,三部分的算法是一樣的,最後解碼得到:

U0NURntzMWduNGxfMXNfZnVubnk6KX0=

echo 
U0NURntzMWduNGxfMXNfZnVubnk6KX0= | base64 -d


得到flag。



後記:

此題看360首發的sctf writeup上,只講了"Mission Complete"和sub_80492E0,然後就直接base64字符串了,不知道那位大神是如何“看”出來的。

C++的throw--catch的逆向分析是頭一回遇到,還是應該寫一個簡單的C++相應程序,然後逆向研究一下它的結構。這樣才知道handler裏面canary和異常處理是人爲的有意爲之,還是編譯器本來就是這樣處理的。

由於信號量的處理有線程再入的特點,異常也會涉及到跨線程的問題,所以程序流程要完全研究透徹,需要理解的內容非常多。有待進一步學習。

這個題目如果調試,如果跟蹤到異常處理的代碼,還請大牛不吝賜教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章