在遊戲開發中,腳本作爲一種資源文件,就像圖片視頻一樣,被引擎所引用,使用腳本做遊戲的好處就在於可以在線patch更新,特別對於蘋果App Store審覈期很長的情況。如果不對腳本進行加密,不懷好意的人鬆鬆解壓出腳本文件,給你瞬間複製一個遊戲出來。
自己寫的小遊戲沒有必要用太複雜的加密方式,最簡單的一種就是利用cocos提供的一種加密方式 luacompile加密
1. 打開terminal cd 到cocos2d-x引擎bin 目錄 ---我的目錄 /Users/apple/Documents/cocos2d-x-3.8.1/tools/cocos2d-console/bin
2.運行 cocos luacompile -s /Users/apple/Desktop/Project/.../src/app -d /Users/apple/Documents/123 -e -k key -b sign --disable-compile
-s :需要加密的文件跟目錄
-d :加密後的文件路徑
-k 和-b:加密的密鑰
--disable-compile 標示簡單用XXTEA加密 對於簡單的小遊戲加密這足夠了也避免了支持64bit的問題
3.替換加密後的文件 ------------打包上線
注: key 和sign
在app delegate文件裏設置key和sign
LuaStack* stack = engine->getLuaStack();
stack->setXXTEAKeyAndSign("key........", strlen("key........."), "sign.......", strlen("sign......"));
這一句的第二和第四個參數都是前一個參數的長度,並不是固定值,可以自己指定
最後需要注意的是: 編譯發佈程序的時候要記得把源代碼文件夾從項目中移除(不是刪除,只是不包含進項目裏),不然一切都白費了 。
到此整個過程結束,我們的代碼已經被很好的保護起來了。
還有一種方式比較複雜,前面的已經能加密成功了後面這種方式就沒再測試了,有興趣可以測試一下
最簡單的一種加密方式,雖然簡單,但是也比較實用。但是防破解方面確實一般,如果你有其他嚴格的仿破解需求,可以將這部分加密算法換成你自己的複雜算法,不過保證解密效率。下面是採用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; } } |