1、無条件ジャンプ命令 JMP#
EIP(ポインタレジスタ)
は次に実行される命令を指し、実行が完了すると EIP は次の命令を指します。EIP(ポインタレジスタ)内の値は、各命令の実行後に自動的に更新され、次に実行される命令のアドレスを指します。アセンブリ言語のいくつかのジャンプ命令(例えば JMP、JE、JNE など)は EIP の値を修正することができ、指定されたアドレスにジャンプして実行することができます。
JMP A
命令の中で、A はプログラム作者が期待する無条件ジャンプのメモリアドレスです。
jmp short 命令
JMP SHORT
命令は 2 バイトの短距離ジャンプ命令で、前方または後方にのみジャンプできます。最初のバイト EB はジャンプオペコード(OPCODE)です。ジャンプの方向は 2 番目のバイトの値によって決まります。このジャンプには距離制限があります。
jmp short 命令の機械語を表示
上の図では、EB は jmp のオペコードであり、この命令は命令の終了後 5 バイト前方にジャンプします。ターゲットアドレスを計算するには、下の図の方法を使用します。命令の開始アドレス➕命令自体の長さ(2 バイト)➕2 番目のバイトのジャンプ距離(5 バイト)。
ジャンプ位置の計算
short のジャンプ距離:最大の前方ジャンプ距離は 0x7f です。
注:ida は機械語を表示します
メニューバー Options-General 設定で、Number of opcode bytes (graph) の値を 12(10)に変更します。デフォルトは 0 です。
注:データベーススナップショット機能
逆アセンブル中にプログラムにいくつかの変更を加えると、既に認識された関数が中断されます。データベーススナップショットを使用すると、以前の状態に戻すことができ、問題が発生したときに修正方法がわからない場合にこの機能を使用できます。
スナップショットに名前を付ける
スナップショットをロードするには、View-Database snapshot manager を選択します。
すべてのスナップショットリストと作成日を確認できます。
実験 2 ジャンプの 2 番目のバイトを 05 から 7f に変更
ida の patch byte 機能を使用して 05 を 7f に変更します。
実験2 05を7fに変更
実験2 変更後のアセンブリビュー 上の図から、左側の矢印が示すように、プログラムはここで0x4013a5に前方ジャンプします。
次に 0x7f を 0x80 に変更します。
0x80 に変更すると、プログラムは後方にジャンプします。以前の 0x7f は最も遠い前方ジャンプであり、したがって 0x80 は最も遠い後方ジャンプです。
Python は数値から前方または後方のジャンプを判断しないため、-0x80 を表す dword を入力する必要があります。つまり、0xffffff80
です。計算結果は0xffffffff
とビットごとの AND 演算を行い、32 ビットを超えるビットはクリアされるため、0x4012a6
という値が得られます。
もし 0xff を 2 番目のバイトのジャンプ距離として使用すると、これは最小のジャンプ距離 - 1 であり、上の図からわかるように、最終的に 0x401325 にジャンプします。つまり、1 バイトジャンプしました。
さらに 1 バイト戻ると、命令の 2 番目のバイトを fe に変更すると、最終的に起点位置に戻り、無限ループが形成されます。
もし 2 番目のバイトを fd に変更すると、命令の末尾から 3 バイト戻ると、最終的に 0x401323 にジャンプします。
短距離ジャンプを使用すると、現在のアドレスの近くでのみジャンプでき、すべてのアドレスにジャンプすることはできません。したがって、プログラムは長距離ジャンプを使用します。
上の図にはいくつかの長距離ジャンプが表示されており、図の loc はその命令が一般的な命令であることを示しています。
上の図は長距離ジャンプであり、0x4026ae から 0x4029b3 までの距離は短距離ジャンプの作用範囲を超えています。
ジャンプ範囲計算公式は次のとおりです:終点命令の開始アドレス - 開始命令の開始アドレス - 5
5 はジャンプ命令の長さであり、結果は 0x300、つまり長距離ジャンプ命令のオペコード E9 の後の dword です。
2、条件ジャンプ命令#
CMP A,B # AとBを比較し、比較結果に基づいて異なる操作を実行
条件ジャンプ命令
上の図では、CMP は eax と ebx を比較します(レジスタの減算)。もしそれらが等しい場合、結果は 0 となり、フラグレジスタ(EFLAGS)の Z フラグまたはゼロフラグがトリガーされ、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 にジャンプします。これはこの関数を呼び出した命令の次の命令です。
戻りアドレス