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
實驗2 將05修改位7f
實驗2 修改後的匯編視圖 從上圖可以看出左側的箭頭,程序在這裡向前跳到0x4013a5。
接下來將 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 處,就是調用這個函數指令的下一條。
返回地址