crackme #11 について   著者:eagle0wlさん

crackme #11 の解法がいろいろ挙がっていますが、私の方からも少し
解説してみたいと思います。


まず Nag の形を確認してみましょう。起動してみるとわかりますが、
1つ目のナグの形を見ると、メッセージボックスであることが直ぐにわかります。
また、eXeScope で実行ファイルを覗くと Resource - Dialog - 2 に
2つ目のナグがあるのでダイアログボックス表示だろうということがわかります。
3つ目のナグは eXeScope で見つけることができないので、CreateWindowEx で生成
しているだろうと予測できます。


3つのナグはそれぞれ、MessageBox、DialogBoxParam、ShowWindow を
用いて表示しています。逆アセンブルリストを眺めて探すという方法もありますが、
プログラムサイズの小さい crackme だからこそ可能であって、実践でこの方法は
使うわけにはいきません。(crackme #20 にも同じ事が言えます)
文字列参照を使うか、前述した API に BP を仕掛けることで発見できます。



一つ目のナグ
004010C0 . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004010C2 . 68 5E304000 push CRKME11.0040305E ; |Title = "Nag(1/3)"
004010C7 . 68 67304000 push CRKME11.00403067 ; |Text = "本ソフト(以下略)
004010CC . FF75 08 push dword ptr ss:[ebp+8] ; |hOwner
004010CF . E8 58050000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004010D4 . EB 0C jmp short CRKME11.004010E2

5行に(最後の jmp 命令は除く) nop 攻撃すれば一つ目のナグは消えてくれます。
ただ、クラッカーの間では nop が連続するパッチは美しくないとされており、
さらに +ORC 氏によるとパッチ対策として連続する nop を検出するソフトが昔は
あったらしいので(JCT クラックチュートリアル参照)、
私は以下のように書き換えました。

004010C0 EB 12 jmp short CRKME11.004010D4 <- 注目!
004010C2 . 68 5E304000 push CRKME11.0040305E ; |Title = "Nag(1/3)"
004010C7 . 68 67304000 push CRKME11.00403067 ; |Text = "本ソフト(以下略)
004010CC . FF75 08 push dword ptr ss:[ebp+8] ; |hOwner
004010CF . E8 58050000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004010D4 . EB 0C jmp short CRKME11.004010E2

004010C0 . 6A 00 push 0

004010C0 EB 12 jmp short CRKME11.004010D4
に書き換えています。

飛び先はMessageBoxA の次の命令アドレス(004010D4)です。この書き換えで、
004010C2 ~ 004010D3 は実行されることのない死んだコードになり、
ナグは見事に消えてくれます。

次に、2つ目のナグです(DialogBoxParamA で表示)
0040114F . 6A 00 push 0 ; /BeepType = MB_OK
00401151 . E8 D0040000 call <jmp.&USER32.MessageBeep> ; \MessageBeep
00401156 . 6A 00 push 0 ; /lParam = NULL
00401158 . 68 72124000 push CRKME11.00401272 ; |DlgProc = CRKME11.00401272
0040115D . FF75 08 push dword ptr ss:[ebp+8] ; |hOwner
00401160 . 6A 02 push 2 ; |pTemplate = 2
00401162 . FF35 00304000 push dword ptr ds:[403000] ; |hInst = NULL
00401168 . E8 7D040000 call <jmp.&USER32.DialogBoxParamA> ; \DialogBoxParamA
0040116D . EB 7B jmp short CRKME11.004011EA

これも同様に nop 攻撃で潰せます。2つ目のナグ表示時にも音が鳴りますが、
DialogBoxParamA を潰すとナグは消えますが、起動時に「ポーン」と音が鳴って
しまいます(笑)。DialogBoxParamA は MessageBox とは違い、窓表示時に音は
鳴らないので DialogBoxParamA とは別に何か音を鳴らす命令があるということになります。


DialogBoxParamA の上を見ると、MessageBeep がありました。MessageBeep は
システムで定義されたビープ音を鳴らす命令です。
DialogBoxParamA と MessageBeep の両方を潰せば OK なので、
1つ目のナグの消し方にならって

0040114F EB 1C jmp short CRKME11.0040116D <- 注目!
00401151 . E8 D0040000 call <jmp.&USER32.MessageBeep> ; \MessageBeep
00401156 . 6A 00 push 0 ; /lParam = NULL
00401158 . 68 72124000 push CRKME11.00401272 ; |DlgProc = CRKME11.00401272
0040115D . FF75 08 push dword ptr ss:[ebp+8] ; |hOwner
00401160 . 6A 02 push 2 ; |pTemplate = 2
00401162 . FF35 00304000 push dword ptr ds:[403000] ; |hInst = NULL
00401168 . E8 7D040000 call <jmp.&USER32.DialogBoxParamA> ; \DialogBoxParamA
0040116D . EB 7B jmp short CRKME11.004011EA

上記のようにすると2つ目のナグは消えます。

最後、3つ目のナグです。(ShowWindow で表示)
004013A9 |> 6A 00 push 0 ; /lParam = NULL
004013AB |. FF35 00304000 push dword ptr ds:[403000] ; |hInst = NULL
004013B1 |. 6A 00 push 0 ; |hMenu = NULL
004013B3 |. FF75 0C push dword ptr ss:[ebp+C] ; |hParent
004013B6 |. FF75 AC push dword ptr ss:[ebp-54] ; |Height
004013B9 |. FF75 B0 push dword ptr ss:[ebp-50] ; |Width
004013BC |. FF75 A4 push dword ptr ss:[ebp-5C] ; |Y
004013BF |. FF75 A8 push dword ptr ss:[ebp-58] ; |X
004013C2 |. 68 0408C810 push 10C80804 ; |Style = (略)
004013C7 |. 68 A0134000 push CRKME11.004013A0 ; |WindowName = "Nag(3/3)"
004013CC |. 68 A0134000 push CRKME11.004013A0 ; |Class = "Nag(3/3)"
004013D1 |. 6A 00 push 0 ; |ExtStyle = 0
004013D3 |. E8 06020000 call <jmp.&USER32.CreateWindowExA> ; \CreateWindowExA
004013D8 |. A3 18304000 mov dword ptr ds:[403018], eax
004013DD |. 6A 01 push 1 ; /ShowState = SW_SHOWNORMAL
004013DF |. FF35 18304000 push dword ptr ds:[403018] ; |hWnd = NULL
004013E5 |. E8 6C020000 call <jmp.&USER32.ShowWindow> ; \ShowWindow

この ShowWindow を潰せば OK ....ではありません(やってみればわかります)。
ShowWindow の前に CreateWindowEx 命令が有ります。
これはナグウィンドウを作る命令です(表示ではない)。
さらにその上には GetSystemMetrics やら LoadIcon やらナグウィンドウ作成に
関係がありそうな命令が見つかるので、この部分にパッチ当てを行うのは
難しそうです。


そこで生成の過程を逆にたどりましょう。ズズズーっと上にスクロールしてみると
このナグを表示する関数はアドレス 004012F4 から始まっていることがわかります。
それではこの関数はどこから呼び出されているのか調べてみましょう。
(アドレス 004012F4 にカーソルを合わせ Ctrl + R)

すると、別窓が開いて
004011E5 call CRKME11.004012F4
004012F4 push ebp <- これは選択行

と表示されるはずです。call 行をダブルクリックすると

004011E0 . FF75 08 push dword ptr ss:[ebp+8] ; /Arg2
004011E3 . 6A 0A push 0A ; |Arg1 = 0000000A
004011E5 . E8 0A010000 call CRKME11.004012F4 ; \CRKME11.004012F4
004011EA > 5F pop edi
004011EB . 5E pop esi

3つ目のナグを表示する関数を呼び出している行にジャンプします。
OllyDbg はお利口なので引数の数が一目で分かるようになっています。
ということで、この関数をバッサリ消してあげましょう。

004011E0 EB 08 jmp short CRKME11.004011EA <- 注目!
004011E2 90 nop <- 注目!

004011E3 . 6A 0A push 0A ; |Arg1 = 0000000A
004011E5 . E8 0A010000 call CRKME11.004012F4 ; \CRKME11.004012F4
004011EA > 5F pop edi
004011EB . 5E pop esi

どうでしょうか?これで3つ目のナグが消えました。

パッチは以下の通り。
FILENAME crkme11.exe
000004C0: 6A EB
000004C1: 00 12
0000054F: 6A EB
00000550: 00 1C
000005E0: FF EB
000005E1: 75 08
000005E2: 08 90