せっかく解析について勉強したので、自分で書いたプログラムを読んでみました。
プログラミングに関しては完全に初学者なので内容についてはつっこまないでいただきたいところです。ひとまず、変数の初期化、文字表示(日本語含む)、数字の入力、条件分岐を入れてexe化したものを見ていきます。
とりあえずなんかやってみる…
演習でやった流れをやってみます。入力できる状態で一時停止をします。そうするとretで止まってしまっていることがわかりました。
これではどうしようもないので、スタックを確認して積まれているアドレスを確認してみます。プログラム本体ではなく、kernelbase.dllに返るようです。
とりあえず、そのkernelbaseのアドレスにブレークポイントを貼って、その後の処理を追っていきました。追ったといっても解読できるような感じではありませんでした。とにかくステップ実行で進めていくと、入力処理が完了して次の処理が開始する部分に到達しました。
!!!をpushしている部分にきました。この部分を読み解くと、
std::cout << “number is ” << number << “!!!” << std::endl;
を実行するために、引数として「!!!」、「numberの値」、「number is」をpushしてスタックに積んでいるように見受けられます。うん、多分そうです。pushの順番からするに、入力して渡した「8」が
push dword ptr ss:[ebp-8]
のようです。この謎の文字列が本当に8を指しているのかどうか確認してみます。
dword ptr : 4バイトとして見る
ss : スタックセグメント(?)
[ebp-8]:ebpのアドレス自体から-8したアドレスにある値
であるはずなので、この時点のebpを確認してみます。
ebpは 0078FDECであることがわかりました。そこからマイナス8なので、指しているアドレスはWindowsの電卓で計算して…
ダンプ画面でアドレスに飛んで確認します。
08 00 00 00 つまり、00 00 00 08 で8であることがわかりました!確かに8!こんな確認しなくてもステップ実行していけば、pushされて8がスタックに乗るので確認できますが、読む練習として見てみました。
条件分岐を読む
入力された数字によって、表示されるメッセージが変わるようになっています。
その部分を見ていきます。
cmpで0x8(入力した8)と0xA(判定に使う10)を比べています。どう見ても値は違うのでZF=0が立ちます。cmpを過ぎた時点のフラグを確認します。
その後、文字列をecx、eaxに格納しています。この部分で面白いのは、入力した値が10だろうが10じゃなかろうが、文字列「OH… number is 10」「NO… number is not 10」2つはメモリ上に展開されるところです。結果がどうであれ、その先の処理は事前にメモリ上に準備されています。よく考えたら魔法解析少女の演習でもプロダクトキーが合ってる間違っているという判定部分の文字がどちらも確認できていました。まてまて、そもそもどんなプログラムもすべてメモリ上に展開されるのだから処理とか関係無しに全てが見えるのが当然でした。頭悪い..
とりあえず、この条件部分を読み解くと読んでみると
入力した数字と10を比較、等しい場合ZF=1、等しくない場合ZF=0フラグを建てる
ecxに10ではないときのメッセージ を格納
eaxに10だったときのメッセージ を格納
ZF=0のとき、mov eax,ecxを実行する(cmovneの部分。)
eaxをpush(メッセージ表示の引数)
メッセージを表示
のようになりますから、最初の比較部分でZF=1にさせておけば、常に10だったときの処理をさせることができそうです。
ここまで。入力処理の部分にたどり着く方法を知りたいのですが、どうすればいいかさっぱりです。