crackme#14 解析手引き

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

OllyDBGを起動して「crkme14.exe」を読込んで下さい。
一度「F9」キーで動かしてみましょう。

「未登録」と表示された crackme #14 のウィンドウが表示されました。
crackme #14 では「キーファイル」が問題で定義されているのに、まだ作ってないので当然ですね。
では、終了ボタンを押してこのウィンドウを閉じてから、Ctrl+F2 でOllyDBGを再スタートさせて下さい。

crackme #12 と同じく「CreateFileA」を探します。
CPUウィンドウで右クリック、「検索」→「現在のモジュール名(ラベル)」から
Address 00402010 の「KERNEL32.CreateFileA」を選択し「Enter」キーを押します。


Names in crkme14
Address Section Type ( Name Comment
00401000 .text Export <ModuleEntryPoint>
00402000 .rdata Import ( KERNEL32.CloseHandle
00402004 .rdata Import ( KERNEL32.ReadFile
00402008 .rdata Import ( KERNEL32.GetModuleHandleA
0040200C .rdata Import ( KERNEL32.ExitProcess
00402010 .rdata Import ( KERNEL32.CreateFileA
00402014 .rdata Import ( KERNEL32.GetFileSize
0040201C .rdata Import ( USER32.LoadIconA
00402020 .rdata Import ( USER32.SetDlgItemTextA
00402024 .rdata Import ( USER32.SendMessageA
00402028 .rdata Import ( USER32.MessageBeep
0040202C .rdata Import ( USER32.EndDialog
00402030 .rdata Import ( USER32.DialogBoxParamA


Address 004010FF call <jmp.&KERNEL32.CreateFileA> を選択して、
「F2」キーでブレークポイントを設定して下さい。

References in crkme14:.text to KERNEL32.CreateFileA
Address Disassembly Comment
004010FF CALL <JMP.&KERNEL32.CreateFileA
0040125A JMP DWORD PTR DS:[<&KERNEL32.CreateFileA KERNEL32.CreateFileA

「F9」で再スタートして下さい。

004010FF . E8 56010000 CALL <JMP.&KERNEL32.CreateFileA> ; \CreateFileA
で止まりましたか?


004010E0 . 6A 00 PUSH 0 ; /hTemplateFile = NULL
004010E2 . 68 80000000 PUSH 80 ; |Attributes = NORMAL
004010E7 . 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
004010E9 . 6A 00 PUSH 0 ; |pSecurity = NULL
004010EB . 6A 00 PUSH 0 ; |ShareMode = 0
004010ED . 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ
004010F2 . BE 00304000 MOV ESI,crkme14.00403000 ; |ASCII "crk14_e0.oly"
004010F7 . C746 08 2E6F6C>MOV DWORD PTR DS:[ESI+8],796C6F2E ; |
004010FE . 56 PUSH ESI ; |FileName => "crk14_e0.oly"
004010FF . E8 56010000 CALL <JMP.&KERNEL32.CreateFileA> ; \CreateFileA
00401104 . 83F8 FF CMP EAX,-1
00401107 . 74 61 JE SHORT crkme14.0040116A
00401109 . A3 18304000 MOV DWORD PTR DS:[403018],EAX
0040110E . 6A 00 PUSH 0 ; /pFileSizeHigh = NULL
00401110 . FF35 18304000 PUSH DWORD PTR DS:[403018] ; |hFile = NULL
00401116 . E8 4B010000 CALL <JMP.&KERNEL32.GetFileSize> ; \GetFileSize
0040111B . A3 24304000 MOV DWORD PTR DS:[403024],EAX
00401120 . 83F8 14 CMP EAX,14
00401123 . 75 3A JNZ SHORT crkme14.0040115F
00401125 . 6A 00 PUSH 0 ; /pOverlapped = NULL
00401127 . 68 28304000 PUSH crkme14.00403028 ; |pBytesRead = crkme14.00403028
0040112C . FF35 24304000 PUSH DWORD PTR DS:[403024] ; |BytesToRead = 0
00401132 . 68 2C304000 PUSH crkme14.0040302C ; |Buffer = crkme14.0040302C
00401137 . FF35 18304000 PUSH DWORD PTR DS:[403018] ; |hFile = NULL
0040113D . E8 30010000 CALL <JMP.&KERNEL32.ReadFile> ; \ReadFile
00401142 . 83F8 FF CMP EAX,-1
00401145 . 74 18 JE SHORT crkme14.0040115F
00401147 . E8 27000000 CALL crkme14.00401173
0040114C . 85C0 TEST EAX,EAX
0040114E . 74 0F JE SHORT crkme14.0040115F
00401150 . 68 0D304000 PUSH crkme14.0040300D ; /Text = "登録済み!"40300
00401155 . 6A 64 PUSH 64 ; |ControlID = 64 (100.)
00401157 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
0040115A . E8 EF000000 CALL <JMP.&USER32.SetDlgItemTextA> ; \SetDlgItemTextA
0040115F > FF35 18304000 PUSH DWORD PTR DS:[403018] ; /hObject = NULL
00401165 . E8 EA000000 CALL <JMP.&KERNEL32.CloseHandle> ; \CloseHandle


ここで前後のプログラムを十字キーの↑↓を使って眺めて見ましょう。

004010FE . 56 PUSH ESI ; |FileName => "crk14_e0.oly"

でファイル名「crk14_e0.oly」を esi レジスタへ入れています。

00401104 . 83F8 FF CMP EAX,-1

で、ファイルの有無をチェックしてます。eax に -1 が入ってるとファイル無しとなり、

00401107 . 74 61 JE SHORT crkme14.0040116A

で、未登録と表示された crackme #14 のウィンドウを表示するルーチンへ行きます。
ファイルがあるとそのまま進んで、

00401116 . E8 4B010000 CALL <JMP.&KERNEL32.GetFileSize> ; \GetFileSize

でファイルサイズをチェックしています。そして、

00401120 . 83F8 14 CMP EAX,14

で、ファイルサイズを 0x14(20バイト)と比較し、等しくないと次の

00401123 . 75 3A JNZ SHORT crkme14.0040115F

で、これも未登録ウィンドウの表示ルーチンへ行きます。
従って、キーファイル名は「crk14_e0.oly」で、サイズは「20バイト」となります。
では、メモ帳等で,内容が「12345678901234567890」、ファイル名「crk14_e0.oly」
を作り、OllyDBGで読込んだ「「crkme14.exe」のある場所へ保存して下さい。

では、「F8」キーを15回連打して,address 0040113D へ行って下さい。

0040113D . E8 30010000 CALL <JMP.&KERNEL32.ReadFile> ; \ReadFile

ここでファイルの中身を読んでます。
次に、「F8」キーを3回押して、

00401147 . E8 27000000 CALL crkme14.00401173

へ行って下さい。

00401173 /$ 33DB XOR EBX,EBX
00401175 |. 33C9 XOR ECX,ECX
00401177 |. 33D2 XOR EDX,EDX
00401179 |. 8D35 2C304000 LEA ESI,DWORD PTR DS:[40302C]
0040117F |> AC /LODS BYTE PTR DS:[ESI]
00401180 |. 83F8 00 |CMP EAX,0
00401183 |. 74 27 |JE SHORT crkme14.004011AC
00401185 |. 83F8 30 |CMP EAX,30
00401188 |. 72 08 |JB SHORT crkme14.00401192
0040118A |. 83F8 39 |CMP EAX,39
0040118D |. 77 03 |JA SHORT crkme14.00401192
0040118F |. 43 |INC EBX
00401190 |.^EB ED |JMP SHORT crkme14.0040117F
00401192 |> 83F8 41 |CMP EAX,41
00401195 |. 72 08 |JB SHORT crkme14.0040119F
00401197 |. 83F8 5A |CMP EAX,5A
0040119A |. 77 03 |JA SHORT crkme14.0040119F
0040119C |. 41 |INC ECX
0040119D |.^EB E0 |JMP SHORT crkme14.0040117F
0040119F |> 83F8 61 |CMP EAX,61
004011A2 |. 72 1A |JB SHORT crkme14.004011BE
004011A4 |. 83F8 7A |CMP EAX,7A
004011A7 |. 77 15 |JA SHORT crkme14.004011BE
004011A9 |. 42 |INC EDX
004011AA |.^EB D3 \JMP SHORT crkme14.0040117F
004011AC |> C1E3 10 SHL EBX,10
004011AF |. C1E1 08 SHL ECX,8
004011B2 |. 0BD9 OR EBX,ECX
004011B4 |. 0BDA OR EBX,EDX
004011B6 |. 81FB 06050900 CMP EBX,90506

004011BC |. 74 03 JE SHORT crkme14.004011C1
004011BE |> 33C0 XOR EAX,EAX
004011C0 |. C3 RETN
004011C1 |> 40 INC EAX
004011C2 \. C3 RETN


「F7」キーを押しながらコール先を見ていきましょう。

00401173 /$ 33DB XOR EBX,EBX
00401175 |. 33C9 XOR ECX,ECX
00401177 |. 33D2 XOR EDX,EDX

で、ebx,ecx,edxの各レジスタのクリアしています。そして、

00401179 |. 8D35 2C304000 LEA ESI,DWORD PTR DS:[40302C]

で、先ほど作成したキーファイル「crk14_e0.oly」の内容(文字列)
「12345678901234567890」の先頭addressを設定し、次の

0040117F |> AC /LODS BYTE PTR DS:[ESI]

で、この文字列を先頭から1バイトずつ取り出して、
ファイルの内容(文字列)が終了するまで 0040117F~004011AA を繰り返します。

「F7」キーから指を離しスクロールバーで下のほうが見えるようにしてから、
ちょっとこの繰り返しの比較を見ていきましょう。

00401180 |. 83F8 00 |CMP EAX,0
00401183 |. 74 27 |JE SHORT crkme14.004011AC

が、終了条件になります。次に

00401185 |. 83F8 30 |CMP EAX,30
00401188 |. 72 08 |JB SHORT crkme14.00401192
0040118A |. 83F8 39 |CMP EAX,39
0040118D |. 77 03 |JA SHORT crkme14.00401192
0040118F |. 43 |INC EBX
00401190 |.^EB ED |JMP SHORT crkme14.0040117F

で、数字文字(ASCIIコード:30~39→0~9)のカウントをして結果を ebx に入れています。
数字文字以外は次の比較に進みます。

00401192 |> 83F8 41 |CMP EAX,41
00401195 |. 72 08 |JB SHORT crkme14.0040119F
00401197 |. 83F8 5A |CMP EAX,5A
0040119A |. 77 03 |JA SHORT crkme14.0040119F
0040119C |. 41 |INC ECX
0040119D |.^EB E0 |JMP SHORT crkme14.0040117F

で、英大文字(ASCIIコード:41~5A→A~Z)のカウントをして結果を ecx に入れています。
数字文字でも英大文字でもない場合は次の比較に進みます。

0040119F |> 83F8 61 |CMP EAX,61
004011A2 |. 72 1A |JB SHORT crkme14.004011BE
004011A4 |. 83F8 7A |CMP EAX,7A
004011A7 |. 77 15 |JA SHORT crkme14.004011BE
004011A9 |. 42 |INC EDX
004011AA |.^EB D3 \JMP SHORT crkme14.0040117F

で、英小文字(ASCIIコード:61~7A→a~z)のカウントをして結果を edx に入れてています。
キーファイルの内容のチェックが終了すると、次の場所に進みます。

004011AC |> C1E3 10 SHL EBX,10
004011AF |. C1E1 08 SHL ECX,8
004011B2 |. 0BD9 OR EBX,ECX
004011B4 |. 0BDA OR EBX,EDX

EBXは数字なのでそれを16bit左に(10→16)9文字なら90000になります。
ECXは英大文字を8bit左にシフト、500になります。
EDX=英小文字はそのまま。
そして、ebx,ecx,edxの順番に結合し,結果を ebx に入れています。
9000+500+6 と言う事で、EBXが90506になります。


では、今度はこれらを2進数に置き換えて考えてみましょう。

004011AC |> C1E3 10 SHL EBX,10

ebx=9 を 0x10(16ビット) 左へシフトを2進数で書くと、1001 0000 0000 0000 0000

004011AF |. C1E1 08 SHL ECX,8

ecx=5 を 0x8(8ビット) 左へシフトを2進数で書くと、0101 0000 0000
edx=6 は2進数で書くと、0110
次のOR命令は論理和で、0 V 0 = 0, 0 V 1 = 1, 1 V 0 = 1, 1 V 1 = 1 ですから,

004011B2 |. 0BD9 OR EBX,ECX

は、1001 0000 0000 0000 0000 or 0101 0000 0000 = 1001 0000 0101 0000 0000 が、
ebx へ入り、次の

004011B4 |. 0BDA OR EBX,EDX

は、1001 0000 0101 0000 0000 or 0110 = 1001 0000 0101 0000 0110 が、ebx へ入ります。
2進数 1001 0000 0101 0000 0110 は、16進数で 90506 となります。



話を戻して次に進みます。

004011B6 |. 81FB 06050900 CMP EBX,90506

で、ebx(結合した結果)を 90506 と比較し、その結果を、このルーチンの戻り先にある

0040114C . 85C0 TEST EAX,EAX
0040114E . 74 0F JE SHORT crkme14.0040115F

で飛ぶか飛ばないかを判断しています。等しいと登録済みになることが解りますね。
等しくないと例の未登録ウィンドウの表示ルーチンへ行きます。

つまり、ebx には 9、ecx には 5、edx には 6 が入っている必要があります。
言い換えると、数字文字が9文字、英大文字が5文字、英小文字が6文字となります。

では、キーファイル書換えのために、Alt+F2 で一旦「crkme14.exe」を閉じて下さい。
そして、先ほど作成したキーファイル「crk14_e0.oly」をメモ帳等で開き、
内容を「123456789ABCDEabcdef」に変更してから、上書き保存して下さい。
出来たら Ctrl+F2 で「crkme14.exe」を再度読込みます。

再スタートして「F9」キーで進めてみましょう。
ブレークポイントは解除していないので,ここで止まったら「F9」キーをもう一度。
登録済!と表示されたcrackme #14のウィンドウが表示されましたか?

後ほどCPUウィンドウとその下のインフォメーションウィンドウを見ながら、
「F7」キーでゆっくりトレースする事をお勧めします。