环境
windows xp sp3
工具
exeinfo pe ollydbg
查壳
无壳的汇编程序(OD载入的出来的)
测试
当name输入为数字时,会弹出两次错误框。
OD载入搜字符串,发现有两个地方:
0040134D /$ 6A 30 push 0x30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0040134F |. 68 29214000 push Cruehead.00402129 ; |Title = "Good work!"
00401354 |. 68 34214000 push Cruehead.00402134 ; |Text = "Great work, mate!
Now try the next CrackMe!"
00401359 |. FF75 08 push [arg.1] ; |hOwner
0040135C |. E8 D9000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401361 \. C3 retn
00401362 /$ 6A 00 push 0x0 ; /BeepType = MB_OK
00401364 |. E8 AD000000 call <jmp.&USER32.MessageBeep> ; \MessageBeep
00401369 |. 6A 30 push 0x30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0040136B |. 68 60214000 push Cruehead.00402160 ; |Title = "No luck!"
00401370 |. 68 69214000 push Cruehead.00402169 ; |Text = "No luck there, mate!"
00401375 |. FF75 08 push [arg.1] ; |hOwner
00401378 |. E8 BD000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
0040137D \. C3 retn
0040137E /$ 8B7424 04 mov esi,dword ptr ss:[esp+0x4]
00401382 |. 56 push esi
00401383 |> 8A06 /mov al,byte ptr ds:[esi]
00401385 |. 84C0 |test al,al
00401387 |. 74 13 |je XCruehead.0040139C
00401389 |. 3C 41 |cmp al,0x41
0040138B |. 72 1F |jb XCruehead.004013AC
0040138D |. 3C 5A |cmp al,0x5A
0040138F |. 73 03 |jnb XCruehead.00401394
00401391 |. 46 |inc esi
00401392 |.^ EB EF |jmp XCruehead.00401383
00401394 |> E8 39000000 |call Cruehead.004013D2
00401399 |. 46 |inc esi
0040139A |.^ EB E7 \jmp XCruehead.00401383
0040139C |> 5E pop esi
0040139D |. E8 20000000 call Cruehead.004013C2
004013A2 |. 81F7 78560000 xor edi,0x5678
004013A8 |. 8BC7 mov eax,edi
004013AA |. EB 15 jmp XCruehead.004013C1
004013AC |> 5E pop esi
004013AD |. 6A 30 push 0x30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004013AF |. 68 60214000 push Cruehead.00402160 ; |Title = "No luck!"
004013B4 |. 68 69214000 push Cruehead.00402169 ; |Text = "No luck there, mate!"
004013B9 |. FF75 08 push [arg.1] ; |hOwner
004013BC |. E8 79000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013C1 \> C3 retn
可以猜测出会有两次判断,当第一次错误时,弹出的错误消息框是[004013BC]的,然后再会弹出[00401378]的消息框。于是可以下断点,看看第一次显示错误消息框的函数是在哪里调用的。
004011E6 > 5B pop ebx
004011E7 . |5F pop edi
004011E8 . |5E pop esi
004011E9 . |C9 leave
004011EA . |C2 1000 retn 0x10
004011ED > |6A 00 push 0x0 ; /lParam = NULL
004011EF . |68 0A134000 push Cruehead.0040130A ; |DlgProc = Cruehead.0040130A
004011F4 . |FF75 08 push dword ptr ss:[ebp+0x8] ; |hOwner
004011F7 . |68 1F214000 push Cruehead.0040211F ; |pTemplate = "DLG_ABOUT"
004011FC . |FF35 CA204000 push dword ptr ds:[0x4020CA] ; |hInst = 00400000
00401202 . |E8 99020000 call <jmp.&USER32.DialogBoxParamA> ; \DialogBoxParamA
00401207 .^ EB DD jmp XCruehead.004011E6
00401209 > |6A 00 push 0x0 ; /lParam = NULL
0040120B . |68 53124000 push Cruehead.00401253 ; |DlgProc = Cruehead.00401253
00401210 . |FF75 08 push dword ptr ss:[ebp+0x8] ; |hOwner
00401213 . |68 15214000 push Cruehead.00402115 ; |pTemplate = "DLG_REGIS"
00401218 . |FF35 CA204000 push dword ptr ds:[0x4020CA] ; |hInst = 00400000
0040121E . |E8 7D020000 call <jmp.&USER32.DialogBoxParamA> ; \DialogBoxParamA
00401223 . |83F8 00 cmp eax,0x0
00401226 .^ 74 BE je XCruehead.004011E6
00401228 . |68 8E214000 push Cruehead.0040218E ; ASCII "123456",这是输入的name
0040122D . |E8 4C010000 call Cruehead.0040137E ; 第一个错误消息框弹出位置
00401232 . |50 push eax
00401233 . |68 7E214000 push Cruehead.0040217E ; ASCII "12345",这是输入的serial
00401238 . |E8 9B010000 call Cruehead.004013D8 ; 第二个比较点
0040123D . |83C4 04 add esp,0x4
00401240 . |58 pop eax
00401241 . |3BC3 cmp eax,ebx
00401243 . |74 07 je XCruehead.0040124C
00401245 . |E8 18010000 call Cruehead.00401362 ; 第二次消息框弹出位置
0040124A .^ EB 9A jmp XCruehead.004011E6
0040124C > |E8 FC000000 call Cruehead.0040134D ; 正确消息框弹出
00401251 .^\EB 93 jmp XCruehead.004011E6
这样就可以在两个关键call的位置下断点分析了。
第一个call的分析:
0040137E /$ 8B7424 04 mov esi,dword ptr ss:[esp+0x4]
00401382 |. 56 push esi
00401383 |> 8A06 /mov al,byte ptr ds:[esi]
00401385 |. 84C0 |test al,al
00401387 |. 74 13 |je XCruehead.0040139C
00401389 |. 3C 41 |cmp al,0x41
0040138B |. 72 1F |jb XCruehead.004013AC ; 如果有比'A'小的就跳出循环,弹出错误
0040138D |. 3C 5A |cmp al,0x5A
0040138F |. 73 03 |jnb XCruehead.00401394 ; 如果有比'Z'大的就减0x20
00401391 |. 46 |inc esi
00401392 |.^ EB EF |jmp XCruehead.00401383
00401394 |> E8 39000000 |call Cruehead.004013D2 ; 这里就是减0x20
00401399 |. 46 |inc esi
0040139A |.^ EB E7 \jmp XCruehead.00401383
0040139C |> 5E pop esi
0040139D |. E8 20000000 call Cruehead.004013C2 ; 这里是将字符串的每个字符的ascii值加起来
004013A2 |. 81F7 78560000 xor edi,0x5678
004013A8 |. 8BC7 mov eax,edi
004013AA |. EB 15 jmp XCruehead.004013C1
004013AC |> 5E pop esi
004013AD |. 6A 30 push 0x30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004013AF |. 68 60214000 push Cruehead.00402160 ; |Title = "No luck!"
004013B4 |. 68 69214000 push Cruehead.00402169 ; |Text = "No luck there, mate!"
004013B9 |. FF75 08 push [arg.1] ; |hOwner
004013BC |. E8 79000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013C1 \> C3 retn
004013C2 /$ 33FF xor edi,edi
004013C4 |. 33DB xor ebx,ebx
004013C6 |> 8A1E /mov bl,byte ptr ds:[esi]
004013C8 |. 84DB |test bl,bl
004013CA |. 74 05 |je XCruehead.004013D1
004013CC |. 03FB |add edi,ebx
004013CE |. 46 |inc esi
004013CF |.^ EB F5 \jmp XCruehead.004013C6
004013D1 \> C3 retn
其实就是按一定要求处理name然后再将name中每个字符加起来后异或0x5678
第二个call的分析:
004013D8 /$ 33C0 xor eax,eax
004013DA |. 33FF xor edi,edi
004013DC |. 33DB xor ebx,ebx
004013DE |. 8B7424 04 mov esi,dword ptr ss:[esp+0x4]
004013E2 |> B0 0A /mov al,0xA
004013E4 |. 8A1E |mov bl,byte ptr ds:[esi]
004013E6 |. 84DB |test bl,bl
004013E8 |. 74 0B |je XCruehead.004013F5
004013EA |. 80EB 30 |sub bl,0x30
004013ED |. 0FAFF8 |imul edi,eax
004013F0 |. 03FB |add edi,ebx
004013F2 |. 46 |inc esi
004013F3 |.^ EB ED \jmp XCruehead.004013E2
004013F5 |> 81F7 34120000 xor edi,0x1234
004013FB |. 8BDF mov ebx,edi
004013FD \. C3 retn
这里是将serial的内容转成16进制后与0x1234进行异或运算。
最后比较两个call的返回值是否相同,不同的话会弹出第二个错误消息框。如果相同的话会弹出正确的消息框。
如:
name:1
serial:4661
就会弹出两个消息框,一个错误的,一个正确的。
name:gnubd
serial:17724