【破解作者】 lelfei
【作者邮箱】 lelfei#sina.com
【使用工具】 Peid0.92,FI3.01,OllyDBG1.10,LordPE,UltraEdit,...
【破解平台】 Win2000
【软件名称】 EasyBoot 5.0.3.426 , 2004年9月22日
【下载地址】 http://cn.ezbsystems.com
【软件简介】 EasyBoot是一款集成化的中文光盘启动菜单制作工具,它可以制作光盘启动菜单、自动生成启动文件、并生成可启动ISO文件。只要通过CD-R/W刻录软件即可制作完全属于自己的启动光盘。
【软件大小】 2.40M
【加壳方式】 未知
【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:)
--------------------------------------------------------------------------------
【破解内容】
一、脱壳:
观察:
用Peid和FI侦察,发现壳为“ASPack 2.12 -> Alexey Solodovnikov”,但实际并非如此。
下手:
用Fly修改的OllyDBG1.10载入程序,停在入口处:
代码:
005AB001 E>pushad <--程序入口点 005AB002 call EasyBoot.005AB00A 005AB007 jmp 45B7B4F7
可以单步跟,我们用最快速的方法到达伪OEP:
查找按“Ctrl+F”,输入命令“Popad”,再按三次“Ctrl+L”(继续查找),来到005AB3AF处,再“F4”到这里:
代码:
005AB3A9 mov dword ptr ss:[ebp+3A8],eax 005AB3AF popad ;<--F4来到这里 005AB3B0 jnz short EasyBoot.005AB3BA 005AB3B2 mov eax,1 005AB3B7 retn 0C 005AB3BA push EasyBoot.00401428 ;可以看见伪OEP了 005AB3BF retn ;返回到 00401428 (EasyBoot.00401428) 00401428 jmp short EasyBoot.0040143A ;<--伪OEP入口 0040142A db 66 ; CHAR 'f' 0040142B db 62 ; CHAR 'b' 0040142C db 3A ; CHAR ':' 0040142D db 43 ; CHAR 'C' 0040142E db 2B ; CHAR '+' 0040142F db 2B ; CHAR '+' 00401430 db 48 ; CHAR 'H' 00401431 db 4F ; CHAR 'O' 00401432 db 4F ; CHAR 'O' 00401433 db 4B ; CHAR 'K' 00401434 nop 00401435 db E9 00401436 dd offset EasyBoot.___CPPdebugHook 0040143A mov eax,dword ptr ds:[50708B] 0040143F shl eax,2 发现伪OEP处的代码并不像我们常见的程序入口点代码,继续往下跟: 0040143A mov eax,dword ptr ds:[50708B] 0040143F shl eax,2 00401442 mov dword ptr ds:[50708F],eax 00401447 push edx 00401448 push 0 ; /pModule = NULL 0040144A call EasyBoot.00506066 ; \GetModuleHandleA 0040144F mov edx,eax 00401451 call EasyBoot.004E303C 00401456 pop edx 00401457 call EasyBoot.004E2FA0 0040145C call EasyBoot.004E307C 00401461 push 0 ; /Arg1 = 00000000 00401463 call EasyBoot.004E4690 ; \EasyBoot.004E4690 00401468 pop ecx 00401469 push EasyBoot.00507034 0040146E push 0 ; /pModule = NULL 00401470 call EasyBoot.00506066 ; \GetModuleHandleA 00401475 mov dword ptr ds:[507093],eax 0040147A push 0 0040147C jmp EasyBoot.004EE16C ;<--这里跳向真正的OEP 00401481 E>jmp EasyBoot.004E46DC 004EE16C push ebp ;<--真实的OEP,观察这里的代码 004EE16D mov ebp,esp 004EE16F add esp,-0C 004EE172 push ebx 004EE173 push esi 004EE174 push edi 004EE175 mov esi,dword ptr ss:[ebp+8] 004EE178 mov eax,dword ptr ds:[esi+10] 004EE17B and eax,1 004EE17E mov dword ptr ds:[51F1A0],eax 004EE183 call EasyBoot.004EADB4
在004EE16C处DUMP内存,存为“Dump.exe”。
修复IAT:
运行ImportREC1.6,选择当前的进程“EasyBoot.exe”,填入OEP:000EE16C,获取输入表,可以看到仅有Kernel32.dll中的函数调用。
不知道各位高手是怎么解决这个问题的,我摸索出一个解决办法如下:
在函数框中点鼠标右键->高级命令菜单->获取API调用信息,填入地址范围00000000-FFFFFFFF,只勾选“获取‘Call X’scheme”,确定后会发现找到一大串;
点“显示无效函数”,在函数框中点鼠标右键->删除指针数据,FixDump生成dump_.exe。
修正OEP:
用OllyDBG载入刚生成的Dump_.exe,运行出错,还是由于程序调用[ESI+XX]引起的,在壳中OEP处ESI=ESP+4=[0012FFC0]=00507034,而脱壳后ESI=ESP+4=[0012FFC8]=005616A8,需要平衡堆栈。
在代码段的空白处,我选在该段的结尾处,输入下面代码:
代码:
00506FF0 1>mov dword ptr ss:[esp+4],fix_dump.00507034 ;<--恢复堆栈数据 00506FF8 jmp fix_dump.004EE16C ;<--跳到真正的OEP
用LordPE修改程序的OEP为00106FF0,保存为fix_dump_.exe,试运行之,成功!
二、爆破:
观察:
未注册版有烦人的弹出窗口提示,还有功能限制,在“关于”里输入注册码,发现为重启验证,注册表里存有注册信息,用户名为明码保存,注册码为加密形式保存。
下手:
既然存到注册表里,我们就从注册表入手:
在命令行里输入:bp RegOpenKeyExA,按F9运行程序,中断后观察ESP+4和ESP+8处的字符,直到分别为“hKey = HKEY_CURRENT_USER”和“Subkey = "SOFTWARE\EasyBoot Systems\EasyBoot\3.0"”为止,(在我的电脑上是按了5次F9),关闭断点,然后按“Alt+F9”返回程序,来到:
代码:
00402630 push ecx ; /pHandle 00402631 push fix_dump.0050A3A5 ; |Subkey = "SOFTWARE\EasyBoot Systems\EasyBoot\3.0" 00402636 push 80000001 ; |hKey = HKEY_CURRENT_USER 0040263B call <jmp.&advapi32.RegOpenKeyA> ; \RegOpenKeyA 00402640 test eax,eax ;<--返回到这里 00402642 jnz fix_dump.004026C9 ;判断是否有注册表信息 00402648 mov dword ptr ss:[ebp-40],400 0040264F lea eax,dword ptr ss:[ebp-40] 00402652 push eax ; /pBufSize 00402653 lea edx,dword ptr ss:[ebp-648] ; | 00402659 push edx ; |Buffer 0040265A lea ecx,dword ptr ss:[ebp-3C] ; | 0040265D push ecx ; |pValueType 0040265E push 0 ; |Reserved = NULL 00402660 push fix_dump.0050A3CC ; |ValueName = "" 00402665 push dword ptr ss:[ebp-38] ; |hKey 00402668 call <jmp.&advapi32.RegQueryValue>; \RegQueryValueExA 0040266D test eax,eax 0040266F jnz short fix_dump.004026C1 ··· 0040272A lea edx,dword ptr ss:[ebp-248] 00402730 push edx ; /Arg2 00402731 lea ecx,dword ptr ss:[ebp-148] ; | 00402737 push ecx ; |Arg1 00402738 call fix_dump.004397F8 ; \fix_dump.004397F8读注册信息 0040273D add esp,8 ;<--到这里可以看到注册信息 00402740 mov dword ptr ds:[50A5AC],eax ;置注册标志位1 00402745 mov eax,dword ptr ds:[50A5AC] 0040274A test eax,eax ;判断注册信息是否存在 0040274C je short fix_dump.0040276B 0040274E lea edx,dword ptr ss:[ebp-248] 00402754 push edx 00402755 lea ecx,dword ptr ss:[ebp-148] 0040275B push ecx 0040275C call fix_dump.004017D3 ;关键CALL,比较注册码,跟进 00402761 add esp,8 00402764 mov dword ptr ds:[50A5AC],eax ;保存注册标志位1 00402769 jmp short fix_dump.00402772 0040276B xor eax,eax ;清除注册标志位1 0040276D mov dword ptr ds:[50A5AC],eax 跟进0040275C处的关键CALL: 004017D3 $ 55 push ebp 004017D4 . 8BE>mov ebp,esp 004017D6 . 81C>add esp,-4C0 004017DC . 33C>xor eax,eax ···注册码计算过程,有兴趣的同志可以慢慢跟:) 00401A93 xor ecx,ecx 00401A95 mov dword ptr ss:[ebp-2C],ecx 00401A98 lea eax,dword ptr ss:[ebp-468] 00401A9E mov edx,dword ptr ds:[eax] 00401AA0 mov ecx,dword ptr ss:[ebp-34] 00401AA3 mov eax,dword ptr ds:[ecx] 00401AA5 cmp edx,eax 00401AA7 jnz short fix_dump.00401B13 ;关键比较1,跳则完完 00401AA9 lea edx,dword ptr ss:[ebp-468] 00401AAF mov dword ptr ss:[ebp-3C],edx 00401AB2 dec dword ptr ds:[5145C0] 00401AB8 mov ecx,dword ptr ss:[ebp-34] 00401ABB mov dword ptr ss:[ebp-40],ecx 00401ABE mov eax,dword ptr ss:[ebp-3C] 00401AC1 mov edx,dword ptr ds:[eax] 00401AC3 mov ecx,dword ptr ss:[ebp-40] 00401AC6 mov eax,dword ptr ds:[ecx] 00401AC8 cmp edx,eax 00401ACA jnz short fix_dump.00401B13 ;关键比较2,跳则完完 00401ACC mov edx,dword ptr ss:[ebp-3C] 00401ACF mov ecx,dword ptr ds:[edx+C] 00401AD2 mov eax,dword ptr ss:[ebp-40] 00401AD5 mov edx,dword ptr ds:[eax+4] 00401AD8 cmp ecx,edx 00401ADA jnz short fix_dump.00401B13 ;关键比较3,跳则完完 00401ADC dec dword ptr ds:[5145C0] 00401AE2 mov ecx,dword ptr ss:[ebp-28] 00401AE5 add ecx,46 00401AE8 mov dword ptr ds:[5083D8],ecx 00401AEE mov eax,dword ptr ss:[ebp-28] 00401AF1 not eax 00401AF3 mov edx,dword ptr ds:[5145C0] 00401AF9 cmp eax,edx 00401AFB jnz short fix_dump.00401B29 ;关键比较4,跳则完完 00401AFD mov dword ptr ds:[5145C0],5000 ;置注册标志位2 00401B07 mov dword ptr ds:[50B5F4],5500 ;置注册标志位3 00401B11 jmp short fix_dump.00401B29 00401B13 add dword ptr ss:[ebp-34],8 00401B17 inc dword ptr ss:[ebp-2C] 00401B1A mov ecx,dword ptr ss:[ebp-2C] 00401B1D cmp ecx,1D0 00401B23 jl fix_dump.00401A98 00401B29 mov eax,dword ptr ss:[ebp-28] 00401B2C add eax,46 00401B2F mov edx,dword ptr ds:[5083D8] 00401B35 cmp eax,edx 00401B37 je short fix_dump.00401B3F 00401B39 dec dword ptr ds:[5145C0] 00401B3F lea ecx,dword ptr ss:[ebp-10] 00401B42 push ecx ; /Arg2 00401B43 push dword ptr ss:[ebp+8] ; |Arg1 00401B46 call fix_dump.00445CDC ; \fix_dump.00445CDC 00401B4B add esp,8 00401B4E push dword ptr ss:[ebp-14] ; /Arg2 00401B51 push dword ptr ss:[ebp-10] ; |Arg1 00401B54 call fix_dump.00442538 ; \fix_dump.00442538 再次判断 00401B59 add esp,8 00401B5C test eax,eax 00401B5E je short fix_dump.00401B64 ;关键比较5,不跳则影响注册标志位1 00401B60 xor eax,eax 00401B62 jmp short fix_dump.00401B69 00401B64 mov eax,1 00401B69 mov esp,ebp 00401B6B pop ebp 00401B6C retn
注册过程总结:
把经过处理的注册码与真注册码分4段比较,(即4个关键比较),有一段出错立即跳出;如果全部都正确则置2个标志位,(即注册标志位2和注册标志位3),再经过一次计算,将结果返回时放到注册标志位1。
于是爆破如下:修改关键比较1、关键比较2、关键比较3、关键比较4为9090(即两个NOP),修改关键比较5为JMP,试运行之,显示为“本产品授权给:asdf”,成功!
去暗桩:
程序还有暗桩,在预览界面中点鼠标右键会直接退出。
如何拦截退出程序的代码呢?我有一个笨方法:回溯找CALL法。办法很笨,但还是比较有效的。
重新载入程序,下断:“bp ExitProcess”,在预览界面中点鼠标右键,果然断下,看堆栈:
代码:
0012F580 004EDFEC /CALL 到 ExitProcess 来自 fix_dump.004EDFE7 是004EDFE7处调用ExitProcess的。回溯查看004EDFE7处的代码: 004EDFE0 /$>push ebp ;Local Call from 004ED390 004EDFE1 |.>mov ebp,esp 004EDFE3 |.>mov eax,dword ptr ss:[ebp+8] 004EDFE6 |.>push eax ; /ExitCode 004EDFE7 \.>call <jmp.&kernel32.ExitProcess> ; \ExitProcess 向上看004EDFE0处,有一个CALL入口“Local Call from 004ED390”。再回溯到004ED390处: 004ED334 /$ 5>push ebp ;Local Calls from 004ED3AB, 004ED3C3, 004ED3D6, 004ED3E6 004ED335 |. 8>mov ebp,esp 004ED337 |. 5>push ebx 004ED338 |. 8>mov ebx,dword ptr ss:[ebp+8] 004ED33B |. E>call fix_dump.004EE138 004ED340 |. 8>test ebx,ebx 004ED342 |. 7>jnz short fix_dump.004ED360 004ED344 |. 8>cmp dword ptr ds:[51EFEC],0 004ED34B |. 7>je short fix_dump.004ED353 004ED34D |. F>call dword ptr ds:[51EFEC] 004ED353 |> E>call fix_dump.004EE0CC 004ED358 |. F>call dword ptr ds:[51EFF0] ; fix_dump.004ED330 004ED35E |. E>jmp short fix_dump.004ED367 004ED360 |> 3>xor eax,eax 004ED362 |. A>mov dword ptr ds:[51EFEC],eax 004ED367 |> 8>cmp dword ptr ss:[ebp+C],0 004ED36B |. 7>jnz short fix_dump.004ED396 004ED36D |. 8>test ebx,ebx 004ED36F |. 7>jnz short fix_dump.004ED37D 004ED371 |. F>call dword ptr ds:[51EFF4] ; fix_dump.004ED330 004ED377 |. F>call dword ptr ds:[51EFF8] ; fix_dump.004ED330 004ED37D |> E>call fix_dump.004EE148 004ED382 |. E>call fix_dump.004E5EEC 004ED387 |. E>call fix_dump.004E76EC 004ED38C |. 8>mov edx,dword ptr ss:[ebp+10] 004ED38F |. 5>push edx 004ED390 |. E>call fix_dump.004EDFE0 ;调用退出程序CALL 004ED395 |. 5>pop ecx 004ED396 |> E>call fix_dump.004EE148 004ED39B |. 5>pop ebx 004ED39C |. 5>pop ebp 004ED39D \. C>retn
这个CALL入口有多个调用,于是重新运行程序,在004ED334下断,看堆栈调用:
0012F59C 004ED3B0 返回到 fix_dump.004ED3B0 来自 fix_dump.004ED334
再回溯到004ED334处。。。。
···
经过几次回溯后来到这里:
代码:
00435773 mov edx,dword ptr ds:[50A5AC] ;取注册标志位1 00435779 test edx,edx 0043577B je short fix_dump.004357BE ;未注册时跳走 0043577D push fix_dump.0052D668 ; /Arg2 = 0052D668 ASCII "1111111111111111" 00435782 push fix_dump.0052D564 ; |Arg1 = 0052D564 ASCII "asdf" 00435787 call fix_dump.0043425F ; \fix_dump.0043425F 判断注册码 0043578C add esp,8 0043578F mov ecx,dword ptr ds:[5145C0] ;取注册标志位2 00435795 cmp ecx,5000 0043579B je short fix_dump.004357BE ;未注册时执行退出命令 0043579D push 0 ; /Arg1 = 00000000 0043579F call fix_dump.004ED3A0 ; \fix_dump.004ED3A0 <--退出程序的Call 004357A4 pop ecx 004357A5 jmp short fix_dump.004357BE 004357A7 push dword ptr ds:[521748] ; /Arg1 = 00000000; Case 2E of switch 0043527D
又找到一个比较注册码的CALL:00435787。跟进后发现与程序启动时的比较过程完全一样,同样修改5处,可突破右键退出的限制。
那么如何找到其他判断注册码的地方呢?我找了一投机取巧的办法:
因为程序在判断注册码后都有一个置注册标志位的命令:
C705 C0455100 00500000 mov dword ptr ds:[5145C0],5000 ;置注册标志位2
C705 F4B55000 00550000 mov dword ptr ds:[50B5F4],5500 ;置注册标志位3
而这二句的十六进制代码与所在程序的位置无关,都是C705C045510000500000C705F4B5500000550000,
在UltraEdit中搜索该代码,根据找到的物理地址再转换到程序的偏移地址,一共可以找到4处,分别修改即可。
--------------------------------------------------------------------------------
【爆破地址】
爆破修改如下:
代码:
查找地址|物理偏移|原值|修改 00001AFD:00001AA7:756A->9090 ;启动时检查,己修改 00001ACA:7547->9090 00001ADA:7537->9090 00001AFB:752C->9090 00004B6E:7404->EB04 00004B0D:00004AB7:756A->9090 ;右键检查 00004ADA:7547->9090 00004AEA:7537->9090 00004B0B:752C->9090 00004B6E:7404->EB04 00034589:00034533:756A->9090 00034556:7547->9090 00034566:7537->9090 00034587:752C->9090 000345EA:7404->EB04 00035D31:00035CDB:756A->9090 00035CFE:7547->9090 00035D0E:7537->9090 00035D2F:752C->9090 00035D92:7404->EB04
至此该程序己完美爆破!!!
--------------------------------------------------------------------------------
【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!
感谢看完!因环境限制,无人交流,上网也不方便,破解该程序所用的方法几乎全靠我自己摸索,用了三天时间才跟出来~~累啊!小弟语言表达能力太差,不知各位看官有没有看出我表达的意思,欢迎与我交流!!