1. 程式人生 > >破解TexturePacker加密資源

破解TexturePacker加密資源

    最近我們要開一個新專案,UI與互動打算借鑑當前正火的《聖火英雄傳》,程式開發為了和美術製作並行,打算用聖火的資源暫代使用。我解壓聖火apk,發現用TexturePacker命令列無法把它的pvr.ccz資原始檔轉成png,稍微瞭解一下,才知道TP提供了加密功能。我最近做Unity開發,只需要TP最基本的打圖集功能,所以一直用v2.4.5,很久沒有升級了,out了。

    

    聖火資源加密了,沒有金鑰無法開啟

    美術同學可以先截圖或畫草圖給程式用,但是,截圖/草圖跟原圖比:大小規格不對,質量差,圖元疊在一起,也會缺漏很多。不說耗費美術大量精力做繁重的體力活,這樣做出的東西也會“慘不忍睹”,等正式美術資源來了,所有美術顯示也都需要程式重新調整,這是不小的工作量。所以,最好的方法是研究破解聖火的加密資源。工程師的工作就是減小人的勞動,提高生產效率。

    動態庫注入與API攔截

    開始時,我心裡一點底兒也沒有,因為我是開發遊戲的,從來沒做過破解。僅有的一點相關經驗是幾年前看《Windows核心程式設計》時用DLL注入和API攔截,做過一些遊戲的反外掛工作。幾年沒做PC開發,具體實現早忘光了,只記得大致原理是通過注入自己的DLL到目標程序,劫持某些API,替換成自己的實現。

    android核心是基於linux的,我想linux下是否也可以通過注入攔截API呢?只要能劫持API,就能破解。google "linux + inject",linux下果然也可以注入,更進一步發現有人已經開源了自己寫的注入庫,LibInject,核心的系統API是

ptrace,還有幾個操作動態連結庫的API,dlopen、dlsym、dlclose、dlerror。注入之後,就是劫持,遍歷got表,找到介面的地址然後替換成自己寫的介面即可。

    注入和劫持都ok之後,我試著劫持printf,替換成自己的函式,成功,我心裡對破解有底了。下面是一些具體的操作過程。

    首先要把手機root,把注入程序和劫持庫拷貝到手機上,比如/data目錄下,adb push命令。如果提示“Permission Denied”,就先把/data掛載(mount),然後改變檔案許可權(chmod)。

    然後,開啟聖火包裡面lib目錄,發現聖火用的是cocos2d-js v2.2開發,去cocos2d-x官方下載v2.2.5。然後,找到載入pvr.ccz

的模組,都在ZipUtils.h/.cpp檔案中。

    void ZipUtils::ccSetPvrEncryptionKeyPart(int index, unsigned int value)// 設定金鑰的介面
    int ZipUtils::ccInflateCCZFile(const char *path, unsigned char **out) // 載入ccz檔案的介面
    我本想劫持設定金鑰的使用者自定義介面:ccSetPvrEncryptionKeyPart,這樣可以直接獲取密碼。但是,從soinfo->symtab中獲取的符號名始終是亂碼,目前我還沒搞明白原因,請知道的朋友指導。我就轉而看ccInflateCCZFile的實現,這個介面會讀取ccz檔案的二進位制資料,然後根據前四個位元組判斷是否合法的ccz檔案(“CCZ!”)或者是否加密的ccz檔案(“CCZp”),如果是加密的,就解密。接著,呼叫了libz的解壓縮介面:
    int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
    原來ccz也是一種zip壓縮格式。這裡需要用到source和destLen這兩個引數,source是解密出來的ccz檔案資料,*destLen是壓縮前的大小。既然如此,我只要把uncompress介面劫持了,就可以破解出資源。ps. 除了劫持uncompress,還可以劫持opengl介面,畢竟所有圖都要送到opengl繪製。

    破解

    看看ccz的檔案頭:

    /** @struct CCZHeader
    */
    struct CCZHeader {
        unsigned char   sig[4];             // signature. Should be 'CCZ!' 4 bytes
        unsigned short  compression_type;   // should 0
        unsigned short  version;            // should be 2 (although version type==1 is also supported)
        unsigned int    reserved;           // Reserverd for users.
        unsigned int    len;                // size of the uncompressed file
    };

   source是不包含檔案頭的,所以需要自己把檔案頭填充進去。sig是“CCZ!”,compress_type是0,version是2,reserved是0,len是*destLen。建立一個ccz檔案,把檔案頭和source寫入。然後,把生成的ccz檔案拷回本機,adb pull,“Permission Denied”?chmod。懷著激動地心情用TexturePacker開啟,卻報告失敗。然後用Notepad++的Hex Editor開啟,轉成16進位制,發現檔案頭的大小端逆序了。比如version,在大端機器上16進製表示是0x00 02,小端機器上是0x02 00。如果是小端,逆序寫就可以了。改了之後重新生成ccz,成功開啟。

    

    解密出來的聖火資源——Activity.pvr.ccz

    檔案命名

    劫持uncompress是無法知道檔名的。寫一個檔案掃描聖火資源目錄,根據以檔案size為key,檔名為value。然後,根據檔案size做匹配就可以了。因為檔案的size是精確到byte的,一般不會有檔案是同樣大小。我檢查了聖火,211個ccz檔案,沒有同樣大小的。

    轉png與切圖

    TexturePacker可以直接命令列把ccz轉png,然後再寫一個工具,讀plist切散圖就可以了,可以用CocosStudio,網上也有人用python寫的。至此,我們已經完美的破解了聖火所有的資源,獲得了所有美術資源。

    

    切出來的聖火美術資源散圖

     除了《聖火英雄傳》,還有很多遊戲也是用TexturePacker加密資源,都可以用這個方法破解。為了避免爭端,暫不放出工具及程式碼。

update1 —— 2015.04.07