9.2 符號檔案#
目標檔案:HOLA_REVERSER.exe
查看目標檔案架構:
目標檔案是 32 位程式,VC++ 2015 編譯。
雙擊執行程式,提示輸入數字
程式會判斷輸入的字元是否正確
9.3 定位 main 函數#
先看下字串
找到了目標程式執行時輸出的一些字串,雙擊上圖中紅線畫出來的。
來到如下位置:
上圖中,0x402108 是這個字串的位址,位址右側的 16 進制是機器碼,機器碼右側的 aPoneUnNumerito 是這個字串的標記或名稱,字串前面的 a 表示這是個 ascii 碼,後面的 db 表示這是個位元組序列。
按 D 鍵可以查看每一個位元組的值:
再按 A 鍵可以重新顯示成字串。
將滑鼠放置在右側引用的箭頭上,可以查看具體的引用位置,按 X 鍵可以進入具體的引用位置。
從這個引用就可以找到 main 函數。
9.4 函數的堆疊#
上述圖中有個局部變數 var_4,大小是 dword。
32 位函數呼叫堆疊視圖
首先所有的函數參數被傳入堆疊中,然後是返回位址,返回位址的上方是上一級函數 EBP,產生於函數的第一句指令PUSH EBP
,最上面的是局部變數。
9.5 Main 函數參數#
來到 main 函數處
按 X 鍵查看 main 函數是在哪裡被引用的。
main 函數呼叫
上圖中有三個 push 指令,通過這三個指令進行傳參,在三個指令的註釋中,可以了解到傳遞了三個參數,分別為 argc、argv 和 envp 等,是函數的預設參數。
9.6 局部變數#
var_c 是一個局部變數,按 X 鍵可以查看在哪裡被引用了,從下圖可知,有兩個地方引用了這個局部變數。
9.7 Atoi 函數#
atoi 函數將字串轉換為一個整數,如果因為數字太大導致無法轉換,會產生錯誤並且返回 0。當然如果比最小的負整數 (int) 還小,也會出錯返回 0,所有輸入的內容都會被轉換為一個整數。如果輸入 41424344,將會被轉換為一個十六進制數保存到 EAX。
#include <stdlib.h>
int atoi(const char *string);
通過上圖可以知道,目標程式會把所有輸入的字串轉換成整數。如果atoi
或者_wtoi
無法將輸入的內容轉換為日標類型將會返回 0。
atoi 返回值
eax 返回值傳給 esi,在輸出使用者輸入的原始字串後,esi 的值會和0x12457
比較,
使用者輸入的十進制數字字串會被解析並返回一個十六進制數,然後再與那個硬編值進行比較,如果輸入硬編值對應的十進制數,應該會成功。
上圖中用了 jnz 指令(不相等 / 不為 0),則輸出bad reverser
,如果相等,則輸出good reverser
。
0x124578
,16 進制轉成 10 進制為 1197432
在目標程式中,輸入這個十進制 1197432 ,可以看到成功驗證,輸出good reverser
。
目標程式分析也到這結束了,這一章學習了函數堆疊的逆向分析,包括函數如何傳參、局部變數和 atoi 函數等。