下文為各位介紹一個Cocos2d-x Lua/Javascript腳本代碼加密實現例子,有需要的朋友可進入參考。
在游戲開發中,腳本作為一種資源文件,就像圖片視頻一樣,被引擎所引用,使用腳本做游戲的好處就在於可以在線patch更新,特別對於蘋果App Store審核期很長的情況。
如果不對腳本進行加密,不懷好意的人松松解壓出腳本文件,給你瞬間復制一個游戲出來。
1.異或加密解密
最簡單的一種加密方式,雖然簡單,但是也比較實用。但是防破解方面確實一般,如果你有其他嚴格的仿破解需求,可以將這部分加密算法換成你自己的復雜算法,不過保證解密效率。下面是采用C++簡單實現的對文件進行加密之後保存到原文件中(注意對原始未加密文件進行備份)
代碼如下
復制代碼
#include "stdafx.h"
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
void Makecode(char *pstr,int *pkey);
void Cutecode(char *pstr,int *pkey);
void encode_file(char *f);
int _tmain(int argc, _TCHAR* argv[])
{
encode_file("e:/src/ResultScene.lua");
/*
encode_file("e:/src/ReadyScene.lua");
encode_file("e:/src/GameScene.lua");
encode_file("e:/src/PutHeadScene.lua");
encode_file("e:/src/TutorialsScene.lua");
encode_file("e:/src/WordsCategoryScene.lua");
encode_file("e:/src/common/DictHelper.lua");
encode_file("e:/src/common/LJ.lua");
encode_file("e:/src/common/DQueue.lua");
encode_file("e:/src/common/UIHelper.lua");
*/
int c;
cin>>c;
return 0;
}
void encode_file(char *f)
{
FILE *fp = NULL;
fopen_s(&fp, f,"rb");
fseek(fp,0,SEEK_END); //定位到文件末
int nFileLen = ftell(fp); //文件長度
cout << "file len = " << nFileLen << endl;
fseek(fp, 0, SEEK_SET);
char *fileContent = NULL;
fileContent = (char *) malloc ((nFileLen + 1) * sizeof(char));//增加一位
memset(fileContent, 0, nFileLen + 1);
fileContent[nFileLen] = '';//最後一位置為結束位
fread_s(fileContent,nFileLen, 1, nFileLen, fp);
//fread(buf,nFileLen, 1, fp);
//cout<<"解密前:"<<fileContent<<endl;
fclose(fp);
cout<<"文件:"<<f<<endl;
cout<<"解密前文件大小:"<<strlen(fileContent)<<endl;
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *p=fileContent;
cout<<"====="<<endl;
Makecode(fileContent,key);//加密
//cout<<"加密後:"<<p<<endl;
cout<<"加密後文件大小:"<<strlen(fileContent)<<endl;
FILE *stream = NULL;
fopen_s(&stream, f,"wb");
if (stream == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.
");
}
else {
fwrite(p, nFileLen, 1, stream); /* 寫的struct文件*/
fclose(stream); /*關閉文件*/
}
cout<<"====="<<endl;
Cutecode(fileContent,key);//解密
//cout<<"解密後:"<<fileContent<<endl;
}
//單個字符異或運算
char MakecodeChar(char c,int key){
return c=c^key;
}
//單個字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//獲取長度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
2.修改Cocos2d-x引擎中加載lua腳本文件(或者js文件)的入口,在加載的時候對其進行解密。可能不同版本引擎有不同的入口文件,在Cocos2d-x3.0中,對應的是文件Cocos2dxLuaLoader.cpp文件中的int cocos2dx_lua_loader(lua_State *L)方法,對其進行修改成如下:
代碼如下
復制代碼
#include "Cocos2dxLuaLoader.h"
#include <string>
#include <algorithm>
#include<iostream>
using namespace cocos2d;
extern "C"
{
//單個字符異或運算
char MakecodeChar(char c,int key){
return c=c^key;
}
//單個字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//獲取長度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
int cocos2dx_lua_loader(lua_State *L)
{
std::string filename(luaL_checkstring(L, 1));
size_t pos = filename.rfind(".lua");
if (pos != std::string::npos)
{
filename = filename.substr(0, pos);
}
pos = filename.find_first_of(".");
while (pos != std::string::npos)
{
filename.replace(pos, 1, "/");
pos = filename.find_first_of(".");
}
filename.append(".lua");
Data data = FileUtils::getInstance()->getDataFromFile(filename);
if (!data.isNull())
{
//====code decode start==================================
log("===encode filename:%s===", filename.c_str());
//如果filename == 'main.lua',則解密
char *fileContent = (char*)data.getBytes();
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *fileContentDecoded = NULL;
if (strcmp(filename.c_str(),"ReadyScene.lua")==0 ||
strcmp(filename.c_str(),"GameScene.lua")==0 ||
strcmp(filename.c_str(),"PutHeadScene.lua")==0 ||
strcmp(filename.c_str(),"TutorialsScene.lua")==0 ||
strcmp(filename.c_str(),"WordsCategoryScene.lua")==0 ||
strcmp(filename.c_str(),"DictHelper.lua")==0 ||
strcmp(filename.c_str(),"LJ.lua")==0 ||
strcmp(filename.c_str(),"ResultScene.lua")==0 ||
strcmp(filename.c_str(),"DQueue.lua")==0 ||
strcmp(filename.c_str(),"UIHelper.lua")==0 ) {
if (data.getSize() < strlen(fileContent)) {
fileContentDecoded = (char *) malloc ((data.getSize() + 1) * sizeof(char));//增加一位
memset(fileContentDecoded, 0, data.getSize() + 1);
fileContentDecoded[data.getSize()] = '';//最後一位置為結束位
strncpy(fileContentDecoded,fileContent,data.getSize());
fileContent = NULL;
}
else {
fileContentDecoded = fileContent;
}
Cutecode(fileContentDecoded,key);//解密
}
else {
fileContentDecoded = fileContent;
}
//====code decode end==================================
if (luaL_loadbuffer(L, fileContentDecoded, data.getSize(), filename.c_str()) != 0)
{
luaL_error(L, "error loading module %s from file %s :
%s",
lua_tostring(L, 1), filename.c_str(), lua_tostring(L, -1));
}
}
else
{
log("can not get file data of %s", filename.c_str());
}
return 1;
}
}
注意加密解密的key保證一致。
代碼注釋應該挺完善的,不進行解釋了,Enjoy~