はじめに
前回はildasmを用いた逆アセンブルとプログラムに出現する文字列から当該処理を行う箇所を特定し、特定の処理の迂回をやってみました。
今回はデバッガを用いて実際の動作を覗いてみましょう。
動的解析
ところで、前回アセンブラを用いてILコードから実行ファイルを生成したときのコマンドをもう一度確認してみましょう。
>ilasm SuperUsefulApplication.il /exe /debug=impl /resource=SuperUsefulApplication.res /output=SuperUsefulApplication2.exe
ここで重要なのが/debug=implの部分です。
このオプションでデバッグシンボルを一緒に生成しています。
プログラムを起動し、デバッガをアタッチしてみましょう。 なお、ここではVisual Studio 2015 community update 3を使用しています。
デバッグ->プロセスにアタッチで一覧から目的のプロセスを見つけ、アタッチします。

ところで、このアプリケーションの処理内容について説明していませんでしたね。 文字列を入力するとその文字が格納され、なにも入力しないと入力した逆順に文字列が返されるようです。
なにそれただのスタックじゃん。なんだろな~。どうやって実装しているんだろうな~。気になるなぁ~。
前回の逆アセンブルコードから、SuperUsefulApplication.SuperUsefulClass`1<string>::Pop()とSuperUsefulApplication.SuperUsefulClass`1<string>::Push()が中核的な処理をつかさどっているようです。
ですので、この二つのメソッドにブレークポイントを設定してみましょう。
デバッグ->ブレークポイントの作成->関数のブレークポイントからPopとPushにブレークポイントを設定します。

文字列を4つ程突っ込んでデバッガで内部状態を確認してみましょう。


ローカル変数を確認すると、線形リストでスタックを実装しているようです。
このアプリケーションは単純なのでここで終わりですが、もっと複雑なアプリケーション/ライブラリの場合でも普段と同じようにデバッグができるでしょう。
おわりに
このように、マネージドアプリケーションはリバースエンジニアリングに対して非常に脆弱であることが分かります。
リバースエンジニアリングに対する防御策としては、
などが挙げられます。
ロジックの重要度と実施するコストとを勘案していい感じにアレすればいいと思います。
おわり