IDA デバッガの選択#
ida は複数のデバッガをサポートしています。
ida がサポートするデバッガ
Local Windows debugger デバッガを選択します。
メニューバーのデバッガー - デバッガオプションを開くと、いくつかのデバッガの機能を設定できます。
ida デバッガオプション
デバッガインターフェース機能#
プロセスエントリポイントを一時停止
にチェックを入れ、イベント条件を選択し、確定をクリックします。
以前の重要なコード 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 位(操作结果中二进制中 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 = Jumps if greater
は、符号なしジャンプの対応する命令はJA、Jumps if above
です。
プログラムのデバッグを続けると、ida は設定された各ブレークポイントで一時停止し、ループを実行します。各ループはターゲットプログラムに入力されたユーザー名の 1 文字を読み取り、0x41 と比較します。もし任意の文字が 0x41 未満であればエラーが表示されます。入力されたのは lca であり、各値は 0x41 より大きいため、エラーは表示されません。
数字を入力してみましょう。
この時、赤いブロックにジャンプします。最初に比較される文字は 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 デバッガを使用することで、動的デバッグと静的分析を行い、プログラムの構造と実行プロセスを深く理解できますが、この章ではソースプログラムを変更することはなく、デバッガ内でフラグレジスタの値を変更しただけです。