用ISDCC2破KPT 6的安裝 (8千字)

看雪資料發表於2001-04-17

用ISDCC2破KPT 6的安裝
Passion

不好意思,近來我只研究一點INSTALLSHIELD的反編譯和破解,這裡又貼半篇引用外界DLL檔案的指令碼破解法,文章水平不高,大夥兒見笑了。――之所以是半篇,因為KPT 6作為PhotoShop濾鏡外掛執行的時候會重新檢測序列號,而本文只僅僅說了說破解安裝的過程。
KPT 6的安裝程式也需要輸入序列號,又是InstallShield在搗鬼。反編譯InstallShield的工具比較多,只是各自適用的版本不同,那個WISDEC能反編譯的SETUP.INS似乎版本比較低,對付KPT 6的指令碼檔案出錯,幸虧有個ISDCC2適用InstallShield 5.5版,可以以命令列的方式進行反編譯,也可重定向到檔案,只是反編譯後的程式碼沒有跳轉、修改等直接的功能。我已經忘了到底是哪兒下載的,幸虧README.TXT中說了網址是http://www.tardis.ed.ac.uk/~adq

在命令列裡執行isdcc2 setup.ins > kptsetup.txt就能把反編譯後的內容寫到KPTSETUP.TXT檔案中。我個人看來,ISDCC2的反編譯效果比WIS要好,可讀性也強一點,但沒程式碼導航、字串引用的功能,修改起來也很不方便。幸虧KPT 6這個東西的破解是不需要修改SETUP.INS的,否則又要麻煩了。

反編譯後的KPTSETUP.TXT中包括變數宣告、結構宣告、函式原型宣告以及反編譯程式碼等幾部份。函式宣告段內有這麼幾句:


    // ------------- FUNCTION PROTOTYPES --------------
……
    prototype MCSetup.MCSerialCheck(LIST, LIST, LIST);
    prototype MCSetup.MCSerialWrite(LIST);
……

這個表示安裝的時候要引用MCSETUP.DLL檔案中的MCSerialCheck和MCSerialWrite兩個函式,看看名稱,八成兒就是直接檢驗輸入的序列號是否正確以及寫入登錄檔的。
正文中又有那麼一段:

    // ------------- MAIN PROGRAM CODE --------------
……
label12:
0011B5:0022:        if (1 = 0) then
                        goto label14;
                    endif;
0011C5:00B5:        function112();
0011CD:0021:        lNumber0 = LAST_RESULT;
0011D5:0128:        lNumber3 = lNumber0 = 12;
0011E7:0022:        if (lNumber3 = 0) then
                        goto label14;
                    endif;
0011F5:002C:        goto label12;
……

當然,光看這段,誰都看不出這是檢驗序列號正確與否的,但這裡面的那個function112();就有點文章。下面是function112()的內容:


    // ------------- FUNCTION function112 --------------
    function function112()
        number lNumber0;
        number lNumber1;
        number lNumber2;
        number lNumber3;
        number lNumber4;
        number lNumber5;
        number lNumber6;
        number lNumber7;
        string lString0;
        string lString1;
        string lString2;
        string lString3;
        string lString4;
        string lString5;
    begin

label64:
0027F1:0110:        RegDBSetDefaultRoot(-2147483646);
0027F8:0021:        lNumber2 = 1;
002802:0022:        if (number34 = 0) then
                        goto label66;
                    endif;
002810:0013:        lString4 = "\\SOFTWARE\\MICROSOFT\\WINDOWS NT\\CURRENTVERSION\\";
002846:002C:        goto label67;
00284F:0013:        lString4 = "\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\";

label66:
002886:0152:        RegDBGetKeyValueEx(lString4, "REGISTEREDOWNER", lNumber2, string5, lNumber0);
0028A6:0110:        RegDBSetDefaultRoot(-2147483648);
0028AD:0013:        lString0 = "Product Registration";
0028C9:0013:        lString1 = "Please enter your name and the product serial number\nfor %P.";
00290D:0013:        lString2 = "Name";
002919:0013:        lString3 = "Serial Number";
00292E:0112:        StrLoadString("", "PRODUCT_ID", lString5);
002943:00BA:        AddressString(lString5);
002948:0021:        lNumber3 = LAST_RESULT;
002950:0021:        lNumber1 = 0;

label67:
002960:0128:        lNumber6 = lNumber1 = 0;
002972:0022:        if (lNumber6 = 0) then
                        goto label73;
                    endif;
002980:00B5:        function17(lString0, lString1, lString2, lString3, string5, string7);
00299A:0021:        lNumber0 = LAST_RESULT;
0029A2:0128:        lNumber6 = lNumber0 = 1;
0029B4:0022:        if (lNumber6 = 0) then
                        goto label71;
                    endif;
0029C2:0023:        StrCompare(string5, "");
0029CA:0128:        lNumber6 = LAST_RESULT = 0;
0029DC:0023:        StrCompare(string7, "");
0029E4:0128:        lNumber7 = LAST_RESULT = 0;
0029F6:0126:        lNumber6 = lNumber6 || lNumber7;
002A01:0022:        if (lNumber6 = 0) then
                        goto label69;
                    endif;
002A0F:002A:        MessageBox("Please enter your name and the product serial number.", -65534);
002A4E:002C:        goto label70;

//以上是要求輸入序列號和公司名的。

label68:
002A57:00BA:        AddressString(string5);
002A5C:0021:        lNumber4 = LAST_RESULT;
002A64:00BA:        AddressString(string7);
002A69:0021:        lNumber5 = LAST_RESULT;
002A71:00B4:        MCSetup.MCSerialCheck(lNumber3, lNumber4, lNumber5);

//就這個MCSerialCheck了。

002A7F:0021:        lNumber1 = LAST_RESULT;

label69:
002A8B:002C:        goto label72;

label70:
002A94:0021:        lNumber1 = 1;

label71:
002AA2:002C:        goto label68;

label72:
002AAB:012F:        return(lNumber0);
002AB2:00B8:        return;
    end;

這裡很明白,如果我們能把MCSETUP.DLL中那個MCSerialCheck函式分析清楚,序列號的檢驗演算法就都能知曉了。要是像我這樣懶得分析的,就跟蹤下去改掉MCSetup.MCSerialCheck函式的返回值也行。MCSETUP.DLL是安裝程式執行的時候解壓臨時生成的,就在WINDOWS/TEMP目錄下的一些子目錄中,安裝程式在執行時就能找到。

下面是MCSerialCheck函式的總體程式碼:

Exported fn(): MCSerialCheck - Ord:0002h
:100015D0 81EC3C020000            sub esp, 0000023C
:100015D6 8D442400                lea eax, dword ptr [esp]
:100015DA 53                      push ebx
:100015DB 56                      push esi
:100015DC 57                      push edi
:100015DD 50                      push eax

* Reference To: KERNEL32.GetLocalTime, Ord:011Bh
……
                                  |
:100015DE FF1508600010            Call dword ptr [10006008]
:100015E4 8B742412                mov esi, dword ptr [esp+12]
:100015E8 8B7C240E                mov edi, dword ptr [esp+0E]
:100015EC 8B8C2454020000          mov ecx, dword ptr [esp+00000254]
:100015F3 8B5C240C                mov ebx, dword ptr [esp+0C]
:100015F7 51                      push ecx
:100015F8 8D4C2420                lea ecx, dword ptr [esp+20]
:100015FC E8FFF9FFFF              call 10001000
:10001601 53                      push ebx
:10001602 57                      push edi
:10001603 8B942454020000          mov edx, dword ptr [esp+00000254]
:1000160A 56                      push esi

* Possible Reference to String Resource ID=00001: "Installer Serialisation"
                                  |
:1000160B 6A01                    push 00000001
:1000160D 52                      push edx
:1000160E 8D4C2430                lea ecx, dword ptr [esp+30]
:10001612 E879FBFFFF              call 10001190                //這個是關鍵CALL
:10001617 8BF0                    mov esi, eax
:10001619 6683FE01                cmp si, 0001
:1000161D 7525                    jne 10001644                //比較結果,正確則跳。
:1000161F 8B842450020000          mov eax, dword ptr [esp+00000250]
:10001626 6858770010              push 10007758
:1000162B 50                      push eax
:1000162C 8D4C2424                lea ecx, dword ptr [esp+24]
:10001630 E88BFEFFFF              call 100014C0
:10001635 5F                      pop edi
:10001636 5E                      pop esi
:10001637 83C8FF                  or eax, FFFFFFFF            //FFFFFFFF是錯誤標誌
:1000163A 5B                      pop ebx
:1000163B 81C43C020000            add esp, 0000023C
:10001641 C20C00                  ret 000C                //出錯返回。

:10001644 …………        //其餘程式碼。


從10001612處的call 10001190跟進去後是大段大段的序列號分析程式碼。我功力不夠,只跟到規定序列號格式的部分,後面的幾個迴圈迭代就把我弄暈了。本來又想暴力法改掉MCSETUP.DLL的程式碼,但我手頭的ICOMP又不能把改了後的檔案給壓縮回去,估計又是版本不對的問題,而SETUP.INS中似乎又沒有明顯的、改一個跳轉就改變流程的程式碼,何況要改也不知道應該改SETUP.INS檔案的什麼地方。

序列號格式我分析了一點點,序列號長度只能是13、17、1a或1e,當然就選13(十進位制是19個字元)了。前兩個字元必須為TF,第三個和第四個字元必須為數字,第五個字元必須是W或者C(WC?和廁所有沒有關係?^_^),第六個字元必須是BCENRU六字母之一,第七個字元必須是BCDFGMJKLMPSTZ之一,第八個字元是短橫-,第九到第十五個字元必須是數字,十六個是短橫-,十七十八十九三個字元必須都是大寫字母,且不能是I或者O,而且……最重要的一點是它會根據註冊碼前面部分先算出一個值,再後面又算出一個,比較相等才對,這段演算法我實在是跟不清,見笑了。

相關文章