由于没学习和使用过Cocos2D,但出于工作需要,后面将要学习与使用Cocos2D。 第一次使用修改过的Cocos的时候遇到一些Lua文件是加过密的,不能看到源码,但是又可以正常的被Cocos读取执行,通过对Lua的调试可以看到读取到内存中的源码,由于调试工具的限制,无法直接将这些源码保存到磁盘,当然有一个笨办法,就是将能看到源码的文件一个一个地保存到磁盘,在没有更好的办法之前,也只能这样了。这样做有一个问题,就是如果有更新,又得重新来过,这样下去肯定是不行的。所以必须搞明白Cocos2D是怎么加载执行Lua的。

Lua有以下几个API加载执行:

  • luaL_loadfile直接从文件中加载执行
  • luaL_loadbuffer从内存中加载代码执行
  • luaL_loadstring从一个字符串中加载执行

加过密的Lua文件一般不能直接使用luaL_loadfile来加载执行,那只能是后面两个API了。Cocos2D是开源,下载了一份源码,看了一下其调用Lua的方式确实是通过luaL_loadbuffer来加载执行的,可以看看源码:

 1int CCLuaStack::luaLoadBuffer(lua_State* L, const char* chunk, int chunkSize, const char* chunkName)
 2{
 3    int r = 0;
 4    
 5    if (m_xxteaEnabled && strncmp(chunk, m_xxteaSign, m_xxteaSignLen) == 0)
 6    {
 7        // decrypt XXTEA
 8        xxtea_long len = 0;
 9        unsigned char* result = xxtea_decrypt((unsigned char*)chunk + m_xxteaSignLen,
10                                              (xxtea_long)chunkSize - m_xxteaSignLen,
11                                              (unsigned char*)m_xxteaKey,
12                                              (xxtea_long)m_xxteaKeyLen,
13                                              &len);
14        r = luaL_loadbuffer(L, (char*)result, len, chunkName);
15        free(result);
16    }
17    else
18    {
19        r = luaL_loadbuffer(L, chunk, chunkSize, chunkName);
20    }
21
22#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0
23    if (r)
24    {
25        switch (r)
26        {
27            case LUA_ERRSYNTAX:
28                CCLOG("[LUA ERROR] load \"%s\", error: syntax error during pre-compilation.", chunkName);
29                break;
30                
31            case LUA_ERRMEM:
32                CCLOG("[LUA ERROR] load \"%s\", error: memory allocation error.", chunkName);
33                break;
34                
35            case LUA_ERRFILE:
36                CCLOG("[LUA ERROR] load \"%s\", error: cannot open/read file.", chunkName);
37                break;
38                
39            default:
40                CCLOG("[LUA ERROR] load \"%s\", error: unknown.", chunkName);
41        }
42    }
43#endif
44    return r;
45}

这个函数在执行luaL_loadbuffer之前有一个逻辑处理,看源码一切就明白了。再回过头来看看那些Lua文件,果然最前面都有几个一样的标记,这个标记就是加密标记。

知道了加密的标记和标记的长度是不够的,还必须要有解密的Key,这个Key怎么得到?直接运行用Cocos源码调试?貌似不行,前面说过,我使用的Cocos是修改过的Cocos,只有使用 OllyDbg或者 IDA来进行调试查找了。 网上有一篇文件有讲怎么查找Key: 《Cocos2d-x的lua官方加密的解密方法》,但这篇文章中的查Key方法只适合比较明显的,或者就是碰运气,我曾按这个方法去查Key发现不对。我是通过调试,在调用luaL_loadbuffer函数处和前面不远的地方打断点,通过调试获取到的Key。我这种方法也只适合Lua是在Dll中执行,调用luaL_loadbuffer之前不远的地方调用xxtea_decrypt,如果是两个差得比较远或者是把Lua链接进主程序也不行。

知道Key了就好写解密程序了,直接把Cocos中的xxtea_decrypt函数拿出来解即可,也可以去 https://github.com/cocos2d/cocos2d-x-3rd-party-libs-bin/tree/v3/xxtea下载。