zoukankan      html  css  js  c++  java
  • 【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] = '';
            }
            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] = '';
            }
        } 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的脚本代码解密也一样非常简单!

    大功告成,再见!

    PS一下广告时间:

    我目前在录制cocos2dx-3.X系列的实战项目视频,可以完全来说是商业项目视频讲解,让你爱上更有趣的游戏开发方式;

    9秒课堂会第一时间上线我们的实战视频!

    可以让大家更快速的掌握cocos2dx-Js的游戏实战开发!现在用脚本做游戏已然成为一个大的趋势;

    而且在手游游戏行业飞速发展的今天,如果不用一种快速上手的脚本语言做游戏开发岂不是会Out了

    另外希望大家支持我们的游戏开发群:【41131516】

     
     
     
     
     
     
     
     
  • 相关阅读:
    计算机 ------- 网络基础
    设计模式------单例模式
    svn 客户端查看用户名和密码
    Docker:DockerFile(DockerFile解析)
    Docker:容器数据卷(命令方式、DockerFile方式)
    SpringBoot再总结
    Docker:镜像(镜像原理)
    Docker:Docker命令(帮助命令、镜像命令、容器命令)
    Docker(Docker的概念与安装)
    ZooKeeper:zookeeper的常用命令(节点的新增、更新、删除)
  • 原文地址:https://www.cnblogs.com/zisou/p/cocos2d-xjm.html
Copyright © 2011-2022 走看看