【文章标题】: 再探 CrackMe001 By飘云[PYG](一)
【文章作者】: petnt
【作者邮箱】: petnt@sohu.com
【软件名称】: CrackMe001 By飘云[PYG]
【下载地址】: 自己搜索下载
【加壳方式】: FSG2.0
【保护方式】: 壳\注册码
【使用工具】: OD\UltraEdit-32\ImportREC.exe
【操作平台】: XpSp2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【前 言】
这两天分析一个小软受挫(其实是经常的事),不得不再次捧起“PEDIY CrackMe 2007”发奋苦读。有破文跟着就不怕受挫了:)。这个CrackMe的算法分析破文已由busheler大侠2006年1月18日完成(再过3个小时就是2008.01.18了 ,小菜我默默无语两眼泪,耳边响起驼铃声),之所以再次提起它,还得从busheler大侠的破文说起。。。。
记得那是2002年的第一场雪。。。。。。。。。又要跑。。。我回:
********************************************************************************
算法初探--Crackme001 By 飘云[PYG]
1.去除启动时的延时。
2.分析算法。
3.去除退出时的Nag。
备注:
1、由于我系统时间格式的问题,该CrackMe运行时总弹出这样的对话框:"'2006-2' is not a valid integer value"...,并造成第三个验证码总为0,呵呵。感谢飘云指导,并顺利完成注册码算法分析!:)
2、关于“去除启动时的延时”及“去除退出时的Nag”未分析。
*********************************************************************************
以上内容引自《算法分析之CrackMe001 By飘云[PYG]》By busheler
busheler提到的bug在我的菜机上也出现了,一是想探个究竟,二是想完成大侠留下的任务,所以有了本破文,算是一篇续吧(只是比2002年来的稍晚了一些)。
【正 文】
第一幕 脱 壳
这个程序是带壳的(FSG 2.0 -> bart/xt ),为了锻炼队伍,我们手动解决。
00400154 > 8725 B8574C00 xchg dword ptr [4C57B8], esp ;;;;;;载入后我们停到这里
0040015A 61 popad
;;;;;;;;;;;此处省略部分代码;;;;;;;;;;;;;
004001B7 56 push esi
004001B8 8BF7 mov esi, edi
004001BA 2BF0 sub esi, eax
004001BC F3:A4 rep movs byte ptr es:[edi], byte ptr>
004001BE 5E pop esi
004001BF ^ EB 9F jmp short 00400160
004001C1 5E pop esi
004001C2 AD lods dword ptr [esi] ;;;;;;;;;;;;;;;;;;;;;;;;
004001C3 97 xchg eax, edi ;
004001C4 AD lods dword ptr [esi] ;
004001C5 50 push eax ;
004001C6 FF53 10 call dword ptr [ebx+10] ;
004001C9 95 xchg eax, ebp ;此
004001CA 8B07 mov eax, dword ptr [edi] ;处
004001CC 40 inc eax ;处
004001CD ^ 78 F3 js short 004001C2 ;理
004001CF 75 03 jnz short 004001D4 ;输
004001D1 FF63 0C jmp dword ptr [ebx+C] ;;;;;;;;可爱的跳转 ;入
004001D4 50 push eax ;表
004001D5 55 push ebp ;
004001D6 FF53 14 call dword ptr [ebx+14] ;
004001D9 AB stos dword ptr es:[edi] ;;;;;;;;IAT的地址 ;
004001DA ^ EB EE jmp short 004001CA ;;;;;;;;;;;;;;;;;;;;;;;;
004001DC 33C9 xor ecx, ecx
004001DE 41 inc ecx
004001DF FF13 call dword ptr [ebx]
004001E1 13C9 adc ecx, ecx
004001E3 FF13 call dword ptr [ebx]
004001E5 ^ 72 F8 jb short 004001DF
004001E7 C3 retn
004001E8 02D2 add dl, dl
004001EA 75 05 jnz short 004001F1
004001EC 8A16 mov dl, byte ptr [esi]
004001EE 46 inc esi
004001EF 12D2 adc dl, dl
004001F1 C3 retn
上面的分析是我一步步跟踪得到的,因为这是个简单的加密壳,所以这些分析结果应该很容易就得出。这里我们关心的只有两处:IAT地址我们将用来修复输入表;可爱的跳转将带我们飞向光明之巅(fly大侠的经典,绝对经典)。先F4到00401D9,记下IAT位置,在F4到可爱的跳转上,F8。
004689C8 55 push ebp ;;;;;;;;传说中的光明之巅
004689C9 8BEC mov ebp, esp
004689CB 83C4 F0 add esp, -10
004689CE B8 D0874600 mov eax, 004687D0
004689D3 E8 88D2F9FF call 00405C60
004689D8 A1 90A94600 mov eax, dword ptr [46A990]
004689DD 8B00 mov eax, dword ptr [eax]
004689DF E8 CCAAFEFF call 004534B0
004689E4 A1 90A94600 mov eax, dword ptr [46A990]
004689E9 8B00 mov eax, dword ptr [eax]
004689EB BA 288A4600 mov edx, 00468A28 ; ASCII "CrackMe 001 By 飘云[PYG]"
004689F0 E8 CBA6FEFF call 004530C0
004689F5 8B0D 84A74600 mov ecx, dword ptr [46A784] ; CrackMe0.0046BC08
004689FB A1 90A94600 mov eax, dword ptr [46A990]
00468A00 8B00 mov eax, dword ptr [eax]
00468A02 8B15 C47E4600 mov edx, dword ptr [467EC4] ; CrackMe0.00467F10
00468A08 E8 BBAAFEFF call 004534C8
00468A0D A1 90A94600 mov eax, dword ptr [46A990]
00468A12 8B00 mov eax, dword ptr [eax]
00468A14 E8 2FABFEFF call 00453548
00468A19 E8 3EB3F9FF call 00403D5C
看到这里我们没有理由再愣着了,dump。先不要关掉OD,赶紧请出ImportREC.exe。Rva填上我们记下的地址(转换RVA),大小我懒得填,默认吧。获取输入表。。。
等着我们的是N多的无效,去我们的记下的地址上看个究竟:
0046C12C 8A 18 93 7C ED 10 92 7C 05 10 92 7C A1 9F 80 7C ?搢?抾抾€|
0046C13C 14 9B 80 7C 81 9A 80 7C 5D 99 80 7C BD 99 80 7C 泙|仛€|]檧|綑€|
0046C14C AB 14 81 7C 37 97 80 7C 94 97 80 7C 7B 97 80 7C ?亅7梹|敆€|{梹|
0046C15C 59 B8 80 7C C7 A0 80 7C AD 9C 80 7C E0 C6 80 7C Y竴|菭€|瓬€|嗥€|
0046C16C 11 03 81 7C B0 2F 88 7C 05 A4 80 7C EE 1E 80 7C 亅?坾|?€|
0046C17C EC 2F 88 7C 29 B5 80 7C 57 B3 80 7C 7E D4 80 7C ?坾)祤|W硛|~詟|
0046C18C 8D 2C 81 7C 66 AA 80 7C 59 35 81 7C D7 EF 80 7C ?亅f獉|Y5亅罪€|
0046C19C A2 CA 81 7C 9F 0F 81 7C 8A 2B 86 7C 40 7A 95 7C ⑹亅?亅?唡@z晐
0046C1AC E1 EA 81 7C A9 2C 81 7C FF FF FF 7F 46 FA D3 77 彡亅?亅Fw
0046C1BC 98 EC D3 77 0B 05 D5 77 40 EC D3 77 FF FF FF 7F 橃觲誻@煊w
0046C1CC 83 78 DA 77 1B 76 DA 77 F0 6B DA 77 FF FF FF 7F 儀趙v趙餶趙
0046C1DC 50 48 0F 77 9D C9 11 77 59 4B 0F 77 FF FF FF 7F PHw澤wYKw
呵呵,原来有很多扎眼的 7FFFFFFF 在这里,把无效的指针和 7FFFFFFF Cut掉,修复我们的Dump文件,修复好后确认入口为:000689C8。程序顺利的运行了。
第二幕 Fix Bug
载入dump,F9。程序会异常在系统领空,观察堆栈,找到SEH上面的返回地址,我们从源头找起。
004685B0 /. 55 push ebp
004685B1 |. 8BEC mov ebp, esp
004685B3 |. 33C9 xor ecx, ecx
004685B5 |. 51 push ecx
004685B6 |. 51 push ecx
004685B7 |. 51 push ecx
004685B8 |. 51 push ecx
004685B9 |. 33C0 xor eax, eax
004685BB |. 55 push ebp
004685BC |. 68 7F864600 push 0046867F ; 安装SEH
004685C1 |. 64:FF30 push dword ptr fs:[eax]
004685C4 |. 64:8920 mov dword ptr fs:[eax], esp
004685C7 |. C705 14BC4600 0A>mov dword ptr [46BC14], 0A
004685D1 |. E8 7A10FAFF call 00409650
004685D6 |. 83C4 F8 add esp, -8 ; /
004685D9 |. DD1C24 fstp qword ptr [esp] ; |Arg1 (8 字节)
004685DC |. 9B wait ; |
004685DD |. 8D45 FC lea eax, dword ptr [ebp-4] ; |
004685E0 |. E8 7F1CFAFF call 0040A264 ; \dump2.0040A264
004685E5 |. 8B55 FC mov edx, dword ptr [ebp-4] ; 上面获取系统时间 我的为“2008-1-17”
004685E8 |. B8 10BC4600 mov eax, 0046BC10
004685ED |. E8 AEB8F9FF call 00403EA0
004685F2 |. 8D45 F8 lea eax, dword ptr [ebp-8]
004685F5 |. 50 push eax
004685F6 |. B9 04000000 mov ecx, 4
004685FB |. BA 01000000 mov edx, 1
00468600 |. A1 10BC4600 mov eax, dword ptr [46BC10]
00468605 |. E8 62BDF9FF call 0040436C ; 取时间字符串的前4(年)
0046860A |. FF75 F8 push dword ptr [ebp-8]
0046860D |. 8D45 F4 lea eax, dword ptr [ebp-C]
00468610 |. 50 push eax
00468611 |. B9 02000000 mov ecx, 2
00468616 |. BA 06000000 mov edx, 6
0046861B |. A1 10BC4600 mov eax, dword ptr [46BC10]
00468620 |. E8 47BDF9FF call 0040436C ; 取第6开始的2位(月)
00468625 |. FF75 F4 push dword ptr [ebp-C]
00468628 |. 8D45 F0 lea eax, dword ptr [ebp-10]
0046862B |. 50 push eax
0046862C |. B9 02000000 mov ecx, 2
00468631 |. BA 09000000 mov edx, 9
00468636 |. A1 10BC4600 mov eax, dword ptr [46BC10]
0046863B |. E8 2CBDF9FF call 0040436C ; 取第9开始的2位(日)
00468640 |. FF75 F0 push dword ptr [ebp-10]
00468643 |. B8 0CBC4600 mov eax, 0046BC0C
00468648 |. BA 03000000 mov edx, 3
0046864D |. E8 7ABBF9FF call 004041CC ; 合并
00468652 |. A1 0CBC4600 mov eax, dword ptr [46BC0C]
00468657 |. E8 44F8F9FF call 00407EA0 ; 字符变数字
0046865C |. C1E0 03 shl eax, 3 ; 相当于 * 2^3
0046865F |. A3 18BC4600 mov dword ptr [46BC18], eax ; 保存(此数字将用于注册码的产生)
00468664 |. 33C0 xor eax, eax
00468666 |. 5A pop edx
00468667 |. 59 pop ecx
00468668 |. 59 pop ecx
00468669 |. 64:8910 mov dword ptr fs:[eax], edx
0046866C |. 68 86864600 push 00468686
00468671 |> 8D45 F0 lea eax, dword ptr [ebp-10]
00468674 |. BA 04000000 mov edx, 4
00468679 |. E8 F2B7F9FF call 00403E70
0046867E \. C3 retn
上面的分析可以明显地看到错误产生的过程,由于时间字符串为“2008-1-17”,而不是作者以为的“2008-01-17”(从取字符的过程知道这是作者想要的),在取月和日的时候,程序将取不到预期的数字,使得程序出错。好了,我们去找这个日期字符串产生的源头看看(我跋山涉水啊,翻山越岭啊)。。
0040ABA4 68 00010000 push 100
0040ABA9 8D8D 00FFFFFF lea ecx, dword ptr [ebp-100]
0040ABAF 51 push ecx
0040ABB0 52 push edx
0040ABB1 50 push eax
0040ABB2 E8 31B3FFFF call <jmp.&kernel32.GetLocaleInfoA> ;;;;;哈哈,他藏在这里
0040ABB7 85C0 test eax, eax
0040ABB9 7E 12 jle short 0040ABCD
0040ABBB 8BC8 mov ecx, eax
0040ABBD 49 dec ecx
0040ABBE 8D95 00FFFFFF lea edx, dword ptr [ebp-100]
0040ABC4 8BC3 mov eax, ebx
0040ABC6 E8 7193FFFF call 00403F3C
0040ABCB EB 09 jmp short 0040ABD6
原来程序在获得系统的日期格式,我的短日期格式为yyyy-M-D。应该是这里的问题,我们做下实验。
区域语言选项 -> 区域选项 -> 自定义区域选项-> 日期:短格式日期 yyyy-M-D 改为 yyyy-MM-DD。再运行程序,呵呵,没有错误了。
我的短日期格式设置中有四个选项,呵呵,程序会出错的几率还是很大的。只有yyyy-M-D(日期和月份必须大于等于10),yyyy-MM-DD时程序才能正确运行。
不让风险存在就是让他永远为yyyy-MM-DD。还用函数获取什么,我们给他固定吧:
先找个地方放好(我选这里) 0040C3D0 00 00 79 79 79 79 2D 4D 4D 2D 44 44 00 00 00 00 ..yyyy-MM-DD....
再来改程序:
0040ABA4 B8 0B000000 mov eax, 0B ; eax为字符串长度,我们也固定
0040ABA9 EB 0C jmp short 0040ABB7 ; 直接跳过
0040ABAB 00FF add bh, bh
0040ABAD FFFF ??? ; 未知命令
0040ABAF 51 push ecx
0040ABB0 52 push edx
0040ABB1 50 push eax
0040ABB2 E8 31B3FFFF call <jmp.&kernel32.GetLocaleInfoA>
0040ABB7 |. 85C0 test eax, eax ; 跳到这里
0040ABB9 |. 7E 12 jle short 0040ABCD
0040ABBB |. 8BC8 mov ecx, eax
0040ABBD |. 49 dec ecx
0040ABBE BA D2C34000 mov edx, 0040C3D2 ; ASCII "yyyy-MM-DD"
0040ABC3 90 nop ; 把我们设计好的值给edx
0040ABC4 |. 8BC3 mov eax, ebx
0040ABC6 |. E8 7193FFFF call 00403F3C
0040ABCB |. EB 09 jmp short 0040ABD6
保存,运行,OK了。当然我们这样做也有风险,就是如果程序加载的基址不是00400000就会出错了,但这种风险因该小得多了吧:)。
好了,时间不早了,就写到这里吧,写的太长也容易让大家看得睡着了。第三幕 Kill Timer ,第四幕 Remove NAG 就明天再写吧。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!(未完,待续)
2008年01月17日 23:32:10
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!