アイジア

CTF, 情報セキュリティの学んだことメモ

crkme02 + 02a

 http://doomo.xyz/crack/

↑答え書いてあるけど自分なりにメモ。

実行

f:id:favoritte15:20180710123544p:plain

いつも通りOllyで起動。

 

①GetWindowTextAを呼び出しているところでブレークポイントを設置する。

f:id:favoritte15:20180710125001p:plain

②GetWindowTextAの引数(EAX)と8を比べて、一致しなければ不正解処理に飛ぶ。

GetWindowText function (Windows)

If the function succeeds, the return value is the length, in characters, of the copied string,

とあり、文字列の長さを返すので正解パターンは8文字。

f:id:favoritte15:20180710125527p:plain

③つぎに0040123Aの関数に入る。

ESIレジスタに入力文字列を代入し一文字ずつ比較している。

不正解なら返り値に0、正解なら1が返ってくる。

文字列は

35, 45, 48, 39, 56, 33, 51, 57

=5EH9V3QW

 

crkme02a.exe

02と同じように検索->ラベル名->GetWindowTextAにブレークポイントを仕掛けて実行すると、

f:id:favoritte15:20180711144232p:plain

ふざけたことを言われる。

ブレークポイントをセットするとそれを検知してプログラムが終了してしまう。

f:id:favoritte15:20180711154733p:plain

CALL GetWindowTextA以降の処理は02とあまり変わらないのでそれより上を調べれば仕掛けが分かるかもしれない。

4011EB LEA ESI, DWORD PTR DS:[401233]

アドレス401233はちょうどGetWindowTextA関数の呼び出しが始まるところだ。

 

GetWindowTextAにブレークポイントがセットされていると

401209 CALL crkme02a.00401233

が実行されない。そうするとGetWindowTextA以降の処理がされずに終了してしまう。

 

なぜそのようなことができるのかというと、

x86_64アーキテクチャではプログラムにint3(0xCC)という1バイトの命令を埋め込むことでブレークポイントを制御しているからだと思われる。

f:id:favoritte15:20180711162539p:plain

①LEA ESI, DWORD PTR DS:[401233]

・ESIにアドレス0x401233を代入

②MOV EBX, 36

    MOV EBX, 96

・EBXに0x36+0x96(=0xCC)を代入

③CMP BYTE PTR DS:[EAX+ESI], BL ~ CMP EAX, 91

・ESIのアドレスを1ずつずらしながらEBXと比較する、つまりブレークポイントがセットされていないかをチェックしている。

つまり0x401233+0x91までの場所にBPを仕掛けていると終了してしまう。

逆に言えば0x401233より小さいアドレスにBPを仕掛けても大丈夫ということ。

401209 CALL crkme02a.00401233

のところにBPをつけて探ってみる。

GetWindowTextA呼び出しを抜けた直後

00401245 CALL crkme02a.00401280

をF7で見てみると

 

f:id:favoritte15:20180711163653p:plain

即値と比較しているわけではなく、0x4012EEを呼び出してDLを加工してそれを入力値と比較しているらしい。動的に実行してDLレジスタを確かめていくとパスワードが分かる。

f:id:favoritte15:20180711164405p:plain

1文字でも違うと不正解処理に飛んでしまうのでJNZ処理をつぶすか、Zフラグを1に書き換えて処理を進めていく。

DLに格納されている値は順に、

57 4D 46 54 50 56 4F 47

WMFTPVOG