playboysen 发表于 2010-2-26 13:40

Watery Desktop 3D算法分析+系列注册机之汇编实现(中级)

本帖最后由 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
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       ;注册码分四段,每段5个字符
00405288   .80E9 41       sub   cl, 41                           ;分别取出每段字符 每一位减去41h后生成一段20位的数据储存
0040528B   .884C04 28   mov   byte ptr , 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        ;求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          ;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
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
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 , cl
0040532A   .40            inc   eax
0040532B   .83F8 14       cmp   eax, 14
0040532E   .^ 7C F0         jl      short 00405320
00405330   .8D4C24 18   lea   ecx, dword ptr
00405334   .51            push    ecx
00405335   .8D9424 480200>lea   edx, dword ptr
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
00405350   >66:8339 00    cmp   word ptr , 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
00405379   .74 34         je      short 004053AF
0040537B   .BF 28044700   mov   edi, 00470428                  ;"12345678901234567890"
......
004053C0   >8A9444 440200>mov   dl, byte ptr    ;K的第三次变换加密
004053C7   .F6D2          not   dl                               ;加密因子为GetUserNameEx + '12345678901234567890'
004053C9   .305404 28   xor   byte ptr , dl
004053CD   .40            inc   eax
004053CE   .83F8 14       cmp   eax, 14
004053D1   .^ 7C ED         jl      short 004053C0
004053D3   .8D8424 4C0400>lea   eax, dword ptr
004053DA   .50            push    eax
004053DB   .6A 00         push    0
004053DD   .FF15 18E44900 call    dword ptr
004053E3   .8D4424 3C   lea   eax, dword ptr
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           ; |
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           ; |
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
0040563A   .51            push    ecx                              ; /hKey
0040563B   .FF15 00F04600 call    dword ptr [<&ADVAPI32.RegCloseKe>; \RegCloseKey
00405641   >8B15 D4DB4900 mov   edx, dword ptr
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
00404F11|.51            push    ecx
00404F12|.FFD3          call    ebx
00404F14|>8D5424 18   lea   edx, dword ptr
00404F18|.52            push    edx
00404F19|.68 98DC4900   push    0049DC98                         ;"Senhuan-PC\Senhuan12345678901234567890"
00404F1E|.6A 02         push    2
00404F20|.C74424 24 040>mov   dword ptr , 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
有点熟悉,嗯一路小跑往下看找找算法,结果翻了上百行代码竟然没发现一点注册码验证的蛛丝马迹
整理下思路。看到上面00404F19处,灵机一动——既然程序用GetUserNmaeEx值参与加密保存注册码,那程序启动时又调用这个API,是不是说明程序解密验证时还要在使用这个字符串呢?我们在上面0049DC98处的字符串下硬件访问断点试一试
事实证明可行
0040C1F0|> /0FB60C45 98DC>/movzx   ecx, byte ptr     ;硬件访问断点找到的第一处算法
0040C1F8|. |0FB61445 9ADC>|movzx   edx, byte ptr
0040C200|. |F6D1          |not   cl
......
0040C250|. |884C04 0C   |mov   byte ptr , 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 , 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
0040C280|>0FB67C04 0C   /movzx   edi, byte ptr
0040C285|.03CF          |add   ecx, edi
0040C287|.0FB67C04 0D   |movzx   edi, byte ptr
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
0040C2A1|>0FB64424 1B   movzx   eax, byte ptr
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 , 1

有没有觉得熟悉?还记得上面我们分析过 程序在弹出注册成功提示时对K进行过两次加密吗?
没错,这一段就是从注册表中取出加密后的字节还原成K并再次验证的过程(没有使用同一段代码来进行重启验证可有效防止菜鸟通过简单修改跳转爆破程序)
算法上面已分析,略过 继续F9
第二处验证
00401FB0|>8A1445 98DC49>/mov   dl, byte ptr                ;硬件访问断点找到的第二处算法
00401FB7|. |8AC8          |mov   cl, al                                    ;解密注册表值,最终还原成K
00401FB9|. |F6D2          |not   dl
00401FBB|. |3290 A0DE4900 |xor   dl, byte ptr
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 , dl
00401FD0|.^\7C DE         \jl      short 00401FB0
00401FD2|.0FB64C24 05   movzx ecx,byte ptr ss:                  ;K6
00401FD7|.0FB64424 01   movzx eax,byte ptr ss:                  ;K2
00401FDC|.0FB65424 09   movzx edx,byte ptr ss:                  ;K10
00401FE1|.03C1            add eax,ecx
00401FE3|.0FB60C24      movzx ecx,byte ptr ss:                      ;K1
00401FE7|.03C2            add eax,edx
00401FE9|.8D5408 05       lea edx,dword ptr ds:               ;edx=K1 + K2 + K6 + K10 +5
00401FED|.83E2 0F         and edx,0F
00401FF0|.385424 0F       cmp byte ptr ss:,dl                     ;=K16
00401FF4|.74 07         je short WateryDe.00401FFD
00401FF6|.C605 B8DE4900 0>mov byte ptr ds:,0

继续,第三处验证

0040C750   > /8A1445 98DC49>mov   dl, byte ptr                ;硬件访问断点找到的第三处算法
0040C757   . |8AC8          mov   cl, al                                    ;最终解密成K
0040C759   . |F6D2          not   dl
0040C75B   . |3290 80DB4900 xor   dl, byte ptr
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 , dl
0040C770   .^\7C DE         jl      short 0040C750
0040C772   .0FB64C24 10   movzx ecx,byte ptr ss:                   ;K13
0040C777   .0FB64424 07   movzx eax,byte ptr ss:                  ;K4
0040C77C   .0FB65424 08   movzx edx,byte ptr ss:                  ;K5
0040C781   .33C1            xor eax,ecx
0040C783   .0FB64C24 0B   movzx ecx,byte ptr ss:                  ;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:,al                      ;K14
0040C796   .74 07         je short WateryDe.0040C79F
0040C798   .C605 74DB4900 0>mov byte ptr ds:,0

继续F9,不再中断 终于长舒一口气了,虽然算法调用放在了不同地方,且对注册码进行分段验证,但我们总算找全了算法
重新更改注册机算法,生成可用注册码输入,运行不再有提示,注册码输入框灰色。嗯,不错
但运行了一会,软件提示需要购买?!
淡定、淡定,不可乱了方寸。整理思路……
嗯,由上面可以看出,K共有20位,上面参与运算的却只有十几位,是不是还有几位在隐式验证,我们没发现?
程序每次验证注册码值之前都会取加密后的注册表值进行循环解密,以此为突破点试试,OD搜索所有命令cmp eax,13
竟然奇迹般地找到了所有验证算法处,逐个看看发现漏网之鱼
第四处验证:
0040CFC2   .0FB64C24 32   movzx   ecx, byte ptr          ;K11
0040CFC7   .0FB64424 33   movzx   eax, byte ptr          ;k12
0040CFCC   .0FB65424 30   movzx   edx, byte ptr          ;k9
0040CFD1   .03C1          add   eax, ecx
0040CFD3   .0FB64C24 38   movzx   ecx, byte ptr          ;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 , 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:
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:
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:,1                      ; |
0040A670   .FF15 D0F24600   call dword ptr ds:[<&USER32.SetTimer>]         ; \SetTimer
第六处验证
00403C50|> \8A0D 92E44900   mov cl,byte ptr ds:            ;第十八位 "Senhuan-PC\Senhuan12345678901234567890"
00403C56|.0FB605 8CE44900 movzx eax,byte ptr ds:         ;第十五位 "Senhuan-PC\Senhuan12345678901234567890"
00403C5D|.0FB615 A5DB4900 movzx edx,byte ptr ds:         ;加密后的注册表密钥第18位
00403C64|.F6D1            not cl
00403C66|.0FB6F1          movzx esi,cl
00403C69|.33F2            xor esi,edx
00403C6B|.0FB615 A2DB4900 movzx edx,byte ptr ds:         ;加密后的注册表密钥第15位
00403C72|.F6D0            not al
00403C74|.0FB6C8          movzx ecx,al
00403C77|.0FB605 7CE44900 movzx eax,byte ptr ds:         ;第七位 "Senhuan-PC\Senhuan12345678901234567890"
00403C7E|.33CA            xor ecx,edx
00403C80|.0FB615 9ADB4900 movzx edx,byte ptr ds:         ;加密后的注册表密钥第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:         ;第十九位 "Senhuan-PC\Senhuan12345678901234567890"
00403C9E|.33CA            xor ecx,edx
00403CA0|.0FB615 A6DB4900 movzx edx,byte ptr ds:         ;加密后的注册表密钥第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:byte
      
;一个大循环,暴力求出符合条件的注册码
   @Fail:
   xorecx,ecx
;生成20位的随机字符并稍作处理生成一组K   
    @@:
   invokeRand,0,25
   
   movesp,offset Const
   movzxedx,byte ptr
   subdl,41h
   mov byte ptr,dl
   incecx
         cmpecx,20
         jl   @B
;第二段验证算法         
         addesp,140    ;使esp指向K
         movzxeax,byte ptr
         movzxecx,byte ptr
         addecx,eax
         movzxeax,byte ptr
         add ecx,eax
         movzxeax,byte ptr
         addecx,eax
         addecx,5
         andecx,0Fh
         movbyte ptr,cl
;第三段验证算法         
         movzxeax,byte ptr
         movzxecx,byte ptr      
         xoreax,ecx
         movzxecx,byte ptr
         xoreax,ecx
         movzxecx,byte ptr
         xoreax,ecx
         addeax,4
         andeax,0Fh
         movbyte ptr,al
;第四段验证算法                        
         movzxecx,byte ptr
         movzxeax,byte ptr
         addeax,ecx
         movzxecx,byte ptr
         movzxedx,byte ptr
         addecx,edx
         xoreax,ecx
         subeax,7
         andeax,0Fh
         movbyte ptr,al
                  
         xoreax,eax
         xorecx,ecx
         xoredx,edx
;求出前19位字符的和
    @@:
      movzxedx,byte ptr
      inceax
      addecx,edx
      cmpeax,19
   jl@B
;第一段验证   
      movzxeax,byte ptr
         notecx
         xoreax,ecx
         testal,0Fh
         jnz@Fail
;第六处验证全代码   
   
         lea edi,@Temp       ;注意@Temp为局部变量,无法使用offset指令,必须用lea指令
         mov esi,esp
         mov ecx,20
         REP MOVS BYTE PTR ES:,BYTE PTR DS:
......
;将K还原成明码——生成可用注册码                     
         xoreax,eax
         xorecx,ecx
          @@:
         movzxeax,byte ptr
         addal,41h
         movbyte ptr,al
         incecx
         cmpecx,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源码(暂不放全部源码,等等看):

blueapplez 发表于 2010-2-26 14:14

晕啊支持支持啦

playboysen 发表于 2010-2-27 10:45

BYTE PTR DS:是个标志位
不过并非全局标志位
赋值共有三处 0040C1E2 00401FF6 0040C7C9
即使全部修改成1 运行看似一切正常 但等等着
程序运行五分钟后你就知道会有什么问题了(无提示自动退出了)

这才是程序的高明之处

CHHSun 发表于 2010-2-27 11:01

感谢LZ发布原创文章,加精鼓劲:victory:

wuhanqi 发表于 2010-2-27 12:42

膜拜大牛~

a2213572 发表于 2010-3-3 09:29

下載收藏教學內容!
感謝分享

qiyi235 发表于 2010-3-6 22:07

谢谢分享!!

nuojiya8 发表于 2010-3-7 23:08

教程很详细。谢谢

咔咔喃 发表于 2010-5-6 15:07

暴强呀!!!

cctv185 发表于 2010-5-6 23:23

下来先看看。
页: [1] 2
查看完整版本: Watery Desktop 3D算法分析+系列注册机之汇编实现(中级)