9.2 シンボルファイル#
ターゲットファイル:HOLA_REVERSER.exe
ターゲットファイルのアーキテクチャを確認します:
ターゲットファイルは 32 ビットプログラムで、VC++ 2015 でコンパイルされています。
ダブルクリックしてプログラムを実行すると、数字の入力を求められます。
プログラムは入力された文字が正しいかどうかを判断します。
9.3 main 関数の特定#
まず、文字列を見てみましょう。
ターゲットプログラムが実行時に出力するいくつかの文字列が見つかりました。上の図で赤線で示された部分をダブルクリックします。
次の場所に移動します:
上の図では、0x402108 はこの文字列のアドレスであり、アドレスの右側の 16 進数はマシンコードです。マシンコードの右側の aPoneUnNumerito はこの文字列のマークまたは名前であり、文字列の前の a は ASCII コードを表し、後の db はバイトシーケンスを表します。
D キーを押すと、各バイトの値を表示できます:
A キーを押すと、再び文字列として表示されます。
右側の矢印が参照している場所にマウスを置くと、具体的な参照位置を確認できます。X キーを押すと、具体的な参照位置に移動できます。
この参照から、main 関数を見つけることができます。
9.4 関数のスタック#
上記の図では、ローカル変数 var_4 があり、サイズは dword です。
32 ビット関数呼び出しスタックビュー
まず、すべての関数引数がスタックに渡され、次に戻りアドレスがあります。戻りアドレスの上には、上位関数の EBP があります。これは、関数の最初の命令で生成されるPUSH EBP
によって生成されます。一番上にはローカル変数があります。
9.5 Main 関数の引数#
main 関数に移動します
X キーを押して、main 関数がどこで参照されているかを確認します。
main 関数の呼び出し
上の図では、3 つの push 命令があり、これらの命令を使用して引数が渡されます。3 つの命令のコメントによって、argc、argv、envp などの 3 つの引数が渡されることがわかります。これらは関数のデフォルトの引数です。
9.6 ローカル変数#
var_c はローカル変数です。X キーを押すと、このローカル変数がどこで参照されているかを確認できます。以下の図から、このローカル変数が 2 つの場所で参照されていることがわかります。
9.7 Atoi 関数#
atoi 関数は文字列を整数に変換します。数字が大きすぎて変換できない場合、エラーが発生し、0 が返されます。もちろん、最小の負の整数 (int) よりも小さい場合もエラーが発生し、0 が返されます。入力された内容はすべて整数に変換されます。たとえば、41424344 と入力すると、16 進数に変換されて EAX に保存されます。
#include <stdlib.h>
int atoi(const char *string);
上の図からわかるように、ターゲットプログラムは入力されたすべての文字列を整数に変換します。atoi
または_wtoi
が入力内容を日本語の型に変換できない場合、0 が返されます。
atoi の戻り値
eax の戻り値が esi に渡され、ユーザーが入力した元の文字列を出力した後、esi の値が0x12457
と比較されます。
ユーザーが入力した 10 進数の文字列は解析され、16 進数に変換され、その後、ハードコードされた値と比較されます。入力された文字列がハードコードされた値に対応する 10 進数と等しい場合、成功するはずです。
上の図では、jnz 命令(not zero)が使用されているため、「bad reverser」と出力されます。等しければ、「good reverser」と出力されます。
0x124578
を 16 進数から 10 進数に変換すると 1197432 になります。
ターゲットプログラムでこの 10 進数の 1197432 を入力すると、成功したことが確認でき、good reverser
が出力されます。
ターゲットプログラムの解析はここで終了です。この章では、関数スタックのリバースエンジニアリングについて学びました。引数の渡し方、ローカル変数、atoi 関数などが含まれます。