crackme#13 解析手引き

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


今回は試用期限解除です。


一度crkme13.exeを起動してみましょう。
crackme #13のウィンドウが表示され、なかに試用期限が10月24日までと表示されているかと思います。
では、windowsの時計を10月25日以降に変更して起動し直してみて下さい。
エラー画面が出力されたかと思います。
OKボタンを押して終了させて下さい。


試用期限が10月24日までとなっていますので、windowsから時間(日付)を取得して判断しているのが分かります。
と、いうことでそれらしいプログラムを探しましょう。

OllyDBGを、起動して「crkme13.exe」を読込んでください。


CPUウィンドウで、右クリックをして、「検索」→「ラベル一覧」(「Search for」→「Name(Label)」)で、
ラベル一覧の一覧を表示します。


Names in crkme13
アドレス  セクション  タイプ ( 名前 コメント 
00401000 .text Export <ModuleEntryPoint>
00402000 .rdata Import ( KERNEL32.ExitProcess
00402004 .rdata Import ( KERNEL32.GetModuleHandleA
00402008 .rdata Import ( KERNEL32.GetLocalTime
00402010 .rdata Import ( USER32.MessageBeep
00402014 .rdata Import ( USER32.LoadIconA
00402018 .rdata Import ( USER32.EndDialog
0040201C .rdata Import ( USER32.MessageBoxA
00402020 .rdata Import ( USER32.DialogBoxParamA
00402024 .rdata Import ( USER32.SendMessageA


GetLocalTimeという怪しい所がありますね・・・。
「KERNEL32.GetLocalTime」を選択して、「Enter」キーを押してください。
「References in crkme13:.text to KERNEL32.GetLocalTime」というウィンドウが表示されます。


References in crkme13:.text to KERNEL32.GetLocalTime
アドレス  逆アセンブル  コメント 
0040108E CALL <JMP.&KERNEL32.GetLocalTime>
004011FC JMP DWORD PTR DS:[<&KERNEL32.GetLocalTim KERNEL32.GetLocalTime


0040108E CALL <JMP.&KERNEL32.GetLocalTime>を選択して、「F2」キーでブレークポイントを設定してください。

「F9」キーで動かしてみましょう。
先程ブレークポイントを仕掛けた場所で止まります。


00401084 /$ 55 PUSH EBP
00401085 |. 8BEC MOV EBP,ESP
00401087 |. 83C4 F0 ADD ESP,-10
0040108A |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
0040108D |. 50 PUSH EAX ; /pLocaltime
0040108E |. E8 69010000 CALL <JMP.&KERNEL32.GetLocalTime> ; \GetLocalTime  ←ココ
00401093 |. FF75 FC PUSH DWORD PTR SS:[EBP-4]
00401096 |. FF75 F8 PUSH DWORD PTR SS:[EBP-8]
00401099 |. FF75 F4 PUSH DWORD PTR SS:[EBP-C]
0040109C |. FF75 F0 PUSH DWORD PTR SS:[EBP-10]
0040109F |. E8 04010000 CALL crkme13.004011A8
004010A4 |. 48 DEC EAX
004010A5 |. 83F8 FF CMP EAX,-1
004010A8 |. 75 36 JNZ SHORT crkme13.004010E0
004010AA |. B8 EA214000 MOV EAX,crkme13.004021EA
004010AF |. A3 40304000 MOV DWORD PTR DS:[403040],EAX
004010B4 |. 6A 30 PUSH 30
004010B6 |. B8 002C4000 MOV EAX,crkme13.00402C00
004010BB |. 05 00040000 ADD EAX,400
004010C0 |. 50 PUSH EAX
004010C1 |. B8 07284000 MOV EAX,crkme13.00402807
004010C6 |. 05 00080000 ADD EAX,800
004010CB |. 50 PUSH EAX
004010CC |. 6A 00 PUSH 0
004010CE |. 812D 40304000 >SUB DWORD PTR DS:[403040],1000
004010D8 |. FF15 40304000 CALL DWORD PTR DS:[403040]
004010DE |. C9 LEAVE
004010DF |. C3 RETN
004010E0 |> 6A 00 PUSH 0 ; /lParam = NULL
004010E2 |. 68 F8104000 PUSH crkme13.004010F8 ; |DlgProc = crkme13.004010F8
004010E7 |. 6A 00 PUSH 0 ; |hOwner = NULL
004010E9 |. 6A 01 PUSH 1 ; |pTemplate = 1
004010EB |. FF35 38304000 PUSH DWORD PTR DS:[403038] ; |hInst = 00400000
004010F1 |. E8 DC000000 CALL <JMP.&USER32.DialogBoxParamA> ; \DialogBoxParamA
004010F6 |. C9 LEAVE
004010F7 \. C3 RETN


0040108D |. 50 PUSH EAX ; /pLocaltime
0040108E |. E8 69010000 CALL <JMP.&KERNEL32.GetLocalTime> ; \GetLocalTime

ここで時間を取得しているようですね。
「F8」キーを押して抜け、「F7」キーを4回押して下さい。

0040109F |. E8 04010000 CALL crkme13.004011A8

このコール先で日付の比較を行っています。
コール先を見てみましょう。「F7」キーを押して下さい。

004011A8 /$ 55 PUSH EBP
004011A9 |. 8BEC MOV EBP,ESP
004011AB |. 66:817D 08 D20>CMP WORD PTR SS:[EBP+8],7D2
004011B1 |. 77 12 JA SHORT crkme13.004011C5
004011B3 |. 72 14 JB SHORT crkme13.004011C9
004011B5 |. 66:837D 0A 0A CMP WORD PTR SS:[EBP+A],0A
004011BA |. 77 09 JA SHORT crkme13.004011C5
004011BC |. 72 0B JB SHORT crkme13.004011C9
004011BE |. 66:837D 0E 18 CMP WORD PTR SS:[EBP+E],18
004011C3 |. 76 04 JBE SHORT crkme13.004011C9
004011C5 |> 33C0 XOR EAX,EAX
004011C7 |. EB 05 JMP SHORT crkme13.004011CE
004011C9 |> B8 01000000 MOV EAX,1
004011CE |> C9 LEAVE
004011CF \. C2 1000 RETN 10


004011AB |. 66:817D 08 D20>CMP WORD PTR SS:[EBP+8],7D2

ここで、西暦を比較しています。
SS:[EBP+8]は SS:[0012FF9C]=07D2ですね、それと 7D2 を比較しているので
下の条件JUMPは、飛びません。
0x7D2は16進数で、10進数に直すと2002です。

004011B5 |. 66:837D 0A 0A CMP WORD PTR SS:[EBP+A],0A
ここで、月を比較しています。
0x0Aは16進数で、10進数に直すと10です。
下の条件JUMPは、飛びません。次も飛びません。

004011BE |. 66:837D 0E 18 CMP WORD PTR SS:[EBP+E],18
ここで、日を比較しています。
0x18は16進数で、10進数に直すと24です。
下の条件JUMPは、飛びません。次は飛びます。

004011C9 |> B8 01000000 MOV EAX,1
004011CE |> C9 LEAVE
004011CF \. C2 1000 RETN 10
ここで、期限内であれば、EAXに 1 を入れて、戻る事が解ります。

16進→10進にはwindows標準の電卓で求めることができます。
では「F7」キーを押して、コール元に戻ります。

004010A4 |. 48 DEC EAX

これはEAXから1を引いています。
「F7」キーを押して下さい。

004010A5 |. 83F8 FF CMP EAX,-1

ここで、EAXを-1と比較しています。
「F7」キーを押して下さい。

004010A8 |. 75 36 JNZ SHORT crkme13.004010E0

JNZ は、違えばジャンプするという命令です。
ここではEAXが-1(EAX = FFFFFFFF)でなければジャンプします。
ジャンプしない場合は、最終的にエラーのナグ(期限終了の画面)の処理へ行きます。

ここでジャンプした先は、

004010E0 |> 6A 00 PUSH 0 ; /lParam = NULL
004010E2 |. 68 F8104000 PUSH crkme13.004010F8 ; |DlgProc = crkme13.004010F8
004010E7 |. 6A 00 PUSH 0 ; |hOwner = NULL
004010E9 |. 6A 01 PUSH 1 ; |pTemplate = 1
004010EB |. FF35 38304000 PUSH DWORD PTR DS:[403038] ; |hInst = 00400000
004010F1 |. E8 DC000000 CALL <JMP.&USER32.DialogBoxParamA> ; \DialogBoxParamA


004010E0 です。DialogBoxParamAの処理ですね。
このDialogBoxParamAは最初に起動した時、表示されていたcrackme #13のウィンドウです。
つまり、期限を過ぎてもエラーのナグの処理へ行かないようにすればよいのですから、

004010A8 |. 75 36 JNZ SHORT crkme13.004010E0

を修正してあげましょう。
この時点で、最初に進めた時計を直してしまった方は、4010A8にブレークポイントを設定して
windowsの時計を10月25日以降に変更して、Ctrl+F2 (解析→再スタート)で起動し直してみて下さい。

004010A8を選択し、右クリック→逆アセ修正でアセンブル画面を出します。
JNZ SHORT 004010E0 を JMP SHORT 004010E0 へ変更します。
もしくは、Ctrl + E(右クリック→バイナリ→編集)でコード編集画面をだします。
Hex +00 の欄に表示されている 75 36 を EB 36 へ変更して下さい。
どちらも同じ結果を反映します。


変更後は、

004010A8 EB 36 JMP SHORT crkme13.004010E0

となります。
変更が出来たら最初に仕掛けた 0040108E のBPを「F2」キーで解除して、「F9」キーで実行してみましょう。
時計は進めてあるので、crackme #13のウィンドウが表示されたら成功です。

または、先ほどのCALLの中の条件JUMP JA SHORT crkme13.004011C5 を強制JUMPに変えてお試しください。

バイナリを編集して結果を反映させたい場合は変更箇所は次の通りです。

FILENAME crkme13.exe
000004A8:75 EB




            著者・編集:ac  改訂・編集:東洋人さん