概要
今回はリバースエンジニアリングの問題である"Crackme"を解いてみたので、その方法をシェアしたいと思います。
タイトルにもあるように、この記事は(超)初心者向けです。リバースエンジニアリングをやったことがない人や始めてみたものの、やり方が分からないという人に是非読んでもらいたいです。
注意点
初心者向けとは言ったものの、アセンブリ言語(今回はx86)やC言語の知識が(ほんの)少しあれば嬉しいです。
mov eax, 0
cmp eax, 0
jz LABEL1
char *s1 = "Elliot";
char *s2 = "Elliot";
if(strcmp(s1,s2)==0){
printf("同じ値です。\n");
}
このくらいのレベルが、Googleを使いながらでも理解できれば十分です。
参考
今回は、このWebサイトにある問題を解いていきます。ここにはたくさんのリバースエンジニアリングの問題があります。
環境
僕が使用した環境を参考までにお伝えします。
今回は、WindowsのバイナリをリバースエンジニアリングするのでWindowsを使うことが望ましいです。
Macユーザーの人も仮想環境を使うことで、Windowsを走らせることが出来ます。(僕はホストWindowsで仮想マシンとしてWindowsを使いました😃)
ホストOS:Windows10
仮想化ソフト:VMware
仮想マシン:Windows10
動的解析ツール:x64dbg
用語解説
リバースエンジニアリング:「逆アセンブル」と「逆コンパイル」を行い、ソースコードを解析することによって、そのプログラムがどのような仕組みなのかを解析すること。
動的解析:実際にプログラムを実行しながら、ソースコードの解析を行うこと。
アセンブリ言語:コンピュータなどのプログラミング言語の1種で、原則として機械語の命令に1対1で対応した、人間に理解しやすい文字列や記号で記述されるもの。(Wikipediaより引用)
実践
まずは、リバースエンジニアリングするバイナリをダウンロードしましょう。
先ほどの紹介したWebサイトに飛んでください。
今回挑戦する問題はこれです。
ダウンロードできたら、早速リバースエンジニアリングしていきましょう。
x64dbgで動的解析
今回は静的解析を飛ばして、いきなり動的解析から入ります。本来は動的解析の前に必ず表層解析/静的解析から行います。
実際は、安全性が判明していない段階でプログラムを実行するのは大変危険ですのでお気を付けください。
「x64dbg」をダウンロードしていない人は、ここからどうぞ。
まずは先ほどダウンロードしたバイナリファイルを普通に走らせてみましょう。
どうやら、入力したパスワードが合っているかどうかを確認するようです。
一応間違えても5回ほどチャンスがあるようですが、その仕様は今回無視します。(特に意味がないからです。)
間違ったパスワードを入力すると、"wrong pass!!"と表示されます。これが重要になってきます。
では、バイナリファイルを右クリックで「x64dbg」と一緒に起動します。
起動した時にはまだプログラムがエントリーポイントに到達していないので、そこまで走らせます。
左から4番目の「右矢印」を何回か押してください。(プログラムにパスワード入力画面が出てくるまで)
文字列からの検索
ではここからどのように進めるのか、大きなヒントがプログラムを走らせた時にありました。
パスワードを間違って入力した時に、"wrong pass!!"というメッセージが出たのを覚えているでしょうか。
間違えた時のメッセージがあるということは、正しいパスワードを入力した時のメッセージもあるはずです。さらに言うと、どちらのメッセージを表示させるのかを決めている処理は、すなわちパスワードが合っているかどうかを確かめている処理と言い換えることも出来ます。
まとめると、"wrong pass!!"と表示される処理の近くに、パスワードが合っているかどうかを確かめる処理もあり、その近くに正解のパスワードが存在するということです。
説明だけでは分かりにくいかもしれませんが、実際にやってみるとクリアになると思います。
では文字列の検索をしましょう。
右からの4つ目の「Az」アイコンをクリックしてください。
下のサーチバーに"wrong"と入れると、1つのアドレスが見つかりました。
ダブルクリックしてそのアドレスに飛んでみましょう。
今飛んだアドレスのすぐ上に、正解のメッセージ:"congrats you cracked the password")がありました。
ということは、この辺りでパスワードが合っているかどうかの処理があると推測できます。
strcmp
先ほどのアドレスのすぐ上に
call <JMP.&strcmp>
という命令が見えると思います。
これは簡単に言うと、strcmpという関数を呼び出すということです。
この関数は文字列を比較するというものです。いったい何の文字列を比較しているのでしょうか?
自分が入力したパスワードと正解のパスワードを比較しているものだと容易に推測できます。
ブレイクポイント
ではブレイクポイントを置いて、正しいパスワードが何か見てみましょう。
<0040148A>のアドレスにブレイクポイントを置きましょう。(アドレスの左にある丸をクリックしてください。)
もう一度プログラムを走らせましょう。
EAXを見てみると、"password123"という文字列があります。
"test"(自分で入力したパスワード)と"password123"(正解のパスワード)が引数として、strcmpが実行されていることがわかります。
逆アセンブリ画面(メイン画面)を見てみると、その様子が見れます。
これで、正解のパスワードが"password123"であることが分かりました。
プログラムを実行し、"password123"を打つと正しいパスワードが入力されたことが確認できます。(プログラムはすぐに終了したと思います。)
おめでとうございます😃
リバースエンジニアリング成功です。
別の方法
もうお腹いっぱいな人は、スキップしてもらって大丈夫です。
一応動的解析ではこんな強引な方法もあるのかというのを、紹介します。
正しいパスワードを入力しなくても、正解のメッセージを表示させることが出来ます。
先ほどのブレイクポイントが置いてある状態から始めます。
cmp dword ptr ss:[esp+48], 0
jne crackme.4014A8
この命令は簡単に言うと、cmpで比較をして、もし同じ値ではなかったら特定のアドレス(不正解のメッセージ)に飛ぶというものです。
では強引にjneの命令を別のものに変えましょう。
jneをクリックしてスペースキーを押すと、命令を変更することが出来ます。
je crackme.4014A8
これは先程とは逆で、もし同じ値だったら特定のアドレスに飛ぶというものです。
これで、本来不正解のメッセージが表示されるところを、強引に正解のメッセージが出るように変えることができます。
これは動的解析でしかできないことです。
最後に
いかがだったでしょうか?
リバースエンジニアリングの問題を解きました。
今回の問題は非常に簡単でしたが、それでもリバースエンジニアリングを皆さんは成功させました。
これを機にリバースエンジニアリングについて興味を持ってもらえると嬉しいです。
僕もまだまだ初心者なので一緒に頑張りましょう。
この記事が皆さんのお役に立てれば嬉しいです。最後まで読んでくださってありがとうございました。
質問がある方は是非コメントしてください😃