Photocaster xtra v3.0.3 注册过程的分析 (15千字)
软件简介:Director的一个插件,支持直接导入用PhotoShop的分层PSD图形文件,并按原样在舞台上自动排列。未注册版会在导入的图形中加上很多蓝色的斜线,从而导致无法正常使用。我在Director中用了一下,感觉确实很不错,稍微遗憾的是,该软件在读取含有汉字的图层文件时,对汉字有点“水土不服”,显示有问题,不过,可以在Director下编辑该层,重新输入一遍汉字就OK了。下载地址:http://www.medialab.com/downloads/PhotoCaster3Win.zip
引用网页:http://www.medialab.com/products/downloadlist.htm
目标文件:Photocaster.x32 380928 bytes
分析工具:SoftICE 4.05,IDA Pro 4.15
Director运行版本:8.5,序列号:WDW850-02044-87235-26475
前言:这个xtra是网上的一个朋友huihuicn问的,当时问我是否有这个xtra,于是我就用google搜索了一下,还真找到了下载URL,顺便还找到了一篇关于Photocaster v2的破解文章,这篇文章对我进行分析还是有不少帮助的,让我知道了一些信息,少走了一些弯路,感谢该文的作者。另外,这个xtra有点奇怪,没有什么壳,但不能用W32Dasm反汇编,估计该软件可能作了防W32Dasm处理。不过用IDA可以反汇编,这正是我所希望的(否则在SoftICE中分析岂不痛苦?)。
破解过程:首先Photocaster.x32复制到Director的xtra文件夹(我一般是新建个Photocaster文件夹,然后将相关文件复制到该文件夹下,这样便于管理),启动Director 8.5,选择Insert-->Media Lab Media-->PhotoCaster,调入PhotoCaster,单击About按钮,填入Unlock Code:654321,Ctrl+D进入SoftICE,设断:bpx getdlgitemtexta,来到下面:
:10017281 call ds:GetDlgItemTextA ;取得注册码字符串
:10017287 test eax, eax
:10017289 jz loc_1001733B
:1001728F lea eax, [esp+2Ch+String]
:10017293 mov ecx, esi
:10017295 push eax
:10017296 call sub_1001C640 ;计算并比对的call
:1001729B test eax, eax ;eax做旗标
:1001729D jz loc_1001733B ;等于0则错误
:1001C640 arg_0 = 注册码
:1001C640 sub esp, 5Ch
:1001C643 push ebx
:1001C644 mov ebx, [esp+60h+arg_0]
:1001C65F mov edi, ebx
:1001C661 or ecx, 0FFFFFFFFh
:1001C664 xor eax, eax
:1001C666 repne scasb
:1001C668 not ecx
:1001C66A dec ecx
:1001C66B cmp ecx, 6 ;注册码长度是否为6
:1001C66E jz short loc_1001C679 ;是则转
:1001C670 pop edi
:1001C679 push ebx
:1001C67A call sub_100024F0 ;将大写字符转为小写
:1001C67F mov al, [ebx+5] ;取第6个注册码字符
:1001C682 add esp, 4
:1001C685 cmp al, 30h
:1001C687 jl short loc_1001C691
:1001C689 cmp al, 39h
:1001C68B jg short loc_1001C691
:1001C68D add al, 0D0h
:1001C68F jmp short loc_1001C693
:1001C691 add al, 0C9h
1c685-1c691为取该字符的“0-9A-Z”的排列值
:1001C693 mov esi, [esi+10h] ;常数,我的是23675,这个值很关键,后面说其产生过程
:1001C696 movsx edi, al ;第一个注册码的取值放到edi
:1001C699 push esi
:1001C69A mov [esp+6Ch+var_3C], edi
:1001C69E call _atol ;转为长整数
:1001C6A3 add esp, 4
:1001C6A6 add eax, edi ;加上第一个注册码的值
:1001C6A8 push eax
:1001C6A9 push offset a05lu ; "%05lu"
:1001C6AE push esi
:1001C6AF call _sprintf ;转为字符串
:1001C6B4 push 5
:1001C6B6 mov [esp+78h+var_33], 0
:1001C6BB mov [esp+78h+var_30], 7
:1001C6C3 mov [esp+78h+var_2C], 0Bh
:1001C6CB mov [esp+78h+var_28], 0Dh
:1001C6D3 mov [esp+78h+var_24], 11h
:1001C6DB mov [esp+78h+var_20], 13h
:1001C6E3 mov [esp+78h+var_1C], 17h
:1001C6EB mov [esp+78h+var_18], 1Dh
:1001C6F3 mov [esp+78h+var_14], 1Fh
:1001C6FB mov [esp+78h+var_10], 25h
:1001C703 mov [esp+78h+var_C], 29h
:1001C70B mov [esp+78h+var_8], 2Bh
:1001C713 mov [esp+78h+var_4], 2Fh
:1001C71B call _malloc
:1001C720 mov esi, eax
:1001C722 push 5
:1001C724 push ebx
:1001C725 push esi
:1001C726 mov [esp+84h+var_58], esi
:1001C72A call _strncpy
:1001C72F push 5
:1001C731 lea eax, [esp+88h+var_38]
:1001C735 push ebx
:1001C736 push eax
:1001C737 call _strncpy
:1001C73C mov ecx, esi
:1001C73E lea eax, [esp+90h+var_38]
:1001C742 add esp, 28h
:1001C745 xor edx, edx
:1001C747 sub ecx, eax
:1001C749 mov [esp+68h+var_44], ecx
:1001C74D lea eax, [esp+edx+68h+var_38]
:1001C751 mov bl, [ecx+eax] ;取注册码字符
:1001C754 add bl, 0D0h ;字符转为数字
:1001C757 mov [ecx+eax], bl
:1001C75A mov bl, [eax] ;取注册码字符
:1001C75C add bl, 0D0h ;字符转为数字
:1001C75F inc edx
:1001C760 cmp edx, 5
:1001C763 mov [eax], bl
:1001C765 jl short loc_1001C74D
:1001C767 mov ebx, 1
:1001C76C push ebp
:1001C76D mov [esp+6Ch+var_5C], ebx
:1001C771 xor ebp, ebp ;置初值
:1001C773 jmp short loc_1001C779
:1001C775 mov esi, [esp+6Ch+var_58]
:1001C779 mov cl, [esi+ebp] ;取注册码字符
:1001C77C mov byte ptr [esp+6Ch+var_54], cl
:1001C780 mov ecx, 5
:1001C785 mov edi, [esp+6Ch+var_54]
:1001C789 and edi, 0FFh
:1001C78F mov eax, edi
:1001C791 cdq
:1001C792 idiv ecx ;整除5
:1001C794 cmp ebp, 4 ;当前注册码是否是第5个
:1001C797 mov byte ptr [esp+6Ch+var_50], dl ;取余数值
:1001C79B jge short loc_1001C7A3 ;是则转
:1001C79D mov cl, [esi+ebp+1] ;下一个注册码
:1001C7A1 jmp short loc_1001C7A5
:1001C7A3 mov cl, [esi] ;取第1个注册码
:1001C7A5 mov al, bl
:1001C7A7 mov esi, 0Ah
:1001C7AC imul cl ;al*cl
:1001C7AE mov dl, al ;dl=al*cl
:1001C7B0 mov eax, [esp+6Ch+var_50]
:1001C7B4 and eax, 0FFh
:1001C7B9 mov byte ptr [esp+6Ch+var_4C], dl
:1001C7BD lea ecx, [esp+eax+6Ch+var_38]
:1001C7C1 mov al, [esp+eax+6Ch+var_38] ;根据1001C797语句的dl值取进行变换的字符
:1001C7C5 add al, dl ;加上dl
:1001C7C7 and eax, 0FFh ;取低位
:1001C7CC cdq
:1001C7CD idiv esi ;整除10
:1001C7CF xor esi, esi
:1001C7D1 xor eax, eax
:1001C7D3 mov [ecx], dl ;余数放到[ecx]
:1001C7D5 mov ecx, 1
:1001C7DA xor edx, edx
:1001C7DC mov dl, [esp+eax+6Ch+var_38] ;从变换的字符中取一个
:1001C7E0 imul edx, ecx ;相乘
:1001C7E3 lea ecx, [ecx+ecx*4]
:1001C7E6 add esi, edx
:1001C7E8 shl ecx, 1
:1001C7EA cmp eax, ebp
:1001C7EC jnz short loc_1001C7F2
:1001C7EE mov [esp+6Ch+var_48], ecx
:1001C7F2 inc eax
:1001C7F3 cmp eax, 5
:1001C7F6 jl short loc_1001C7DA
:1001C7F8 mov eax, ebp
:1001C7FA mov ebx, 0Bh
:1001C7FF cdq
:1001C800 idiv ebx
:1001C802 and edx, 0FFh
:1001C808 mov eax, [esp+edx*4+6Ch+var_30] ;取1001C6BB-1001C713的赋值
:1001C80C mov edx, [esp+6Ch+var_4C]
:1001C810 and edx, 0FFh
:1001C816 imul eax, edi
:1001C819 imul edx, [esp+6Ch+var_48]
:1001C81E imul edx, [esp+6Ch+var_5C]
:1001C823 add edx, esi
:1001C825 mov edi, 4
:1001C82A lea esi, [edx+eax]
:1001C82D mov eax, 66666667h ;注意66666667h/100000000h=0.4
:1001C832 mov ebx, 0Ah
:1001C837 imul ecx
:1001C839 sar edx, 2 ;0.4/4=0.1,说明ecx每次循环的计算结果均*0.1
:1001C83C mov eax, edx
:1001C83E shr eax, 1Fh
:1001C841 add edx, eax
:1001C843 mov eax, esi
:1001C845 mov ecx, edx ;即ecx=ecx/10 (语句1001C82D-1001C841的结果)
:1001C847 cdq
:1001C848 idiv ecx ;eax=esi/ecx
:1001C84A and eax, 0FFh ;取商的低位
:1001C84F cdq
:1001C850 idiv ebx ;整除10
:1001C852 mov eax, esi
:1001C854 mov [esp+edi+6Ch+var_38], dl ;余数放回
:1001C858 cdq
:1001C859 idiv ecx
:1001C85B dec edi ;计数器-1
:1001C85C mov esi, edx ;esi=esi mod ecx
:1001C85E jns short loc_1001C82D
:1001C860 mov ebx, [esp+6Ch+var_5C]
:1001C864 neg ebx ;ebx=-ebx
:1001C866 inc ebp ;计数器加1
:1001C867 mov [esp+6Ch+var_5C], ebx
:1001C86B cmp ebp, 5 ;计算了5组了吗
:1001C86E jl loc_1001C775 ;没有则继续
:1001C874 mov edx, [esp+6Ch+var_44]
:1001C878 xor ebx, ebx
:1001C87A xor ecx, ecx
:1001C87C lea eax, [esp+ecx+6Ch+var_38] ;注册码经过5次循环变换计算的结果
:1001C880 add byte ptr [edx+eax], 30h
:1001C884 add byte ptr [eax], 30h ;将变换后的字符变为数字
:1001C887 inc ecx
:1001C888 cmp ecx, 5
:1001C88B jl short loc_1001C87C
:1001C88D mov ecx, [esp+6Ch+var_58]
:1001C891 push ecx
:1001C892 call sub_1002651C
:1001C897 mov ebp, [esp+70h+var_40]
:1001C89B add esp, 4
:1001C89E xor edi, edi
:1001C8A0 xor eax, eax
:1001C8A2 mov esi, [ebp+10h]
:1001C8A5 xor edx, edx
:1001C8A7 xor ecx, ecx
:1001C8A9 mov dl, [esi+eax] ;取"23675"字符串+第6个注册码字符的变换值
:1001C8AC mov cl, [esp+eax+6Ch+var_38] ;前5个注册码变换生成的字符串
:1001C8B0 xor edx, ecx ;如果相等,则异或为0
:1001C8B2 add edi, edx ;异或结果累加
:1001C8B4 inc eax
:1001C8B5 cmp eax, 5
:1001C8B8 jl short loc_1001C8A5
:1001C8BA push esi
:1001C8BB call _atol
:1001C8C0 mov edx, [esp+70h+var_3C]
:1001C8C4 add esp, 4
:1001C8C7 sub eax, edx
:1001C8C9 push eax
:1001C8CA push offset a05lu ; "%05lu"
:1001C8CF push esi
:1001C8D0 call _sprintf
:1001C8D5 add esp, 0Ch
:1001C8D8 cmp edi, ebx ;累加结果是否为0
:1001C8DA jz short loc_1001C907 ;如果为0则注册码正确
:1001C8DC mov eax, [ebp+5Ch]
:1001C8DF mov [ebp+6Ch], ebx
:1001C8E2 mov ecx, [eax+0Ch] ;取PhotoCaster Lingo Prefs_D8.PRF文件的注册次数,文件偏移量的0Ch处
:1001C8E5 inc ecx ;注册次数加1
:1001C8E6 mov [eax+0Ch], ecx
:1001C8E9 mov edx, [ebp+5Ch]
:1001C8EC cmp dword ptr [edx+0Ch], 32h ;注册次数是否大于50,小小的一暗桩
:1001C8F0 jg short loc_1001C90E ;大于则转,假装显示注册成功
:1001C8F2 mov ecx, ebp
:1001C8F4 xor esi, esi ;失败旗标
:1001C8F6 call sub_1001B650 ;注册次数等信息写回文件(PhotoCaster Lingo Prefs_D8.PRF)
:1001C8FB pop ebp
:1001C8FC mov eax, esi ;注册失败
:1001C8FE pop edi
:1001C8FF pop esi
:1001C900 pop ebx
:1001C901 add esp, 5Ch
:1001C904 retn 4
:1001C907 mov dword ptr [ebp+6Ch], 1
:1001C90E mov eax, [ebp+5Ch]
:1001C911 mov edi, [esp+6Ch+arg_0] ;注册码
:1001C915 or ecx, 0FFFFFFFFh
:1001C918 mov [eax+14h], bl
:1001C91B mov edx, [ebp+5Ch]
:1001C91E xor eax, eax
:1001C920 add edx, 14h
:1001C923 repne scasb
:1001C925 not ecx
:1001C927 sub edi, ecx
:1001C929 mov eax, ecx
:1001C92B mov esi, edi
:1001C92D mov edi, edx
:1001C92F shr ecx, 2
:1001C932 repe movsd
:1001C934 mov ecx, eax
:1001C936 and ecx, 3
:1001C939 repe movsb
:1001C93B mov ecx, ebp
:1001C93D mov esi, 1 ;旗标
:1001C942 call sub_1001B650 ;注册信息写回文件
:1001C947 pop ebp
:1001C948 mov eax, esi ;注册成功
:1001C94A pop edi
:1001C94B pop esi
:1001C94C pop ebx
:1001C94D add esp, 5Ch
:1001C950 retn 4
:1001C950 sub_1001C640 endp
根据上面的计算程序,我用VB编了一个函数,传递参数为Unlock Code,返回值为计算结果,如果返回值等于常数+第6个字符的变换值就说明注册码正确。程序如下:
Function GetSerial(regcode As String)
Dim Serial As String, i As Integer, j As Integer, k As Integer
Dim ebp As Integer, al As Integer, bl As Integer, cl As Integer, dl As Integer
Dim eax As Integer, ebx As Long, ecx As Long, edx As Long, esi As Long, edi As Long
Serial = regcode
bl = 1: ebp = 0
For i = 1 To 5 '对5个注册码字符变换
edi = CInt(Mid(regcode, i, 1)): cl = edi Mod 5
j = i + 1
If i = 5 Then j = 1
eax = cl + 1: cl = CInt(Mid(regcode, j, 1)): dl = bl * cl
If CInt(Mid(Serial, eax, 1)) + dl < 0 Then '检测变换的字符是否有“负值”,如果有则返回
GetSerial = "负值!" '表示该Unlock Code错误
Exit Function
End If
Mid(Serial, eax, 1) = CStr((CInt(Mid(Serial, eax, 1)) + dl) Mod 10)
dl = CInt("&H" + Right(Hex(dl), 2)) '取低位,即1001C7C7语句
'以上对应于程序的1001C775-1001C7D5语句
ecx = 1: esi = 0
For j = 1 To 5
edx = CLng(Mid(Serial, j, 1))
edx = edx * ecx: esi = esi + edx: ecx = ecx * 10
If j = ebp + 1 Then ebx = ecx
Next j
'以上对应于程序的1001C7DA-1001C7F6语句
al = 2 * (ebp Mod 12) + 1
al = CInt("&H" + Mid("070B0D1113171D1F25292B2F", al, 2)) '其实字符串取前5个就行了
edx = dl * ebx * bl: esi = esi + al * edi + edx
'以上对应于程序的1001C7F8-1001C82A语句
For j = 5 To 1 Step -1
ecx = ecx / 10: ebx = esi: ebx = ebx \ ecx
ebx = CLng("&H" + Right(Hex(ebx), 2)) Mod 10
Mid(Serial, j, 1) = CStr(ebx)
esi = esi Mod ecx
Next j
'以上对应于程序的1001C82D-1001C85D语句
bl = -bl: ebp = ebp + 1
Next i
GetSerial = Serial
End Function
根据上面的函数,我编了一个算码程序,共找到了15个注册码,介绍其中好记的一个:98567G
