|
[已结束][PEDIY.华章 Crackme 竞赛 2009] [第六回] –lelfei
为什么我一看到的时候就已经被秒破了撒~~~~ |
|
[已结束][PEDIY.华章 Crackme 竞赛 2009] [第五回] –CL
这个壳没搞定,看高手表演…… |
|
|
|
|
|
[讨论]第二部分比赛[第三回]CrackMe破解提交
出去了下,回来发现,原来我刚发帖不久就被爆了,哎,早知道这么容易,我先搞定它再出去就好了~,后悔呀~ 不多说了,下面是我的分析: W32dsm的字符串参考,很快就能定位到关键地方: 004018AE F7EA imul edx 004018B0 8BC2 mov eax, edx 004018B2 C1E8 1F shr eax, 0x1F 004018B5 03D0 add edx, eax 004018B7 8BEA mov ebp, edx 004018B9 3BE9 cmp ebp, ecx 004018BB 74 1F je short 004018DC ; 密码有问题,应该让它调走 004018BD 8D4B 64 lea ecx, dword ptr [ebx+0x64] 004018C0 68 B8604100 push 004160B8 ; 错误提示压栈 004018C5 51 push ecx 004018C6 E8 9C6F0000 call 00408867 004018CB 83C4 08 add esp, 0x8 004018CE 8BCB mov ecx, ebx 004018D0 6A 00 push 0x0 004018D2 E8 C1AD0000 call 0040C698 00401BAF ^\75 DB jnz short 00401B8C 00401BB1 33C0 xor eax, eax 00401BB3 EB 05 jmp short 00401BBA 00401BB5 1BC0 sbb eax, eax 00401BB7 83D8 FF sbb eax, -0x1 00401BBA 85C0 test eax, eax 00401BBC 74 1C je short 00401BDA ; 如果这里跳了,就提示恭喜你 00401BBE 8D43 64 lea eax, dword ptr [ebx+0x64] 00401BC1 68 B8604100 push 004160B8 ; 这里提示密码有问题 00401BC6 50 push eax 00401BC7 E8 9B6C0000 call 00408867 00401BCC 83C4 08 add esp, 0x8 00401BCF 8BCB mov ecx, ebx 00401BD1 6A 00 push 0x0 00401BD3 E8 C0AA0000 call 0040C698 00401BD8 EB 58 jmp short 00401C32 00401BDA 8D4B 64 lea ecx, dword ptr [ebx+0x64] ; 这里提示恭喜你 00401BDD 68 B0604100 push 004160B0 00401BE2 51 push ecx 把上面跳转改成JMP本以为大功告成,结果提示还是密码有问题。再上下看了这个错误提示的地方,发现,有个跳转直接跳转到这个错误地址的地址,如下: 00401AA9 2B7410 FC sub esi, dword ptr [eax+edx-0x4] 00401AAD 83EE 02 sub esi, 0x2 00401AB0 0F88 08010000 js 00401BBE ; 这个跳转跳到密码有问题的地方 ... 00401BC1 68 B8604100 push 004160B8 ; 这里提示密码有问题 00401BC6 50 push eax 00401BC7 E8 9B6C0000 call 00408867 00401BCC 83C4 08 add esp, 0x8 00401BCF 8BCB mov ecx, ebx 00401BD1 6A 00 push 0x0 00401BD3 E8 C0AA0000 call 0040C698 00401BD8 EB 58 jmp short 00401C32 00401BDA 8D4B 64 lea ecx, dword ptr [ebx+0x64] ; 这里提示恭喜你 00401BDD 68 B0604100 push 004160B0 看到了吧,我们让他JMP到成功的地方就OK了,把代码改成如下模样: 00401AAD 83EE 02 sub esi, 0x2 00401AB0 E9 25010000 jmp 00401BDA ; 这个跳转跳到密码有问题的地方 00401AB5 90 nop 00401AB6 8D0CB5 00000000 lea ecx, dword ptr [esi*4] 本以为这样就真的可以了。结果一运行,异常了…… 但不跟踪,发现问题出在下面这函数中。 00401BF8 52 push edx 00401BF9 E8 EB7C0000 call 004098E9 00401BFE 8B4424 28 mov eax, dword ptr [esp+0x28] 00401C02 50 push eax ; 密码前两位压栈 00401C03 E8 E17C0000 call 004098E9 00401C08 8B8C24 B4000000 mov ecx, dword ptr [esp+0xB4] ; 密码再两位 00401C0F 51 push ecx 00401C10 E8 D47C0000 call 004098E9 00401C15 8B5424 20 mov edx, dword ptr [esp+0x20] 00401C19 52 push edx 00401C1A E8 CA7C0000 call 004098E9 ; 这里异常了 00401C1F 57 push edi 00401C20 E8 C47C0000 call 004098E9 00401C25 8B4424 30 mov eax, dword ptr [esp+0x30] 00401C29 50 push eax 00401C2A E8 BA7C0000 call 004098E9 00401C2F 83C4 18 add esp, 0x18 这些代码调用的都是同一个CALL,结果出问题了,仔细看代码,发现这些函数的堆栈一起平衡的,那我们跳过这些函数调用看看“ 00401BDA 8D4B 64 lea ecx, dword ptr [ebx+0x64] ; 这里提示恭喜你 00401BDD 68 B0604100 push 004160B0 00401BE2 51 push ecx 00401BE3 E8 7F6C0000 call 00408867 00401BE8 83C4 08 add esp, 0x8 00401BEB 8BCB mov ecx, ebx 00401BED 6A 00 push 0x0 00401BEF E8 A4AA0000 call 0040C698 00401BF4 EB 3C jmp short 00401C32 ; 这里改成JMP,跳过下面的函数调用,以免程序异常 00401BF6 90 nop 00401BF7 90 nop 再运行,OK,收工了~ |
|
|
|
|
|
[讨论]第二部分比赛[第一回]CrackMe破解提交
这个CrackMe带有一个校验文件Crackme.atom,我感觉它里面的内容作用无非就是提供一些数据参与计算,或者保存文件的校验信息防止crackme被修改之类。故OD调试得到信息如下: 00401D58 894C24 14 mov dword ptr [esp+0x14], ecx 00401D5C C68424 6C010000>mov byte ptr [esp+0x16C], 0x2 00401D64 894C24 18 mov dword ptr [esp+0x18], ecx 00401D68 894C24 1C mov dword ptr [esp+0x1C], ecx 00401D6C 894C24 20 mov dword ptr [esp+0x20], ecx 00401D70 884C24 24 mov byte ptr [esp+0x24], cl 00401D74 8D4C24 48 lea ecx, dword ptr [esp+0x48] 00401D78 E8 B30E0000 call 00402C30 00401D7D 68 B0514000 push 004051B0 ; ASCII "rb" 00401D82 68 A0514000 push 004051A0 ; ASCII "CrackMe.Atom" 00401D87 FF15 DC414000 call dword ptr [<&MSVCRT.fopen>] ; msvcrt.fopen 00401D8D 8BF8 mov edi, eax 00401D8F 83C4 08 add esp, 0x8 00401D92 85FF test edi, edi 00401D94 75 10 jnz short 00401DA6 00401D96 8B06 mov eax, dword ptr [esi] 00401D98 8BCE mov ecx, esi 00401D9A FF90 D0000000 call dword ptr [eax+0xD0] 00401DA0 8B6C24 0C mov ebp, dword ptr [esp+0xC] 00401DA4 EB 1C jmp short 00401DC2 00401DA6 57 push edi 00401DA7 6A 11 push 0x11 00401DA9 8D4C24 38 lea ecx, dword ptr [esp+0x38] 00401DAD 6A 01 push 0x1 00401DAF 51 push ecx 00401DB0 FF15 E0414000 call dword ptr [<&MSVCRT.fread>] ; msvcrt.fread 返回长度是0x11个字符。 0013F6A0 1F F5 35 57 9A 9E 8E B6 03 BC 5E E0 4B 77 F8 1B ?W殲幎糬郖w? 00401DB6 57 push edi 00401DB7 8BE8 mov ebp, eax 00401DB9 FF15 E4414000 call dword ptr [<&MSVCRT.fclose>] ; msvcrt.fclose 00401DBF 83C4 14 add esp, 0x14 00401DC2 83FD 11 cmp ebp, 0x11 00401DC5 74 0A je short 00401DD1 00401DC7 8B16 mov edx, dword ptr [esi] 00401DC9 8BCE mov ecx, esi 00401DCB FF92 D0000000 call dword ptr [edx+0xD0] 00401DD1 8D4424 10 lea eax, dword ptr [esp+0x10] ; 缓冲区,用来存放从CheckMe.exe中读取的数据 00401DD5 8D4C24 60 lea ecx, dword ptr [esp+0x60] 00401DD9 50 push eax 00401DDA 51 push ecx 00401DDB 8D4C24 2C lea ecx, dword ptr [esp+0x2C] 00401DDF E8 2C140000 call 00403210 ; 这里打开了程序本身,应该是做了校验 读取出来的数据如下: 0013F680 1F F5 35 57 9A 9E 8E B6 03 BC 5E E0 4B 77 F8 1B ?W殲幎糬郖w? 00401DE4 8D7C24 30 lea edi, dword ptr [esp+0x30] ; 取出从CrackMe.Atom中读取到的数据 00401DE8 8D4424 10 lea eax, dword ptr [esp+0x10] ; 取出从CrackMe.exe中读取到的数据 00401DEC 8A10 mov dl, byte ptr [eax] ; 应该是开始做校验了,可能是用来防爆破的。 00401DEE 8ACA mov cl, dl ; 所以,我们可以吧修改之后从EXE中取到的内容填到ATOM文件中,来绕过校验 00401DF0 3A17 cmp dl, byte ptr [edi] 00401DF2 75 1C jnz short 00401E10 如上所述,atom文件的问题解决,我们来看一下它用户名和序列号的处理方法。 关于绕过时间的校验 通过分析它处理用户名和序列号的代码发现: 0040250E B9 58544000 mov ecx, 00405458 00402513 E8 E8060000 call 00402C00 { 00402C00 51 push ecx 00402C01 8D4424 00 lea eax, dword ptr [esp] 00402C05 50 push eax 00402C06 FF15 D0414000 call dword ptr [<&MSVCRT.time>] ; msvcrt.time 00402C0C 8D4C24 04 lea ecx, dword ptr [esp+0x4] 00402C10 51 push ecx 00402C11 FF15 D4414000 call dword ptr [<&MSVCRT.localtime>] ; msvcrt.localtime 00402C17 8B48 04 mov ecx, dword ptr [eax+0x4] 00402C1A 8B00 mov eax, dword ptr [eax] 00402C1C 8D0C49 lea ecx, dword ptr [ecx+ecx*2] 00402C1F 8D1489 lea edx, dword ptr [ecx+ecx*4] 00402C22 8D0490 lea eax, dword ptr [eax+edx*4] 00402C25 83C4 0C add esp, 0xC 00402C28 C3 retn } 00402518 2BC6 sub eax, esi 0040251A 83F8 01 cmp eax, 0x1 0040251D 7E 07 jle short 00402526 0040251F 8BCD mov ecx, ebp 00402521 E8 9C120000 call <jmp.&MFC42.#CDialog::OnCancel_4>; 退出应用程序了 00402526 803B 6D cmp byte ptr [ebx], 0x6D 00402529 75 19 jnz short 00402544 0040252B 43 inc ebx 这样的校验非常多,影响我们的调试分析,所以我将代码改成如下样子,绕过了这个时间的校验: 00402C00 51 push ecx 00402C01 8D4424 00 lea eax, dword ptr [esp] 00402C05 50 push eax 00402C06 FF15 D0414000 call dword ptr [<&MSVCRT.time>] ; msvcrt.time 00402C0C 8D4C24 04 lea ecx, dword ptr [esp+0x4] 00402C10 51 push ecx 00402C11 FF15 D4414000 call dword ptr [<&MSVCRT.localtime>] ; msvcrt.localtime 00402C17 8B48 04 mov ecx, dword ptr [eax+0x4] 00402C1A 8B00 mov eax, dword ptr [eax] 00402C1C 8D0C49 lea ecx, dword ptr [ecx+ecx*2] 00402C1F B8 00000000 mov eax, 0x0 ;修改了它的返回值,这样下面所有的时间校验就都报废了 00402C24 90 nop 00402C25 83C4 0C add esp, 0xC 00402C28 C3 retn 以上代码不改也可以的,当时是为了调试方便才改的。 我们继续分析用户名和序列号的校验代码,根据以前看雪坛子上的前辈留下的找MFC事件处理代码的方法,我们来到如下的地方: 00401FF0 /. 55 push ebp 00401FF1 |. 8BEC mov ebp, esp 00401FF3 |. 6A FF push -0x1 00401FF5 |. 68 B33A4000 push 00403AB3 ; SE handler installation 00401FFA |. 64:A1 0000000>mov eax, dword ptr fs:[0] 00402000 |. 50 push eax 00402001 |. 64:8925 00000>mov dword ptr fs:[0], esp 00402008 |. 81EC AC000000 sub esp, 0xAC 0040200E |. 53 push ebx 0040200F |. 8BD9 mov ebx, ecx 00402011 |. 56 push esi 00402012 |. 57 push edi 00402013 |. 8D8D 48FFFFFF lea ecx, dword ptr [ebp-0xB8] 00402019 |. E8 32F9FFFF call 00401950 0040201E |. 8D4D E4 lea ecx, dword ptr [ebp-0x1C] 00402021 |. C745 FC 00000>mov dword ptr [ebp-0x4], 0x0 00402028 |. E8 B3100000 call 004030E0 0040202D |. 8D4D A8 lea ecx, dword ptr [ebp-0x58] 00402030 |. C645 FC 01 mov byte ptr [ebp-0x4], 0x1 00402034 |. E8 27F3FFFF call 00401360 00402039 |. 90 nop 0040203A |. 6A 00 push 0x0 ; /pThreadId = NULL 0040203C |. 6A 00 push 0x0 ; |CreationFlags = 0 0040203E |. 53 push ebx ; |pThreadParm 0040203F |. 68 D01F4000 push 00401FD0 ; |ThreadFunction = CrackMe.00401FD0 00402044 |. 6A 00 push 0x0 ; |StackSize = 0 00402046 |. 6A 00 push 0x0 ; |pSecurity = NULL 00402048 |. FF15 08404000 call dword ptr [<&KERNEL32.CreateThre>; \CreateThread 这里以挂起的方式起了一个线程,由于没有执行,所以没分析到它的所用,估计也是一个校验的代码,先不管它。 继续向下,我们看到了用户名和序列号的规则如下: 004020A1 |. 8B4B 60 mov ecx, dword ptr [ebx+0x60] ; 取出用户名 004020A4 |. 8B41 F8 mov eax, dword ptr [ecx-0x8] ; 用户名的长度 6~20 004020A7 |. 83F8 06 cmp eax, 0x6 004020AA |. 0F8C 49020000 jl 004022F9 004020B0 |. 83F8 20 cmp eax, 0x20 004020B3 |. 0F8F 40020000 jg 004022F9 004020B9 |. 8B53 64 mov edx, dword ptr [ebx+0x64] ; 取出密码 004020BC |. 8B52 F8 mov edx, dword ptr [edx-0x8] ; 密码的长度 6~A0 004020BF |. 83FA 06 cmp edx, 0x6 004020C2 |. 0F8C 31020000 jl 004022F9 004020C8 |. 81FA A0000000 cmp edx, 0xA0 004020CE |. 0F8F 25020000 jg 004022F9 004020F2 |. BF 34534000 mov edi, 00405334 ; 取出用户名及拼凑字符(将用户名凑够了32位),开始运算了 004020F7 |. 83C9 FF or ecx, -0x1 004020FA |. 33C0 xor eax, eax 004020FC |. 83C4 18 add esp, 0x18 004020FF |. 33F6 xor esi, esi 00402101 |. 33D2 xor edx, edx 00402103 |. F2:AE repne scas byte ptr es:[edi] 00402105 |. F7D1 not ecx 00402107 |. 49 dec ecx 00402108 |. 74 39 je short 00402143 0040210A |> 8A82 34534000 /mov al, byte ptr [edx+0x405334] ; 判断用户名是不是合法的数字及大小写字母 00402110 |. 3C 30 |cmp al, 0x30 00402112 |. 7C 04 |jl short 00402118 00402114 |. 3C 39 |cmp al, 0x39 00402116 |. 7E 10 |jle short 00402128 00402118 |> 3C 61 |cmp al, 0x61 0040211A |. 7C 04 |jl short 00402120 0040211C |. 3C 7A |cmp al, 0x7A 0040211E |. 7E 08 |jle short 00402128 00402120 |> 3C 41 |cmp al, 0x41 00402122 |. 7C 1A |jl short 0040213E 00402124 |. 3C 5A |cmp al, 0x5A 00402126 |. 7F 16 |jg short 0040213E 00402128 |> BF 34534000 |mov edi, 00405334 ; ASCII "}esterCheneghmfnopqrijklstuvabcd" 0040212D |. 83C9 FF |or ecx, -0x1 00402130 |. 33C0 |xor eax, eax 00402132 |. 42 |inc edx 00402133 |. F2:AE |repne scas byte ptr es:[edi] 00402135 |. F7D1 |not ecx 00402137 |. 49 |dec ecx 00402138 |. 3BD1 |cmp edx, ecx 0040213A |.^ 75 CE \jnz short 0040210A 00402143 |> \BF 68534000 mov edi, 00405368 ; 取出密码 00402148 |. 83C9 FF or ecx, -0x1 0040214B |. 33C0 xor eax, eax 0040214D |. 33D2 xor edx, edx 0040214F |. F2:AE repne scas byte ptr es:[edi] 00402151 |. F7D1 not ecx 00402153 |. 49 dec ecx 00402154 |. 74 32 je short 00402188 00402156 |> 8A82 68534000 /mov al, byte ptr [edx+0x405368] 0040215C |. 3C 30 |cmp al, 0x30 0040215E |. 7C 04 |jl short 00402164 00402160 |. 3C 39 |cmp al, 0x39 00402162 |. 7E 10 |jle short 00402174 00402164 |> 3C 61 |cmp al, 0x61 00402166 |. 7C 04 |jl short 0040216C 00402168 |. 3C 7A |cmp al, 0x7A 0040216A |. 7E 08 |jle short 00402174 0040216C |> 3C 41 |cmp al, 0x41 0040216E |. 7C 1D |jl short 0040218D 00402170 |. 3C 5A |cmp al, 0x5A 00402172 |. 7F 19 |jg short 0040218D 00402174 |> BF 68534000 |mov edi, 00405368 ; ASCII "14725lmn858963efghi369jk2741abcd" 00402179 |. 83C9 FF |or ecx, -0x1 0040217C |. 33C0 |xor eax, eax 0040217E |. 42 |inc edx 0040217F |. F2:AE |repne scas byte ptr es:[edi] 00402181 |. F7D1 |not ecx 00402183 |. 49 |dec ecx 00402184 |. 3BD1 |cmp edx, ecx 00402186 |.^ 75 CE \jnz short 00402156 00402188 |> 83FE 01 cmp esi, 0x1 0040218B |. 75 0B jnz short 00402198 0040218D |> 8B45 F0 mov eax, dword ptr [ebp-0x10] 00402190 |. 6A 00 push 0x0 00402192 |. 50 push eax 00402193 |. E9 64010000 jmp 004022FC 004021B3 |> \BF 68534000 mov edi, 00405368 ; 取出密码 004021B8 |. 83C9 FF or ecx, -0x1 004021BB |. 33C0 xor eax, eax 004021BD |. F2:AE repne scas byte ptr es:[edi] 004021BF |. F7D1 not ecx ; 取出密码的长度然后减1的值必须大于等于0x20 004021C1 |. 49 dec ecx 004021C2 |. 83F9 20 cmp ecx, 0x20 004021C5 |. 73 0A jnb short 004021D1 ; 只要不大于0x20,就结束线程停止校验 可见这个CrackMe的规矩有很多哦…… 00402610 /$ 56 push esi 00402611 |. 8BF1 mov esi, ecx 00402613 |. 6A 03 push 0x3 00402615 |. E8 66FEFFFF call 00402480 0040261A |. 83F8 01 cmp eax, 0x1 0040261D |. 74 04 je short 00402623 0040261F |. 33C0 xor eax, eax 00402621 |. 5E pop esi 00402622 |. C3 retn 00402623 |> 8BCE mov ecx, esi 00402625 |. E8 8E120000 call <jmp.&MFC42.#CDialog::DoModal_2514> 0040262A |. 5E pop esi 0040262B \. C3 retn 根据CrackMe作者的注册成功界面提示,可以想象出来,这个成功界面应该是个模式对话框,不是简单的AfxMessageBox,跟进00402480这个函数看看条件是什么…… 00402480 /$ 53 push ebx 00402481 |. 55 push ebp 00402482 |. 8BE9 mov ebp, ecx 00402484 |. 56 push esi 00402485 |. 57 push edi 00402486 |. B9 58544000 mov ecx, 00405458 0040248B |. E8 70070000 call 00402C00 00402490 |. 8B4C24 14 mov ecx, dword ptr [esp+0x14] 00402494 |. 8BF0 mov esi, eax 00402496 8D41 FD lea eax, dword ptr [ecx-0x3] ; 把EAX值改成4,来跳到0040254D 00402499 83F8 04 cmp eax, 0x4 0040249C 0F87 A2000000 ja 00402544 004024A2 |. 8BF8 mov edi, eax 004024A4 |. 8D99 68534000 lea ebx, dword ptr [ecx+0x405368] 004024AA |> FF2485 782540>/jmp dword ptr [eax*4+0x402578] ; 这里要调到关键的函数,需要让EAX=4 004024B1 |> B9 58544000 |mov ecx, 00405458 004024B6 |. E8 45070000 |call 00402C00 004024BB |. 2BC6 |sub eax, esi 004024BD |. 83F8 01 |cmp eax, 0x1 004024C0 |. 7E 07 |jle short 004024C9 004024C2 |. 8BCD |mov ecx, ebp 004024C4 |. E8 F9120000 |call <jmp.&MFC42.#CDialog::OnCancel_4376> 004024C9 |> 803B 41 |cmp byte ptr [ebx], 0x41 004024CC |. 75 76 |jnz short 00402544 004024CE |. EB 5B |jmp short 0040252B ... 00402544 |> 5F pop edi 00402545 |. 5E pop esi 00402546 |. 5D pop ebp 00402547 |. 33C0 xor eax, eax 00402549 |. 5B pop ebx 0040254A |. C2 0400 retn 0x4 0040254D |> B9 58544000 mov ecx, 00405458 00402552 |. E8 A9060000 call 00402C00 00402557 |. 2BC6 sub eax, esi 00402559 |. 83F8 01 cmp eax, 0x1 0040255C |. 7E 07 jle short 00402565 0040255E |. 8BCD mov ecx, ebp 00402560 |. E8 5D120000 call <jmp.&MFC42.#CDialog::OnCancel_4376> 00402565 |> 6A 0E push 0xE 00402567 |. 8BCD mov ecx, ebp 00402569 |. E8 22000000 call 00402590 ; 这里面是关键 0040256E |. 5F pop edi 0040256F |. 5E pop esi 00402570 |. 5D pop ebp 00402571 |. 5B pop ebx 00402572 \. C2 0400 retn 0x4 进入关键的函数,得到信息如下: 00402590 /$ 8B4424 04 mov eax, dword ptr [esp+0x4] 00402594 |. 56 push esi 00402595 |. 83F8 1D cmp eax, 0x1D 00402598 |. 74 2C je short 004025C6 0040259A |. B9 34534000 mov ecx, 00405334 ; ASCII "}esterCheneghmfnopqrijklstuvabcd"这个是根据用户名算出来的值 0040259F |. 81E9 68534000 sub ecx, 00405368 ; ASCII "14725lmn858963efghi369jk2741abcd"这个是根据密码算出来的值 004025A5 |. 83F8 1D cmp eax, 0x1D 004025A8 |> 7F 30 /jg short 004025DA 004025AA |. 0FBE9401 6853>|movsx edx, byte ptr [ecx+eax+0x405368] ; ECX=FFFFFFCC,eax=E 004025B2 |. 0FBEB0 685340>|movsx esi, byte ptr [eax+0x405368] 004025B9 |. 2BD6 |sub edx, esi 004025BB |. 83FA 01 |cmp edx, 0x1 004025BE |. 75 1A |jnz short 004025DA 004025C0 |. 40 |inc eax 004025C1 |. 83F8 1D |cmp eax, 0x1D 004025C4 |.^ 75 E2 \jnz short 004025A8 004025C6 |> 0FBE88 345340>movsx ecx, byte ptr [eax+0x405334] 004025CD |. 0FBE80 685340>movsx eax, byte ptr [eax+0x405368] 004025D4 |. 2BC1 sub eax, ecx 相减如果等于1,则就可以满足上面的条件,调用Domodal函数显示界面了。 004025D6 |. 5E pop esi 004025D7 |. C2 0400 retn 0x4 004025DA |> 33C0 xor eax, eax 004025DC |. 5E pop esi 004025DD \. C2 0400 retn 0x4 004025E0 . 56 push esi 004025E1 . 8BF1 mov esi, ecx 004025E3 . 6A 07 push 0x7 004025E5 . E8 66FDFFFF call 00402350 004025EA . 85C0 test eax, eax 004025EC . 8BCE mov ecx, esi 004025EE . 75 09 jnz short 004025F9 004025F0 . E8 CD110000 call <jmp.&MFC42.#CDialog::OnCancel_4376> 004025F5 . 33C0 xor eax, eax 004025F7 . 5E pop esi 004025F8 . C3 retn 004025F9 > E8 B4120000 call <jmp.&MFC42.#CDialog::OnInitDialog_4710> 004025FE . B8 01000000 mov eax, 0x1 00402603 . 5E pop esi 00402604 . C3 retn 由此可知,由用户名算出来的值中中间一部分的每个字符都要比由序列号算出来的值大1,这样就可以通过校验了比如ccfer老大提供的名和序列号: eT_oxnldviuotv qqpqhkr{vkpujmnv ms 这样我们就明白了一个道理: 用户名的长度应该是32位,否则程序自己按照字母表填出起来得到的字符串减一再逆出来的序列号不会满足我们在上面贴出来的序列号的规则,所以,用户名需要枚举。 先不管这些了,先爆破了它: 把: 0040261D |. 74 04 je short 00402623 改成: 0040261D /EB 04 jmp short 00402623 这样,不管注册对错,都应该弹出一个模式对话框。修改了Crackme.atom文件以后,运行发现没有对话框弹出,先后比较过多次,传入的this指针什么的都是一样的,CPU上下文也一样的时候还是不能弹出来,所以,我估计 应该是做了处理,这个crackme无数次的调用OnCancel,我觉得这次模式对话框没有出现也应该是它搞的鬼,所以就在OnCancel上下了个断点,来到如下地方: 004025E0 56 push esi ; Decoded as <WinProc> 004025E1 . 8BF1 mov esi, ecx 004025E3 . 6A 07 push 0x7 004025E5 . E8 66FDFFFF call 00402350 004025EA . 85C0 test eax, eax 004025EC . 8BCE mov ecx, esi 004025EE EB 09 jnz short 004025F9 ; 这里改成JMP就可以了应该。 004025F0 . E8 CD110000 call <jmp.&MFC42.#CDialog::OnCancel_4> 004025F5 . 33C0 xor eax, eax 004025F7 . 5E pop esi 004025F8 . C3 retn 004025F9 > E8 B4120000 call <jmp.&MFC42.#CDialog::OnInitDial> 004025FE . B8 01000000 mov eax, 0x1 00402603 . 5E pop esi 00402604 . C3 retn 把004025EE处的JNZ改成JMP,如: EB 09 jmp short 004025F9,这样,就爆破完成了! 经过观察,发现,这里提示失败,但是只要让窗口重新刷新一下,比如找个别的窗口遮盖一下,再露出来就提示成功了。 我猜测应该是在一些刷新消息的响应函数里有个暗装在搞怪的原因,我看了这个crackme的资源,它的注册失败和成功是两个标签资源,我想他应该是通过修改资源的显示来动的手脚或者修改的资源的Z轴。 但是我下断ShowWindow,和一些我知道的消息断点比如WM_PAINT,OnPaint()这些函数都没有找到可疑代码。所以就提交了这个不是没成功的破解文件。希望能通过审核。 另外,我会继续找这个暗装到底是在哪里出的问题,明天有时间的话给出用户名和注册码的算法部分…… |
|
|
|
[已结束] [PEDIY.华章 Crackme 竞赛 2009] [第一回] – Atom
越来越崇拜ccfer大师了·~~~~ |
|
[已结束] [PEDIY.华章 Crackme 竞赛 2009] [第一回] – Atom
上面都是些走后门提前入场的家伙…… 太不公平了~~~~ 先去吃饭去了~~~~ 另:本楼低价出租,具体价格请回帖联系…… |
|
|
|
|
|
|
|
|
|
|
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值