主要分为两种加密方式:
一:修改cocos引擎中的代码,修改解密函数
Cocos2dxLuaLoader文件中的解密函数
extern "C"
{
int cocos2dx_lua_loader(lua_State *L)
{
static const std::string BYTECODE_FILE_EXT = ".luac";
static const std::string NOT_BYTECODE_FILE_EXT = ".lua";
std::string filename(luaL_checkstring(L, 1));
size_t pos = filename.rfind(BYTECODE_FILE_EXT);
if (pos != std::string::npos)
{
filename = filename.substr(0, pos);
}
else
{
pos = filename.rfind(NOT_BYTECODE_FILE_EXT);
if (pos == filename.length() - NOT_BYTECODE_FILE_EXT.length())
{
filename = filename.substr(0, pos);
}
}
pos = filename.find_first_of(".");
while (pos != std::string::npos)
{
filename.replace(pos, 1, "/");
pos = filename.find_first_of(".");
}
// search file in package.path
unsigned char* chunk = nullptr;
ssize_t chunkSize = 0;
std::string chunkName;
FileUtils* utils = FileUtils::getInstance();
lua_getglobal(L, "package");
lua_getfield(L, -1, "path");
std::string searchpath(lua_tostring(L, -1));
lua_pop(L, 1);
size_t begin = 0;
size_t next = searchpath.find_first_of(";", 0);
do
{
if (next == std::string::npos)
next = searchpath.length();
std::string prefix = searchpath.substr(begin, next);
if (prefix[0] == '.' && prefix[1] == '/')
{
prefix = prefix.substr(2);
}
pos = prefix.find("?.lua");
chunkName = prefix.substr(0, pos) + filename + BYTECODE_FILE_EXT;
if (utils->isFileExist(chunkName))
{
chunk = utils->getFileData(chunkName.c_str(), "rb", &chunkSize);
break;
}
else
{
chunkName = prefix.substr(0, pos) + filename + NOT_BYTECODE_FILE_EXT;
if (utils->isFileExist(chunkName))
{
chunk = utils->getFileData(chunkName.c_str(), "rb", &chunkSize);
break;
}
}
begin = next + 1;
next = searchpath.find_first_of(";", begin);
} while (begin < (int)searchpath.length());
if (chunk)
{
LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
stack->luaLoadBuffer(L, (char*)chunk, (int)chunkSize, chunkName.c_str());Decode in here
free(chunk);
}
else
{
CCLOG("can not get file data of %s", chunkName.c_str());
return 0;
}
return 1;
}
}
解密用的是游戏开始时的加密方式
LuaStack* stack = engine->getLuaStack();
stack->setXXTEAKeyAndSign("2dxLua", strlen("2dxLua"), "XXTEA", strlen("XXTEA"));
注意:有个局限性,在非android平台下调用pEngine->executeScriptFile是不调用loader的,只有require这种才会调用loader。也就是说你直接executeScriptFile("main.lua")这个脚本不能加密,main.lua里面require的才能加密
第二种方式:直接修个Lua源码,在加载文件的时候,对文件进行解密
lua底层加载文件的函数
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
LoadF lf;
int status, readstatus;
int c;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
lf.extraline = 0;
if (filename == NULL) {
lua_pushliteral(L, "=stdin");
lf.f = stdin;
}
else {
lua_pushfstring(L, "@%s", filename);
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
c = getc(lf.f);
if (c == '#') { /* Unix exec. file? */
lf.extraline = 1;
while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */
if (c == '\n') c = getc(lf.f);
}
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
/* skip eventual `#!...' */
while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
lf.extraline = 0;
}
ungetc(c, lf.f);
status = lua_load(L, getF, &lf, lua_tostring(L, -1));
readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */
if (readstatus) {
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
return errfile(L, "read", fnameindex);
}
lua_remove(L, fnameindex);
return status;
}
每当要加载新的lua文件时都会调用luaL_loadfile,当执行status = lua_load(L, getF, &lf, lua_tostring(L, -1))时传入了一个函数getF,j就是将文件的内容读取到内存中,getF就是一个函数指针
static const char *getF (lua_State *L, void *ud, size_t *size) {
LoadF *lf = (LoadF *)ud;
(void)L;
if (lf->extraline) {
lf->extraline = 0;
*size = 1;
return "\n";
}
if (feof(lf->f)) return NULL;
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
DeCode(lf->buff, *size); -- 在这个地方加上解密的函数,加载出的数据就是解密之后的数据
return (*size > 0) ? lf->buff : NULL;
}
补充一点:在对文件进行解密的时候注意文件的编码格式,UTF-8的有文件头,进行加密后就自动变成将文件头也加密了,变成了不是UTF-8的格式,最好统一用ASII的文本,不然会出现格式错误的问题