首页
社区
课程
招聘
[原创]Active Desktop Calendar v4.6 算法分析
发表于: 2007-9-26 14:19 6617

[原创]Active Desktop Calendar v4.6 算法分析

2007-9-26 14:19
6617

说实在的,这个软件是偶见过的(其实偶也没见过多少),反正是偶见过的最难算注册码的啦!
不是说算法很难。而是知道了算法,手工算出注册码很难,花了偶近半小时,写了两张32开的
纸。
===================================================================================
软件用VC++编写,用OD载入,下断点GetWindowTextA,(要在用户名和注册码都输好之后再下断)
不然会一直中断。

点"Register",程序中断在:
004ADDB7        call    [<&USER32.GetWindowTextA>]        ; \GetWindowTextA
返回到:0044EF2C,继续返回。来到:

004A5D1F        mov     dword ptr [ebp+8], 1                ; 返回到这里
004A5D26        jmp     short <loc_4A5D4F>
...
再返回(看过偶写的破VC++的文章都是要返回大约3次吧),来到:

0044EFD3        call    <sub_4A5CCA>
0044EFD8        lea     esi, [edi+154]                ; 返回到这里
0044EFDE        mov     ecx, esi
0044EFE0        call    <sub_49DD96>
0044EFE5        mov     ecx, esi                ; esi指向注册码
0044EFE7        call    <sub_49DC9F>
0044EFEC        push    ecx
0044EFED        mov     ecx, esp
0044EFEF        mov     [esp+14], esp
0044EFF3        push    esi
0044EFF4        call    <sub_4A2B2A>
0044EFF9        call    <sub_457C80>                ; 计算注册码,进入
0044EFFE        add     esp, 4
0044F001        test    eax, eax
0044F003        je      <loc_44F167>                ; 不跳则注册成功

现在说一下,看倒数第二行代码,可见注册成功返回的是非0值。我们进入函数
call    <sub_457C80>。看函数的最后,有两个retn,一个返回的是0,另一个返回的是1。
看一下跳到返回0的跳转有:

跳转来自 00457E49, 00457E63, 00457E7D, 00457F1E, 00457F60
把上面的跳转全部nop掉就可以爆破了。
但00457E49, 00457E63, 00457E7D:这三处是不会跳转的。不知道用来干什么。
00457F1E, 00457F60:这两处是用来判断注册码中是否有非法字符的,这个待会会说。

现在分析一下算法,还是刚才那个函数
call    <sub_457C80>:
...
00457D29        mov     eax, [esp+10]              ;  注册码
00457D2D        xor     esi, esi
00457D2F        mov     ecx, [eax-8]               ;  注册码长度
00457D32        test    ecx, ecx
00457D34        jle     short <loc_457D54>
00457D36        /cmp     byte ptr [esi+eax], 2D
00457D3A        |jnz     short <loc_457D4C>
00457D3C        |push    2C
00457D3E         |push    esi
00457D3F         |lea     ecx, [esp+18]
00457D43        |call    <CString::SetAt(int,char)>
00457D48        |mov     eax, [esp+10]
00457D4C        |mov     ecx, [eax-8]
00457D4F         |inc     esi
00457D50          |cmp     esi, ecx
00457D52        \jl      short <loc_457D36>
00457D54        push    2C
00457D56        lea     ecx, [esp+14]
00457D5A        call    <sub_4A327C>                ; 判断注册码是否满足格式,如:DC8B7-02FC1-27AAE
00457D5F        mov     esi, eax
00457D61        or      ebp, FFFFFFFF
00457D64        cmp     esi, ebp
00457D66        jle     short <loc_457DBF>
...
下面的一段有点长的代码,大概就是分割注册码吧,就不贴出来了。
...
00457E30        call    <sub_4A2EEE>
00457E35        mov     eax, [esp+20]                ; 第一段注册码
00457E39        push    0050A850                ; /Arg2 = 0050A850
00457E3E        push    eax                        ; |Arg1
00457E3F        call    <__mbscmp>                ; \ADC.004877A5
00457E44        add     esp, 8
00457E47        test    eax, eax
00457E49        je      <loc_458018>                ; 跳到注册失败,但根本不会跳.下面还有比
                                                ; 较第二、第三段的注册码,跟这个一样。
...
00457EED        mov     esi, [esp+14]
00457EF1        xor     ebx, ebx
00457EF3        mov     edx, 1
00457EF8        mov     eax, [esi-8]
00457EFB        lea     ecx, [eax-1]
00457EFE        test    ecx, ecx
00457F00        jl      short <loc_457F2F>
00457F02        /mov     al, [ecx+esi]                ; 第二段注册码第n位(倒数)
00457F05        |cmp     al, 30
00457F07        |jl      short <loc_457F15>        ; < 30,跳
00457F09        |cmp     al, 39
00457F0B        |jg      short <loc_457F15>        ; > 39,跳
00457F0D        |movsx   eax, al
00457F10        |sub     eax, 30
00457F13        |jmp     short <loc_457F24>
00457F15        |movsx   eax, al
00457F18        |sub     eax, 37
00457F1B        |cmp     eax, 0F
00457F1E        |jg      <loc_458018>                ; 不能跳,也就是注册码只能是A-F,0-9,就是16进制啦
00457F24        |imul    eax, edx
00457F27        |add     ebx, eax                ; *****
00457F29        |shl     edx, 4
00457F2C        |dec     ecx
00457F2D        \jns     short <loc_457F02>
                                                ; 上面的代码主要是判断注册码是否是16进制数。
                                                ; 其实还有一个功能。运行到00457F2F,看一下
                                                ; 寄存器ebx的值,另一个功能就是把字符串转
                                                ; 成数字,下面的也一样
00457F2F        mov     edi, [esp+24]                ; 第一段注册码和第三段注册码后3位
00457F33        xor     esi, esi
00457F35        mov     edx, 1
00457F3A        mov     eax, [edi-8]
00457F3D        lea     ecx, [eax-1]
00457F40         test    ecx, ecx
00457F42        jl      short <loc_457F71>
00457F44        /mov     al, [ecx+edi]                ; 从最后一位开始
00457F47        |cmp     al, 30
00457F49        |jl      short <loc_457F57>
00457F4B        |cmp     al, 39
00457F4D        |jg      short <loc_457F57>
00457F4F        |movsx   eax, al
00457F52        |sub     eax, 30
00457F55        |jmp     short <loc_457F66>
00457F57        |movsx   eax, al
00457F5A        |sub     eax, 37
00457F5D        |cmp     eax, 0F
00457F60        |jg      <loc_458018>                ; 不能跳
00457F66        |imul    eax, edx
00457F69        |add     esi, eax                ; *****
00457F6B        |shl     edx, 4
00457F6E        |dec     ecx
00457F6F        \jns     short <loc_457F44>        ; 下面这几行才是算法。

00457F71        lea     ecx, [esi+237505C5]        ; esi=第一段注册码和第三段注册码后3位转成的数字
00457F77        mov     eax, 487EDE05
00457F7C        imul    ecx                        ; "溢出"(不知道是不是这样说)部份放入edx
00457F7E        sar     edx, 5
00457F81        mov     eax, edx
00457F83        mov     byte ptr [esp+34], 5
00457F88        shr     eax, 1F
00457F8B        add     edx, eax                ; 注意edx的值
00457F8D        mov     eax, 30C30C31                ; 这条指令应该和下一条换一下位置,这样更好看
00457F92        mov     ecx, edx                ; ecx=edx,值1

00457F94        imul    ebx                        ; eax=eax*ebx,eax的值在00457F8D
00457F96        sar     edx, 3
00457F99        mov     eax, edx
00457F9B        shr     eax, 1F
00457F9E        add     edx, eax                ; 值2
00457FA0        cmp     ecx, edx                ; 不相等则注册失败
00457FA2        lea     ecx, [esp+24]
00457FA6        jnz     short <loc_458021>        ; 跳到注册失败
======================================================
现在分析一下算法:

程序通过注册码算出两个值,这两个值不相等则注册失败。

以下全为16进制
值1:

X equ esi=第一段注册码和第三段注册码后3位转成的数字

(X+237505c5)*487EDE05,高位(正确的说法好像是这样吧)放入edx
sar edx,5
;下面的运算实际上是不需要的,因为值2也是这样算,约掉了。
shr eax,1f        ;eax=edx
add eax,ebx
-------------------------------
值2:

第二段注册码*30C30C31
sar edx,3
;下面的运算实际上是不需要的,因为值1也是这样算,约掉了。
shr eax,1f        ;eax=edx
add eax,ebx

就是这样了,暂时还没想到怎么写注册机,先给个注册码吧!
DC8B7-02FC1-27AAE

偶是用最后的值去逆推的。以123为例

2460 <- 123 sal 5
918  <- 123 sal 3

下面这两步推了好久,偶用的是"类穷举法"
Z*487EDE05,高位为2460,==>Z=8073~8076,X=DC8B7AAE~DC8B7AB1
S*30C30C31,高位为918,==>S=02FC1~2FC3,所以注册码就是DC8B7-02FC1-27AAE
=============================================================================================
注册码保存在:HKEY_CURRENT_USER\Software\XemiComputers\Active Desktop Calendar\4.6\regdata
============================================================================================
偶然间发现,这个软件和Flash ScreenSaver Builder v4.7是同一家公司写的,真对不起,又破了你的一个
软件,不过也不能关偶,谁叫你那么"自信",软件从不加壳,要是加个ASProtect或Armadillo偶不就没辄了吗!
---------------------------
Author:Suyana


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 50121
活跃值: (20750)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
鼓励一下,继续努力,进步会很快的
2007-9-26 20:42
0
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
3
楼上老大,怎不鼓励鼓励我啊!! 呵呵

支持楼主!
2007-9-27 10:23
0
雪    币: 313
活跃值: (14)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
4
谢谢老大,偶一定会努力D!
2007-9-27 13:14
0
雪    币: 1355
活跃值: (344)
能力值: ( LV13,RANK:920 )
在线值:
发帖
回帖
粉丝
5
顶,谢谢楼主好文
2007-9-27 17:57
0
雪    币: 224
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
牛啊,这么快又出精拉~~~5555555学习,学习
2007-9-27 18:28
0
游客
登录 | 注册 方可回帖
返回
// // 统计代码