CoolFocus Java Applet的破解 (4千字)

看雪資料發表於2001-02-19

http://www.coolfocus.com有不少很酷的Java Applet,可以做出多種特效。其保護如下:

Registered Applets
If you register an applet with Cool Focus, we'll send you  personal code parameters that remove the shareware restrictions. You'll continue to use the same class files and documentation and simply add these codes to the applet tags in your own pages. We'll also notify you by email when an updated version of the applet you registered is available, and you can return to this section of the site to download it. The same registration codes will continue to work with all updated versions.

在網頁中應按照如下格式使用其applet(只列出了與註冊碼有關的部分):

<APPLET CODE="ryElevator.class" ARCHIVE="Elevator.jar" MAYSCRIPT WIDTH="400" HEIGHT="990">
    <param name=Copyright value="Elevator (c) 1999 Cool Focus [www.coolfocus.com]">
    <param name=Base value="http://members.tripod.lycos.nl/tool_place/">
    <param name=Key value="7392045-1209-0-1038">
</APPLET>

其中Key就是註冊碼,這個註冊碼是根據嵌有該applet的HTML文件的document base字串計算出來的,所以必需寫序號產生器。

雖然現在已經有處理*.class檔案的工具以防止被反編譯,但大多數applet還是未作過任何手腳,所以可以輕易地利用Java反編譯器/反彙編器將class檔案反編譯/反彙編,從而得到其原始碼。有了原始碼,破解它的難度近乎為0,同時還可以“偷”到設計者的Java程式設計技巧。在這一點上Java applet和VB3、FoxPro程式沒太大區別。

以ryImageWizard.class為例,反編譯後查詢“Key”,看它如何處理註冊碼。非常簡單:

    private boolean _mth0146(String s)
        throws NoSuchElementException
    {
        String s1 = getParameter("Key");  //取出註冊碼
        if(s1 == null)
        {
            s1 = "";
            return false;
        }
        StringTokenizer stringtokenizer = new StringTokenizer(s1, "-");  //以“-”字元將註冊碼分成4部分
        String s2 = stringtokenizer.nextToken(); //註冊碼第1部分
        String s3 = stringtokenizer.nextToken(); //註冊碼第2部分
        String s4 = stringtokenizer.nextToken(); //註冊碼第3部分
        String s5 = stringtokenizer.nextToken(); //註冊碼第4部分
        int i = s.length();
        i = i * 7510 + 928;
        i -= 28338;
        i *= 12;
        if(!s2.equals(Integer.toString(i)))  //判斷第1部分
            return false;
        int j = _mth0145(s, 'e') * 684;
        if(!s3.equals(Integer.toString(j)))  //判斷第2部分
            return false;
        j = _mth0145(s, 'w') * 947;
        if(!s4.equals(Integer.toString(j)))  //判斷第3部分
            return false;
        j = _mth0145(s, 's') * 456;
        return s5.equals(Integer.toString(j)); //判斷第4部分
    }

上面所用到的函式_mth0145( )只是簡單地統計某字元在一個串中出現的次數:

    private int _mth0145(String s, char c)
    {
        int i = 0;
        byte byte0 = 120;        //垃圾程式碼還是反編譯器有問題?
        for(int j = 0; j < s.length(); j++)
        {
            char c1 = s.charAt(j);
            if(c1 == c)
                i++;
        }

        return i;
    }

那麼函式_mth0146( )是在哪裡被呼叫的呢?查詢即知在如下的地方。很顯然_fld0104是個全域性標誌,表示註冊與否。傳遞給_mth0146( )的引數就是嵌有applet的HTML的URL。

    private void _mth0147()
    {
        String s = getDocumentBase().toString().toLowerCase(); //取得HTML的URL
        boolean flag = false;
        if(s.startsWith("file:") && s.indexOf("imagewizard/docs/") >= 0)    //是否是在本地執行本applet
        {
            _fld0104 = true;  //本地則不判註冊碼
            return;
        }
        String s1 = getParameter("Base");
        if(s1 == null)
        {
            s1 = "";
            _fld0104 = false;
            return;
        }
        String s2 = "";
        if(s1.indexOf("|") >= 0)  //多個URL用豎線隔開
        {
            StringTokenizer stringtokenizer = new StringTokenizer(s1, "|");
            String as[] = new String[stringtokenizer.countTokens()];
            for(int i = 0; i < as.length; i++)
            {
                String s4 = stringtokenizer.nextToken();
                if(!s4.startsWith("http"))
                    as[i] = "http://" + s4;
                else
                    as[i] = s4;
                s2 = s2 + as[i];
                if(s.indexOf(s4) >= 0 || s.startsWith("file:"))
                    flag = true;
            }

        } else
        {
            String s3 = s1;
            if(!s1.startsWith("http"))
                s2 = "http://" + s1;
            else
                s2 = s1;
            if(s.indexOf(s3) >= 0 || s.startsWith("file:"))
                flag = true;
        }
        if(!flag)
        {
            _fld0104 = false;
            return;
        }
        try
        {
            _fld0104 = _mth0146(s2);  //這裡判註冊碼
            return;
        }
        catch(NoSuchElementException _ex)
        {
            _fld0104 = false;
        }
    }

至此就可以寫出序號產生器。

相關文章