分类分类
关注+2004-10-15作者:蓝点
软件简介: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
相关文章
更多+相同厂商
热门推荐
点击查看更多
点击查看更多
点击查看更多
说两句网友评论