Cocos2d-x 3.X 資源及腳本解密

加密就不用說了,看上一篇2.X加密的方式,怎麼弄都可以。的保證解密規則就行;

現在重點說3.X解密:

在新的3.X引擎中官方整合了大部分獲取資源的方法,最終合成一個getdata;

可以從源碼,和堆棧調用中看到:

CCFileUtils.cpp:

Data FileUtils::getDataFromFile(const std::string& filename)
{
    return getData(filename, false);
}

getDataFromFile目前只調用getData(filename,false);

Data getData(const std::string& filename, bool forString)

這個函數是一個非類成員靜態函數。

forString是用來標識是否是一個文本文件,如果是那麼buffer需要多一個字節。

這個其實不重要,因爲我們處理的最終buffer是獲取完全的

所以直接改代碼:

複製代碼
static Data getData(const std::string& filename, bool forString)
{
    if (filename.empty())
    {
        return Data::Null;
    }
    
    Data ret;
    unsigned char* buffer = nullptr;
    size_t size = 0;
    size_t readsize;
    const char* mode = nullptr;
    
    if (forString)
        mode = "rt";
    else
        mode = "rb";
    
    std::string lastname = FileUtils::getInstance()->fullPathForFilename(filename);
    lastname = lastname.substr(lastname.length()-5,lastname.length());
    
    do
    {
        // Read the file from hardware
        std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename);
        FILE *fp = fopen(fullPath.c_str(), mode);
        CC_BREAK_IF(!fp);
        fseek(fp,0,SEEK_END);
        size = ftell(fp);
        fseek(fp,0,SEEK_SET);
        
        if (forString)
        {
            buffer = (unsigned char*)malloc(sizeof(unsigned char) * (size + 1));
            buffer[size] = '\0';
        }
        else
        {
            buffer = (unsigned char*)malloc(sizeof(unsigned char) * size);
        }
        
        readsize = fread(buffer, sizeof(unsigned char), size, fp);
        fclose(fp);
        
        if (forString && readsize < size)
        {
            buffer[readsize] = '\0';
        }
    } while (0);
    
    if (nullptr == buffer || 0 == readsize)
    {
        std::string msg = "Get data from file(";
        msg.append(filename).append(") failed!");
        CCLOG("%s", msg.c_str());
    }
    else
    {
        if(lastname == "_jm.d")
        {
            for (int i = 0; i<readsize; i++) {
                buffer[i]=MD5(buffer[i]);
            }
            buffer[readsize]=buffer[readsize]-MD5size;
        }
        ret.fastSet(buffer, readsize);
    }
    
    return ret;
}
複製代碼

紅色代碼是我們自定義加密的文件解密,不管你用什麼加密,或者修改地址擾碼,只要保證加密解密格式相同;

OK,解密就算完成了,但是注意還有資源類型需要判斷,在2.X中,處理了EImageFormat的判斷,可以定義資源類型

但是還是建議還是不要去大改源碼,3.2以上版本已經非常簡潔強大了

3.X中整合了Format後,也有資源類型另外一種方式定義_fileType = detectFormat(unpackedData, unpackedLen);

我們解密後的資源類型在3.X中是行不通的,是Format::UNKOWN;

那麼就在不大改的情況下重載函數方式解決這個問題:

重載initWithImageData,在CCImage.h中CCImage.cpp中

.h添加:

/*
    jmflag 加密標識
     */
    bool initWithImageData(const unsigned char * data, ssize_t dataLen,bool jmflag);

.cpp添加:

複製代碼
bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen,bool jmflag)
{
    bool ret = false;
    
    do
    {
        CC_BREAK_IF(! data || dataLen <= 0);
        
        unsigned char* unpackedData = nullptr;
        ssize_t unpackedLen = 0;
        
        //detecgt and unzip the compress file
        if (ZipUtils::isCCZBuffer(data, dataLen))
        {
            unpackedLen = ZipUtils::inflateCCZBuffer(data, dataLen, &unpackedData);
        }
        else if (ZipUtils::isGZipBuffer(data, dataLen))
        {
            unpackedLen = ZipUtils::inflateMemory(const_cast<unsigned char*>(data), dataLen, &unpackedData);
        }
        else
        {
            unpackedData = const_cast<unsigned char*>(data);
            unpackedLen = dataLen;
        }
        
        if(jmflag == true)
        {
            _fileType=Format::PNG;
        }
        
        ret = initWithPngData(unpackedData, unpackedLen);
        
        if(unpackedData != data)
        {
            free(unpackedData);
        }
    } while (0);
    
    return ret;
}
複製代碼

另外在initWithImageFile函數中得修改調用方法

CCImage.cpp:

複製代碼
Data data = FileUtils::getInstance()->getDataFromFile(_filePath);

    if (!data.isNull())
    {
        std::string lastname = _filePath;
        lastname = lastname.substr(lastname.length()-5,lastname.length());
        if(lastname=="_jm.d")
        {
            ret = initWithImageData(data.getBytes(), data.getSize(),true);
        }
        else
        {
            ret = initWithImageData(data.getBytes(), data.getSize());
        }
    }
複製代碼

OK,自定義類型的資源解密就搞定了,但這隻處理了PNG圖片類型的加密,其他圖片類型資源可以按照這種方式處理。

好了,那麼有同學問,那麼JS,Lua腳本的解密呢?

看這裏

ScirptingCore.cpp:

複製代碼
  // Check whether '.jsc' files exist to avoid outputing log which says 'couldn't find .jsc file'.
    CCLOG("byteCodePath > %s",byteCodePath.c_str());
    if (futil->isFileExist(byteCodePath))
    {
        Data data = futil->getDataFromFile(byteCodePath);
        if (!data.isNull())
        {
            script = JS_DecodeScript(cx, data.getBytes(), static_cast<uint32_t>(data.getSize()), nullptr, nullptr);
        }
    }
複製代碼

 Data data = futil->getDataFromFile(byteCodePath);

對於腳本語言的加載讀取還是上面我們已經改過的getDataFromFile方法噢!

但是還有一點

script = JS_DecodeScript(cx, data.getBytes(), static_cast<uint32_t>(data.getSize()), nullptr, nullptr);

這樣是直接拿不到script的,JS_DecodeScript只是處理.jsc的,那麼怎麼給script複製呢?

代碼修改如下:

複製代碼
        //只解密scr下面目錄文件
        if(jmflag==true)
        {
            if (futil->isFileExist(jmfullPath))
            {
                Data data = futil->getDataFromFile(jmfullPath,true);
                if (!data.isNull())
                {
                    script = JS::Compile(cx, obj, options, (const char*)data.getBytes(), data.getSize());
                }
            }
        }
        else
        {
            script = JS::Compile(cx, obj, options, fullPath.c_str());
        }    
複製代碼

script = JS::Compile(cx, obj, options, (const char*)data.getBytes(), data.getSize());

用Compile的這個重載函數賦值就全部搞定了;Lua和JS的腳本代碼解密也一樣非常簡單!

大功告成,再見!


http://www.cnblogs.com/zisou/p/cocos2d-xjm.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章