图片资源加密,Lua文件加密详解
一、游戏开发中的资源保护问题
在游戏开发过程中,资源保护是一个常见的需求。目前,游戏开发中常需要加密的文件类型包括图片、Lua 文件、音频等。然而,加密是一把双刃剑,要实现更高的安全性,就需要消耗一定的资源。虽然网上有使用 TexturePacker 工具进行加密的方法,但这种方法的针对性不够强。
二、加密原理分析
1. 转格式
将需要加密的文件转换为流的形式。
2. 加密
可以根据自身需求选择合适的加密手段,例如 MD5、AES 等,甚至可以通过改变位移、添加特殊字符等方式对文件进行简单加密。加密完成后,图片文件基本无法使用特殊软件预览或打开,Lua 文件则会呈现一片乱码。
3. 保存自定义格式文件
将加密后的文件另存为自定义的文件类型,如 “xx.d”、“xx.xyz” 等。
4. 图片解密
需要修改 cocos2dx 底层库中获取路径的部分,以及加载 CCImage 纹理处理时的源码。
5. 特殊 Lua 文件界面
修改对应的 Lua 加载方法。
三、常用加密方式
转格式并加密的代码实现
bool PublicCommen::recode_getFileByName(string pFileName) {
unsigned long nSize = 0;
unsigned char* pBuffer = CCFileUtils::sharedFileUtils()->getFileData(pFileName.c_str(), "rb", &nSize);
unsigned char* newBuf = new unsigned char[nSize];
int newblen = nSize;
if (pBuffer != NULL && nSize > 0) {
for (int i = 0; i < nSize; i++) {
// 这里的 MD5 应该是一个具体的值或者变量,原代码表述不准确,需要根据实际情况修改
newBuf[i] = pBuffer[i] + MD5;
}
}
string savepath = pFileName;
savepath = savepath.substr(0, savepath.length() - 4);
savepath = savepath + "xx.X";
FILE *fp = fopen(savepath.c_str(), "wb+");
fwrite(newBuf, 1, newblen, fp);
fclose(fp);
CCLOG("save file ok. path = %s", savepath.c_str());
return true;
}
return false;
通常可以编写一个应用程序,遍历自定义目录下需要转换的资源文件,将所有资源进行转换和加密。newBuf[i] = pBuffer[i] + MD5; 这部分可以根据实际需求进行修改,但解密时需要与之对应。
此外,也可以将加密逻辑放入游戏中,修改 Cocos2d - x 底层的 CCFileUtils::fullPathForFilename 方法来获取全路径。
四、解密方法
图片解密
1. 修改 CCTextureCache::addImage 方法
CCTexture2D * CCTextureCache::addImage(const char * path) {
CCAssert(path != NULL, "TextureCache: fileimage MUST not be NULL");
CCTexture2D * texture = NULL;
CCImage* pImage = NULL;
std::string pathKey = path;
pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(pathKey.c_str());
if (pathKey.size() == 0) {
return NULL;
}
texture = (CCTexture2D*)m_pTextures->objectForKey(pathKey.c_str());
std::string fullpath = pathKey;
if (!texture) {
std::string lowerCase(pathKey);
for (unsigned int i = 0; i < lowerCase.length(); ++i) {
lowerCase[i] = tolower(lowerCase[i]);
}
do {
if (std::string::npos != lowerCase.find(".pvr")) {
texture = this->addPVRImage(fullpath.c_str());
} else if (std::string::npos != lowerCase.find(".pkm")) {
texture = this->addETCImage(fullpath.c_str());
} else {
CCImage::EImageFormat eImageFormat = CCImage::kFmtUnKnown;
if (std::string::npos != lowerCase.find(".png")) {
eImageFormat = CCImage::kFmtPng;
} else if (std::string::npos != lowerCase.find(".jpg") || std::string::npos != lowerCase.find(".jpeg")) {
eImageFormat = CCImage::kFmtJpg;
} else if (std::string::npos != lowerCase.find(".tif") || std::string::npos != lowerCase.find(".tiff")) {
eImageFormat = CCImage::kFmtTiff;
} else if (std::string::npos != lowerCase.find(".webp")) {
eImageFormat = CCImage::kFmtWebp;
} else if (std::string::npos != lowerCase.find("XX.X")) {
eImageFormat = CCImage::xxxxx;
}
pImage = new CCImage();
CC_BREAK_IF(NULL == pImage);
bool bRet = pImage->initWithImageFile(fullpath.c_str(), eImageFormat);
CC_BREAK_IF(!bRet);
texture = new CCTexture2D();
if (texture && texture->initWithImage(pImage)) {
#if CC_ENABLE_CACHE_TEXTURE_DATA
VolatileTexture::addImageTexture(texture, fullpath.c_str(), eImageFormat);
#endif
m_pTextures->setObject(texture, pathKey.c_str());
texture->release();
} else {
CCLOG("cocos2d: Couldn't create texture for file:%s in CCTextureCache", path);
}
}
} while (0);
}
CC_SAFE_RELEASE(pImage);
return texture;
}
2. 添加加密后图片类型
在 CCImage 的图片类型中添加加密后的图片类型,如 CCImage::xxxxx。
3. 修改 CCImage::initWithImageFile 方法
bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = eFmtPng*/) {
bool bRet = false;
unsigned long nSize = 0;
unsigned char* pBuffer = CCFileUtils::sharedFileUtils()->getFileData(CCFileUtils::sharedFileUtils()->fullPathForFilename(strPath).c_str(), "rb", &nSize);
if (eImgFmt == xxxxxx) {
for (int i = 0; i < nSize; i++) {
pBuffer[i] = pBuffer[i] - MD5;
}
pBuffer[nSize] = pBuffer[nSize] - 1;
eImgFmt = kFmtPng;
}
if (pBuffer != NULL && nSize > 0) {
bRet = initWithImageData(pBuffer, nSize, eImgFmt);
}
CC_SAFE_DELETE_ARRAY(pBuffer);
return bRet;
}
需要注意的是,pBuffer[i] = pBuffer[i] - MD5; 这部分需要与加密时的操作对应。经过上述修改,只要是自定义类型的图片,都能得到解密后的真实纹理。
Lua 解密
Lua 文件的解密思路与图片基本相同,但需要在加载 Lua 文件的方法前单独进行解密操作,同时要考虑跨平台性。