【文章标题】: 一个过关类型的FaNt0m's CrackMe #5的分析(总共有4个关卡)
【文章标题】: 一个过关类型的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 ; |句柄
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
004011D3|.6A 00 push 0 ; /(最初的 CPU 选择)
004011D5|.50 push eax ; |DlgProc => CRACKME5.004013C3
004011D6|.FF75 08 push dword ptr ; |hOwner
004011D9|.68 3C304000 push CRACKME5.0040303C ; |NAGDIALOG
004011DE|.FF35 B0314000 push dword ptr ; |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 ; |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 ; |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:, 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 , al ;第一个字符清零
00401660|.B9 00010000 mov ecx, 100 ;初始化ecx
00401665|.8D35 B8314000 lea esi, dword ptr ;注册名
0040166B|.8D3D B8334000 lea edi, dword ptr ;初始化edi
00401671|>33C0 /xor eax, eax ;初始化eax
00401673|.8A06 |mov al, byte ptr ;依次取注册名的字符
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 , al ;结果送变量
00401692|.^ EB DD \jmp short CRACKME5.00401671
00401694|>47 inc edi ;指向下一字符
00401695|.C607 00 mov byte ptr , 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 ;注册名
004016A9|.8D3D B8334000 lea edi, dword ptr ;Key1 = 上面的运算结果数
004016AF|.8D15 A2304000 lea edx, dword ptr ;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 ;依次取注册名的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 , 0 ;Key是否为空
004016D0|.75 06 |jnz short CRACKME5.004016D8 ;不为空,跳走
004016D2|.8D15 A2304000 |lea edx, dword ptr
004016D8|>3202 |xor al, byte ptr ;异或
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 , 2D
00401703|.47 |inc edi
00401704|>58 |pop eax
00401705|.8807 |mov byte ptr , 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 原创, 转载请注明作者并保持文章的完整性, 谢谢! 再见!! 分析得很详细,照着做一下
页:
[1]