Photocaster xtra v3.0.3 註冊過程的分析 (15千字)

看雪資料發表於2001-11-22

軟體簡介: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

相關文章