-
-
[原创][文章标题]: 一个过关类型的FaNt0m's CrackMe #5的分析(总共有4个关卡)
-
发表于: 2007-12-29 14:44 5581
-
【文章标题】: 一个过关类型的FaNt0m's CrackMe #5的分析(总共有4个关卡)
【文章作者】: CuteSnail
【作者QQ号】: 121567771
【作者声明】: 只是感兴趣的自娱自乐,没有其他目的。失误之处还要敬请诸位大侠赐教!
-------------------------------------------------------------------------------
【详细过程】
(A).先看第一关,PassWord的检查:
0040133E |> \68 00010000 push 100 ; /第一关 PassWord 检查
00401343 |. 68 B8334000 push CRACKME5.004033B8 ; |EXN9-CK4-5QV345
00401348 |. 68 E8030000 push 3E8 ; |
0040134D |. FF35 B8344000 push dword ptr [4034B8] ; |句柄
00401353 |. E8 F4030000 call <jmp.&USER32.GetDlgItemTextA> ; \得到输入的PassWord
00401358 |. 68 B8334000 push CRACKME5.004033B8 ; /EXN9-CK4-5QV345
0040135D |. 68 A2304000 push CRACKME5.004030A2 ; |JD39-CK4-5QV345
00401362 |. E8 51040000 call <jmp.&KERNEL32.lstrcmpA> ; \两者比较,相等,eax返回0
00401367 |. 50 push eax ; 压入比较结果
00401368 |. 6A 00 push 0
0040136A |. 83F0 40 xor eax, 40
0040136D |. 66:83E0 10 and ax, 10
00401371 |. C1E8 0D shr eax, 0D
00401374 |. C1E0 03 shl eax, 3
00401377 |. 58 pop eax
00401378 |. 83F8 00 cmp eax, 0
0040137B |. 75 28 jnz short CRACKME5.004013A5
0040137D |. 83F0 40 xor eax, 40
00401380 |. C1E8 0D shr eax, 0D
00401383 |. 66:83E0 10 and ax, 10
00401387 |. C1E0 03 shl eax, 3
0040138A |. 58 pop eax ; 弹出比较结果
0040138B |. 83F8 00 cmp eax, 0 ; 与0比较
0040138E |. 74 15 je short CRACKME5.004013A5 ; 相等,跳走,成功
00401390 |. 6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401392 |. 68 B2304000 push CRACKME5.004030B2 ; |Password Check
00401397 |. 68 E9304000 push CRACKME5.004030E9 ; |Nope, try again!
0040139C |. 6A 00 push 0 ; |hOwner = NULL
0040139E |. E8 C7030000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013A3 |. EB 15 jmp short CRACKME5.004013BA
004013A5 |> 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004013A7 |. 68 B2304000 push CRACKME5.004030B2 ; |Password Check
004013AC |. 68 C1304000 push CRACKME5.004030C1 ; |Good job, you got the correct password!
004013B1 |. 6A 00 push 0 ; |hOwner = NULL
004013B3 |. E8 B2030000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013B8 |. EB 00 jmp short CRACKME5.004013BA
004013BA |> B8 01000000 mov eax, 1
004013BF |. C9 leave
004013C0 \. C2 1000 retn 10
从上面可以一面了然的知道password就是: JD39-CK4-5QV345 ,输入这个password后,程序便显示正确的信息了;
(B).再来到第二关,将程序拖入OD中,下 MessageBoxA 断点后运行,被断下后Alt+F9键返回程序领空,来到这里:
004011C8 E8 57020000 call CRACKME5.00401424 ; 第二关 这里弹出NAG对话框,nop掉
004011CD |. 8D05 C3134000 lea eax, dword ptr [4013C3]
004011D3 |. 6A 00 push 0 ; /(最初的 CPU 选择)
004011D5 |. 50 push eax ; |DlgProc => CRACKME5.004013C3
004011D6 |. FF75 08 push dword ptr [ebp+8] ; |hOwner
004011D9 |. 68 3C304000 push CRACKME5.0040303C ; |NAGDIALOG
004011DE |. FF35 B0314000 push dword ptr [4031B0] ; |hInst = 00400000
004011E4 E8 4B050000 call <jmp.&USER32.DialogBoxParamA> ; 第二关 这里弹出NAG窗口,nop掉
004011E9 |. EB 2A jmp short CRACKME5.00401215
将004011C8处的call CRACKME5.00401424 和 004011E4处的call <jmp.&USER32.DialogBoxParamA>都修改 Nop 掉,便可以了,这样就过了第二关了;
(C).然后开始第三关 CD Check 检查的分析:
00401438 /$ 53 push ebx ; 第三关 CD Check 检查
00401439 |. 50 push eax
0040143A |. 6A 00 push 0 ; /RootPathName = NULL
0040143C |. E8 6B030000 call <jmp.&KERNEL32.GetDriveTypeA> ; \GetDriveTypeA
00401441 |. 33DB xor ebx, ebx
00401443 |. 43 inc ebx
00401444 |. 43 inc ebx
00401445 |. F6F3 div bl
00401447 |. 3C 02 cmp al, 2 ; al 与 2 比较
00401449 75 1C jnz short CRACKME5.00401467 ; 不相等,跳走,失败,改为je
0040144B |. 80FC 01 cmp ah, 1 ; al 与 1 比较
0040144E |. 74 02 je short CRACKME5.00401452 ; 相等,跳走,成功
00401450 |. EB 15 jmp short CRACKME5.00401467
00401452 |> 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401454 |. 68 88314000 push CRACKME5.00403188 ; |CD Check
00401459 |. 68 91314000 push CRACKME5.00403191 ; |CDROM found!
0040145E |. 6A 00 push 0 ; |hOwner = NULL
00401460 |. E8 05030000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401465 |. EB 15 jmp short CRACKME5.0040147C
00401467 |> 6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401469 |. 68 88314000 push CRACKME5.00403188 ; |CD Check
0040146E |. 68 9E314000 push CRACKME5.0040319E ; |CDROM Not found!
00401473 |. 6A 00 push 0 ; |hOwner = NULL
00401475 |. E8 F0020000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
0040147A |. EB 00 jmp short CRACKME5.0040147C
0040147C |> 58 pop eax
0040147D |. 5B pop ebx
0040147E \. C3 retn
将00401449处的jnz short CRACKME5.00401467修改为je short CRACKME5.00401467,便可以了,这样就又把第三关也过了;
(D).接着,开始第四关 Name/Serial 检查的分析了:
0040153F |> \68 00010000 push 100 ; /第四关 Name/Serial 检查
00401544 |. 68 B8314000 push CRACKME5.004031B8 ; |注册名
00401549 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
0040154E |. FF35 BC344000 push dword ptr [4034BC] ; |hWnd = 00860236 ('Name/Serial Protection',class='#32770',parent=01260102)
00401554 |. E8 F3010000 call <jmp.&USER32.GetDlgItemText>; \得到注册名
00401559 |. 68 00010000 push 100 ; /Count = 100 (256.)
0040155E |. 68 B8324000 push CRACKME5.004032B8 ; |注册码
00401563 |. 68 EC030000 push 3EC ; |ControlID = 3EC (1004.)
00401568 |. FF35 BC344000 push dword ptr [4034BC] ; |hWnd = 00860236 ('Name/Serial Protection',class='#32770',parent=01260102)
0040156E |. E8 D9010000 call <jmp.&USER32.GetDlgItemText>; \得到注册码
00401573 |. 68 B8314000 push CRACKME5.004031B8 ; /注册名
00401578 |. E8 41020000 call <jmp.&KERNEL32.lstrlenA> ; \得到注册名的长度
0040157D |. 83F8 02 cmp eax, 2 ; 与 2 比较
00401580 |. 0F8E A1000000 jle CRACKME5.00401627 ; 小于等于,跳走,失败
00401586 |. 68 B8324000 push CRACKME5.004032B8 ; /注册码
0040158B |. E8 2E020000 call <jmp.&KERNEL32.lstrlenA> ; \得到注册码的长度
00401590 |. 83F8 02 cmp eax, 2 ; 与 2 比较
00401593 |. 0F8E 8E000000 jle CRACKME5.00401627 ; 小于等于,跳走,失败
00401599 |. 68 B8334000 push CRACKME5.004033B8 ; /运算结果字符串
0040159E |. 68 B8324000 push CRACKME5.004032B8 ; |压入注册码
004015A3 |. E8 10020000 call <jmp.&KERNEL32.lstrcmpA> ; \两字符串比较
004015A8 |. 50 push eax ; 结果 入栈
004015A9 |. 6A 00 push 0
004015AB |. 83F0 40 xor eax, 40
004015AE |. 66:83E0 10 and ax, 10
004015B2 |. C1E8 0D shr eax, 0D
004015B5 |. C1E0 03 shl eax, 3
004015B8 |. 58 pop eax
004015B9 |. 83F8 00 cmp eax, 0
004015BC |. 75 2A jnz short CRACKME5.004015E8
004015BE |. 83F0 40 xor eax, 40
004015C1 |. C1E8 0D shr eax, 0D
004015C4 |. 66:83E0 10 and ax, 10
004015C8 |. C1E0 03 shl eax, 3
004015CB |. 58 pop eax ; 结果 出栈
004015CC |. 83F8 00 cmp eax, 0 ; 与 0 比较
004015CF 74 17 je short CRACKME5.004015E8 ; 相等,成功(注册码和运算结果比较)
004015D1 75 2A jnz short CRACKME5.004015FD ; 不相等,继续
004015D3 |> 6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004015D5 |. 68 FA304000 push CRACKME5.004030FA ; |Check Serial
004015DA |. 68 07314000 push CRACKME5.00403107 ; |Wrong Serial! Keep trying, you'll get it!
004015DF |. 6A 00 push 0 ; |hOwner = NULL
004015E1 |. E8 84010000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004015E6 |. EB 54 jmp short CRACKME5.0040163C
004015E8 |> 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004015EA |. 68 FA304000 push CRACKME5.004030FA ; |Check Serial
004015EF |. 68 31314000 push CRACKME5.00403131 ; |You got it! Congrats! :)
004015F4 |. 6A 00 push 0 ; |hOwner = NULL
004015F6 |. E8 6F010000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004015FB |. EB 3F jmp short CRACKME5.0040163C
004015FD |> 68 B8314000 push CRACKME5.004031B8 ; 压入注册名
00401602 |. 68 B8324000 push CRACKME5.004032B8 ; 压入注册码
00401607 |. E8 39000000 call CRACKME5.00401645 ; ×关键算法1,返回下面运算需要的KEY1
0040160C |. 83F0 40 xor eax, 40 ; 异或 64
0040160F |. 66:83E0 10 and ax, 10 ; 与 16
00401613 |. C1E8 0D shr eax, 0D ; 右移 12
00401616 |. C1E0 03 shl eax, 3 ; 左移3
00401619 |. 6A 00 push 0
0040161B |. E8 7C000000 call CRACKME5.0040169C ; ×关键算法2,返回eax结果,跟进分析
00401620 |. 83F8 00 cmp eax, 0 ; 与0比较
00401623 |.^ 74 C3 je short CRACKME5.004015E8 ; 相等,跳向成功
00401625 |.^ EB AC jmp short CRACKME5.004015D3 ; 否则,跳向失败
00401627 |> 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401629 |. 68 56304000 push CRACKME5.00403056 ; |Input Error
0040162E |. 68 62304000 push CRACKME5.00403062 ; |You must input minimum 3 characters\r\nand maximum 255 characters
00401633 |. 6A 00 push 0 ; |hOwner = NULL
00401635 |. E8 30010000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
0040163A |. EB 00 jmp short CRACKME5.0040163C
0040163C |> B8 01000000 mov eax, 1
00401641 |. C9 leave
00401642 \. C2 1000 retn 10
从上面可以看到,0040161B处的call CRACKME5.0040169C便是关键算法call了,而它前面的00401607处的call CRACKME5.00401645则负责为其产生一个运算需要的数据,因此先进入00401607处的call分析:
00401645 /$ 55 push ebp ; 产生KEY1数据
00401646 |. 8BEC mov ebp, esp
00401648 |. 68 B8334000 push CRACKME5.004033B8 ; 随即字符串
0040164D |. 68 B8324000 push CRACKME5.004032B8 ; 输入注册码
00401652 |. 5E pop esi
00401653 |. 5F pop edi
00401654 |. A4 movs byte ptr es:[edi], byte ptr>; 修改随即字符串
00401655 |. 68 B8334000 push CRACKME5.004033B8 ; 再压入
0040165A |. 6A 00 push 0
0040165C |. 58 pop eax
0040165D |. 5A pop edx
0040165E |. 8802 mov byte ptr [edx], al ; 第一个字符清零
00401660 |. B9 00010000 mov ecx, 100 ; 初始化ecx
00401665 |. 8D35 B8314000 lea esi, dword ptr [4031B8] ; 注册名
0040166B |. 8D3D B8334000 lea edi, dword ptr [4033B8] ; 初始化edi
00401671 |> 33C0 /xor eax, eax ; 初始化eax
00401673 |. 8A06 |mov al, byte ptr [esi] ; 依次取注册名的字符
00401675 |. 46 |inc esi ; 指向注册名的下一个字符
00401676 |. 83F8 00 |cmp eax, 0 ; 是否取完了注册名
00401679 |. 74 19 |je short CRACKME5.00401694 ; 如果取完,则跳走
0040167B |. C1E8 03 |shr eax, 3 ; 右移3
0040167E |. 83F0 2C |xor eax, 2C ; 异或 44
00401681 |. C1E0 04 |shl eax, 4 ; 左移4
00401684 |. C1C8 0A |ror eax, 0A ; 循环右移10
00401687 |. 83F0 1A |xor eax, 1A ; 异或 26
0040168A |. 83C0 40 |add eax, 40 ; 加上 64
0040168D |. C1E8 04 |shr eax, 4 ; 右移4
00401690 |. 8807 |mov byte ptr [edi], al ; 结果送变量
00401692 |.^ EB DD \jmp short CRACKME5.00401671
00401694 |> 47 inc edi ; 指向下一字符
00401695 |. C607 00 mov byte ptr [edi], 0 ; 设置为空,得到其前一位的数据 KEY1
00401698 |. C9 leave
00401699 \. C2 0800 retn 8
再了解了上面的预算后,便来到了主算法的call中了:
0040169C /$ 55 push ebp ; 算法开始:
0040169D |. 8BEC mov ebp, esp
0040169F |. 56 push esi
004016A0 |. 57 push edi
004016A1 |. 52 push edx
004016A2 |. 53 push ebx
004016A3 |. 8D35 B8314000 lea esi, dword ptr [4031B8] ; 注册名
004016A9 |. 8D3D B8334000 lea edi, dword ptr [4033B8] ; Key1 = 上面的运算结果数
004016AF |. 8D15 A2304000 lea edx, dword ptr [4030A2] ; Key2 = "JD39-CK4-5QV345"(固定字符串)
004016B5 |. B9 01000000 mov ecx, 1 ; 初始化ecx
004016BA |. BB 45000000 mov ebx, 45 ; 初始化ebx
004016BF |. C1E3 08 shl ebx, 8 ; 左移8
004016C2 |> B3 1A /mov bl, 1A ; 初始化bl
004016C4 |. 33C0 |xor eax, eax ; eax清零
004016C6 |. 8A06 |mov al, byte ptr [esi] ; 依次取注册名的ASCII码值
004016C8 |. 3C 00 |cmp al, 0 ; 与0比较
004016CA |. 74 40 |je short CRACKME5.0040170C ; 为空,跳走
004016CC |. 46 |inc esi ; 指向注册名的下一字符
004016CD |. 803A 00 |cmp byte ptr [edx], 0 ; Key是否为空
004016D0 |. 75 06 |jnz short CRACKME5.004016D8 ; 不为空,跳走
004016D2 |. 8D15 A2304000 |lea edx, dword ptr [4030A2]
004016D8 |> 3202 |xor al, byte ptr [edx] ; 异或
004016DA |. F6E7 |mul bh ; 乘以 69
004016DC |. 66:F7D0 |not ax ; 取反
004016DF |. 25 FF0F0000 |and eax, 0FFF ; 与 4095 与运算
004016E4 |. F6F3 |div bl ; 除以 26
004016E6 |. 80C4 41 |add ah, 41 ; 加上 65
004016E9 |. C1E0 10 |shl eax, 10 ; 左移 16
004016EC |. C1E8 18 |shr eax, 18 ; 右移 24
004016EF |. 50 |push eax ; 结果 入栈
004016F0 |. B3 05 |mov bl, 5 ; bl 等于 5
004016F2 |. 8BC1 |mov eax, ecx
004016F4 |. 25 FF0F0000 |and eax, 0FFF
004016F9 |. F6F3 |div bl ; 除以 05
004016FB |. 80FC 00 |cmp ah, 0 ; 与0比较
004016FE |. 75 04 |jnz short CRACKME5.00401704 ; 不等,跳走
00401700 |. C607 2D |mov byte ptr [edi], 2D
00401703 |. 47 |inc edi
00401704 |> 58 |pop eax
00401705 |. 8807 |mov byte ptr [edi], al ; 结果回写KEY1
00401707 |. 47 |inc edi ; 注册名指向下一字符
00401708 |. 42 |inc edx ; KEY2 指向下一字符
00401709 |. 41 |inc ecx ; 计数,增加1
0040170A |.^ EB B6 \jmp short CRACKME5.004016C2 ; 循环
0040170C |> 68 B8334000 push CRACKME5.004033B8 ; /得到真正的注册码
00401711 |. 68 B8324000 push CRACKME5.004032B8 ; |输入的注册码
00401716 |. E8 9D000000 call <jmp.&KERNEL32.lstrcmpA> ; \两者比较,相等,eax返回0
0040171B |. 5A pop edx
0040171C |. 5F pop edi
0040171D |. 5E pop esi
0040171E |. C9 leave
0040171F \. C2 0400 retn 4
从上面的分析知道了:运算是由注册名,注册名的运算结果(KEY1),以及固定的字符串"JD39-CK4-5QV345"(KEY2),三方共同参与运算的,以注册名的长度为循环次数,依次取注册名的ASCII码值,经过异或、乘法、取反、除法、左移、右移等操作后,与KEY2的运算结果再运算,结果送KEy1替换,然后再次往复的循环运算,便得到最终的注册码值了。而只要这个数值与输入的注册码一样,就注册成功了,比如我输入的注册名是:1234,那么经过运算后,我真正的注册码就是: EXNA 了, 哈哈 ^_^
成功的注册信息:
注册名: 1234
注册码: EXNA
-----------------------------------------------------------------------------------
【版权声明】: 本文由 CuteSnail 原创, 转载请注明作者并保持文章的完整性, 谢谢! 再见!!
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!