好友
阅读权限 40
听众
最后登录 1970-1-1
本帖最后由 playboysen 于 2010-2-26 13:42 编辑
【破文标题】Watery Desktop 3D算法分析+系列注册机之汇编实现(中级)
【破文作者】Playboysen
【作者邮箱】playboysen#126.com
【破解 工具】OD
【破解平台】Windows7
【软件语言】英文
【原版下载】http://www.push-wallpaper.com/01/
【保护方式】用户名 注册码
【软件简介】Watery Desktop 3D——迄今为止我见过的效果最炫的动态壁纸和屏保,惊叹!多处搜索发现此软件只有屏保部分的爆破版本,网上无法找到任何一组全功能注册码(在国外网站找到三个注册码,可以弹出注册成功提示,但其实功能不正常)遂兴趣盎然着手研究……
【破解声明】看本文需要极大耐心。版权所有,转载需注明作者!
【破解内容】
毫不夸张地说这是我折腾过的所有软件中单靠程序算法验证保护(不靠强壳、VM之类)最严密的一个,从试用、分析到算法还原写注册机,前后耗时一月有余,叹为观止!此程序的注册验证机制精巧,也许有些东西值得我们学习……
1、输入假码无提示,获取文本尽量避开常用API如GetDlgItemText GetWindowText等
2、程序对注册码分段、分时、多处验证,验证为假码后无提示功能限制,注册码加密保存(其实大部分时间都耗在暗桩处算法的查找分析上了,汗)
3、验证时临时解密注册表密钥,且解密后参与验证的数据并不是明文注册码(已经过简单处理)
4、程序使用GetUserNameEx参与验证注册码,隐式绑定电脑
上面这些似乎并不高明的伎俩足足耗费了我两三周的时间来分析和应付,几欲放弃……
然而,智者千虑必有一失,程序未加壳、有注册成功提示、配置对话框标题有(unregistered)字样且字符为明文。
有的放矢,搜索字符串轻易找到注册码验证的第一处00405264 . 6A 00 push 0 ; /lParam = 0
00405266 . 6A 00 push 0 ; |wParam = 0
00405268 . 6A 0E push 0E ; |Message = WM_GETTEXTLENGTH
0040526A . 52 push edx ; |hWnd
0040526B . FFD6 call esi ; \SendMessageW
0040526D . 83F8 05 cmp eax, 5
00405270 . 0F85 01040000 jnz 00405677
00405276 . 8D4424 1C lea eax, dword ptr [esp+1C]
0040527A . 50 push eax ; /lParam
0040527B . 6A 06 push 6 ; |wParam = 6
0040527D . 6A 0D push 0D ; |Message = WM_GETTEXT
0040527F . 57 push edi ; |hWnd
00405280 . FFD6 call esi ; \SendMessageW
00405282 . 33C0 xor eax, eax
00405284 > 8A4C44 1C mov cl, byte ptr [esp+eax*2+1C] ; 注册码分四段,每段5个字符
00405288 . 80E9 41 sub cl, 41 ; 分别取出每段字符 每一位减去41h后生成一段20位的数据储存
0040528B . 884C04 28 mov byte ptr [esp+eax+28], cl
0040528F . 40 inc eax
00405290 . 83F8 05 cmp eax, 5
00405293 .^ 7C EF jl short 00405284
……
假设我们输入假码:
U P K P E D I Y P L A Y B O Y S E N H U
对应十六进制为:
55 50 4B 50 45 44 49 59 50 4C 41 59 42 4F 59 53 45 4E 48 55
对应每位减去41h(将这一段数据设为K):
14 0F 0A 0F 04 03 08 18 0F 0B 00 18 01 0E 18 12 04 0D 07 14
第一处验证00405300 > /0FB65404 28 movzx edx, byte ptr [esp+eax+28] ; 求K的前19位之和放入ecx
00405305 . |40 inc eax
00405306 . |03CA add ecx, edx
00405308 . |83F8 13 cmp eax, 13
0040530B .^\7C F3 jl short 00405300
0040530D . 0FB64424 3B movzx eax, byte ptr [esp+3B] ; K20放入eax
00405312 . F7D1 not ecx
00405314 . 33C1 xor eax, ecx
00405316 . A8 0F test al, 0F
00405318 . 0F85 59030000 jnz 00405677
事实证明00405318处的跳转会跳过注册成功提示,说明上面算法就是注册码验证关键了。
不屑~~~ 这么简单,汗。随便写几句代码做个JJ枚举出来几个符合条件的字符串输入,提示注册成功!
本以为万事大吉。重启软件右键任务栏程序图标打开配置对话框,依然显示未注册,注册码输入框可用。
嗯,不是我们太愚钝,实在是敌人太狡猾……
重载程序,接着上面的代码一路小跑企图再找突破点:00405300 > /0FB65404 28 movzx edx, byte ptr [esp+eax+28]
00405305 . |40 inc eax
00405306 . |03CA add ecx, edx
00405308 . |83F8 13 cmp eax, 13
0040530B .^\7C F3 jl short 00405300
0040530D . 0FB64424 3B movzx eax, byte ptr [esp+3B]
00405312 . F7D1 not ecx
00405314 . 33C1 xor eax, ecx
00405316 . A8 0F test al, 0F
00405318 . 0F85 59030000 jnz 00405677
0040531E . 33C0 xor eax, eax
00405320 > 8BC8 mov ecx, eax ; K的第二次变换加密
00405322 . 83E1 03 and ecx, 3
00405325 . 41 inc ecx
00405326 . D26404 28 shl byte ptr [esp+eax+28], cl
0040532A . 40 inc eax
0040532B . 83F8 14 cmp eax, 14
0040532E .^ 7C F0 jl short 00405320
00405330 . 8D4C24 18 lea ecx, dword ptr [esp+18]
00405334 . 51 push ecx
00405335 . 8D9424 480200>lea edx, dword ptr [esp+248]
0040533C . 52 push edx
0040533D . 6A 02 push 2 ; 注意这个参数,写注册机时必须用这个参数,否则结果会出错
0040533F . E8 52B90400 call <jmp.&Secur32.GetUserNameExW>
00405344 . B8 04010000 mov eax, 104
00405349 . 8D8C24 440200>lea ecx, dword ptr [esp+244]
00405350 > 66:8339 00 cmp word ptr [ecx], 0
00405354 . 74 0A je short 00405360
00405356 . 83C1 02 add ecx, 2
00405359 . 83E8 01 sub eax, 1
0040535C .^ 75 F2 jnz short 00405350
0040535E . EB 57 jmp short 004053B7
00405360 > 85C0 test eax, eax
00405362 . 74 53 je short 004053B7
00405364 . BA 04010000 mov edx, 104
00405369 . 2BD0 sub edx, eax
0040536B . B9 04010000 mov ecx, 104
00405370 . 2BCA sub ecx, edx
00405372 . 8D8454 440200>lea eax, dword ptr [esp+edx*2+244]
00405379 . 74 34 je short 004053AF
0040537B . BF 28044700 mov edi, 00470428 ; "12345678901234567890"
......
004053C0 > 8A9444 440200>mov dl, byte ptr [esp+eax*2+244] ; K的第三次变换加密
004053C7 . F6D2 not dl ; 加密因子为GetUserNameEx + '12345678901234567890'
004053C9 . 305404 28 xor byte ptr [esp+eax+28], dl
004053CD . 40 inc eax
004053CE . 83F8 14 cmp eax, 14
004053D1 .^ 7C ED jl short 004053C0
004053D3 . 8D8424 4C0400>lea eax, dword ptr [esp+44C]
004053DA . 50 push eax
004053DB . 6A 00 push 0
004053DD . FF15 18E44900 call dword ptr [49E418]
004053E3 . 8D4424 3C lea eax, dword ptr [esp+3C]
004053E7 . BE 04064700 mov esi, 00470604 ; "Thank you for registrating "
......
0040561C . 6A 14 push 14 ; /BufSize = 14 (20.)
0040561E . 8D5424 2C lea edx, dword ptr [esp+2C] ; |
00405622 . 52 push edx ; |Buffer
00405623 . 6A 03 push 3 ; |ValueType = REG_BINARY
00405625 . 50 push eax ; |Reserved
00405626 . 8B4424 20 mov eax, dword ptr [esp+20] ; |
0040562A . 68 54044700 push 00470454 ; |ValueName = "REG"
0040562F . 50 push eax ; |hKey
00405630 . FF15 10F04600 call dword ptr [<&ADVAPI32.RegSetValu>; \RegSetValueExW
00405636 . 8B4C24 10 mov ecx, dword ptr [esp+10]
0040563A . 51 push ecx ; /hKey
0040563B . FF15 00F04600 call dword ptr [<&ADVAPI32.RegCloseKe>; \RegCloseKey
00405641 > 8B15 D4DB4900 mov edx, dword ptr [49DBD4]
00405647 . 6A 00 push 0 ; /lParam = 0
00405649 . 6A 00 push 0 ; |wParam = 0
0040564B . 6A 12 push 12 ; |Message = WM_QUIT
0040564D . 52 push edx ; |hWnd => NULL
0040564E . FF15 64F24600 call dword ptr [<&USER32.SendMessageW>; \SendMessageW
上面代码有上百行,我们一路F8下来,重点了解上面几处关键点即可
我们知道过了上面第一处验证,程序会对K再进行两次加密然后设置注册表值重启验证
RegQueryValueA RegQueryValueW RegQueryValueExA RegQueryValueExW四个断点齐下
重载,断在RegQueryValueExW,F9几次找到下处00404F05 |. 68 54044700 push 00470454 ; "REG"
00404F0A |. 50 push eax
00404F0B |. FFD6 call esi
00404F0D |. 8B4C24 0C mov ecx, dword ptr [esp+C]
00404F11 |. 51 push ecx
00404F12 |. FFD3 call ebx
00404F14 |> 8D5424 18 lea edx, dword ptr [esp+18]
00404F18 |. 52 push edx
00404F19 |. 68 98DC4900 push 0049DC98 ; "Senhuan-PC\Senhuan12345678901234567890"
00404F1E |. 6A 02 push 2
00404F20 |. C74424 24 040>mov dword ptr [esp+24], 104
00404F28 |. E8 69BD0400 call <jmp.&Secur32.GetUserNameExW>
00404F2D |. 68 28044700 push 00470428 ; "12345678901234567890"
00404F32 |. 68 04010000 push 104
00404F37 |. 68 98DC4900 push 0049DC98 ; "Senhuan-PC\Senhuan12345678901234567890"
00404F3C |. E8 CFC9FFFF call 00401910
00404F41 |. 8B8C24 240200>mov ecx, dword ptr [esp+224]
有点熟悉,嗯一路小跑往下看找找算法,结果翻了上百行代码竟然没发现一点注册码验证的蛛丝马迹
整理下思路。看到上面00404F19处,灵机一动——既然程序用GetUserNmaeEx值参与加密保存注册码,那程序启动时又调用这个API,是不是说明程序解密验证时还要在使用这个字符串呢?我们在上面0049DC98处的字符串下硬件访问断点试一试
事实证明可行0040C1F0 |> /0FB60C45 98DC>/movzx ecx, byte ptr [eax*2+49DC98] ; 硬件访问断点找到的第一处算法
0040C1F8 |. |0FB61445 9ADC>|movzx edx, byte ptr [eax*2+49DC9A]
0040C200 |. |F6D1 |not cl
......
0040C250 |. |884C04 0C |mov byte ptr [esp+eax+C], cl
0040C254 |. |83C0 05 |add eax, 5
0040C257 |. |83F8 14 |cmp eax, 14
0040C25A |.^\7C 94 \jl short 0040C1F0
0040C25C |. 33C0 xor eax, eax
0040C25E |. 8BFF mov edi, edi
0040C260 |> 8AC8 /mov cl, al
0040C262 |. 80E1 03 |and cl, 3
0040C265 |. FEC1 |inc cl
0040C267 |. D26C04 08 |shr byte ptr [esp+eax+8], cl
0040C26B |. 40 |inc eax
0040C26C |. 83F8 14 |cmp eax, 14
0040C26F |.^ 7C EF \jl short 0040C260
0040C271 |. 33C9 xor ecx, ecx
0040C273 |. 33D2 xor edx, edx
0040C275 |. 33F6 xor esi, esi
0040C277 |. 33C0 xor eax, eax
0040C279 |. 57 push edi
0040C27A |. 8D9B 00000000 lea ebx, dword ptr [ebx]
0040C280 |> 0FB67C04 0C /movzx edi, byte ptr [esp+eax+C]
0040C285 |. 03CF |add ecx, edi
0040C287 |. 0FB67C04 0D |movzx edi, byte ptr [esp+eax+D]
0040C28C |. 83C0 02 |add eax, 2
0040C28F |. 03D7 |add edx, edi
0040C291 |. 83F8 12 |cmp eax, 12
0040C294 |.^ 7C EA \jl short 0040C280
0040C296 |. 83F8 13 cmp eax, 13
0040C299 |. 5F pop edi
0040C29A |. 7D 05 jge short 0040C2A1
0040C29C |. 0FB67404 08 movzx esi, byte ptr [esp+eax+8]
0040C2A1 |> 0FB64424 1B movzx eax, byte ptr [esp+1B]
0040C2A6 |. 03D1 add edx, ecx
0040C2A8 |. 03D6 add edx, esi
0040C2AA |. F7D2 not edx
0040C2AC |. 33D0 xor edx, eax
0040C2AE |. F6C2 0F test dl, 0F
0040C2B1 |. 75 07 jnz short 0040C2BA
0040C2B3 |. C605 B8DE4900>mov byte ptr [49DEB8], 1
有没有觉得熟悉?还记得上面我们分析过 程序在弹出注册成功提示时对K进行过两次加密吗?
没错,这一段就是从注册表中取出加密后的字节还原成K并再次验证的过程(没有使用同一段代码来进行重启验证可有效防止菜鸟通过简单修改跳转爆破程序)
算法上面已分析,略过 继续F9
第二处验证00401FB0 |> 8A1445 98DC49>/mov dl, byte ptr [eax*2+49DC98] ; 硬件访问断点找到的第二处算法
00401FB7 |. |8AC8 |mov cl, al ; 解密注册表值,最终还原成K
00401FB9 |. |F6D2 |not dl
00401FBB |. |3290 A0DE4900 |xor dl, byte ptr [eax+49DEA0]
00401FC1 |. |80E1 03 |and cl, 3
00401FC4 |. |FEC1 |inc cl
00401FC6 |. |D2EA |shr dl, cl
00401FC8 |. |40 |inc eax
00401FC9 |. |83F8 13 |cmp eax, 13
00401FCC |. |885404 FF |mov byte ptr [esp+eax-1], dl
00401FD0 |.^\7C DE \jl short 00401FB0
00401FD2 |. 0FB64C24 05 movzx ecx,byte ptr ss:[esp+5] ; K6
00401FD7 |. 0FB64424 01 movzx eax,byte ptr ss:[esp+1] ; K2
00401FDC |. 0FB65424 09 movzx edx,byte ptr ss:[esp+9] ; K10
00401FE1 |. 03C1 add eax,ecx
00401FE3 |. 0FB60C24 movzx ecx,byte ptr ss:[esp] ; K1
00401FE7 |. 03C2 add eax,edx
00401FE9 |. 8D5408 05 lea edx,dword ptr ds:[eax+ecx+5] ; edx=K1 + K2 + K6 + K10 +5
00401FED |. 83E2 0F and edx,0F
00401FF0 |. 385424 0F cmp byte ptr ss:[esp+F],dl ; =K16
00401FF4 |. 74 07 je short WateryDe.00401FFD
00401FF6 |. C605 B8DE4900 0>mov byte ptr ds:[49DEB8],0
继续,第三处验证0040C750 > /8A1445 98DC49>mov dl, byte ptr [eax*2+49DC98] ; 硬件访问断点找到的第三处算法
0040C757 . |8AC8 mov cl, al ; 最终解密成K
0040C759 . |F6D2 not dl
0040C75B . |3290 80DB4900 xor dl, byte ptr [eax+49DB80]
0040C761 . |80E1 03 and cl, 3
0040C764 . |FEC1 inc cl
0040C766 . |D2EA shr dl, cl
0040C768 . |40 inc eax
0040C769 . |83F8 13 cmp eax, 13
0040C76C . |885404 03 mov byte ptr [esp+eax+3], dl
0040C770 .^\7C DE jl short 0040C750
0040C772 . 0FB64C24 10 movzx ecx,byte ptr ss:[esp+10] ; K13
0040C777 . 0FB64424 07 movzx eax,byte ptr ss:[esp+7] ; K4
0040C77C . 0FB65424 08 movzx edx,byte ptr ss:[esp+8] ; K5
0040C781 . 33C1 xor eax,ecx
0040C783 . 0FB64C24 0B movzx ecx,byte ptr ss:[esp+B] ; K8
0040C788 . 33C2 xor eax,edx
0040C78A . 33C1 xor eax,ecx ; eax=K4 xor K13 xor K5 xor K8
0040C78C . 83C0 04 add eax,4
0040C78F . 83E0 0F and eax,0F
0040C792 . 384424 11 cmp byte ptr ss:[esp+11],al ; K14
0040C796 . 74 07 je short WateryDe.0040C79F
0040C798 . C605 74DB4900 0>mov byte ptr ds:[49DB74],0
继续F9,不再中断 终于长舒一口气了,虽然算法调用放在了不同地方,且对注册码进行分段验证,但我们总算找全了算法
重新更改注册机算法,生成可用注册码输入,运行不再有[unregistered]提示,注册码输入框灰色。嗯,不错
但运行了一会,软件提示需要购买?!
淡定、淡定,不可乱了方寸。整理思路……
嗯,由上面可以看出,K共有20位,上面参与运算的却只有十几位,是不是还有几位在隐式验证,我们没发现?
程序每次验证注册码值之前都会取加密后的注册表值进行循环解密,以此为突破点试试,OD搜索所有命令cmp eax,13
竟然奇迹般地找到了所有验证算法处,逐个看看发现漏网之鱼
第四处验证:0040CFC2 . 0FB64C24 32 movzx ecx, byte ptr [esp+32] ; K11
0040CFC7 . 0FB64424 33 movzx eax, byte ptr [esp+33] ; k12
0040CFCC . 0FB65424 30 movzx edx, byte ptr [esp+30] ; k9
0040CFD1 . 03C1 add eax, ecx
0040CFD3 . 0FB64C24 38 movzx ecx, byte ptr [esp+38] ; k17
0040CFD8 . 03D1 add edx, ecx
0040CFDA . 33C2 xor eax, edx
0040CFDC . 83E8 07 sub eax, 7
0040CFDF . 83E0 0F and eax, 0F
0040CFE2 . 384424 2A cmp byte ptr [esp+2A], al ; k3
0040CFE6 . 74 15 je short 0040CFFD
再改注册机 测试,终于一切看起来那么顺利。
大约4分钟左右,运行正常的程序突然没了!
崩溃……
bp SetTimer 找到如下代码处,好长一段
跟踪几遍之后发现前面的代码都没什么用处的,关键的在这几句0040A639 > 8BC6 mov eax,esi ; esi里面的值参与运算,但却不知哪里算出的
0040A63B . C1F8 04 sar eax,4 ; 下硬件写入断点,断下后回溯找到第六处验证
0040A63E . 8BCE mov ecx,esi
0040A640 . C1F9 0C sar ecx,0C
0040A643 . 2BC8 sub ecx,eax
0040A645 . 8BD6 mov edx,esi
0040A647 . C1FA 08 sar edx,8
0040A64A . 8D4411 FE lea eax,dword ptr ds:[ecx+edx-2]
0040A64E . 33C6 xor eax,esi
0040A650 . A8 0F test al,0F
0040A652 . 74 22 je short WateryDe.0040A676
0040A654 . 8B0D D4DB4900 mov ecx,dword ptr ds:[49DBD4]
0040A65A . 57 push edi ; /Timerproc
0040A65B . 68 78DA0200 push 2DA78 ; |Timeout = 187000. ms
0040A660 . 68 93010000 push 193 ; |TimerID = 193 (403.)
0040A665 . 51 push ecx ; |hWnd => 001A03CA ('PUSH Wallpaper',class='PushWallpaper',parent=000100E4)
0040A666 . C705 A8DB4900 0>mov dword ptr ds:[49DBA8],1 ; |
0040A670 . FF15 D0F24600 call dword ptr ds:[<&USER32.SetTimer>] ; \SetTimer
第六处验证
00403C50 |> \8A0D 92E44900 mov cl,byte ptr ds:[49E492] ; 第十八位 "Senhuan-PC\Senhuan12345678901234567890"
00403C56 |. 0FB605 8CE44900 movzx eax,byte ptr ds:[49E48C] ; 第十五位 "Senhuan-PC\Senhuan12345678901234567890"
00403C5D |. 0FB615 A5DB4900 movzx edx,byte ptr ds:[49DBA5] ; 加密后的注册表密钥第18位
00403C64 |. F6D1 not cl
00403C66 |. 0FB6F1 movzx esi,cl
00403C69 |. 33F2 xor esi,edx
00403C6B |. 0FB615 A2DB4900 movzx edx,byte ptr ds:[49DBA2] ; 加密后的注册表密钥第15位
00403C72 |. F6D0 not al
00403C74 |. 0FB6C8 movzx ecx,al
00403C77 |. 0FB605 7CE44900 movzx eax,byte ptr ds:[49E47C] ; 第七位 "Senhuan-PC\Senhuan12345678901234567890"
00403C7E |. 33CA xor ecx,edx
00403C80 |. 0FB615 9ADB4900 movzx edx,byte ptr ds:[49DB9A] ; 加密后的注册表密钥第7位
00403C87 |. C1EE 02 shr esi,2
00403C8A |. C1E9 03 shr ecx,3
00403C8D |. C1E6 04 shl esi,4
00403C90 |. 03F1 add esi,ecx
00403C92 |. F6D0 not al
00403C94 |. 0FB6C8 movzx ecx,al
00403C97 |. 0FB605 94E44900 movzx eax,byte ptr ds:[49E494] ; 第十九位 "Senhuan-PC\Senhuan12345678901234567890"
00403C9E |. 33CA xor ecx,edx
00403CA0 |. 0FB615 A6DB4900 movzx edx,byte ptr ds:[49DBA6] ; 加密后的注册表密钥第19位
00403CA7 |. C1E9 03 shr ecx,3
00403CAA |. C1E6 04 shl esi,4
00403CAD |. 03F1 add esi,ecx
00403CAF |. F6D0 not al
00403CB1 |. 0FB6C8 movzx ecx,al
00403CB4 |. 33CA xor ecx,edx
00403CB6 |. C1E9 03 shr ecx,3
00403CB9 |. C1E6 04 shl esi,4
00403CBC |. 03F1 add esi,ecx
一段折腾之后算出esi的值,参与定时器附近的那段验证,总算找全了所有验证算法。
休息一天,静心好好整理一下思路 然后——还原算法
首先,生成那个加密因子:.data
temp db '12345678901234567890',0
Const db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',0
.data?
String db MAX_PATH dup (?)
nSize dd ?
mov nSize,sizeof String
invoke GetUserNameEx,2,addr String,addr nSize
invoke lstrcat,addr String,addr temp
其次,还原六处验证算法:WateryDesktop3D proc
LOCAL @Temp[256]:byte
;一个大循环,暴力求出符合条件的注册码
@Fail:
xor ecx,ecx
;生成20位的随机字符并稍作处理生成一组K
@@:
invoke Rand,0,25
mov esp,offset Const
movzx edx,byte ptr[esp+eax]
sub dl,41h
mov byte ptr[esp+ecx+140],dl
inc ecx
cmp ecx,20
jl @B
;第二段验证算法
add esp,140 ;使esp指向K
movzx eax,byte ptr[esp]
movzx ecx,byte ptr[esp+1]
add ecx,eax
movzx eax,byte ptr[esp+5]
add ecx,eax
movzx eax,byte ptr[esp+9]
add ecx,eax
add ecx,5
and ecx,0Fh
mov byte ptr[esp+15],cl
;第三段验证算法
movzx eax,byte ptr[esp+3]
movzx ecx,byte ptr[esp+12]
xor eax,ecx
movzx ecx,byte ptr[esp+4]
xor eax,ecx
movzx ecx,byte ptr[esp+7]
xor eax,ecx
add eax,4
and eax,0Fh
mov byte ptr[esp+13],al
;第四段验证算法
movzx ecx,byte ptr[esp+10]
movzx eax,byte ptr[esp+11]
add eax,ecx
movzx ecx,byte ptr[esp+8]
movzx edx,byte ptr[esp+16]
add ecx,edx
xor eax,ecx
sub eax,7
and eax,0Fh
mov byte ptr[esp+2],al
xor eax,eax
xor ecx,ecx
xor edx,edx
;求出前19位字符的和
@@:
movzx edx,byte ptr[esp+eax]
inc eax
add ecx,edx
cmp eax,19
jl @B
;第一段验证
movzx eax,byte ptr[esp+19]
not ecx
xor eax,ecx
test al,0Fh
jnz @Fail
;第六处验证全代码
lea edi,@Temp ; 注意@Temp为局部变量,无法使用offset指令,必须用lea指令
mov esi,esp
mov ecx,20
REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
......
;将K还原成明码——生成可用注册码
xor eax,eax
xor ecx,ecx
@@:
movzx eax,byte ptr[esp+ecx]
add al,41h
mov byte ptr[esp+ecx],al
inc ecx
cmp ecx,19
jle @B
invoke lstrcpy,addr serial,esp
ret
WateryDesktop3D endp
总结:
1、其实这个软件算法平平,出彩的是其注册验证的思路和方法;
2、使用计算机名作为注册码的运算因子,绑定电脑。其实我们可以修改自己的计算机名,从而使用别人的注册码;
3、经过多次分析,该公司所有软件加密算法相似(只是变动了相关数值),快速定位几处算法段的方法:
OD加载后搜索“所有命令”--“cmp eax,13”(因为每次运算几乎都会有循环解密)
注意有一处暗桩就是即使过了四处验证程序运行时一切正常且提示已注册的情况下,大约3~4分钟无提示自动关闭!!!(下断点SetTimer)
4、给作者的建议:
1)可以使用这种比较出彩的验证机制和思路,但不要把公司所有的软件使用同一种验证算法(弊端显而易见,就是我研究了一款软件的算法,就直接秒了公司所有软件,系列注册机应运而生!)
2)让用户名参与注册码的运算,这样算法会更复杂且如果有正版注册码流出,可同时结合用户名和计算机名来定位黑名单
3)加密一些关键提示字符,尽量无明文(当然全部字符加密不现实也没必要,注册验证相关的几个字串加密即可)
4)既然输入假码无提示,那么输入真码也无提示就可以了,每次输入注册码后都重启验证(有效浪费Cracker时间),若验证注册码可用就直接解锁所有功能(简单是真,花式越多越容易被人抓小辫儿)
5)CRC32或其他算法,程序加个自校验吧,校验方法越非主流越好,检验代码也不写在同一处,越隐蔽越好(这样网上就不会有那么多乱飞的爆破版了)
6)多处暗桩隐式验证注册码(这个估计作者很有心得!四处暗桩前后浪费我近半个月时间)
7)最好VM一下算法函数,这样很多像我这样的小鸟就只能望洋兴叹
8)可选择加个强壳(无奈之举,缓兵之计,可挡一大批初级Cracker,但一定记住———把希望寄托在别人身上,就是你希望破灭的开始)
注册机运行界面(不用试了,界面显示的注册码只能用在我电脑上,别忘了程序注册码是绑定电脑的):
部分Asm源码(暂不放全部源码,等等看):
Push Entertinment.rar
(4.24 KB, 下载次数: 43)