CSAPP 深入理解計算機系統課程實驗 bomb實驗 反向編譯 彙編(4)
隱藏關卡。Secretphase
這個隱藏關卡還是很難發現的,自己帶的班上的學生中,僅有3個學生髮現並解除了炸彈。中間也出現了一些小小問題,在給他們驗收的時候也有意識的去引導他們發現一些小問題,並討論解決。
首先是隱藏關卡的發現,其實在彙編程式碼中就有一個secret_phase.就是看怎麼跳到隱藏關卡了,搜尋發現,是通過phase_defused作為入口點的。其實這裡可以不分析這個函式,看到在main函式中沒通關一關就會呼叫這個函式,可以在這個函式中設定斷點,可以直接利用jump跳到隱藏關卡去做。後面分析這個函式也會發現為什麼每次通過一關它會呼叫,大概是用來比較一下你是否已經全部通關吧。
接下來是常規的進入隱藏關卡:
Phase_defused的彙編程式碼分析一下:
這裡是首先判斷一下是否已經通過了六個關卡。
接下來是sscanf函式的呼叫,在這裡有三個ebp的偏移,按照以前通關的經驗分析,應該是要輸入三個東西,輸入的格式規定在立即數0x804a200中檢視,另外呼叫之後的返回值可以發現確實如果輸入的小於3就不會進入隱藏關卡。關於sscanf函式一直猜測它的返回值就是輸入的個數,沒有具體進入去看,但是中間在某一關中輸入了123456這6個數,查看了返回值eax居然是2,但是在這裡卻可以返回大於3的數,所以這個函式也是很有意思的,不像我們猜測的那麼簡單,但是並不影響我們解除炸彈,我們分析這個sscanf函式應該是根據不同的情況返回不同範圍的值,不是具體個數的值,有興趣的朋友可以自己深入研究一下。
通過gdb除錯看看立即數裡面的輸入的格式,首先先在phasedefused函式中的0x804959處設定斷點,是要將全部六個關卡都通過後,跳到斷點處。
看到確實是輸入三個東西,其中前兩個是兩個數字,最後一個是一個字串
再接著就是看到呼叫了string_not_equal這個函式,呼叫之前先傳參,可以看到,一個是從一個立即數0x804a209中傳入的,另外一個則是通過sscanf輸入的引數傳入的,比較它們要相同才會跳入。
把裡面涉及的立即數都給檢視一下
可以看到8 1 非常熟悉,就是第四關我們輸入的數,可以看到應該就是在第四關的時候除了輸入一個8 1之外還在額外輸入一個字串 DrEvil(涉及這個實驗的一個博士)就會輸出後面那串你發現了隱藏關卡的提示資訊。在這裡我問班上有一個做了的同學,我說第四關中有幾個答案,除了8,1之外還有9,1和11,1,那這樣設計不是不合理了啊,輸入其他答案的同學必須要用8,1才可以跳。那個同學點點頭。其實並不是這樣的,字串比較的時候,傳遞的引數是-0x5c(%ebp)正好是對應的後面輸入的那串字串,所以前面已經判斷你已經通過所有關卡了,這裡只要判斷你在第四關有沒有輸入這個字串。所以只要輸入了那三組中其中任一組再加那個字串就可以通過了。所有的猜想都可以通過除錯檢視內容來驗證一下,接下來就來驗證一下,首先現在第四關輸入9,1和DrEvil。
輸入之後發現果然是這樣的。然後進一步看一下每個地方存的是些什麼內容。
這樣看到傳入到string_no_equal的引數確實只是後面的字串
接下來就要來看看隱藏關中的內容了,
首先是棧的一系列操作,然後對輸入的值進行strtol函式的呼叫stringtolong也就是轉換為長整型,而且根據比較可知輸入的值減1後要小於等於0x3e8。
接下來可以看到是呼叫了fun7,呼叫前先傳入引數,可以看到第一個引數是立即數0x804c178中的內容,第二個引數是我們輸入的值經過前面的出後的值。看到呼叫完fun7後的返回值要等於5.
用gdb除錯看一下,立即數裡面的內容:是一個$符號,對應的ASCII值為36
看到該關主要就是分析fun7呼叫以後返回值如何是5,接下來就來分析一下fun7這個函式的彙編程式碼。
首先是棧操作
看出將出入的引數賦值給暫存器,edx,設edx中存的是x,第一次的時候x=36,第二個引數賦值給ecx暫存器中,設為y。
第一種情況,將eax賦值為-1,如果edx中的值為x=0就返回為-1;接下來看第二種情況,
如果x>y,看到後面又呼叫了fun7看出來fun7是一個遞迴函式,在前面關卡中我們也遇到過,呼叫之前要傳遞引數,將edx偏移0x4再次作為第一個引數x,輸入的y作為第二個引數。返回值是做了乘以2的操作。接下來是x==y的情況:
這種情況下,返回值為0。
再看x<y的情況:
這種情況下,也是要遞迴呼叫fun7函式,傳入的第一個引數變成了edx偏移0x8.第二個引數與為y,返回值為2eax+1.
由於分析返回值必須為5,則只有第三種情況,所以5=4+1(case3),eax=2,2=2*1(case1),所以eax要等於1,1=2*0+1(case3),eax=0(case2)。由於遞迴呼叫是從最裡面返回的。最裡面返回值應該為0.外層遞迴呼叫也是case3-case1-case3-case2。不同的是,case3,edx偏移0x8,case1,edx偏移0x4.
按照上面的分析,那麼我們輸入的數應該就是edx經過(case3-case1-case3-case2)一系列偏移後的值:
由圖可知輸入的數為0x2f轉換為十進位制就是47也就是這一關的金鑰。
其實後來跟班上同學探討了一下,發現這個題應該是一個二叉查詢樹。小於的在一邊加0x4,大於的時候在右邊加0x8. 就是說輸入的是47,比36大,右邊走,比50小左邊走,又比45大右邊走,最後找到了47相等。
至此通過全部關卡: