crackme#04 解析手引き

この解析環境はWindows98 OllyDBG1.07(日本語化)で行っています。


Ollyは立ち上げてcrkme04.exeを開いてください。
画面左上には逆アセンブルリストが表示されていますが、

ここで右クリックして検索→ラベル一覧 を選択して下さい。
英語メニューの方は、「search for」→「label」です。
やはり例によって GetWindowTextA を使います。

Get~上で右クリック「全ての参照をブレークポイントにセット」を選択して下さい。
すると、GetWindowTextAにブレークポイントがセットされるはずです。


Names in crkme04
Address Section Type ( Name Comment
00401000 .text Export <ModuleEntryPoint>
00402000 .rdata Import ( KERNEL32.GetModuleHandleA
00402004 .rdata Import ( KERNEL32.ExitProcess
0040200C .rdata Import ( USER32.GetWindowTextA ←ココ
00402010 .rdata Import ( USER32.LoadIconA
00402014 .rdata Import ( USER32.GetDlgItem
00402018 .rdata Import ( USER32.DialogBoxParamA
0040201C .rdata Import ( USER32.EndDialog
00402020 .rdata Import ( USER32.SetWindowLongA
00402024 .rdata Import ( USER32.ShowWindow
00402028 .rdata Import ( USER32.CallWindowProcA
0040202C .rdata Import ( USER32.MessageBoxA
00402030 .rdata Import ( USER32.SendMessageA


F9を押してプログラムを実行します。
crackme#04ウィンドウが現れました。
それではフェイクパスとして「98765432」と入れて登録ボタンを押しましょう。
004011F5にブレークするはずです。


004011C3 . 6A 00 PUSH 0 ; /lParam = 0
004011C5 . 6A 02 PUSH 2 ; |wParam = 2
004011C7 . 68 A1000000 PUSH 0A1 ; |Message = WM_NCLBUTTONDOWN
004011CC . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011CF . E8 A8000000 CALL <JMP.&USER32.SendMessageA> ; \SendMessageA
004011D4 >^E9 C5FEFFFF JMP CRKME04.0040109E
004011D9 > 6A 00 PUSH 0 ; /Result = 0
004011DB . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011DE . E8 7B000000 CALL <JMP.&USER32.EndDialog> ; \EndDialog
004011E3 .^E9 B6FEFFFF JMP CRKME04.0040109E
004011E8 > 6A 7E PUSH 7E ; /Count = 7E (126.)
004011EA . 68 2C304000 PUSH CRKME04.0040302C ; |Buffer = CRKME04.0040302C
004011EF . FF35 04304000 PUSH DWORD PTR DS:[403004] ; |hWnd = 00000B24 (class='Edit',wndproc=0040102B,parent=00000B18)
004011F5 . E8 70000000 CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA      ←ココ
004011FA . 68 2C304000 PUSH CRKME04.0040302C
004011FF . E8 20000000 CALL CRKME04.00401224
00401204 . 3D F9602E2C CMP EAX,2C2E60F9
00401209 . 75 14 JNZ SHORT CRKME04.0040121F
0040120B . 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
0040120D . 68 ED304000 PUSH CRKME04.004030ED ; |Title = "登録情報"4030
00401212 . 68 F6304000 PUSH CRKME04.004030F6 ; |Text = "正解です!"4030F
00401217 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
0040121A . E8 57000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
0040121F >^E9 7AFEFFFF JMP CRKME04.0040109E
00401224 /$ 55 PUSH EBP
00401225 |. 8BEC MOV EBP,ESP
00401227 |. 33DB XOR EBX,EBX
00401229 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8]
0040122C |> AC /LODS BYTE PTR DS:[ESI]
0040122D |. 83F8 00 |CMP EAX,0
00401230 |. 74 19 |JE SHORT CRKME04.0040124B
00401232 |. 83F8 30 |CMP EAX,30
00401235 |. 72 12 |JB SHORT CRKME04.00401249
00401237 |. 83F8 39 |CMP EAX,39
0040123A |. 77 0D |JA SHORT CRKME04.00401249
0040123C |. 83E8 30 |SUB EAX,30
0040123F |. 93 |XCHG EAX,EBX
00401240 |. 6BC0 0A |IMUL EAX,EAX,0A
00401243 |. 03D8 |ADD EBX,EAX
00401245 |. 33C0 |XOR EAX,EAX
00401247 |.^EB E3 \JMP SHORT CRKME04.0040122C
00401249 |> 33DB XOR EBX,EBX
0040124B |> 8BC3 MOV EAX,EBX
0040124D |. C9 LEAVE
0040124E \. C2 0400 RETN 4
00401251 CC


ここでチェックルーチンをざっとみてみましょう。
push , call , cmp , jnz と続いています。
その中で、

00401204 . 3D F9602E2C CMP EAX,2C2E60F9 

が怪しそうです。
このeaxは直前のcall命令の帰り値です。
入力パスを push して call 命令に入っています。ここで call 内部に潜るのもありですが、
F8で素通りしてみましょう。


004011FA . 68 2C304000 PUSH CRKME04.0040302C
004011FF . E8 20000000 CALL CRKME04.00401224
00401204 . 3D F9602E2C CMP EAX,2C2E60F9
00401209 . 75 14 JNZ SHORT CRKME04.0040121F


call 命令の後に eax の値と比較しているのですが、eax の値をよく見て下さい。
フェイクパス「98765432」で、 eax = 5E30A78 です。これは十進数に直すと、98765432 です。
call 命令は、入力文字列を10進数とみなして、値に変えて eax レジスタに変換した値を返していることがわかります。

なお、アクセサリから「電卓」→表示→関数電卓で16進計算できます。

cmp eax, 2C2E60F9 、eax には入力パスの値が入っています。これと 2C2E60F9 を比較しているわけですから、
2C2E60F9 を10進数になおしたものが答えになるはずです。

741236985

レジスタの部分をダブルクリックすれば10進数も表示出来ますので御参考までに・・・。
16進数は解析を行う上では必須の知識ですのでこれを機会に覚えましょう(^^;。