转自看雪原文连接:http://bbs.pediy.com/showthread.php?t=159883
[KFC]fish’s CrackMe 破文
用OD载入程序,按F9运行,程序显示了窗口就退出了,初步分析有anti代码.打开OD的插件IsDebuggerPresent plugin v1.4后再运行程序,这样就没问题了,说明此程序是用IsDebuggerPresent()这个函数来anti debugger的,但是用W32Dasm或C32ASM又找不出相应的字符串,说明了程序有可能是动态生成了字符串.大约的浏览一下程序的反汇编代码,发现有点地方是与平常不同的,如:
00401670 |. B3 73 mov bl,73
00401672 |. 884C24 22 mov byte ptr ss:[esp+22],cl
00401676 |. 884C24 23 mov byte ptr ss:[esp+23],cl
0040167A |. 56 push esi
0040167B |. 8D4C24 0C lea ecx,dword ptr ss:[esp+C]
0040167F |. C64424 10 4B mov byte ptr ss:[esp+10],4B
00401684 |. 884424 11 mov byte ptr ss:[esp+11],al
00401688 |. 885424 12 mov byte ptr ss:[esp+12],dl
0040168C |. C64424 13 6E mov byte ptr ss:[esp+13],6E
00401691 |. 884424 14 mov byte ptr ss:[esp+14],al
00401695 |. C64424 16 33 mov byte ptr ss:[esp+16],33
0040169A |. C64424 17 32 mov byte ptr ss:[esp+17],32
0040169F |. C64424 18 2E mov byte ptr ss:[esp+18],2E
004016A4 |. C64424 19 64 mov byte ptr ss:[esp+19],64
004016A9 |. C64424 1C 00 mov byte ptr ss:[esp+1C],0
004016AE |. C64424 20 49 mov byte ptr ss:[esp+20],49
004016B3 |. 885C24 21 mov byte ptr ss:[esp+21],bl
004016B7 |. C64424 22 44 mov byte ptr ss:[esp+22],44
004016BC |. 884424 23 mov byte ptr ss:[esp+23],al
004016C0 |. C64424 24 62 mov byte ptr ss:[esp+24],62
004016C5 |. C64424 25 75 mov byte ptr ss:[esp+25],75
004016CA |. 884424 28 mov byte ptr ss:[esp+28],al
还有
0040145E . 8D4C24 10 lea ecx,dword ptr ss:[esp+10]
00401462 . 33FF xor edi,edi
00401464 . E8 7F080000 call <jmp.&MFC42.#540_CString::CString>
00401469 . B0 41 mov al,41
0040146B . B1 62 mov cl,62
0040146D . 884424 1D mov byte ptr ss:[esp+1D],al
00401471 . 884424 29 mov byte ptr ss:[esp+29],al
00401475 . 884424 31 mov byte ptr ss:[esp+31],al
00401479 . 884424 35 mov byte ptr ss:[esp+35],al
0040147D . 884C24 20 mov byte ptr ss:[esp+20],cl
00401481 . 884C24 34 mov byte ptr ss:[esp+34],cl
00401485 . B0 11 mov al,11
00401487 . B1 69 mov cl,69
00401489 . 884424 38 mov byte ptr ss:[esp+38],al
0040148D . 884424 3C mov byte ptr ss:[esp+3C],al
00401491 . B3 4B mov bl,4B
00401493 . B2 68 mov dl,68
00401495 . 884C24 37 mov byte ptr ss:[esp+37],cl
00401499 . 884C24 3A mov byte ptr ss:[esp+3A],cl
0040149D . B0 CF mov al,0CF
0040149F . 6A 01 push 1
004014A1 . 8BCE mov ecx,esi
004014A3 . 897C24 54 mov dword ptr ss:[esp+54],edi
004014A7 . C64424 1C 7D mov byte ptr ss:[esp+1C],7D
004014AC . C64424 1D 08 mov byte ptr ss:[esp+1D],8
004014B1 . C64424 1E 18 mov byte ptr ss:[esp+1E],18
004014B6 . 885C24 1F mov byte ptr ss:[esp+1F],bl
这两处好像是初始化字符串的地方,在这两个地方设了断点,运行程序,注意要打开IsDebuggerPresent plugin,输入了UserName和Regkey以后点OK.跟着程序又退出了,这样说明了程序除了IsDebuggerPresent的Anti代码外还有其它的Anti代码.两次都是退出程序,一般VC退出程序来说PostQuitMessage()用得很多,那就用OD来查一查PostQuitMessage()函数,发现两处:
0040172E |. 8BF8 mov edi,eax
00401730 |. E8 AD050000 call <jmp.&MFC42.#860_CString::operator=>
00401735 |. 8B1D 00324000 mov ebx,dword ptr ds:[<&USER32.PostQuitM>; USER32.PostQuitMessage
0040173B |. 85FF test edi,edi
还有一处就是
00401A18 . 85C0 test eax,eax
00401A1A . 75 07 jnz short CrackMe.00401A23
00401A1C . 50 push eax ; /ExitCode
00401A1D . FF15 00324000 call dword ptr ds:[<&USER32.PostQuitMess>; \PostQuitMessage
00401A23 > 8BCE mov ecx,esi
00401A25 . E8 16000000 call CrackMe.00401A40
00401A2A . 8BCE mov ecx,esi
在这两处下断点,再次运行程序,第一次断在这里
004016FB |. C74424 3C 000>mov dword ptr ss:[esp+3C],0
00401703 |. 33F6 xor esi,esi
00401705 |> 8A4434 10 /mov al,byte ptr ss:[esp+esi+10] ;字母解码开始,注意12FE4C处的内存,解码完毕后是Kernel32.dll 字符串
00401709 |. 8D4C24 0C |lea ecx,dword ptr ss:[esp+C]
0040170D |. 50 |push eax
0040170E |. E8 05060000 |call <jmp.&MFC42.#940_CString::operator+=>
00401713 |. 46 |inc esi
00401714 |. 83FE 0C |cmp esi,0C
00401717 |.^ 7C EC \jl short CrackMe.00401705
00401719 |. 8B4C24 0C mov ecx,dword ptr ss:[esp+C] ;解码完毕后的字符串送到ECX寄存器里面
0040171D |. 57 push edi
0040171E |. 51 push ecx ; /FileName
0040171F |. FF15 04304000 call dword ptr ds:[<&KERNEL32.LoadLibraryA>] ; \LoadLibraryA 这个函数的用法查查MSDN就知道了
00401725 |. 68 EC404000 push CrackMe.004040EC
0040172A |. 8D4C24 14 lea ecx,dword ptr ss:[esp+14]
0040172E |. 8BF8 mov edi,eax
00401730 |. E8 AD050000 call <jmp.&MFC42.#860_CString::operator=>
00401735 |. 8B1D 00324000 mov ebx,dword ptr ds:[<&USER32.PostQuitMessa>; USER32.PostQuitMessage 这个只是把PostQuitMessage的地址送到EBX里面,不执行
0040173B |. 85FF test edi,edi 看看LoadLibraryA函数是否执行成功,不成功就跳走
0040173D |. 74 2C je short CrackMe.0040176B
0040173F |. 33F6 xor esi,esi
00401741 |> 8A5434 24 /mov dl,byte ptr ss:[esp+esi+24] ;又开始解码字符串了,注意12FE4C内存处(堆栈里面) 解码完毕以后是IsDebuggerPresent字符串
00401745 |. 8D4C24 10 |lea ecx,dword ptr ss:[esp+10]
00401749 |. 52 |push edx
0040174A |. E8 C9050000 |call <jmp.&MFC42.#940_CString::operator+=>
0040174F |. 46 |inc esi
00401750 |. 83FE 11 |cmp esi,11
00401753 |.^ 7C EC \jl short CrackMe.00401741
00401755 |. 8B4424 10 mov eax,dword ptr ss:[esp+10]
00401759 |. 50 push eax ; 这时候要注意字符串是什么,
0040175A |. 57 push edi ; |hModule
0040175B |. FF15 00304000 call dword ptr ds:[<&KERNEL32.GetProcAddress>; \GetProcAddress 这个函数的用法也可以查MSDN,这是得到函数的地址,成功后在EAX处返回函数的地址
00401761 |. FFD0 call eax ;执行IsDebuggerPresent(),留意EAX处的值
00401763 |. 85C0 test eax,eax
00401765 |. 74 04 je short CrackMe.0040176B ;如果没有发现Debugger就跳下去
00401767 |. 6A 00 push 0
00401769 |. FFD3 call ebx ; 这个是PostQuitMessage函数
0040176B |> 8BCD mov ecx,ebp
0040176D |. E8 2E000000 call CrackMe.004017A0 ;不知是什么 按F7 CALL进去看看
00401772 |. 85C0 test eax,eax
00401774 |. 5F pop edi
00401775 |. 75 03 jnz short CrackMe.0040177A 上面那个CALL是文件的CRC32检验的,如果CRC32检验与原来的CRC值不同,就不会跳了
00401777 |. 50 push eax
00401778 |. FFD3 call ebx
0040177A |> 8D4C24 0C lea ecx,dword ptr ss:[esp+C]
0040177E |. C74424 3C FFF>mov dword ptr ss:[esp+3C],-1
004017A0 /$ 81EC 0C010000 sub esp,10C
004017A6 |. 8D4424 08 lea eax,dword ptr ss:[esp+8]
004017AA |. 53 push ebx
004017AB |. 55 push ebp
004017AC |. 56 push esi
004017AD |. 68 04010000 push 104 ; /BufSize = 104 (260.)
004017B2 |. 50 push eax ; |PathBuffer
004017B3 |. 8BE9 mov ebp,ecx ; |
004017B5 |. 6A 00 push 0 ; |hModule = NULL
004017B7 |. FF15 18304000 call dword ptr ds:[<&KERNEL32.GetModuleFileN>; \GetModuleFileNameA 得到文件进程的文件名
004017BD |. 6A 00 push 0 ; /hTemplateFile = NULL
004017BF |. 68 80000000 push 80 ; |Attributes = NORMAL
004017C4 |. 6A 03 push 3 ; |Mode = OPEN_EXISTING
004017C6 |. 6A 00 push 0 ; |pSecurity = NULL
004017C8 |. 6A 01 push 1 ; |ShareMode = FILE_SHARE_READ
004017CA |. 8D4C24 28 lea ecx,dword ptr ss:[esp+28] ; |
004017CE |. 68 00000080 push 80000000 ; |Access = GENERIC_READ
004017D3 |. 51 push ecx ; |FileName
004017D4 |. FF15 14304000 call dword ptr ds:[<&KERNEL32.CreateFileA>] ; \CreateFileA 打开文件,
004017DA |. 8BD8 mov ebx,eax
004017DC |. 83FB FF cmp ebx,-1
004017DF |. 75 0C jnz short CrackMe.004017ED
004017E1 |. 5E pop esi
004017E2 |. 5D pop ebp
004017E3 |. 33C0 xor eax,eax
004017E5 |. 5B pop ebx
004017E6 |. 81C4 0C010000 add esp,10C
004017EC |. C3 retn
004017ED |> 6A 00 push 0 ; /pFileSizeHigh = NULL
004017EF |. 53 push ebx ; |hFile
004017F0 |. FF15 10304000 call dword ptr ds:[<&KERNEL32.GetFileSize>] ; \GetFileSize ;得到文件的SIZE
004017F6 |. 8BF0 mov esi,eax
004017F8 |. 83FE FF cmp esi,-1
004017FB |. 75 0C jnz short CrackMe.00401809
004017FD |. 5E pop esi
004017FE |. 5D pop ebp
004017FF |. 33C0 xor eax,eax
00401801 |. 5B pop ebx
00401802 |. 81C4 0C010000 add esp,10C
00401808 |. C3 retn
00401809 |> 57 push edi
0040180A |. 56 push esi
0040180B |. E8 1A050000 call <jmp.&MFC42.#823_operator new> ;分配内存
00401810 |. 83C4 04 add esp,4
00401813 |. 8D5424 14 lea edx,dword ptr ss:[esp+14]
00401817 |. 8BF8 mov edi,eax
00401819 |. 6A 00 push 0 ; /pOverlapped = NULL
0040181B |. 52 push edx ; |pBytesRead
0040181C |. 56 push esi ; |BytesToRead
0040181D |. 57 push edi ; |Buffer
0040181E |. 53 push ebx ; |hFile
0040181F |. FF15 0C304000 call dword ptr ds:[<&KERNEL32.ReadFile>] ; \ReadFile ;读文件,把自己映射到内存里面
00401825 |. 53 push ebx ; /hObject
00401826 |. FF15 08304000 call dword ptr ds:[<&KERNEL32.CloseHandle>] ; \CloseHandle ;关闭文件句柄
0040182C |. 8A47 3C mov al,byte ptr ds:[edi+3C]
0040182F |. 884424 10 mov byte ptr ss:[esp+10],al
00401833 |. 8B4424 10 mov eax,dword ptr ss:[esp+10]
00401837 |. 25 FF000000 and eax,0FF
0040183C |. 2BF0 sub esi,eax
0040183E |. 8D0C38 lea ecx,dword ptr ds:[eax+edi]
00401841 |. 56 push esi ; /Arg2
00401842 |. 51 push ecx ; |Arg1
00401843 |. 8B79 FC mov edi,dword ptr ds:[ecx-4] ; |
00401846 |. 8BCD mov ecx,ebp ; |
00401848 |. E8 23000000 call CrackMe.00401870 ; \CrackMe.00401870 要CALL进去,注意看看堆栈
0040184D |. 33C9 xor ecx,ecx
00401870 /$ 81EC 00040000 sub esp,400 ;平衡堆栈
00401876 |. 33C9 xor ecx,ecx
00401878 |. 8D5424 00 lea edx,dword ptr ss:[esp]
0040187C |. 56 push esi
0040187D |> 8BC1 /mov eax,ecx ;聪明人一眼就看出了,这是生成CRC32的表
0040187F |. BE 08000000 |mov esi,8
00401884 |> A8 01 |/test al,1
00401886 |. 74 09 ||je short CrackMe.00401891
00401888 |. D1E8 ||shr eax,1
0040188A |. 35 2083B8ED ||xor eax,EDB88320 ;0xEDB88320是CRC32出现的常数
0040188F |. EB 02 ||jmp short CrackMe.00401893
00401891 |> D1E8 ||shr eax,1
00401893 |> 4E ||dec esi
00401894 |.^ 75 EE |\jnz short CrackMe.00401884
00401896 |. 8902 |mov dword ptr ds:[edx],eax
00401898 |. 41 |inc ecx
00401899 |. 83C2 04 |add edx,4
0040189C |. 81F9 00010000 |cmp ecx,100
004018A2 |.^ 7C D9 \jl short CrackMe.0040187D
004018A4 |. 8B8C24 0C0400>mov ecx,dword ptr ss:[esp+40C]
004018AB |. 83C8 FF or eax,FFFFFFFF
004018AE |. 8BD1 mov edx,ecx
004018B0 |. 49 dec ecx
004018B1 |. 85D2 test edx,edx
004018B3 |. 74 27 je short CrackMe.004018DC
004018B5 |. 8D71 01 lea esi,dword ptr ds:[ecx+1]
004018B8 |. 8B8C24 080400>mov ecx,dword ptr ss:[esp+408]
004018BF |. 53 push ebx
004018C0 |> 8BD0 /mov edx,eax ;这个循环是计算文件CRC32值的
004018C2 |. 33DB |xor ebx,ebx
004018C4 |. 8A19 |mov bl,byte ptr ds:[ecx]
004018C6 |. 81E2 FF000000 |and edx,0FF
004018CC |. 33D3 |xor edx,ebx
004018CE |. C1E8 08 |shr eax,8
004018D1 |. 8B5494 08 |mov edx,dword ptr ss:[esp+edx*4+8]
004018D5 |. 33C2 |xor eax,edx
004018D7 |. 41 |inc ecx
004018D8 |. 4E |dec esi
004018D9 |.^ 75 E5 \jnz short CrackMe.004018C0
004018DB |. 5B pop ebx ;这时候EDI寄存器就是文件的CRC32值
004018DC |> F7D0 not eax
004018DE |. 5E pop esi
004018DF |. 81C4 00040000 add esp,400
004018E5 \. C2 0800 retn 8
第一层文件CRC文件攻破了,一直按F8不久,程序又会中断下来了,看这里:
00401A10 . 56 push esi
00401A11 . 8BF1 mov esi,ecx
00401A13 . E8 28000000 call CrackMe.00401A40 按F7 CALL进去
00401A18 . 85C0 test eax,eax
00401A1A . 75 07 jnz short CrackMe.00401A23
00401A1C . 50 push eax ; /ExitCode
00401A1D . FF15 00324000 call dword ptr ds:[<&USER32.PostQuitMessage>>; \PostQuitMessage 又一个PostQuitMessage()
CALL进去以后的代码,与上面的CRC代码相似,只是检查的是程序在内存中的.text区块的代码的CRC值,原程序的CRC32值放在程序的最尾处,可以用UltraEdit打开来看看.
进一步跟踪可以发现是每一个Timer消息就检查一次,也就是0.5秒就检查一次CRC值,发现CRC值不同的话就直接退出程序
00401A40 /$ 81EC 08010000 sub esp,108
00401A46 |. 8D4424 04 lea eax,dword ptr ss:[esp+4]
00401A4A |. 53 push ebx
00401A4B |. 55 push ebp
00401A4C |. 57 push edi
00401A4D |. 68 04010000 push 104 ; /BufSize = 104 (260.)
00401A52 |. 50 push eax ; |PathBuffer
00401A53 |. 8BE9 mov ebp,ecx ; |
00401A55 |. 6A 00 push 0 ; |hModule = NULL
00401A57 |. FF15 18304000 call dword ptr ds:[<&KERNEL32.GetModuleFileN>; \GetModuleFileNameA
00401A5D |. 6A 00 push 0 ; /hTemplateFile = NULL
00401A5F |. 68 80000000 push 80 ; |Attributes = NORMAL
00401A64 |. 6A 03 push 3 ; |Mode = OPEN_EXISTING
00401A66 |. 6A 00 push 0 ; |pSecurity = NULL
00401A68 |. 6A 01 push 1 ; |ShareMode = FILE_SHARE_READ
00401A6A |. 8D4C24 24 lea ecx,dword ptr ss:[esp+24] ; |
00401A6E |. 68 00000080 push 80000000 ; |Access = GENERIC_READ
00401A73 |. 51 push ecx ; |FileName
00401A74 |. FF15 14304000 call dword ptr ds:[<&KERNEL32.CreateFileA>] ; \CreateFileA
00401A7A |. 8BF8 mov edi,eax
00401A7C |. 83FF FF cmp edi,-1
00401A7F |. 74 67 je short CrackMe.00401AE8
00401A81 |. 6A 00 push 0 ; /pFileSizeHigh = NULL
00401A83 |. 57 push edi ; |hFile
00401A84 |. FF15 10304000 call dword ptr ds:[<&KERNEL32.GetFileSize>] ; \GetFileSize
00401A8A |. 8BD8 mov ebx,eax
00401A8C |. 83FB FF cmp ebx,-1
00401A8F |. 74 57 je short CrackMe.00401AE8
00401A91 |. 56 push esi
00401A92 |. 53 push ebx
00401A93 |. E8 92020000 call <jmp.&MFC42.#823_operator new>
00401A98 |. 83C4 04 add esp,4
00401A9B |. 8D5424 10 lea edx,dword ptr ss:[esp+10]
00401A9F |. 8BF0 mov esi,eax
00401AA1 |. 6A 00 push 0 ; /pOverlapped = NULL
00401AA3 |. 52 push edx ; |pBytesRead
00401AA4 |. 53 push ebx ; |BytesToRead
00401AA5 |. 56 push esi ; |Buffer
00401AA6 |. 57 push edi ; |hFile
00401AA7 |. FF15 0C304000 call dword ptr ds:[<&KERNEL32.ReadFile>] ; \ReadFile
00401AAD |. 57 push edi ; /hObject
00401AAE |. FF15 08304000 call dword ptr ds:[<&KERNEL32.CloseHandle>] ; \CloseHandle
00401AB4 |. 8BBE 00600000 mov edi,dword ptr ds:[esi+6000]
00401ABA |. 56 push esi
00401ABB |. E8 38010000 call <jmp.&MFC42.#825_operator delete>
00401AC0 |. 83C4 04 add esp,4
00401AC3 |. 8BCD mov ecx,ebp
00401AC5 |. 68 42100000 push 1042 ; /Arg2 = 00001042
00401ACA |. 68 00104000 push CrackMe.00401000 ; |Arg1 = 00401000
00401ACF |. E8 9CFDFFFF call CrackMe.00401870 ; \CrackMe.00401870 ;这是检查CRC32值
00401AD4 |. 33C9 xor ecx,ecx
00401AD6 |. 3BF8 cmp edi,eax
00401AD8 |. 5E pop esi
00401AD9 |. 5F pop edi
爆破了这两个CRC处以后,程序就可以运行了,下面就是来想想注册码的算法了
查MessageBox()处,发现以下处
00401546 . E8 D9070000 call <jmp.&MFC42.#6334_CWnd::UpdateData>
0040154B . 8B46 64 mov eax,dword ptr ds:[esi+64]
0040154E . 8B2D D4314000 mov ebp,dword ptr ds:[<&MSVCRT._mbscmp>] ; MSVCRT._mbscmp
00401554 . 68 EC404000 push CrackMe.004040EC ; /s2 = ""
00401559 . 50 push eax ; |s1
0040155A . FFD5 call ebp ; \_mbscmp ;看RegKey是否为空
0040155C . 83C4 08 add esp,8
0040155F . 85C0 test eax,eax
00401561 . 74 7A je short CrackMe.004015DD ;RegKey为空就跳走
00401563 . 8B46 60 mov eax,dword ptr ds:[esi+60] ;注意:用户名
00401566 . 8D5E 60 lea ebx,dword ptr ds:[esi+60]
00401569 . 68 EC404000 push CrackMe.004040EC
0040156E . 50 push eax
0040156F . FFD5 call ebp ;看用户名是否为空
00401571 . 83C4 08 add esp,8
00401574 . 85C0 test eax,eax
00401576 . 74 65 je short CrackMe.004015DD ;用户名为空就跳走
00401578 . 8B4E 64 mov ecx,dword ptr ds:[esi+64]
0040157B . 33C0 xor eax,eax
0040157D > 0FBE1401 movsx edx,byte ptr ds:[ecx+eax] ;密码的每一个字符
00401581 . 81F2 AA000000 xor edx,0AA ;与0xAA或异
00401587 . 03FA add edi,edx ;相加
00401589 . 40 inc eax
0040158A . 83F8 09 cmp eax,9 ;循环9次
0040158D .^ 7C EE jl short CrackMe.0040157D ;loop 这个用C来写就是 a=int(RegKey.GetAt(i)^0xAA); i=1~9
0040158F . 57 push edi
00401590 . 51 push ecx
00401591 . 8BCC mov ecx,esp
00401593 . 896424 1C mov dword ptr ss:[esp+1C],esp
00401597 . 53 push ebx
00401598 . E8 81070000 call <jmp.&MFC42.#535_CString::CString>
0040159D . 8BCE mov ecx,esi ; |
0040159F . E8 8C030000 call CrackMe.00401930 ; \CrackMe.00401930 ;重要,算法CALL 按F7进去
004015A4 . 85C0 test eax,eax
004015A6 . 74 1A je short CrackMe.004015C2 ;跳下去就over了
004015A8 . 33FF xor edi,edi
004015AA > 8A443C 18 mov al,byte ptr ss:[esp+edi+18] ;字符又开始解码了
004015AE . 8D4C24 10 lea ecx,dword ptr ss:[esp+10]
004015B2 . 34 AA xor al,0AA
004015B4 . 50 push eax
004015B5 . E8 5E070000 call <jmp.&MFC42.#940_CString::operator+=>
004015BA . 47 inc edi
004015BB . 83FF 0A cmp edi,0A
004015BE .^ 7C EA jl short CrackMe.004015AA
004015C0 . EB 34 jmp short CrackMe.004015F6
004015C2 > 33FF xor edi,edi
004015C4 > 8A4C3C 24 mov cl,byte ptr ss:[esp+edi+24]
004015C8 . 80F1 AA xor cl,0AA
004015CB . 51 push ecx
004015CC . 8D4C24 14 lea ecx,dword ptr ss:[esp+14]
004015D0 . E8 43070000 call <jmp.&MFC42.#940_CString::operator+=>
004015D5 . 47 inc edi
004015D6 . 83FF 0A cmp edi,0A
004015D9 .^ 7C E9 jl short CrackMe.004015C4
004015DB . EB 19 jmp short CrackMe.004015F6
004015DD > 33FF xor edi,edi
004015DF > 8A543C 30 mov dl,byte ptr ss:[esp+edi+30]
004015E3 . 8D4C24 10 lea ecx,dword ptr ss:[esp+10]
004015E7 . 80F2 AA xor dl,0AA
004015EA . 52 push edx
004015EB . E8 28070000 call <jmp.&MFC42.#940_CString::operator+=>
004015F0 . 47 inc edi
004015F1 . 83FF 14 cmp edi,14
004015F4 .^ 7C E9 jl short CrackMe.004015DF
004015F6 > 8B4424 10 mov eax,dword ptr ss:[esp+10]
004015FA . 6A 00 push 0
004015FC . 6A 00 push 0
004015FE . 50 push eax
004015FF . 8BCE mov ecx,esi
00401601 . E8 0C070000 call <jmp.&MFC42.#4224_CWnd::MessageBoxA> ;提示信息
算法CALL
00401930 /$ 6A FF push -1
00401932 |. 68 38204000 push CrackMe.00402038 ; SE handler installation
00401937 |. 64:A1 0000000>mov eax,dword ptr fs:[0]
0040193D |. 50 push eax
0040193E |. 64:8925 00000>mov dword ptr fs:[0],esp
00401945 |. 83EC 0C sub esp,0C
00401948 |. 53 push ebx
00401949 |. 56 push esi
0040194A |. 57 push edi
0040194B |. 8B5424 28 mov edx,dword ptr ss:[esp+28]
0040194F |. B0 4B mov al,4B
00401951 |. 884424 0C mov byte ptr ss:[esp+C],al
00401955 |. 884424 10 mov byte ptr ss:[esp+10],al
00401959 |. 8B4A F8 mov ecx,dword ptr ds:[edx-8]
0040195C |. B0 4E mov al,4E
0040195E |. 884424 12 mov byte ptr ss:[esp+12],al
00401962 |. 884424 14 mov byte ptr ss:[esp+14],al
00401966 |. 33FF xor edi,edi
00401968 |. 33F6 xor esi,esi
0040196A |. 33C0 xor eax,eax
0040196C |. C64424 0D 45 mov byte ptr ss:[esp+D],45 ;初始化字符表
00401971 |. 85C9 test ecx,ecx
00401973 |. C64424 0E 59 mov byte ptr ss:[esp+E],59
00401978 |. C64424 0F 2D mov byte ptr ss:[esp+F],2D
0040197D |. C64424 11 41 mov byte ptr ss:[esp+11],41
00401982 |. C64424 13 4F mov byte ptr ss:[esp+13],4F ;字符表初始化完成,是”KEY-KANON”这个字符 (ps:本人是Key游戏的fans,觉得AIR这个名字太短了,就用KANON了 :))
00401987 |. 7E 0B jle short CrackMe.00401994
00401989 |> 0FBE1C10 /movsx ebx,byte ptr ds:[eax+edx] ;用户名的每一位
0040198D |. 03F3 |add esi,ebx ;前一位的ASCII码+后一位的ASCII码
0040198F |. 40 |inc eax
00401990 |. 3BC1 |cmp eax,ecx
00401992 |.^ 7C F5 \jl short CrackMe.00401989 ;loop
00401994 |> 33C9 xor ecx,ecx
00401996 |> 0FBE440C 0C /movsx eax,byte ptr ss:[esp+ecx+C] 字符表的每一位
0040199B |. 0FAFC6 |imul eax,esi 与用户名的ASCII码累加值相乘
0040199E |. 99 |cdq ;把扩展数位为64位,防止溢出,不用管它
0040199F |. BB 1A000000 |mov ebx,1A
004019A4 |. F7FB |idiv ebx ;EAX除以0x1A
004019A6 |. 83C2 61 |add edx,61 ;上面除法以后的余数+0x61
004019A9 |. 81F2 AA000000 |xor edx,0AA ;与0xAA或异
004019AF |. 03FA |add edi,edx ;相加
004019B1 |. 41 |inc ecx ;ECX+1 这是做计数器
004019B2 |. 83F9 09 |cmp ecx,9 ;循环9次
004019B5 |.^ 7C DF \jl short CrackMe.00401996
004019B7 |. 8B4424 2C mov eax,dword ptr ss:[esp+2C] ;这是RegKey或异了0xAA以后的累加值
004019BB |. C74424 20 FFF>mov dword ptr ss:[esp+20],-1
004019C3 |. 3BF8 cmp edi,eax ;比较了,爆破点就在附近了
004019C5 |. 5F pop edi
004019C6 |. 5E pop esi
004019C7 |. 5B pop ebx
004019C8 |. 8D4C24 1C lea ecx,dword ptr ss:[esp+1C]
004019CC |. 75 1B jnz short CrackMe.004019E9 ;爆破点,改为不跳就OK了
004019CE |. E8 37020000 call <jmp.&MFC42.#800_CString::~CString>
004019D3 |. B8 01000000 mov eax,1
004019D8 |. 8B4C24 0C mov ecx,dword ptr ss:[esp+C]
004019DC |. 64:890D 00000>mov dword ptr fs:[0],ecx
004019E3 |. 83C4 18 add esp,18
004019E6 |. C2 0800 retn 8
004019E9 |> E8 1C020000 call <jmp.&MFC42.#800_CString::~CString>
004019EE |. 8B4C24 0C mov ecx,dword ptr ss:[esp+C]
004019F2 |. 33C0 xor eax,eax
004019F4 |. 64:890D 00000>mov dword ptr fs:[0],ecx
004019FB |. 83C4 18 add esp,18
004019FE \. C2 0800 retn 8
算法总结:
(“KEY-KANON”的每一位的ASCII码值之和)%0x21 +0x61
但是它用了间接比较,把(RegKey的每一位)^0xAA 的int值与
((“KEY-KANON”的每一位的ASCII码值之和)%0x21 +0x61)^0xAA的int值对比,对就认为注册码正确;
注册机:
CString ori="KEY-KANON";
int usr=0;
for(int i=0;i<UserName.GetLength();i++)
{
usr+=int(UserName.GetAt(i));
}
for(i=0;i<9;i++)
{
RegKey+=char((ori.GetAt(i)*usr)%0x1A+0x61);
}
ps:第一次写CrackMe然后自己写对应的破文 :D
永远支持AIR和Kanon, 被AIR动画感动得流了N次泪了 :~(
[KFC]fish (Pr0Zel)