環境設定#
リモートデバッグの大体のアーキテクチャは以下の図の通りです。
Mac 上で Windows のデバッガを実行できないため、リモートデバッグを通じて Mac でデバッグを行うことができます。
まず、パッキングされたファイルとリモートデバッグサービスファイルをTARGET(win10)
マシンにコピーします。リモートデバッグサービスファイルは dbgsrv ディレクトリにあります。
TARGET(win10)
の最終的な構造は以下の通りです。
パッキングプログラムは upx を使用してパッキングされており、32 ビットプログラムです。
リモートデバッグ#
リモートデバッグの前に、パッキングされたプログラムPACKED_PRACTICA_1.EXE
を Mac(ida7.0)上で局所分析し、MANUAL LOAD を選択して手動でファイルのすべてのセクションをロードします。
デバッグを実行する前に、IDA ローダーはパッキングされたプログラムのエントリポイントに移動します。
プログラムエントリ
注意:データベースファイル IDB の名前を変更しないでください。
TARGET(win10)
で win32_remote.exe リモートデバッグサーバーを実行し、-i で IP アドレスを指定します。
デバッガはRemote Windows debugger
を選択します。
プロセスオプションで、Hostname にTARGET(win10)
の IP アドレスとポートを入力し、Application と Input file にTARGET(win10)
内のパッキングプログラムの絶対パスを記入し、Directory にディレクトリパスを入力します。設定が完了したら、ok をクリックします。
デバッガメニューを開き、Start process を選択します。デバッグが開始された後、プログラムエントリで一時停止します(修正:0x638ec でブレークポイントを設定する必要があります。そうしないとここで一時停止しません)。
実行可能ファイルはランダム化処理が施されているため、毎回実行されるアドレスが変わります。そのため、同じ実行中にダンプと IAT の再構築を完了する必要があり、途中でプログラムを閉じることはできません。
segments タブを開き、ヘッダーファイルの後の最初のコードセクションを観察します。このセクションの開始アドレスは 631000、終了アドレスは 238000 です。
OEP の検索#
最初の方法として、テキスト検索機能を使用して popad または popa 命令を検索できます。このプログラム内では、1 つの popa 命令を検索できます。
図から、このアドレス 0x63146e が OEP であることがわかります。
2 番目の方法は、以前学習した最初のセクションの実行ブレークポイントをオーバーライドして OEP を探すことです。
セグメントビューの最初のセクションをダブルクリックし、0x631000 にジャンプしてセクションデータを確認します。アドレスはランダム化されており、ベースアドレスは 0x401000 ではありませんが、メモリ使用量は 0x7000 です。upx0 セクションは 0x631000 から 0x638000 までで、差は 0x7000 バイトです。
F2 キーを押して upx0 セクションの起点にブレークポイントを設定します。ここは 0x601000 で、ブレークポイントのサイズは 0x7000 です。
他のブレークポイントを削除し、このブレークポイントだけを残して、F9 キーを押してデバッグを開始します。
プログラムはここで一時停止し、以前の OEP 位置と一致していることを確認したら、このブレークポイントを削除し、赤い背景を取り除きます。
画面左下の Reanalyze program をクリックして、プログラムを再分析します。
OEP 以降の内容は IDA によって STUB の一部として認識されているため、sub_
ではなくloc_
としてマークされています。
ダンプと IAT の再構築#
OEP を見つけた後、ダンプと IAT の再構築を開始します。まず、ファイルのベースアドレスと最高アドレスを確認します。
ここでファイルのベースアドレスは 0x630000、最高アドレスは 0x63B000 です。ダンプ用のスクリプトファイルを取り出し、ファイル内のアドレスを修正してからスクリプトをロードして実行します。
スクリプトは以下の通りです:
import idaapi
import idc
import struct
start_ea = 0x630000
end_ea = 0x63b000
step = 4 # 各アドレスのデータは4バイトを占有します
file_path = "dump.bin"
with open(file_path, "wb") as f:
for ea in range(start_ea, end_ea, step):
# 指定されたアドレスの4バイトデータを読み取り、小端バイトオーダーに変換します
bin_data = struct.pack("<L", idaapi.get_32bit(ea))
f.write(bin_data)
実行が完了すると、ダンプファイルが生成されます(スクリプトファイルは Mac 上で実行されるため、ダンプファイルも Mac 上に生成されます)。
dump.bin ファイルを Windows にコピーし、peeditor で開きます。
各セクションで右クリックして dumpfixer を選択し、操作を完了したら、.bin を.exe ファイルに変更します。結果は以下の通りです:
dump.exe ファイルを scylla で開き、パッキングプログラムプロセスをロードします。
OEP アドレスを入力します。ここでは 0x63146e です。その後、IAT Autosearch と Get Imports をクリックすると、認識できない API 関数が見つかります。
API アドレスにベースアドレスを加えます。0x630000+0x20d4=0x6320d4 に移動し、16 進数ビューに切り替えますが、IAT の一部ではありません。
逆アセンブルビューに切り替えて、その参照を確認します。内容は以下の通りです:
x キーを押すと、2 つの参照が表示されます。
そして、0x6320d4
が指すアドレスは RET 命令のみを返します。以下の通りです:
0x6320d4
はプログラム内の固定アドレスを指しており、単なる RET 命令であり、参照されている API 関数ではないため、削除できます。Syclla で API 関数エラーの場所を右クリックして CUT THUNK で IAT から削除します。
削除後は以下の通りです:
最後に Fix Dump をクリックして dump.exe の IAT を再構築し、最終的に dump_SCY.exe 実行可能プログラムを生成します。
この時点で dump_SCY.exe を実行すると、まだ黒い画面が一瞬表示されます。
ランダムベースアドレスの解除#
IAT の他に、実行時に生成されるアドレスがリダイレクトされていないため、常に変わるので、このランダム性を排除する必要があります。ida を開き、dump_SCY.exe ファイルをロードし、Manual Load で pe ヘッダセクションをロードして、このセクションに移動します。
ヘッダー内で以下の内容 Dll characteristics を見つけ、その値を 0 に変更する必要があります。
メニュー Edit-patch program-change word を開き、この値を 0 に変更します。
ok をクリックし、apply patches to input file を使用して変更を実行可能ファイルに保存します。
この時点で、再度dump_SCY.exe
を実行すると、正常に実行され、脱殻されたファイルが成功裏に実行されることが確認されます。