crkme02 + 02a
↑答え書いてあるけど自分なりにメモ。
実行
いつも通りOllyで起動。
①GetWindowTextAを呼び出しているところでブレークポイントを設置する。
②GetWindowTextAの引数(EAX)と8を比べて、一致しなければ不正解処理に飛ぶ。
GetWindowText function (Windows)
If the function succeeds, the return value is the length, in characters, of the copied string,
とあり、文字列の長さを返すので正解パターンは8文字。
③つぎに0040123Aの関数に入る。
ESIレジスタに入力文字列を代入し一文字ずつ比較している。
不正解なら返り値に0、正解なら1が返ってくる。
文字列は
35, 45, 48, 39, 56, 33, 51, 57
=5EH9V3QW
crkme02a.exe
02と同じように検索->ラベル名->GetWindowTextAにブレークポイントを仕掛けて実行すると、
ふざけたことを言われる。
ブレークポイントをセットするとそれを検知してプログラムが終了してしまう。
CALL GetWindowTextA以降の処理は02とあまり変わらないのでそれより上を調べれば仕掛けが分かるかもしれない。
4011EB LEA ESI, DWORD PTR DS:[401233]
アドレス401233はちょうどGetWindowTextA関数の呼び出しが始まるところだ。
GetWindowTextAにブレークポイントがセットされていると
401209 CALL crkme02a.00401233
が実行されない。そうするとGetWindowTextA以降の処理がされずに終了してしまう。
なぜそのようなことができるのかというと、
x86_64アーキテクチャではプログラムにint3(0xCC)という1バイトの命令を埋め込むことでブレークポイントを制御しているからだと思われる。
①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で見てみると
即値と比較しているわけではなく、0x4012EEを呼び出してDLを加工してそれを入力値と比較しているらしい。動的に実行してDLレジスタを確かめていくとパスワードが分かる。
1文字でも違うと不正解処理に飛んでしまうのでJNZ処理をつぶすか、Zフラグを1に書き換えて処理を進めていく。
DLに格納されている値は順に、
57 4D 46 54 50 56 4F 47
→WMFTPVOG