IDA デバッガの選択#
ida は複数のデバッガをサポートしています。
ida がサポートするデバッガ
Local Windows debugger デバッガを選択します。
メニューバーのデバッガ - デバッガオプションを開くと、いくつかのデバッガの機能を設定できます。
ida デバッガオプション
デバッガインターフェース機能#
プロセスエントリポイントを一時停止
にチェックを入れ、イベント条件を選択し、OK をクリックします。
以前の重要なコード jinx の名前を変更し、色を変更します。
変更後は以下のようになります。X キーを押して、この関数がどこで参照されているかを確認します:
参照ポイントに色を付けます。
0x00401243 でブレークポイントを設定し、この行にマウスを置き、右クリック - ブレークポイントを追加します。ブレークポイントを追加すると、赤い背景に変わります。
メニューバーのデバッガ - プロセスを開始(F9)
を使用してデバッグを開始します。ローカルで実行可能ファイルをデバッグすると、以下の警告ウィンドウが表示されます。
注:
ローダーがプログラムを分析しているとき、プログラムはローカルで実行されませんが、デバッグは異なります。プログラムがウイルスや他の危険なマルウェアである場合は、特に注意が必要です。この場合、リモートデバッガ(REMOTE DEBUGGER)を使用して仮想マシン内でプログラムを実行する必要があります。
はい
をクリックしてデバッグを続行します。
デバッガがエントリポイントで一時停止するように設定したため、以下の図のように、ida はエントリポイント(0x00401000)で一時停止します。
右上の汎用レジスタとフラグレジスタウィンドウを調整して、表示を確認します。
上の図では、これらのレジスタの値を見ることができます。正常に調整した後、メニューバーのウィンドウ - デスクトップを保存
を開き、default
オプションにチェックを入れて、デバッガのデフォルトウィンドウ設定として保存します。これにより、デバッガを実行する際にプログラムはデフォルト設定で実行され、必要に応じて変更も可能です。
汎用レジスタの下にスタックビューを配置できます。
左側と最下部は逆アセンブルおよび 16 進数ウィンドウです。
逆アセンブルビューの下には現在のメモリアドレスとファイルオフセット(FILE OFFSET)が表示されます。このオフセットは実行可能ファイルのオフセットを指します。
ida では、デフォルトで G キーはメモリアドレスに移動するショートカットキーです。G を押して 0x401389 を入力し、以前に設定したブレークポイントに移動します。
すべての静的分析、名前変更などの変更内容は保存されます。
メニューバーのビュー - サブビューを開く - セグメントを開くと、ローダーが 3 つのセグメントを読み込んだことがわかります。
0x401000 の code フィールドと、下の data および.idata フィールドが読み込まれます。これらのセグメントの変更はすべて保存されますが、それ以外の変更は保存されません。なぜなら、それらはデバッガによって読み込まれたセグメントであり、IDA データベースに保存されることはないからです。
上の図の L マークは、このプログラムがローダーとデバッガによって同時に読み込まれたことを示しています。静的分析を実施できるだけでなく、動的デバッグ中に静的分析の情報が失われることもありません。
以下にいくつかの小ツールバーを紹介します。
1、メニューバーの view(ビュー) - toolbars(ツールバー) - jump(ジャンプ)を選択し、デスクトップ保存機能を使用してデフォルトで有効に設定します。
戻るキーを押すと、以前のプログラムエントリポイントに戻ります。
メニューバーの debugger(デバッガ) - breakpoints(ブレークポイント) - breakpoint list(ブレークポイントリスト)で、すべてのプログラムブレークポイントを確認できます。
任意の場所をクリックすると、対応するブレークポイントにジャンプできます。
条件ジャンプ命令とフラグレジスタ#
現在、デバッガはプログラムエントリに到達し、2 つのブレークポイントが設定されており、F9 を押して実行を続けます。
この時、crackme.exe プログラムが実行され、ターゲットプログラムの Help-register メニューバーにユーザー名とパスワードを入力します。
OK をクリックします。
上の図で、左側の点滅する赤い矢印はプログラムが続行するパスを示しています。この時、eax の値は 0x6c です。
0x6c を文字列に変換すると l になります。
上の図で、al レジスタは 0x41 と比較され、0x41(A)未満かどうかが判断されます。下の緑のコードブロックでは、al レジスタも 0x5a と比較されています。
asm | condition | operation |
---|---|---|
JA | z=0 and c=0 | jump if above(もし大きければジャンプ) |
JAE | c=0 | jump if above or equal(もし大きいか等しければジャンプ) |
JB | c=1 | jump if below (もし小さければジャンプ) |
JBE | z=1 or c=1 | jump if below or equal(もし小さいか等しければジャンプ) |
JC | c=1 | jump if carry(もしキャリーならジャンプ) |
JECXZ | ecx=0 | jump if ecx is 0 (もし ecx が 0 ならジャンプ) |
JE | z=1 | jump if equal(もし等しければジャンプ) |
JZ | z=1 | jump if zero(もしゼロならジャンプ) |
JNE | z=0 | jump if not equal(もし等しくなければジャンプ) |
JNZ | z=0 | jump if not zero (もしゼロでなければジャンプ) |
JO | 範囲を超える | jump if overflow |
JP | 偶数の 1 ビット(操作結果の 2 進数中の 1 の個数、01110000) | jump if parity |
JPE | 偶数チェック | jump if parity even |
JNP | 偶数の 1 ビットがない | jump if not parity |
JPO | 奇数チェック | jump if parity odd |
JS | 符号ビットが 1 | jump if sign(もしフラグがあればジャンプ) |
JNS | 符号ビットが 0 | jump if not sign(もしフラグがなければジャンプ) |
JL/JNGE | 符号ビットとオーバーフローが同じ | jump if less or not greater/equal |
JLE/JNG | z=1 or 符号ビットとオーバーフローが同じ | jump if less or equal/not greater |
JG/JNLE | z=0 and 符号ビットとオーバーフローが同じ | jump is greater/not less or equal |
条件ジャンプ命令とジャンプ条件
次に ida のフラグレジスタビューに移ります。以下の図のようになります。
表からわかるように、CF=0 の場合、ジャンプせず、プログラムは緑のコードブロックに進みます。では、この C フラグをトリガーする数学的条件は何でしょうか?
C フラグは、符号なし整数演算にエラーがあることを示す情報です。cmp 命令を結果を保存しない減算アルゴリズムと見なすと、0x6c - 0x41 = 0x2b
、結果は正数です。もし al が 0x30 であれば、0x30 - 0x41 = -0x11
になります。
-0x11 は負数であり、プログラムはそれに対応する 16 進数で実行を続けることしかできません。
上の図のように、-0x11 の 16 進数は 0xffffffef で、10 進数は 4294967279 です。この値は非常に大きく、0x30-0x41
も正数にはなりません。
では、演算中に符号が考慮されているかどうかをどうやって知るのでしょうか。これは使用されるジャンプタイプによります。JB は符号なし数の比較後のジャンプ命令であり、対応する符号付き数の命令は JL です。
JB 命令を使用する場合、通常は符号なし整数が特定の値より小さいかどうかを検出するために使用されます。演算結果が借位を生じた場合、2 番目のオペランド(比較される数)が 1 番目のオペランド(比較数)より大きいことを示します。この場合、JB フラグは 1 になり、ジャンプが可能です。そうでなければ、演算結果が借位を生じなければ、JB フラグは 0 になり、条件を満たさず、ジャンプは行われません。
例:
mov al, 150 ;150をalに代入
cmp al, 255 ;alと255を比較
jb smaller ;もしalが255未満なら、smallerラベルにジャンプ
;他の操作を実行
smaller:
;もしalが255以下なら、ここにジャンプ
この例では、al の値が 255 未満であれば、CF フラグは 1 になり、smaller ラベルにジャンプします。そうでなければ、al の値が 255 を超える場合、CF フラグは 0 になり、ジャンプせず、他の操作を実行します。(要するに、alが255未満であればジャンプ)
符号付きかどうかの比較は、その後の条件ジャンプ命令によって判断する必要があります。
符号なしジャンプ
符号 | 説明 | フラグ |
---|---|---|
JE/JZ | 等しいかゼロの場合にジャンプ | zf |
JNE/JNZ | 等しくないかゼロの場合にジャンプ | zf |
JA/JNBE | より大きいか、または以下でない場合にジャンプ | zf,cf |
JB/JNAE | より小さいか、または以上でない場合にジャンプ | cf |
JBE/JNA | より小さいか等しいか、または以上でない場合にジャンプ | cf,af |
符号なしジャンプ
上の図の命令は符号を考慮していません。各ジャンプには対応する符号付きジャンプがあります。
符号 | 説明 | フラグ |
---|---|---|
JE/JZ | 等しいかゼロの場合にジャンプ | zf |
JNE/JNZ | 等しくないかゼロの場合にジャンプ | zf |
JG/JNLE | より大きいか、または以下でない場合にジャンプ | zf,sf,of |
JGE/JNL | より大きいか、または等しくないか、以下の場合にジャンプ | sf,of |
JL/JNGE | より小さいか、または等しくないか、以下の場合にジャンプ | sf,of |
JLE/JNG | より小さいか等しいか、または以上でない場合にジャンプ | zf,sf,of |
符号付きジャンプ
上の 2 つの図において、JE(等しいかどうか)
は両方の図に現れます。なぜなら、この特例では符号は重要ではなく、もし 2 つの数が等しければ、zf=1
となり、フラグがトリガーされるからです。
符号付きジャンプの中でJG = より大きい場合にジャンプ
は、符号なしジャンプの中で対応する命令はJA、より大きい場合にジャンプ
です。
プログラムをデバッグしていると、ida は設定された各ブレークポイントで一時停止し、ループを実行します。各ループはターゲットプログラムに入力されたユーザー名の 1 文字を読み取り、0x41 と比較します。どの文字でも 0x41 未満であればエラーが表示されます。入力が lca の場合、各値は 0x41 より大きいため、エラーは表示されません。
数字を入力してみましょう。
この時、赤いブロックにジャンプします。つまり、jb がジャンプする場所です。最初に比較される文字は 2(0x32)であり、2 は確実に 0x41 より小さいです。
同時に C フラグがトリガーされ、CF=1 になります。なぜなら、0x32 - 0x41 の符号なし数の減算結果は負数であり、これが C フラグをトリガーします。
C フラグを右クリックし、Zero Value を選択して C フラグを 0 にします。
F9 を押してプロセスを続行すると、プログラムは 22lca の 2 文字目を読み取り、左側の赤い矢印が再び点滅し始めます。CF フラグを 0 に設定し続けると、その後の文字 lca はすべて 0x41 より大きくなり、フラグはトリガーされず、プログラムは左側の赤い矢印を進みます。
文字の検出が完了すると、プログラムは最後のジャンプに到達します。
上の図の cmp 命令は eax と ebx を比較し、jz は比較が等しいかどうかを判断します。符号なしで、プログラムは赤いブロックに進みます。なぜなら、これらの 2 つのレジスタは等しくないからです。
等しくないため、zf フラグはトリガーされません。
もし手動で zf フラグをトリガーし、ジャンプ方向を変更すると、プログラムは緑のブロックに進み、登録成功が表示されます。
SET IP#
set ip はデバッガモードでのみ使用できます。
時には、ジャンプを直接変更するのではなく、マウスを実行したいコードブロックに移動し、右クリックして SET EIP を選択することもできます。
0x40124c で set eip を設定すると、プログラムは 0x40124c から実行を開始します。
注:7.7 でこの操作を行うと、複数回実行した後に以下のエラーが表示されます。
「不正な命令を実行しようとしました」というメッセージが表示されます。
エラーメッセージはメモリが書き込み不可であることを示しており、読み取る内容が範囲を超えている可能性があります。
まとめ#
IDA デバッガを使用することで、動的デバッグと静的分析を行い、プログラムの構造と実行プロセスを深く理解することができますが、この章ではソースプログラムを変更することはなく、デバッガ内でフラグレジスタの値を変更しただけです。