【破文标题】Ashampoo Magical Snap 2.31算法分析
【破文作者】Playboysen
【作者邮箱】playboysen@126.com
【破解工具】PEiD,OD
【破解平台】Windows XP SP2
【软件名称】Ashampoo Magical Snap 2.31(20081105)
【软件大小】12.7 MB
【软件授权】共享版($14.99)
【软件语言】英文
【原版下载】http://www.ashampoo.com/dl/0224/ashampoo_magicalsnap2_se.exe
【保护方式】注册码
【软件简介】Magical Snap是一款专业的屏幕截图工具.它添加了编辑工具和效果工具还有非常华丽的用户界面. 特点: 3种不同的抓图模式; 多张抓图; 紧密结合--支持全屏抓图; 抓图编辑工具; 高质量效果图容易使用的鼠标工具。支持抓取任意形状,滚动窗口等。
【破解声明】一点心得,愿与大家分享o(∩_∩)o 版权所有,转载注明作者!
【破解内容】
初步踩点:软件无壳,VC7.0编译,单一注册码保护,注册有错误提示,未注册所抓图片有文字水印。
假设注册码为AMASAo-77nhEB-96HD2N(这里说明一下,注册码并不是一开始就假设成这样的,我一开始粗略跟踪用的假码是playboysen963852,跟踪一遍将假码修正为playbo-ysenhu-an9638,再跟踪一遍修正假码为AMASbo-ysenhu-an9638,再跟踪一次将假码修正为AMASAo-77enhu-an9638的,第五遍跟踪才将注册码修正成这样的(当然其实这已经被“修正”为真注册码了^_^)自己跟踪时可随便输入一个假码,自由练习)
尝试MessageBoxA、MessageBoxW、GetDlgItemTextA断错误提示无果,最终发现软件使用的是GetDlgItemTextW断点,汗~~~
004455DE > \53 push ebx ; Case 1 of switch 0044559C
004455DF . 55 push ebp
004455E0 . 8BAC24 380A0000 mov ebp,dword ptr ss:[esp+A38]
004455E7 . 57 push edi
004455E8 . 6A 20 push 20 ; /Count = 20 (32.)
004455EA . 8D5424 28 lea edx,dword ptr ss:[esp+28] ; |
004455EE . 52 push edx ; |Buffer
004455EF . 68 F1030000 push 3F1 ; |ControlID = 3F1 (1009.)
004455F4 . 55 push ebp ; |hWnd
004455F5 . FF15 58144800 call dword ptr ds:[<&USER32.GetDlgItemTextW>] ; \GetDlgItemTextW
004455FB . 8D4424 24 lea eax,dword ptr ss:[esp+24] ; 注册码出现
004455FF . 50 push eax ; /Arg1
00445600 . 8D4C24 18 lea ecx,dword ptr ss:[esp+18] ; |
00445604 . E8 47DAFBFF call ashsnap.00403050 ; \关键处,F7进入
00445609 . 68 4C774E00 push ashsnap.004E774C ; /Arg1 = 004E774C
0044560E . 8D4C24 20 lea ecx,dword ptr ss:[esp+20] ; |
00445612 . C78424 380A0000>mov dword ptr ss:[esp+A38],0 ; |
0044561D . E8 2EDAFBFF call ashsnap.00403050 ; \同上,关键
跟入00445604处关键算法call
00403050 /$ 83EC 40 sub esp,40 00403053 |. 8B4424 44 mov eax,dword ptr ss:[esp+44] ...... 00403068 |. C706 00000000 mov dword ptr ds:[esi],0 0040306E |. E8 0DF50200 call ashsnap.00432580 ; kernel32.WideCharToMultiByte 00403073 |. 8B15 98204800 mov edx,dword ptr ds:[482098] ...... 004030C3 |. 52 push edx 004030C4 |. E8 573A0500 call ashsnap.00456B20 ; 关键call,F7进入 004030C9 |. 83C4 20 add esp,20
00456B20 /$ 8B4424 14 mov eax,dword ptr ss:[esp+14] 00456B24 |. 8B4C24 10 mov ecx,dword ptr ss:[esp+10] ...... 00456B3F |. 55 push ebp 00456B40 |. E8 EBFDFFFF call ashsnap.00456930 ; 关键call,F7进入 00456B45 |. 83C4 14 add esp,14 00456B48 |. 84C0 test al,al 00456B4A |. 74 20 je short ashsnap.00456B6C
好,我们接着跟入00456B40关键call
00456930 /$ 83EC 44 sub esp,44 00456933 |. 83C9 FF or ecx,FFFFFFFF 00456936 |. 33C0 xor eax,eax 00456938 |. 53 push ebx 00456939 |. 55 push ebp 0045693A |. 56 push esi 0045693B |. 8B7424 54 mov esi,dword ptr ss:[esp+54] 0045693F |. 57 push edi 00456940 |. 8BFE mov edi,esi ; 注册码放入EDI 00456942 |. F2:AE repne scas byte ptr es:[edi] ; 计算注册码的长度 00456944 |. F7D1 not ecx 00456946 |. 49 dec ecx 00456947 |. 83F9 14 cmp ecx,14 ; 注册码必须20位 0045694A |. 0F85 BE010000 jnz ashsnap.00456B0E 00456950 |. 8A4E 06 mov cl,byte ptr ds:[esi+6] ; 注册码第七位必须是"-" 00456953 |. B0 2D mov al,2D 00456955 |. 3AC8 cmp cl,al 00456957 |. 0F85 B1010000 jnz ashsnap.00456B0E 0045695D |. 3846 0D cmp byte ptr ds:[esi+D],al ; 注册码第十四位必须是"-" 00456960 |. 0F85 A8010000 jnz ashsnap.00456B0E 00456966 |. 6A 04 push 4 00456968 |. 8D4424 20 lea eax,dword ptr ss:[esp+20] 0045696C |. 56 push esi 0045696D |. 50 push eax 0045696E |. E8 BD24FFFF call ashsnap.00448E30 ; 提取注册码前四位 00456973 |. 8D6E 04 lea ebp,dword ptr ds:[esi+4] 00456976 |. 6A 01 push 1 00456978 |. 8D4C24 68 lea ecx,dword ptr ss:[esp+68] 0045697C |. 55 push ebp 0045697D |. 51 push ecx 0045697E |. E8 AD24FFFF call ashsnap.00448E30 ; 提取注册码第五位 00456983 |. 8D56 05 lea edx,dword ptr ds:[esi+5] 00456986 |. 6A 01 push 1 00456988 |. 8D4424 48 lea eax,dword ptr ss:[esp+48] 0045698C |. 52 push edx 0045698D |. 50 push eax 0045698E |. E8 9D24FFFF call ashsnap.00448E30 ; 提取注册码第六位("-"被忽略) 00456993 |. 8D4E 07 lea ecx,dword ptr ds:[esi+7] 00456996 |. 6A 02 push 2 00456998 |. 8D5424 38 lea edx,dword ptr ss:[esp+38] 0045699C |. 51 push ecx 0045699D |. 52 push edx 0045699E |. E8 8D24FFFF call ashsnap.00448E30 ; 提取注册码第八九位 004569A3 |. 8D46 09 lea eax,dword ptr ds:[esi+9] 004569A6 |. 6A 02 push 2 004569A8 |. 8D4C24 61 lea ecx,dword ptr ss:[esp+61] 004569AC |. 50 push eax 004569AD |. 51 push ecx 004569AE |. E8 7D24FFFF call ashsnap.00448E30 ; 提取注册码第十、十一位 004569B3 |. 8D56 0B lea edx,dword ptr ds:[esi+B] 004569B6 |. 6A 02 push 2 004569B8 |. 8D4424 54 lea eax,dword ptr ss:[esp+54] 004569BC |. 52 push edx 004569BD |. 50 push eax 004569BE |. E8 6D24FFFF call ashsnap.00448E30 ; 分析注册码第十二、十三位 004569C3 |. 83C4 48 add esp,48 004569C6 |. 8D4E 0E lea ecx,dword ptr ds:[esi+E] 004569C9 |. 8D5424 2F lea edx,dword ptr ss:[esp+2F] 004569CD |. 6A 03 push 3 004569CF |. 51 push ecx 004569D0 |. 52 push edx 004569D1 |. E8 5A24FFFF call ashsnap.00448E30 ; 分离注册码15-17位 004569D6 |. 8D46 11 lea eax,dword ptr ds:[esi+11] 004569D9 |. 6A 02 push 2 004569DB |. 8D4C24 26 lea ecx,dword ptr ss:[esp+26] 004569DF |. 50 push eax 004569E0 |. 51 push ecx 004569E1 |. E8 4A24FFFF call ashsnap.00448E30 004569E6 |. 8D56 13 lea edx,dword ptr ds:[esi+13] 004569E9 |. 6A 01 push 1 004569EB |. 8D4424 4E lea eax,dword ptr ss:[esp+4E] 004569EF |. 52 push edx 004569F0 |. 50 push eax 004569F1 |. E8 3A24FFFF call ashsnap.00448E30 ; 分离出注册码最后一位 004569F6 |. 8D4C24 50 lea ecx,dword ptr ss:[esp+50] ; 字符串组合“onh96HN” ...... 00456A54 |. E8 D723FFFF call ashsnap.00448E30 00456A59 |. 8B7C24 68 mov edi,dword ptr ss:[esp+68] ; 固定字符串"sk()44$$GFSNM099023$" 00456A5D |. 8D4424 40 lea eax,dword ptr ss:[esp+40] ; 字符串组合"onh96HNA77AMAS" 00456A61 |. 57 push edi 00456A62 |. 6A 0E push 0E ; 常数14(参数之一) 00456A64 |. 50 push eax 00456A65 |. E8 46040000 call ashsnap.00456EB0 ; 截取"sk()44$$GFSNM099023$"后6位放入EDX 00456A6A |. 57 push edi 00456A6B |. 8D4C24 50 lea ecx,dword ptr ss:[esp+50] 00456A6F |. 6A 0E push 0E ; 常数14(参数之一) 00456A71 |. 51 push ecx 00456A72 |. E8 B9030000 call ashsnap.00456E30 ; 这里直接关系到00456A8E的值,关键 00456A77 |. 50 push eax 00456A78 |. 8D5424 4C lea edx,dword ptr ss:[esp+4C] 00456A7C |. 68 B0B94900 push ashsnap.0049B9B0 ; %04x 00456A81 |. 52 push edx 00456A82 |. E8 6B0AFFFF call ashsnap.004474F2 00456A87 |. 83C4 30 add esp,30 00456A8A |. 8D7C24 14 lea edi,dword ptr ss:[esp+14] ; 从注册码中提取出的值"EBD2" 00456A8E |. 8D4424 24 lea eax,dword ptr ss:[esp+24] ; 这个值是上面的关键call计算出的 00456A92 |> 8A10 /mov dl,byte ptr ds:[eax] ; 这一段循环很显然是比较上面两个值是否相等 00456A94 |. 8ACA |mov cl,dl ...... 00456AAE |. 3ACB |cmp cl,bl 00456AB0 |.^ 75 E0 \jnz short ashsnap.00456A92 00456AB2 |> 33C0 xor eax,eax 00456AB4 |. EB 05 jmp short ashsnap.00456ABB
00456E30 /$ 8B5424 0C mov edx,dword ptr ss:[esp+C] 00456E34 |. 57 push edi 00456E35 |. 8BFA mov edi,edx 00456E37 |. 83C9 FF or ecx,FFFFFFFF 00456E3A |. 33C0 xor eax,eax 00456E3C |. F2:AE repne scas byte ptr es:[edi] ; 求"sk()44$$GFSNM099023$"长度 00456E3E |. F7D1 not ecx 00456E40 |. 49 dec ecx 00456E41 |. 5F pop edi 00456E42 |. 83F9 03 cmp ecx,3 00456E45 |. 72 18 jb short ashsnap.00456E5F ; 我们设"sk()44$$GFSNM099023$"为Y 00456E47 |. 0FBE42 01 movsx eax,byte ptr ds:[edx+1] ; Y的第二位 k 00456E4B |. 0FBE0A movsx ecx,byte ptr ds:[edx] ; Y的第一位 s 00456E4E |. 0FBE52 02 movsx edx,byte ptr ds:[edx+2] ; Y的第三位 ( 00456E52 |. C1E0 04 shl eax,4 ; 对这三位做运算 00456E55 |. 0BC1 or eax,ecx 00456E57 |. C1E0 10 shl eax,10 00456E5A |. 0BC2 or eax,edx 00456E5C |. C1E0 03 shl eax,3 ; 到这里算出值 EAX=37980140 00456E5F |> 8B4C24 08 mov ecx,dword ptr ss:[esp+8] ; 常数14 00456E63 |. 8B5424 04 mov edx,dword ptr ss:[esp+4] 00456E67 |. 56 push esi ; 注册码值 00456E68 |. 51 push ecx 00456E69 |. 52 push edx 00456E6A |. 50 push eax ; 上面是四个参数,EAX即可上面算出的值 00456E6B |. E8 90FEFFFF call ashsnap.00456D00 ; 得出另外一个运算函数 00456E70 |. 8BC8 mov ecx,eax ; 运算结果放入ECX保存,EAX继续运算 00456E72 |. 83C4 0C add esp,0C 00456E75 |. C1E8 09 shr eax,9 ; 又是一串运算,位移、与、或、异或等等 00456E78 |. 8BD1 mov edx,ecx ; 但是不用怕,这种平铺直叙的运算我们可懒得去逆向 00456E7A |. 25 00F87F00 and eax,7FF800 ; 直接复制出来,Delphi嵌入汇编搞定 00456E7F |. 81E2 80070000 and edx,780 ; 不过说实话,这些运算基本上在高级语言中都可以直接还原的 ...... 00456EA5 |. 33C2 xor eax,edx 00456EA7 |. 5E pop esi 00456EA8 |. 33C1 xor eax,ecx ; 到这里,终于算完了,幸亏运算很简单 00456EAA \. C3 retn
...... 00456AEA |. 885E 01 mov byte ptr ds:[esi+1],bl 00456AED |> 8B7424 68 mov esi,dword ptr ss:[esp+68] 00456AF1 |. 3BF3 cmp esi,ebx 00456AF3 |. 74 0F je short ashsnap.00456B04 00456AF5 |. 8D4424 10 lea eax,dword ptr ss:[esp+10] ; 一定要注意,这里是最最最关键的地方 00456AF9 |. 50 push eax ; 这是一处关键校验,验证注册码的第八、九位 00456AFA |. E8 20F1FFFF call ashsnap.00455C1F ; 我因为刚开始忽略了这里,走了很多弯路 00456AFF |. 83C4 04 add esp,4 ; 到底关键在哪里,等会单步下去你就知道了 00456B02 |. 8906 mov dword ptr ds:[esi],eax
...... 00455BDC |> 0FB60E movzx ecx,byte ptr ds:[esi] ; 注册码第八位放入 00455BDF |. 46 inc esi 00455BE0 |. 83F9 2D cmp ecx,2D ; 比较是不是“-” 00455BE3 |. 8BD1 mov edx,ecx 00455BE5 |. 74 05 je short ashsnap.00455BEC 00455BE7 |. 83F9 2B cmp ecx,2B ; 比较是不是“+” 00455BEA |. 75 04 jnz short ashsnap.00455BF0 00455BEC |> 0FB60E movzx ecx,byte ptr ds:[esi] 00455BEF |. 46 inc esi 00455BF0 |> 33C0 xor eax,eax 00455BF2 |> 83F9 30 /cmp ecx,30 ; 比较是不是数字 00455BF5 |. 7C 0A |jl short ashsnap.00455C01 00455BF7 |. 83F9 39 |cmp ecx,39 00455BFA |. 7F 05 |jg short ashsnap.00455C01 00455BFC |. 83E9 30 |sub ecx,30 00455BFF |. EB 03 |jmp short ashsnap.00455C04 00455C01 |> 83C9 FF |or ecx,FFFFFFFF ; 如果不是数字就直接跳到这里,就错误了,不信你可以试试 00455C04 |> 83F9 FF |cmp ecx,-1 00455C07 |. 74 0C |je short ashsnap.00455C15 00455C09 |. 8D0480 |lea eax,dword ptr ds:[eax+eax*4] ; [eax+eax*4]其实就是[5*eax] 00455C0C |. 8D0441 |lea eax,dword ptr ds:[ecx+eax*2] ; [ecx+eax*2]放入EAX 00455C0F |. 0FB60E |movzx ecx,byte ptr ds:[esi] ; 这两步是关键运算,所得出的EAX值会作为最终校验的关键 00455C12 |. 46 |inc esi ; 提前透露下,根据注册码第八九位运算出的EAX值应该等于4Dh 00455C13 |.^ EB DD \jmp short ashsnap.00455BF2 00455C15 |> 83FA 2D cmp edx,2D ; 比较第八位是不是“-” 00455C18 |. 5F pop edi 00455C19 |. 5E pop esi 00455C1A |. 75 02 jnz short ashsnap.00455C1E ; 对应上面的cmp指令 00455C1C |. F7D8 neg eax 00455C1E |> C3 retn
004030CC |. 8845 00 mov byte ptr ss:[ebp],al ; 把返回值保存备用 004030CF |. BE 241F4800 mov esi,ashsnap.00481F24 ; 固定字符串"AMAS" 004030D4 |. 8D4424 08 lea eax,dword ptr ss:[esp+8] ; 这里是注册码的前四位 004030D8 |. 53 push ebx 004030D9 |. 8DA424 00000000 lea esp,dword ptr ss:[esp] 004030E0 |> 8A10 /mov dl,byte ptr ds:[eax] ; 这个循环在做比较 004030E2 |. 8A1E |mov bl,byte ptr ds:[esi] ; 说明注册码前四位应该是"AMAS" 004030E4 |. 8ACA |mov cl,dl ...... 004030FD |. 83C6 02 |add esi,2 00403100 |. 84C9 |test cl,cl 00403102 |.^ 75 DC \jnz short ashsnap.004030E0 00403104 |> 33C0 xor eax,eax 00403106 |. EB 05 jmp short ashsnap.0040310D 00403108 |> 1BC0 sbb eax,eax 0040310A |. 83D8 FF sbb eax,-1 0040310D |> 85C0 test eax,eax 0040310F |. 5B pop ebx 00403110 |. 75 16 jnz short ashsnap.00403128 00403112 |. 57 push edi 00403113 |. BF 94204800 mov edi,ashsnap.00482094 ; 这里是一个固定字符"A" 00403118 |. 8D7424 50 lea esi,dword ptr ss:[esp+50] 0040311C |. B9 02000000 mov ecx,2 00403121 |. 33C0 xor eax,eax 00403123 |. F3:A6 repe cmps byte ptr es:[edi],byte ptr ds:[esi] ; 这里是注册码的另一处校验,注册码第五位必须是“A” 00403125 |. 5F pop edi 00403126 |. 74 04 je short ashsnap.0040312C ; 这里必须跳,否则错误 00403128 |> C645 00 00 mov byte ptr ss:[ebp],0 0040312C |> 5E pop esi
00445622 . 8A4424 14 mov al,byte ptr ss:[esp+14] 00445626 . 84C0 test al,al 00445628 . 8B7C24 20 mov edi,dword ptr ss:[esp+20] 0044562C . 8A5C24 1C mov bl,byte ptr ss:[esp+1C] 00445630 . C68424 340A0000>mov byte ptr ss:[esp+A34],1 00445638 . 0F84 13020000 je ashsnap.00445851 ; 关键 0044563E . 8B7424 18 mov esi,dword ptr ss:[esp+18] 00445642 . 83FE 0A cmp esi,0A 00445645 . 0F85 3C010000 jnz ashsnap.00445787 ; 跳过去,就会验证最后一处 0044564B . 84DB test bl,bl 0044564D . 74 08 je short ashsnap.00445657 ...... 0044566D . 8D4C24 24 lea ecx,dword ptr ss:[esp+24] 00445671 . 51 push ecx ; /String2 00445672 . 68 4C774E00 push ashsnap.004E774C ; |String1 = ashsnap.004E774C 00445677 . FF15 DC124800 call dword ptr ds:[<&KERNEL32.lstrcpyW>] ; \lstrcpyW 0044567D . 68 18944800 push ashsnap.00489418 ; 提示试用期延长,即符合条件的注册码即认为是官方试用码 ...... 00445787 > \83FE 4D cmp esi,4D ; 这里就是在检验00455C09处得出的值,呵呵 0044578A . 0F85 C1000000 jnz ashsnap.00445851 ; 关键跳 00445790 . 8D4C24 24 lea ecx,dword ptr ss:[esp+24] 00445794 . 51 push ecx ; /String2 00445795 . 68 4C774E00 push ashsnap.004E774C ; |String1 = ashsnap.004E774C 0044579A . FF15 DC124800 call dword ptr ds:[<&KERNEL32.lstrcpyW>] ; \lstrcpyW 004457A0 . 68 78934800 push ashsnap.00489378 ; "Your key is valid. Thank you very much for buying the software. :-)" 004457A5 . 8D9424 30020000 lea edx,dword ptr ss:[esp+230]
到这里,算法基本完了,剩下的工作肯定是总结算法,有精力就搞个注册机
大致总结如下:
1.注册码必须20位
2.第七位和第十四位必须是"-"(连字符)
3.程序把注册码分成九份进行验证(忽略“-”连字符),大致分割为
注册码: AMASAo-77nhEB-96HD2N
分割后: AMAS A o 77 nh EB 96H D2 N
设为: K1 K2 K3 K4 K5 K6 K7 K8 9
对应关系:K1K2是“AMASA”;K6K8处的字符是00456A72处的函数(如果懒得去逆向,可以直接复制汇编代码从而Delphi或者C++嵌入汇编)计算出的,其值取决于K3K5K7K9K4K1;K4处的两个字符经过00455C09处的计算结果应该为4Dh。
一组可用注册码AMASAo-77nhEB-96HD2N,有兴趣可以试一试~~
正确注册后,软件将注册码明码保存在以下位置(方便大家多次调试):
Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Ashampoo\Ashampoo Magical Snap 2] "RegistrationKey"="AMASAo-77nhEB-96HD2N" [HKEY_LOCAL_MACHINE\SOFTWARE\Ashampoo\Ashampoo Magical Snap 2] "RegistrationKey"="AMASAo-77nhEB-96HD2N"