crackme#16 解析手引き

―お知らせ―

作者であられる eagle0wlさんより、crackme#16 は認証部分において作者の意図しない動作をするというバグが発見されました。
本来は、最後のボックスの文字で正解が1通りだけ出来るようにする予定だったそうです。
今回は、こういうのもあるよって事で修正はされません。

下記の解説内の解答をもって正解となります。





OllyDBGを、起動して「crkme16.exe」を読込んでください。
取りあえず1度「F9」キーで動かしてみましょう。

crackme #16のウィンドウが、表示されました。
pass入力ウィンドウの下に、「未登録」と表示されてます。
では、OllyDBGを再スタートさせてください。
crackme #16 ではバージョン情報を確認していただけば分かるように、今回は[iniファイル] が作成されるタイプです。
iniファイルがまだ作られてないのでウィンドウに「未登録」と表示されているのは当然ですね。
iniファイルはpassが認証されて初めて作られるのですから、そのpassを求めます。

表示されたウィンドウから GetDlgItemText と判断して、話を進めます。

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

Names in CRKME16
Address Section Type ( Name Comment
00401000 .text Export <ModuleEntryPoint>
00402000 .rdata Import ( KERNEL32.ExitProcess
00402004 .rdata Import ( KERNEL32.lstrcmpA
00402008 .rdata Import ( KERNEL32.lstrcatA
0040200C .rdata Import ( KERNEL32.WritePrivateProfileStringA
00402010 .rdata Import ( KERNEL32.GetPrivateProfileStringA
00402014 .rdata Import ( KERNEL32.GetModuleHandleA
00402018 .rdata Import ( KERNEL32.GetModuleFileNameA
00402020 .rdata Import ( SHLWAPI.PathRemoveFileSpecA
00402024 .rdata Import ( SHLWAPI.PathAddBackslashA
0040202C .rdata Import ( USER32.MessageBeep
00402030 .rdata Import ( USER32.SendMessageA
00402034 .rdata Import ( USER32.MessageBoxA
00402038 .rdata Import ( USER32.SetDlgItemTextA
0040203C .rdata Import ( USER32.LoadIconA
00402040 .rdata Import ( USER32.GetDlgItemTextA
00402044 .rdata Import ( USER32.GetDlgItem
00402048 .rdata Import ( USER32.EndDialog
0040204C .rdata Import ( USER32.EnableWindow
00402050 .rdata Import ( USER32.DialogBoxParamA


00402040 .rdata Import ( USER32.GetDlgItemTextA

を選択し、エンターキーを押すと、「References in crkme16:.text to USER32.GetDlgItemTextA」のウィンドウが表示されます。

References in CRKME16:.text to USER32.GetDlgItemTextA
Address Disassembly Comment
00401216 CALL <JMP.&USER32.GetDlgItemTextA>
00401480 JMP DWORD PTR DS:[<&USER32.GetDlgItemTex


Address 00401216 CALL <JMP.&USER32.GetDlgItemTextA> に「F2」でブレークポイントを設定します。

「F9」キーで実行します。
crackme #16のウィンドウが、表示されました。
フェークパス、12345-23456-34567-45678と入力して、「登録」ボタンクリックしてください。
Ollyに制御が移ります。

では、トレースしていきます。「F8」で順に進んでいって下さい。

00401216 . E8 65020000 CALL ; \GetDlgItemTextA
0040121B . 83F8 05 CMP EAX,5
0040121E . 75 70 JNZ SHORT crkme16.00401290

ここで各欄の文字数を取得しています。
CMP EAX,5ということで、文字数は5文字であると分かります。
ここで5文字でなければ、0040127Dへジャンプします。
ジャンプ先はエラーナグ("パスワードが違います!")になってます。
今回はそれぞれ5文字ずつ入っているので、そのまま進みます。


00401204 > 51 PUSH ECX
00401205 . BA 68000000 MOV EDX,68
0040120A . 2BD1 SUB EDX,ECX
0040120C . 6A 7E PUSH 7E ; /Count = 7E (126.)
0040120E . 8D45 80 LEA EAX,DWORD PTR SS:[EBP-80] ; |
00401211 . 50 PUSH EAX ; |Buffer
00401212 . 52 PUSH EDX ; |ControlID
00401213 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401216 . E8 65020000 CALL ; \GetDlgItemTextA
0040121B . 83F8 05 CMP EAX,5
0040121E . 75 70 JNZ SHORT crkme16.00401290
00401220 . 8D45 80 LEA EAX,DWORD PTR SS:[EBP-80]
00401223 . 50 PUSH EAX ; /StringToAdd
00401224 . 8D85 60FFFFFF LEA EAX,DWORD PTR SS:[EBP-A0] ; |
0040122A . 50 PUSH EAX ; |ConcatString
0040122B . E8 92020000 CALL ; \lstrcatA
00401230 . 59 POP ECX
00401231 . 51 PUSH ECX
00401232 . 83F9 01 CMP ECX,1
00401235 . 74 11 JE SHORT crkme16.00401248
00401237 . 68 6F304000 PUSH crkme16.0040306F ; /StringToAdd = "-"
0040123C . 8D85 60FFFFFF LEA EAX,DWORD PTR SS:[EBP-A0] ; |
00401242 . 50 PUSH EAX ; |ConcatString
00401243 . E8 7A020000 CALL ; \lstrcatA
00401248 > 59 POP ECX
00401249 .^E2 B9 LOOPD SHORT crkme16.00401204

00401204~00401249 の部分でフェークパス、12345-23456-34567-45678を取得しています。

00401249に「F2」でBPを仕掛け、「F9」で実行して、レジスターの動きを見ていくと、一ヶ所ごとに
取り込まれていくのを確認できます。
下を見ていくと、登録完了のナグの手前に

00401252 . E8 8B010000 CALL crkme16.004013E2 ; \crkme16.004013E2

がありますね。どうやらこの先で取得したパスをゴニョゴニョしているようです。
では、「F7」で飛んでみます。

004013E2 /$ 55 PUSH EBP
004013E3 |. 8BEC MOV EBP,ESP
004013E5 |. 83C4 F0 ADD ESP,-10
004013E8 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8]
004013EB |. B9 03000000 MOV ECX,3
004013F0 |> 51 /PUSH ECX
004013F1 |. B9 05000000 |MOV ECX,5
004013F6 |. 33D2 |XOR EDX,EDX
004013F8 |> C1E2 04 |/SHL EDX,4
004013FB |. 0FBE4431 05 ||MOVSX EAX,BYTE PTR DS:[ECX+ESI+5]
00401400 |. 83E0 0F ||AND EAX,0F
00401403 |. 0BD0 ||OR EDX,EAX
00401405 |.^E2 F1 |\LOOPD SHORT crkme16.004013F8

00401407 |. 52 |PUSH EDX
00401408 |. E8 1BFCFFFF |CALL crkme16.00401028
0040140D |. 8D7D F0 |LEA EDI,DWORD PTR SS:[EBP-10]
00401410 |. B9 05000000 |MOV ECX,5
00401415 |. C60439 00 |MOV BYTE PTR DS:[ECX+EDI],0
00401419 |> 0FBE4431 04 |/MOVSX EAX,BYTE PTR DS:[ECX+ESI+4]
0040141E |. F7E1 ||MUL ECX
00401420 |. BB FF000000 ||MOV EBX,0FF
00401425 |. F7F3 ||DIV EBX
00401427 |. 0FBE82 8030400>||MOVSX EAX,BYTE PTR DS:[EDX+403080]
0040142E |. 884439 FF ||MOV BYTE PTR DS:[ECX+EDI-1],AL
00401432 |.^E2 E5 |\LOOPD SHORT crkme16.00401419
00401434 |. C646 05 00 |MOV BYTE PTR DS:[ESI+5],0
00401438 |. 57 |PUSH EDI ; /String2
00401439 |. 56 |PUSH ESI ; |String1
0040143A |. E8 89000000 |CALL ; \lstrcmpA
0040143F |. 59 |POP ECX
00401440 |. 50 |PUSH EAX
00401441 |. C646 05 2D |MOV BYTE PTR DS:[ESI+5],2D
00401445 |. 83C6 06 |ADD ESI,6
00401448 |.^E2 A6 \LOOPD SHORT crkme16.004013F0

0040144A |. B9 03000000 MOV ECX,3
0040144F |. 33C0 XOR EAX,EAX
00401451 |> 5B /POP EBX
00401452 |. 0BC3 |OR EAX,EBX
00401454 |.^E2 FB \LOOPD SHORT crkme16.00401451
00401456 |. 40 INC EAX
00401457 |. 85C0 TEST EAX,EAX
00401459 |. 74 07 JE SHORT crkme16.00401462
0040145B |. B8 01000000 MOV EAX,1
00401460 |. EB 02 JMP SHORT crkme16.00401464
00401462 |> 33C0 XOR EAX,EAX
00401464 |> C9 LEAVE
00401465 \. C2 0400 RETN 4


004013F8 |> C1E2 04 |/SHL EDX,4
004013FB |. 0FBE4431 05 ||MOVSX EAX,BYTE PTR DS:[ECX+ESI+5]
00401400 |. 83E0 0F ||AND EAX,0F
00401403 |. 0BD0 ||OR EDX,EAX
00401405 |.^E2 F1 |\LOOPD SHORT crkme16.004013F8

ここで、 4ヶ所に区切られているパスのうち、順にその一塊りを後ろから読んでいきます。
AND EAX,0FでASCIIコードの一桁にしてます。35を5にといった感じで、要するに"12345"と言うパスなら数字で 54321 になるわけです。

そして、

00401408 |. E8 1BFCFFFF |CALL crkme16.00401028

にコールがあるので、そこも見ておきます。「F7」を押して下さい。

00401000 >/$ 6A 00 PUSH 0 ; /pModule = NULL
00401002 |. E8 A9040000 CALL ; \GetModuleHandleA
00401007 |. A3 63304000 MOV DWORD PTR DS:[403063],EAX
0040100C |. 6A 00 PUSH 0 ; /lParam = NULL
0040100E |. 68 D3114000 PUSH crkme16.004011D3 ; |DlgProc = crkme16.004011D3
00401013 |. 6A 00 PUSH 0 ; |hOwner = NULL
00401015 |. 6A 01 PUSH 1 ; |pTemplate = 1
00401017 |. FF35 63304000 PUSH DWORD PTR DS:[403063] ; |hInst = 00400000
0040101D |. E8 46040000 CALL ; \DialogBoxParamA
00401022 |. 50 PUSH EAX ; /ExitCode
00401023 |. E8 7C040000 CALL ; \ExitProcess
00401028 |$ 55 PUSH EBP
00401029 |. 8BEC MOV EBP,ESP
0040102B |. 8B5D 08 MOV EBX,DWORD PTR SS:[EBP+8]
0040102E |. B9 00010000 MOV ECX,100
00401033 |> 51 /PUSH ECX
00401034 |. 8BC3 |MOV EAX,EBX
00401036 |. B9 3E000000 |MOV ECX,3E
0040103B |. 33D2 |XOR EDX,EDX
0040103D |. F7F1 |DIV ECX
0040103F |. 83FA 09 |CMP EDX,9
00401042 |. 77 05 |JA SHORT crkme16.00401049
00401044 |. 83C2 30 |ADD EDX,30
00401047 |. EB 0D |JMP SHORT crkme16.00401056
00401049 |> 83FA 23 |CMP EDX,23
0040104C |. 77 05 |JA SHORT crkme16.00401053
0040104E |. 83C2 37 |ADD EDX,37
00401051 |. EB 03 |JMP SHORT crkme16.00401056
00401053 |> 83C2 3D |ADD EDX,3D
00401056 |> 59 |POP ECX
00401057 |. 8891 7F304000 |MOV BYTE PTR DS:[ECX+40307F],DL
0040105D |. 81F3 5B7CCB3D |XOR EBX,3DCB7C5B
00401063 |. 81C3 F56ED76F |ADD EBX,6FD76EF5
00401069 |. C1C3 07 |ROL EBX,7
0040106C |.^E2 C5 \LOOPD SHORT crkme16.00401033

0040106E |. C9 LEAVE
0040106F \. C2 0400 RETN 4

00401033~0040106CでCPUウィンドウの下のHEXDUMPに下記を算出、アドレス403178から上に取得して行ってます。
0040106Cに「F2」でブレーキポイントを設定して「F9」で実行(256回)、連打していくと確認できます。

00403080 38 46 57 33 42 37 5A 62 8FW3B7Zb
00403088 47 4C 4E 63 42 54 48 4A GLNcBTHJ
00403090 4E 5A 68 62 4B 4C 67 42 NZhbKLgB
00403098 56 4F 36 49 78 36 31 53 VO6Ix61S
004030A0 73 6B 63 48 61 37 52 35 skcHa7R5
004030A8 6E 4C 74 6F 45 78 6D 68 nLtoExmh
004030B0 62 55 36 6E 67 77 57 64 bU6ngwWd
004030B8 78 4A 37 64 6D 32 68 70 xJ7dm2hp
004030C0 4A 75 59 58 4A 77 31 46 JuYXJw1F
004030C8 74 65 43 49 32 64 42 73 teCI2dBs
004030D0 71 76 78 56 77 69 39 62 qvxVwi9b
004030D8 71 5A 78 72 65 34 46 42 qZxre4FB
004030E0 46 54 63 50 32 31 38 61 FTcP218a
004030E8 37 4A 67 42 33 52 59 65 7JgB3RYe
004030F0 54 51 5A 33 4D 70 53 37 TQZ3MpS7
004030F8 36 68 69 6F 49 6B 37 6F 6hioIk7o
00403100 69 4B 51 71 37 4F 72 30 iKQq7Or0
00403108 6D 65 55 31 35 64 77 55 meU15dwU
00403110 5A 6A 32 77 43 54 62 6D Zj2wCTbm
00403118 66 4F 79 54 41 4C 55 46 fOyTALUF
00403120 5A 61 70 36 44 6A 53 4F Zap6DjSO
00403128 33 41 77 34 75 48 74 42 3Aw4uHtB
00403130 72 38 70 63 33 74 4E 67 r8pc3tNg
00403138 30 4E 4E 76 31 62 70 55 0NNv1bpU
00403140 42 79 4C 32 7A 47 4A 52 ByL2zGJR
00403148 38 42 50 53 67 39 6A 4C 8BPSg9jL
00403150 63 58 54 75 34 59 79 72 cXTu4Yyr
00403158 68 34 50 45 7A 4A 50 76 h4PEzJPv
00403160 44 64 61 63 78 33 33 6D Ddacx33m
00403168 52 7A 63 4C 4D 65 76 41 RzcLMevA
00403170 77 55 61 39 53 75 67 35 wUa9Sug5
00403178 72 50 68 31 68 53 6B 70 rPh1hSkp


コール元に戻って先に進みます。「F8」を押して下さい。

00401419 |> 0FBE4431 04 |/MOVSX EAX,BYTE PTR DS:[ECX+ESI+4]
0040141E |. F7E1 ||MUL ECX
00401420 |. BB FF000000 ||MOV EBX,0FF
00401425 |. F7F3 ||DIV EBX
00401427 |. 0FBE82 8030400>||MOVSX EAX,BYTE PTR DS:[EDX+403080]
0040142E |. 884439 FF ||MOV BYTE PTR DS:[ECX+EDI-1],AL
00401432 |.^E2 E5 |\LOOPD SHORT crkme16.00401419

ここで入力した文字を00401033~0040106Cで得た文字列に変換を行っています。
5回ループして、EDIに変換した文字(ASCII) が入ります。
その値(文字を)メモしておいて下さい。

これを3回繰り返し、各欄がそれぞれ置き換えられます。

ここで"12345-23456-34567"までの値が出来あがります →EDQr6-CxEkl-Xz2Ym
このルーチンを抜けると、戻った先の

00401259 . 74 22 JE SHORT crkme16.0040127D

でジャンプして、エラーナグ"パスワードが違います!"へ行ってしまいました。
もちろん、フェークパスですから仕方ないですね。
では、一度再スタートして下さい。

さて、先程までのルーチンには、45678の部分のパスだしルーチンがありませんでした。
困りましたね~。

逆アセリストを覗いていくと、


004010D8 /$ 55 PUSH EBP
004010D9 |. 8BEC MOV EBP,ESP
004010DB |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8]
004010DE |. 4E DEC ESI
004010DF |. B9 03000000 MOV ECX,3
004010E4 |> 83C6 06 /ADD ESI,6
004010E7 |. 803E 2D |CMP BYTE PTR DS:[ESI],2D
004010EA |. 75 44 |JNZ SHORT crkme16.00401130
004010EC |.^E2 F6 \LOOPD SHORT crkme16.004010E4
004010EE |. 46 INC ESI
004010EF |. 803E 30 CMP BYTE PTR DS:[ESI],30
004010F2 |. 72 3C JB SHORT crkme16.00401130
004010F4 |. 803E 39 CMP BYTE PTR DS:[ESI],39
004010F7 |. 77 37 JA SHORT crkme16.00401130
004010F9 |. 807E 01 41 CMP BYTE PTR DS:[ESI+1],41
004010FD |. 72 31 JB SHORT crkme16.00401130
004010FF |. 807E 01 5A CMP BYTE PTR DS:[ESI+1],5A
00401103 |. 77 2B JA SHORT crkme16.00401130
00401105 |. 807E 02 61 CMP BYTE PTR DS:[ESI+2],61
00401109 |. 72 25 JB SHORT crkme16.00401130
0040110B |. 807E 02 7A CMP BYTE PTR DS:[ESI+2],7A
0040110F |. 77 1F JA SHORT crkme16.00401130
00401111 |. 807E 03 45 CMP BYTE PTR DS:[ESI+3],45
00401115 |. 72 19 JB SHORT crkme16.00401130
00401117 |. 807E 03 55 CMP BYTE PTR DS:[ESI+3],55
0040111B |. 77 13 JA SHORT crkme16.00401130
0040111D |. 807E 04 6B CMP BYTE PTR DS:[ESI+4],6B
00401121 |. 72 0D JB SHORT crkme16.00401130
00401123 |. 807E 04 73 CMP BYTE PTR DS:[ESI+4],73
00401127 |. 77 07 JA SHORT crkme16.00401130
00401129 |. B8 01000000 MOV EAX,1
0040112E |. EB 02 JMP SHORT crkme16.00401132
00401130 |> 33C0 XOR EAX,EAX
00401132 |> C9 LEAVE
00401133 \. C2 0400 RETN 4

と言う場所を発見。臭いですね~。
このルーチンがどこからきているのか調べてみます。

004010D8 を Ctrl + r でみてみます。

0040135A から来ているのが分かりますね? ではそこにいきます。
0040135A をダブルクリックして、アセンブラ画面に飛んでください。

下を見ていくと、

0040135A . E8 79FDFFFF CALL crkme16.004010D8
0040135F . 85C0 TEST EAX,EAX
00401361 . 74 24 JE SHORT crkme16.00401387
00401363 . 8D85 60FFFFFF LEA EAX,DWORD PTR SS:[EBP-A0]
00401369 . 50 PUSH EAX ; /Arg1
0040136A . E8 73000000 CALL crkme16.004013E2 ; \crkme16.004013E2
0040136F . 85C0 TEST EAX,EAX
00401371 . 74 54 JE SHORT crkme16.004013C7
00401373 . 68 00304000 PUSH crkme16.00403000 ; /Text = "登録済み!"40300
00401378 . 68 F4010000 PUSH 1F4 ; |ControlID = 1F4 (500.)
0040137D . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401380 . E8 19010000 CALL <JMP.&USER32.SetDlgItemTextA> ; \SetDlgItemTextA

登録済みのナグがある・・・。
と言う事は、iniファイル作成後に確認されるルーチンであり、
登録情報が正しいかを確かめる場所でもあるようです。
つまり、ここで4桁目の部分のチェックをしている可能性が非常に高い!

と言う事で、検証してみます。


>1の条件
004010EF |. 803E 30 CMP BYTE PTR DS:[ESI],30
004010F2 |. 72 3C JB SHORT crkme16.00401130
004010F4 |. 803E 39 CMP BYTE PTR DS:[ESI],39
004010F7 |. 77 37 JA SHORT crkme16.00401130
つまり、0~9

>2の条件
004010F9 |. 807E 01 41 CMP BYTE PTR DS:[ESI+1],41
004010FD |. 72 31 JB SHORT crkme16.00401130
004010FF |. 807E 01 5A CMP BYTE PTR DS:[ESI+1],5A
00401103 |. 77 2B JA SHORT crkme16.00401130
つまりA~Z

>3の条件
00401105 |. 807E 02 61 CMP BYTE PTR DS:[ESI+2],61
00401109 |. 72 25 JB SHORT crkme16.00401130
0040110B |. 807E 02 7A CMP BYTE PTR DS:[ESI+2],7A
0040110F |. 77 1F JA SHORT crkme16.00401130
つまり、a~z

>4の条件
00401111 |. 807E 03 45 CMP BYTE PTR DS:[ESI+3],45
00401115 |. 72 19 JB SHORT crkme16.00401130
00401117 |. 807E 03 55 CMP BYTE PTR DS:[ESI+3],55
0040111B |. 77 13 JA SHORT crkme16.00401130
つまり、E~U

>5の条件
0040111D |. 807E 04 6B CMP BYTE PTR DS:[ESI+4],6B
00401121 |. 72 0D JB SHORT crkme16.00401130
00401123 |. 807E 04 73 CMP BYTE PTR DS:[ESI+4],73
00401127 |. 77 07 JA SHORT crkme16.00401130
つまり、k~s

整理すると、4桁目の条件は
1文字目は1~9、2文字目はA~Z、3文字目はa~z、4文字目はE~U、5文字目はk~s と考えられます。
ずいぶんと幅があるご様子・・・。

では、1AaEk としてやってみます。

先に算出された値と組み合わせてみます。
EDQr6-CxEkl-Xz2Ym-1AaEk でチャレンジ!

もう一度同じトレースを最初から繰り返します。

00401419 |> 0FBE4431 04 |/MOVSX EAX,BYTE PTR DS:[ECX+ESI+4]
0040141E |. F7E1 ||MUL ECX
00401420 |. BB FF000000 ||MOV EBX,0FF
00401425 |. F7F3 ||DIV EBX
00401427 |. 0FBE82 8030400>||MOVSX EAX,BYTE PTR DS:[EDX+403080]
0040142E |. 884439 FF ||MOV BYTE PTR DS:[ECX+EDI-1],AL
00401432 |.^E2 E5 |\LOOPD SHORT crkme16.00401419

ここを再度注目しておきます。
各欄ごとEDIに変換した文字(ASCII) をメモしておきます。

これを3回繰り返します。

すると、EDIの値が、順に zF5Pp、zGZ2H、69dlN となり、

00401257 . 85C0 TEST EAX,EAX
00401259 . 74 22 JE SHORT crkme16.0040127D
0040125B . 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
0040125D . 6A 00 PUSH 0 ; |Title = NULL
0040125F . 68 0B304000 PUSH crkme16.0040300B ; |Text = "登録が完了しました。設定を反映させるためにいったん終了します。"
00401264 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
00401267 . E8 26020000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
0040126C . 8D85 60FFFFFF LEA EAX,DWORD PTR SS:[EBP-A0]
00401272 . 50 PUSH EAX ; /Arg1
00401273 . E8 FAFDFFFF CALL crkme16.00401072 ; \crkme16.00401072
00401278 . E9 52010000 JMP crkme16.004013CF
0040127D > 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
0040127F . 6A 00 PUSH 0 ; |Title = NULL
00401281 . 68 4C304000 PUSH crkme16.0040304C ; |Text = "パスワードが違います!"
00401286 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
00401289 . E8 04020000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA

戻り先にある、

00401259 . 74 22 JE SHORT crkme16.0040127D

でジャンプして、エラーナグ"パスワードが違います!"へ行ってしまいました。
先程の組合せでは駄目なようです。

では、先程出力された zF5Pp、zGZ2H、69dlN を使って再度トレースし直してみます。

zF5Pp-zGZ2H-69dlN-1AaEk にして再度同じようにトレースを繰り返していきます。

すると、

00401257 . 85C0 TEST EAX,EAX
00401259 . 74 23 JE SHORT crkme16.0040127E
0040125B . 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
0040125D . 6A 00 PUSH 0 ; |Title = NULL
0040125F . 68 0B304000 PUSH crkme16.0040300B ; |Text = "登録が完了しました。設定を反映させるためにいったん終了します。"
00401264 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
00401267 . E8 26020000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA

先程まで00401259でエラーに飛んでいたのが、飛ばずに登録ナグに入りました。

crackme#16のウィンドウに"登録が完了しました。設定を反映させるためにいったん終了します。"
というメッセージがでるので、OKを押すと、Ollyに制御が移ります。
「F8」で進めていきます。

0040126C . 8D85 60FFFFFF LEA EAX,DWORD PTR SS:[EBP-A0]
00401272 . 50 PUSH EAX ; /Arg1
00401273 . E8 FAFDFFFF CALL crkme16.00401072 ; \crkme16.00401072

00401273のコールがありますので「F7」でに飛びます。


00401072 /$ 55 PUSH EBP
00401073 |. 8BEC MOV EBP,ESP
00401075 |. 81C4 00FDFFFF ADD ESP,-300
0040107B |. 8DB5 00FDFFFF LEA ESI,DWORD PTR SS:[EBP-300]
00401081 |. 56 PUSH ESI
00401082 |. E8 17000000 CALL crkme16.0040109E
00401087 |. 56 PUSH ESI ; /FileName
00401088 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |String
0040108B |. 68 95314000 PUSH crkme16.00403195 ; |Key = "Serial"
00401090 |. 68 8E314000 PUSH crkme16.0040318E ; |Section = "Regist"
00401095 |. E8 22040000 CALL <JMP.&KERNEL32.WritePrivateProfileS>; \WritePrivateProfileStringA
0040109A |. C9 LEAVE
0040109B \. C2 0400 RETN 4

00401082にもコールがあるので飛んでみます。


0040109E /$ 55 PUSH EBP
0040109F |. 8BEC MOV EBP,ESP
004010A1 |. 68 FF020000 PUSH 2FF ; /BufSize = 2FF (767.)
004010A6 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |PathBuffer
004010A9 |. FF35 63304000 PUSH DWORD PTR DS:[403063] ; |hModule = 00400000 (crkme16)
004010AF |. E8 F6030000 CALL <JMP.&KERNEL32.GetModuleFileNameA> ; \GetModuleFileNameA
004010B4 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; /Path
004010B7 |. E8 18040000 CALL <JMP.&SHLWAPI.PathRemoveFileSpecA> ; \PathRemoveFileSpecA
004010BC |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; /Path
004010BF |. E8 0A040000 CALL <JMP.&SHLWAPI.PathAddBackslashA> ; \PathAddBackslashA
004010C4 |. 68 80314000 PUSH crkme16.00403180 ; /StringToAdd = "crackme16.ini"
004010C9 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |ConcatString
004010CC |. E8 F1030000 CALL <JMP.&KERNEL32.lstrcatA> ; \lstrcatA
004010D1 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8]
004010D4 |. C9 LEAVE
004010D5 \. C2 0400 RETN 4


ここでiniファイルが作成されていました。
さて、コール先に戻って、

00401072 /$ 55 PUSH EBP
00401073 |. 8BEC MOV EBP,ESP
00401075 |. 81C4 00FDFFFF ADD ESP,-300
0040107B |. 8DB5 00FDFFFF LEA ESI,DWORD PTR SS:[EBP-300]
00401081 |. 56 PUSH ESI
00401082 |. E8 17000000 CALL crkme16.0040109E
00401087 |. 56 PUSH ESI ; /FileName
00401088 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |String
0040108B |. 68 95314000 PUSH crkme16.00403195 ; |Key = "Serial"
00401090 |. 68 8E314000 PUSH crkme16.0040318E ; |Section = "Regist"

00401095 |. E8 22040000 CALL <JMP.&KERNEL32.WritePrivateProfileS>; \WritePrivateProfileStringA
0040109A |. C9 LEAVE
0040109B \. C2 0400 RETN 4

取得したパスがiniファイルに入ります。
そして戻っています。

00401278 . E9 52010000 JMP crkme16.004013CF

戻った先がjmp命令になっていますね。そのまま飛びましょう。

004013CF > 6A 00 PUSH 0 ; /Result = 0
004013D1 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004013D4 . E8 9B000000 CALL <JMP.&USER32.EndDialog> ; \EndDialog

ここでEndDialogに到達しました。
EndDialogで「F9」を押せばプログラムが終了すると思います。

終了したら、再スタートし、「F9」で順にトレースしていきましょう。 ・・・「登録済み!」のナグがでたら大成功です。

もし、"登録情報に問題があります"になってしまった場合は、crackme16.ini を削除してやり直して下さい。

今回の正解:
zF5Pp-zGZ2H-69dlN-1AaEk


パスは5文字×4ヶの形を取っていますが、aaaaa-bbbbb-ccccc-ddddd とすると、
aaaaa の値は bbbbb から決まります。同様に bbbbb の値は ccccc から、
ccccc の値は ddddd から決まります。即ち、ddddd の値が決まればパス全体が決定されます。

dddddの条件は、1文字目は1~9、2文字目はA~Z、3文字目はa~z、4文字目はE~U、5文字目はk~s を満たせば
前の3つはトレースしていく中で出力されるものに置き換えていくと、そのうちに正解になります。



正解例:
zF5Pp-zGZ2H-Xz2Ym-1AaEk
zF5Pp-XmhhH-69dlN-1AaEk
USoKq-XmhhH-69dlN-1AaEk
xcpux-16Po9-AGpFi-0AaEk
zzzzz-zzzzz-zzzzz-6AaEk