老文章档案 · 2003 年

AlgoLab PtVector的破解及注册机的编写

赢政天下 [WINZHENG.COM] · 网络学院 · 2003-06-09 · 作者:robot 人气: · 出处:赢政天下收集整理)

软件简介:algolab_photo_vector_v1.01 能将位图转换成矢量图!使用方便、功能强大!

下载地址:ftp://202.108.252.18/stcsr/rj/txtx/b-apv101.zip

破解工具:SoftICE 4.05,W32Dasm

说明:该软件没有壳,而且可以反复注册,真是合Cracker的脾气。分析一下程序后,进行暴破还是很容易的,但我更喜欢看他的注册码的计算。

破解开始:

运行程序后,选择Help下的About,就会进行注册。分别填入User Name,Company Name,E-mail Address和Registration,Ctrl+D进入SoftICE,下bpx GetWindowTextA,按注册按钮,程序会被拦下来,下面为用W32Dasm反编译的注册时的Call

* Reference To: MFC42.Ordinal:0217, Ord:0217h

|

:004171AF E8E2120200 Call 00438496 ====> GetWindowTextA

......

:004171F5 8D55E0 lea edx, dword ptr [ebp-20]

:004171F8 52 push edx ====> Registration

:004171F9 8D45E8 lea eax, dword ptr [ebp-18]

:004171FC 50 push eax ====> E-mail Address

:004171FD 8D4DDC lea ecx, dword ptr [ebp-24]

:00417200 51 push ecx ====> User Name

:00417201 E888CFFFFF call 0041418E ====> 关键比对,我们将追进去

:00417206 83C40C add esp, 0000000C

:00417209 898578FFFFFF mov dword ptr [ebp+FFFFFF78], eax ====> eax作为判断标志

:0041720F 83BD78FFFFFF00 cmp dword ptr [ebp+FFFFFF78], 00000000 ====> 是否注册成功

:00417216 7559 jne 00417271 ====> 没有则转

......

:00417234 6A00 push 00000000

:00417236 6A00 push 00000000

* Possible StringData Ref from Data Obj ->"Successful Registration!"

|

:00417238 68740A4400 push 00440A74

* Reference To: MFC42.Ordinal:04B0, Ord:04B0h

|

:0041723D E838130200 Call 0043857A ====> MessageBoxA

:00417242 C645FC01 mov [ebp-04], 01

:00417246 8D4DF0 lea ecx, dword ptr [ebp-10]

上面的其他判断过程略过,其中,eax=1则用户名输入错误;eax=2则E-mail地址输入错误;eax=3则注册码输入错误

从上面我们看出,00417201语句的call 0041418E是注册计算和比对的关键,我们追进去,如下:

:004141B8 8B4D10 mov ecx, dword ptr [ebp+10]

:004141BB E860DEFEFF call 00402020

:004141C0 50 push eax ====> 注册码地址入栈

:004141C1 E8DF63FFFF call 0040A5A5 ====> 计算注册码是否正确的call

此call首先比较注册码长度是否等于19(13h),如果相等则将前18个注册码的ascii值相加,除以36(24h),余数如果小于10,则检测值等于相应的数字,否则检测值等于'A'+余数-10,即为A-Z的一个字符,如果检测值与第19个字符相等,则注册码正确,返回EAX=1,否则EAX=0

4141C1语句可以这样理解,程序建立一个子程序或函数,用来检测注册码是否正确:call TestCorrect(Registration)

:004141C6 83C404 add esp, 00000004

:004141C9 8845F8 mov byte ptr [ebp-08], al

:004141CC 8B45F8 mov eax, dword ptr [ebp-08]

:004141CF 25FF000000 and eax, 000000FF

:004141D4 85C0 test eax, eax ====> 注册码是否正确

:004141D6 7507 jne 004141DF ====> 正确则转

:004141D8 B803000000 mov eax, 00000003 ====> 错误号

:004141DD EB7F jmp 0041425E

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004141D6(C)

|

:004141DF 8B4D10 mov ecx, dword ptr [ebp+10]

:004141E2 E839DEFEFF call 00402020 ====> 返回ecx的内容地址指针

====> 这里指向输入的注册码地址

:004141E7 50 push eax

* Reference To: MSVCRT.strlen, Ord:02BEh

|

:004141E8 E88F480200 Call 00438A7C

:004141ED 83C404 add esp, 00000004

:004141F0 8945DC mov dword ptr [ebp-24], eax

:004141F3 8B4DDC mov ecx, dword ptr [ebp-24]

:004141F6 51 push ecx ====> 注册码的长度

:004141F7 8B4D10 mov ecx, dword ptr [ebp+10]

:004141FA E821DEFEFF call 00402020

:004141FF 50 push eax ====> 注册码地址

:00414200 6A11 push 00000011 ====> 进行计算并变换代码的长度

:00414202 8D55E0 lea edx, dword ptr [ebp-20]

:00414205 52 push edx ====> 进行计算并变换代码的存放地址

:00414206 E84362FFFF call 0040A44E ====> 代码变换,共17(11h)个,很重要

:0041420B 83C410 add esp, 00000010

:0041420E 8B4D08 mov ecx, dword ptr [ebp+08] ====> ecx用户名地址

:00414211 E80ADEFEFF call 00402020

:00414216 50 push eax

:00414217 E8FF5CFFFF call 00409F1B ====> 进行计算

对用户名变换后得到一个检测值,结果返回到EAX

变换过程:将用户名各个字符的ascii值相加,然后除以1Ah(26),余数+"A"-0Ah即余数+37h

:0041421C 83C404 add esp, 00000004

:0041421F 8845FC mov byte ptr [ebp-04], al

:00414222 0FBE45E4 movsx eax, byte ptr [ebp-1C] ====> 变换代码的第5个值

:00414226 0FBE4DFC movsx ecx, byte ptr [ebp-04] ====> 取出用户名的计算值

:0041422A 3BC1 cmp eax, ecx ====> 进行比较

:0041422C 7407 je 00414235 ====> 相等则继续

:0041422E B801000000 mov eax, 00000001 ====> 错误号

:00414233 EB29 jmp 0041425E

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0041422C(C)

|

:00414235 8B4D0C mov ecx, dword ptr [ebp+0C]

:00414238 E8E3DDFEFF call 00402020

:0041423D 50 push eax ====> E-mail地址

:0041423E E8D85CFFFF call 00409F1B ====> 进行计算,过程同用户名计算一样

:00414243 83C404 add esp, 00000004

:00414246 8845F4 mov byte ptr [ebp-0C], al

:00414249 0FBE55E6 movsx edx, byte ptr [ebp-1A] ====> 变换代码的第7个值

:0041424D 0FBE45F4 movsx eax, byte ptr [ebp-0C] ====> 取出E-mail的计算值

:00414251 3BD0 cmp edx, eax ====> 进行比较

:00414253 7407 je 0041425C ====> 相等则转

:00414255 B802000000 mov eax, 00000002 ====> 错误号

:0041425A EB02 jmp 0041425E

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00414253(C)

|

:0041425C 33C0 xor eax, eax ====> 正确的eax值

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:

|:004141DD(U), :00414233(U), :0041425A(U)

|

:0041425E 8BE5 mov esp, ebp

:00414260 5D pop ebp

:00414261 C3 ret

上面这段的关键是对注册码进行变换和对用户名和E-mail地址的计算,其中,对用户名和E-mail地址的计算已经说完,现在看看如何对注册码进行变换,即414206的call 0040A44E语句,如下:

* Referenced by a CALL at Addresses:

|:00409D73 , :0040A673 , :0040A6F6 , :00414206 , :004142DD

|

:0040A44E 55 push ebp

:0040A44F 8BEC mov ebp, esp

:0040A451 83EC24 sub esp, 00000024

:0040A454 C745F810000000 mov [ebp-08], 00000010 ====> 设初值

:0040A45B 8B4510 mov eax, dword ptr [ebp+10]

:0040A45E 8A4811 mov cl, byte ptr [eax+11] ====> 取出注册码的第18个字符

:0040A461 884DF4 mov byte ptr [ebp-0C], cl

:0040A464 8A55F4 mov dl, byte ptr [ebp-0C]

:0040A467 52 push edx ====> 第18个字符入栈

:0040A468 E801FDFFFF call 0040A16E ====> 进行计算,计算结果返回到eax中

上句可以看作是对某个参数进行变换的函数,如ChangeCode(edx),计算过程:如果edx(要计算的字符的ascii值)在30h-39h,则返回结果为0-9,否则返回结果为edx+"A"-0ah=edx-37h

:0040A46D 83C404 add esp, 00000004

:0040A470 8945FC mov dword ptr [ebp-04], eax ====> 计算结果放到[ebp-04]中,为说明方便,设值为X18

:0040A473 8B4508 mov eax, dword ptr [ebp+08] ====> 变换码的地址

:0040A476 8B4D10 mov ecx, dword ptr [ebp+10]

:0040A479 8A11 mov dl, byte ptr [ecx] ====> 取注册码的第1个字符

:0040A47B 8810 mov byte ptr [eax], dl ====> 放到变换码中,即注册码的第1个字符也是变换码的第1个字符

:0040A47D C745F000000000 mov [ebp-10], 00000000 ====> 设初值

:0040A484 EB09 jmp 0040A48F

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040A51D(U)

|

:0040A486 8B45F0 mov eax, dword ptr [ebp-10] ====> 取出变换次数值

:0040A489 83C001 add eax, 00000001 ====> 准备取下一个字符

:0040A48C 8945F0 mov dword ptr [ebp-10], eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040A484(U)

|

:0040A48F 8B4DF0 mov ecx, dword ptr [ebp-10]

:0040A492 3B4DF8 cmp ecx, dword ptr [ebp-08] ====> 是否变换完毕

:0040A495 0F8D87000000 jnl 0040A522 ====> 没有,则继续

:0040A49B 8B45F0 mov eax, dword ptr [ebp-10] ====> 取出变换次数值

:0040A49E 99 cdq

:0040A49F 2BC2 sub eax, edx

:0040A4A1 D1F8 sar eax, 1 ====> 除以2

:0040A4A3 8945E4 mov dword ptr [ebp-1C], eax

:0040A4A6 8B55FC mov edx, dword ptr [ebp-04] ====> 第18个注册码的计算值X18

:0040A4A9 F7DA neg edx ====> 取负数,即-X18

:0040A4AB 2B55F0 sub edx, dword ptr [ebp-10] ====> -X18-变换次数

:0040A4AE 8955DC mov dword ptr [ebp-24], edx ====> 放到[ebp-24]中

:0040A4B1 837DE400 cmp dword ptr [ebp-1C], 00000000 ====> 要变换的是否是第2、3个的注册码

:0040A4B5 7409 je 0040A4C0 ====> 是则转

:0040A4B7 8B45FC mov eax, dword ptr [ebp-04] ====> 第18个注册码的计算值X18

:0040A4BA 0345F0 add eax, dword ptr [ebp-10] ====> X18+变换次数

:0040A4BD 8945DC mov dword ptr [ebp-24], eax ====> 放到[ebp-24]中

40A486-40A4BD的计算:i=1~19表示注册码字符所在的位置,如果变换的是第2和3个的注册码,则[ebp-24]=-(X18+i-2),否则=(X18+i-2)

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040A4B5(C)

|

:0040A4C0 6A24 push 00000024 \

:0040A4C2 8B4DDC mov ecx, dword ptr [ebp-24] \

:0040A4C5 F7D9 neg ecx |

:0040A4C7 51 push ecx ====> 这段跟注册码变换无关

:0040A4C8 E829FEFFFF call 0040A2F6 |

:0040A4CD 83C408 add esp, 00000008 /

:0040A4D0 8945E8 mov dword ptr [ebp-18], eax /

:0040A4D3 8B5510 mov edx, dword ptr [ebp+10] ====> 注册码地址

:0040A4D6 0355F0 add edx, dword ptr [ebp-10]

:0040A4D9 8A4201 mov al, byte ptr [edx+01] ====> 取出相应的注册码

:0040A4DC 8845E0 mov byte ptr [ebp-20], al

:0040A4DF 8A4DE0 mov cl, byte ptr [ebp-20]

:0040A4E2 51 push ecx

:0040A4E3 E886FCFFFF call 0040A16E ====> 进行变换

:0040A4E8 83C404 add esp, 00000004

:0040A4EB 8945EC mov dword ptr [ebp-14], eax ====> 结果放入到[ebp-14]中

:0040A4EE 8B55EC mov edx, dword ptr [ebp-14]

:0040A4F1 2B55DC sub edx, dword ptr [ebp-24] ====> -[ebp-24],因此跟注册码所在的位置有关

:0040A4F4 8955EC mov dword ptr [ebp-14], edx

:0040A4F7 6A24 push 00000024 ====> 为什么是24h?因为字符0~9加上A~Z正好共36个(24h)

:0040A4F9 8B45EC mov eax, dword ptr [ebp-14]

:0040A4FC 50 push eax

:0040A4FD E8F4FDFFFF call 0040A2F6 ====> 进行变换

变换过程:如果[ebp-14]为负数,则[ebp-14]+24h,直到为非负值且小于24h;如果[ebp-14]为正数且大于等于24h,则[ebp-14]-24h直到为非负值且小于24h

:0040A502 83C408 add esp, 00000008

:0040A505 8945EC mov dword ptr [ebp-14], eax

:0040A508 8B4DEC mov ecx, dword ptr [ebp-14]

:0040A50B 51 push ecx

:0040A50C E8A9FBFFFF call 0040A0BA ====> 根据上面相应的计算结果确定变换代码

确定过程:如果[ebp-14](即ecx)的值在0-9,则转为相应的数字,即eax=ecx+30h,否则eax=ecx+"A"-0ah=ecx+37h

:0040A511 83C404 add esp, 00000004

:0040A514 8B5508 mov edx, dword ptr [ebp+08]

:0040A517 0355F0 add edx, dword ptr [ebp-10]

:0040A51A 884201 mov byte ptr [edx+01], al ====> 变换结果放入到变换代码地址中

:0040A51D E964FFFFFF jmp 0040A486

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040A495(C)

|

:0040A522 8BE5 mov esp, ebp

:0040A524 5D pop ebp

:0040A525 C3 ret

总结上面的变换过程:

1. 注册码必须是19个字符且字符范围在0~9和A~Z之间

2. 设注册码用R来表示,则R19=((R1+R2+...+R18) mod 24h)+(30h或37h),如果前面的余数<=9则+30h,否则+37h

3. 设第18位注册码的变换码为X18,则X18=R18-37h(注册码在A~Z)或X18=R18-30h(注册码在0~9),如果用笔计算一下就可知道,R18肯定是A~Z之间的字符,因此,X18=R18-37h

4. 用户名和E-mail地址名的计算值=(所有字符的ascii值相加 mod 1Ah)+37h,注意:用户名和E-mail地址名不能用中文字符

5. 变换代码的计算过程(用y表示)

(1) y1=r1

(2) 如果i=2或3, yi=((X1-(-(X18+i-2))) mod 24h)+30h或37h=(X1+X18+i-2) mod 24h)+30h或37h

(3) 如果i=4到17,yi=((X1-(X18+i-2))±n*24h)+30h或37h=(X1-X18-i+2±n*24h)+30h或37h n=0,1,2

6. y5与用户名的计算值相等,y7与E-mail地址的计算值相等,因此,y5和y7肯定是在A~Z之间

根据上面的变换过程我们可以做出这个软件的注册器,第一种方法是先构造一个19位的注册码,然后利用第5,7,18位的注册码再相应构造用户名和E-mail地址,这种方法虽然简单,但用户名和E-mail地址可能很难看,因为我们还是喜欢用户名和E-mail地址易懂的注册码,因此采用第二种方法

第二种方法是先构造用户名和密码,生成相应的计算值,再构造第18位的注册码,然后根据用户名和密码的计算值及第18位的注册码确定第5和第7位的注册码,而第1~4,6,8~17位的注册码随机生成,只要符合在0~9或A~Z之间即可,最后生成第18位的注册码,根据这个思路,注册机如下(VB程序):

Private Sub Command1_Click()

Dim UserName, EmailAddress, RegCode, UserNameLong, EmailLong

Dim CheckUserCode, CheckEmailCode, RandCode, CheckCode

RegCode = "": CheckCode = ""

UserName = Text1.Text

EmailAddress = Text2.Text

UserNameLong = Len(Text1.Text)

EmailLong = Len(Text2.Text)

If UserNameLong = 0 Then

MsgBox "用户名不能为空!", vbOKOnly, "请输入用户名"

Exit Sub

Else

For i = 1 To UserNameLong

CheckUserCode = CheckUserCode + Asc(Mid(UserName, i, 1))

Next

CheckUserCode = (CheckUserCode Mod 26) + &H41

End If

If EmailLong = 0 Then

MsgBox "Email地址不能为空!", vbOKOnly, "请输入Email地址"

Exit Sub

Else

For i = 1 To EmailLong

CheckEmailCode = CheckEmailCode + Asc(Mid(EmailAddress, i, 1))

Next

CheckEmailCode = (CheckEmailCode Mod 26) + &H41

End If

GetReg18:

Reg18 = MakeRndCode()

If Reg18 <= &H39 Then

GoTo GetReg18

Else

Reg18Mod = Reg18 - &H37

End If

Reg5 = (Reg18Mod + 3 + CheckUserCode - &H37) Mod &H24

If Reg5 <= 9 Then

Reg5 = Reg5 + &H30

Else

Reg5 = Reg5 + &H37

End If

If Reg5 > &H5A Then GoTo GetReg18

Reg7 = (Reg18Mod + 5 + CheckEmailCode - &H37) Mod &H24

If Reg7 <= 9 Then

Reg7 = Reg7 + &H30

Else

Reg7 = Reg7 + &H37

End If

If Reg7 > &H5A Then GoTo GetReg18

For i = 1 To 4

RandCode = MakeRndCode()

RegCode = RegCode + Chr(RandCode)

Next

RegCode = RegCode + Chr(Reg5)

RandCode = MakeRndCode()

RegCode = RegCode + Chr(RandCode)

RegCode = RegCode + Chr(Reg7)

For i = 8 To 17

RandCode = MakeRndCode()

RegCode = RegCode + Chr(RandCode)

Next

RegCode = RegCode + Chr(Reg18)

RandCode = 0

For i = 1 To 18

RandCode = RandCode + Asc(Mid(RegCode, i, 1))

Next

RandCode = RandCode Mod &H24

If RandCode <= 9 Then

RegCode = RegCode + Chr(RandCode + &H30)

Else

RegCode = RegCode + Chr(RandCode + &H37)

End If

Text3.Text = RegCode

End Sub

Function MakeRndCode()

Dim a

Randomize

NextRnd:

Do

a = Int(Rnd * 120)

Loop Until a >= &H30 And a <= &H5A

If a > &H39 And a < &H41 Then

GoTo NextRnd

End If

MakeRndCode = a

End Function

(出处:赢政天下收集整理)

相关文章:

·ASProtect的加密算法初步分析

·MD5算法研究

·Active Ebook Compiler的注册算法

·语音界面2.0算法分析及注册机源码!

·简单算法——小护士 V1.2

·侠客系统修改器1.21破解手记--算法分析

·中文拨号上网计时计费器 V4.12注册算法分析

·加密算法之RSA算法

·加密算法之DES算法

·加密算法之ElGamal算法

相关软件:

·胜新通用人事工资管理系统 V5.01注册码算法

·胜新出纳-支票打印软件 V4.0X 的注册码算法

·胜新现代办公百宝箱 V5.01 的注册码算法

·胜新信函宝典-信封打印软件 V2.02 注册码的算法

·胜新通用企业计划管理系统的注册码算法

·共享软件加密算法库 V3.0

·操作系统内存分配银行家算法模拟系统 XP

→ 特别推荐

→ 热点TOP10

关于我们 |

帮助(?)

| 广告服务 |

版权声明 |

商业合作 |

发展历程 |

加盟我们 |

联系我们

Copyright © 1999-2003

winzheng.com All Rights Reserved.

繁体版:由华琦数码技术提供

Powered

by:MeSky.Net

2003-2004 年,宽带刚刚普及,下载站的文章区是许多人学电脑的第一课堂。
🕰 → 🤖 从那时到现在

当年一篇教程能让一台电脑焕然一新;今天的效率工具换成了 AI。 想知道当下最可靠的 AI 模型怎么选?看 赢政指数——我们用了 28 年的选软件严谨,现在用来评测大模型。

档案性质声明:本页为赢政天下(1998-2011)老文章的历史档案复原, 内容反映当年发表时的原貌——包括当年的技术表述、软件版本与观点,部分方法在今天已不适用或不合规,仅作互联网历史记录与研究用途, 不提供任何形式的下载。原始数据经由公共网络存档(Internet Archive)复原。发现问题请联系我们
← 返回老文章档案 · 软件史档案馆 · 赢政天下站史