针对cocos2d图片资源自定义加密的解密

来源:互联网 发布:淘宝上有没有卖视频的 编辑:程序博客网 时间:2024/05/16 14:25

http://zhaoxiaodan.com/cocos2dx/%E9%92%88%E5%AF%B9cocos2d%E5%9B%BE%E7%89%87%E8%B5%84%E6%BA%90%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8A%A0%E5%AF%86%E7%9A%84%E8%A7%A3%E5%AF%86.html


发现某游戏其assets目录的图片打开是雪花, 而且用二进制打开查看文件, 找魔数啊什么的, 都没发定义, 是新的文件格式? 还是被加密了?

google到这篇文章 破解TexturePacker加密资源 - 使用IDA才想起来, 可以使用ida进行反编译.(调试后发现, 该游戏并不是使用TexturePacker提供的加密方式)

在哪里解密的?

虽然游戏没有源码, 但是cocos2dx是有源码的, 参考进行调试, 还是蛮简单的, 而且记得一句话, 不管你怎么加密, 最后你在内存里, 肯定有一份解密之后的数据.

好, 按这个思路, 那我首先看, 这个解密之后的数据到底放在哪里?

根据以前的经验, cocos2dx的图片资源加载, 是在Image::initWithImageData(const unsigned char * data, ssize_t dataLen) 函数, 按照函数名称顾名思义:用数据初始化Image, 好了, 在ida 给这个函数下个断点, 先看看这个传进来的data

可以看到, data这个内存地址是debug148:797363E8, 而且这个地址的内容跟上面打开看到的完全不一样, 再再而且, 前4个字节就是png文件的魔数!.png

那也就是说, 图片文件是在被读入内存之后, 在被初始化之前就解密了;

那图片在哪里被读入?

cocos2dx的图片资源加载, 一般都是从TextureCache::addImage(const std::string &path) 这个函数开始的, 参考源码

Texture2D * TextureCache::addImage(const std::string &path){    //cache中是否已经有这个图片    auto it = _textures.find(fullpath);    if( it != _textures.end() )        texture = it->second;    //没有    if (! texture)    {        do         {            image = new (std::nothrow) Image();            CC_BREAK_IF(nullptr == image);            //初始化image            bool bRet = image->initWithImageFile(fullpath);            CC_BREAK_IF(!bRet);            texture = new (std::nothrow) Texture2D();            //再用image初始化texture            if( texture && texture->initWithImage(image) )            {                //hold 住                _textures.insert( std::make_pair(fullpath, texture) );            }            else            {                CCLOG("cocos2d: Couldn't create texture for file:%s in TextureCache", path.c_str());            }        } while (0);    }    CC_SAFE_RELEASE(image);    return texture;}

然后追到

bool Image::initWithImageFile(const std::string& path){    ...    //从文件读入数据    Data data = FileUtils::getInstance()->getDataFromFile(_filePath);    ...}

其实也就是CCFileUtils.cpp中的Data FileUtils::getDataFromFile(const std::string& filename)

这个CCFileUtils.cpp是平台相关的, 每个平台有每个平台的具体实现. android的版本是CCFileUtils-android.cpp文件

Data FileUtilsAndroid::getData(const std::string& filename, bool forString){    ...    //上面一大堆, 主要就是先判断这个filename是绝对目录还是assets目录,    //如果是assets目录则用AssetManager 来打开并读取,再做些分配内存什么的事情    //   int bytesread = AAsset_read(asset, (void*)data, fileSize);   size = bytesread;   AAsset_close(asset);    ...}

在ida中找到相应的代码查看

发现在AAsset_read 之后多了一个FileUtils::xxxxxxxxx函数的调用, 并且,v10这个指针指向的就是文件读入后的内存, 传给了这个函数.

进到函数看一眼:

哦? 内存每4个字节位与一个数再存回去? 得了, 基本是解密函数无疑. 验证下

在115行也就是AAsset_read之后下个断

看到文件被读入内存, 并且内存中的数据跟文件是一致的

再在FileUtils::xxxxxxxxx之后下个断

看到, v10 这个内存变化了, 出现了png的魔数.png

那么FileUtils::xxxxxxxxx函数就是解密函数无疑

知道解密算法了, 怎么把图还原出来?

很简单, 照着这个函数写一个c函数, 读文件进内存, 调这个函数解密, 就可以了

#include <stdio.h>#include <stdlib.h>void xxxxx(unsigned char* fileData, int fileSize){    int v5,v6,v7,v8,v9,i;    v5=0x00000000;    v6=0;    while(1)    {        v7=v6+v5;        if( v6 >= fileSize / 4)            break;        v8= 4 * v6;        v9 = *(int *)&fileData[4 * v6++];        *(int *)&fileData[v8] = v7 ^ v9;    }    for ( i = 0; ; *(&fileData[fileSize] + i) = *(&fileData[fileSize] + i) ^ 0xCC )    {        --i;        if ( ~i >= fileSize % 4 )            break;    }}int main(int argc,char** args){    if(argc <= 2){        printf("paramters wrong\n");        return 1;    }    char* filePath = args[1];    char* savePath = args[2];    printf("%s => %s\n",filePath,savePath);    FILE *fp = fopen(filePath, "r");    if(!fp)    {        printf("read file %s fail !!\n",filePath);        return 1;    }    fseek(fp,0,SEEK_END);    size_t size = ftell(fp);    fseek(fp,0,SEEK_SET);    unsigned char* buffer = (unsigned char*)malloc(sizeof(unsigned char) * size);    size_t readsize = fread(buffer, sizeof(unsigned char), size, fp);    fclose(fp);    xxxxx(buffer,readsize);    FILE *pFile = fopen(savePath, "w");    if(!pFile)    {        printf("write file %s fail !!\n",savePath);        return 1;    }    fwrite (buffer , sizeof(char), readsize, pFile);    fclose (pFile);    return 0;}
0 0
原创粉丝点击