1、無條件跳轉指令 JMP#
EIP(指針寄存器)
指向下一條將要執行的命令,執行完畢後,EIP 指向再下一條。EIP(指針寄存器)中的值會在每條指令執行後自動更新,指向下一條將要執行的指令的地址。匯編語言中的一些跳轉指令(例如 JMP、JE、JNE 等)可以修 EIP 的值,從而實現跳轉到指定地址處執行。
JMP A
指令當中,A 是程序作者期望的無條件轉向的一個內存地址。
jmp short 指令
JMP SHORT
指令是一個兩字節的短程跳轉指令,只能向前或者往回跳轉。第一個字節 EB 是跳轉操作碼 (OPCODE)。跳轉的方向由第二個字節的值確定。這種跳轉是有距離限制的。
顯示 jmp short 指令的機器碼
上圖中,EB 是 jmp 的操作碼,這條指令向前跳轉到指令結束後的 5 個字節,計算目標地址可以採用下圖的方式,指令的起始地址➕指令本身的長度(2 字節)➕第二個字節跳轉的距離(5 字節)。
計算跳轉位置
short 的跳轉距離:最大的正向跳轉距離是 0x7f。
注:ida 顯示機器碼
菜單欄 Options-General 設置,將 Number of opcode bytes (graph) 的值改為 12(10),默認位 0。
注:數據庫快照功能
逆向其間會對程序做些修改,會打斷已識別的函數,使用數據庫快照能夠返回之前某個時候的狀態,當遇到問題不知如何修復時,可以使用這個功能。
給快照命名
加載快照,View-Database snapshot manager
可以看到所有的快照清單以及創建的日期
實驗 2 將跳轉的第二個字節從 05 改成 7f
使用 ida patch byte 功能將 05 改成 7f
接下來將 0x7f 改為 0x80。
改為 0x80 後,程序往回跳轉,之前的 0x7f 是最遠的向前跳轉,那麼,0x80 是最遠的往後跳轉。
由於 python 不會從數值上判斷向前還是往後跳轉,必須輸入一個 dword 表示 - 0x80,也就是0xffffff80
,計算的結果和0xffffffff
進行按位與運算,超過 32 位的比特位會被清零,所以得到0x4012a6
這個值。
如果把 0xff 作為第二個字節的跳轉距離,這是一個最小跳轉距離 - 1,由上圖可知,最終跳到 0x401325,也就是跳轉了 1 個字節。
如果再往回多跳轉一個字節,指令的第二個字節改為 fe,最終會跳回起點位置,從而形成一個無限循環。
如果將第二個字節改為 fd,從指令的結尾往回跳轉 3 個字節,最終跳到 0x401323。
使用短跳轉只能在當前地址的附近跳轉,無法跳轉到所有的地址。所以程序會使用長跳轉。
上圖中顯示了一些長跳轉,圖中的 loc 表示那一條指令是一般指令。
上圖是一個長跳轉,0x4026ae 到 0x4029b3 的距離超過了短跳轉的作用範圍。
跳轉範圍計算公式位:終點指令起始地址 - 起點指令起始地址 - 5
5 是跳轉指令的長度,結果是 0x300,也就是長跳轉指令操作碼 E9 後面的 dword。
2、有條件跳轉指令#
CMP A,B #對A和B進行比較,根據比較結果進行不同的操作
條件跳轉指令
上圖中,CMP 對 eax、ebx 進行比較(寄存器相減),如果它們相等,那麼結果就是 0,就觸發了標誌寄存器(EFLAGS)中 Z 標記或者 zero 標記,JZ 指令檢測到這個標記然後進行跳轉。如果觸發 Z 標記,就會執行上圖中的綠色
箭頭路徑,如果沒有觸發,那麼就執行青色
箭頭路徑。
16 進制 | ASM | 描述 | |
---|---|---|---|
74 or 0F84 | JE | 等於則跳轉 | |
75 or 0F85 | JNE | 不等於則跳轉 | |
77 or 0F87 | JA | 大於則跳轉 | |
7C | JL | 小於則跳轉 | |
7D | JGE | 不小於則跳轉 | |
7E | JLE | 小於等於則跳轉 | |
7F | JG | 大於等於則跳轉 | |
80 | JO | 溢出則跳轉 | |
81 | JNO | 不溢出則跳轉 | |
82 | JB/JNAE | 低於則跳轉 | |
83 | JNB/JAE | 不低於則跳轉 | |
86 | JNA/JBE | 不大於等於則跳轉 | |
88 | JS | 符號為負則跳轉 | |
89 | JNS | 符號為正則跳轉 | |
8C | JL/JNGE | 小於則跳轉 | |
8D | JGE/JNL | 不小於則跳轉 | |
8E | JLE/JNG | 小於等於則跳轉 | |
8F | JG/JNLE | 大於等於則跳轉 |
除了 JMP 和 NOP 之外,剩餘的都是根據比較結果執行的條件跳轉指令。
3、CALL 和 RET 指令#
- CALL 指令用來調用一個函數。
- RET 指令用來返回調用這個函數的指令的下面一條指令處。
下圖中有一個 CALL 調用指令,程序將跳轉到0x4013d8
去執行這個函數。(在0x4013d8
這個地址前面的sub_
表示這裡是一個函數)CALL 指令會將返回的地址0x40123d
保存到棧上。
call 指令實例
雙擊這個函數,可以跳轉到如下位置,函數具體內容如下:
0x4013d8 函數具體內容
如上圖所示,函數執行完畢後執行 ret 指令,跳轉到棧上保存的返回地址 0x4012d 處,就是調用這個函數指令的下一條。
返回地址