说实在的,这个软件是偶见过的(其实偶也没见过多少),反正是偶见过的最难算注册码的啦!
不是说算法很难。而是知道了算法,手工算出注册码很难,花了偶近半小时,写了两张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直播授课