Photocaster xtra v3.0.3 注册过程的分析 (15千字)

发布者:Editor
发布于:2001-11-22 23:07

软件简介: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


声明:该文观点仅代表作者本人,转载请注明来自看雪