对于经常做游戏安全逆向的读者来说,可能会经常遇到Cocos2dx编写的游戏。这个国产开源的游戏开发引擎支持多种编程语言进行游戏开发:发括主流的C/C++/JavaScript/Lua,之前,与大家讨论的Lua软件安全系列的文章,讨论的是采用Cocos2dx+Lua开发的游戏。而今天要聊的是基于JavaScript开发的游戏Cocos2dx+js。
初步分析
研究逆向先看正向,这通常是一个好的出发点。
jsc游戏打包流程
我们下载好Cocos2dx,这里选择的是cocos2d-x-3.16版本。安装配置好后,执行如下命令:
本人使用的分析与开发平台是macOS 10.12系统,其他平台的读者可能需要调事路径参数。命令执行完成后,会生成一个JavaScript的游戏工程test_jsc_cocos2dx。效果如图所示:
可以执行如下命令查看项目中有很多js源文件:
命令以树的形式显示目录层次,”-f”参数显示完整的路径;工具用来正式表达式方式过滤结果,“[.]js$”表示js扩展名的文件;表示只输出结果的前10行。输出效果如图所示:
我这里选择macOS平台进行编译,执行如下命令:
效果如图所示:
当然,你也可以选择更直观的IDE方式进行编译,使用Xcode打开文件,选择js-tests Mac进行编译即可。如图所示:
编译完成会在test_jsc_cocos2dx/MyJSGame/simulator/mac目录下生成MyJSGame-desktop.app游戏程序。并自动运行,如图所示:
我们来看看生成的MyJSGame-desktop.app游戏程序里面的代码,执行如下命令:
效果如图所示:
你看到的没错,默认生成的游戏程序的js文件是没有加密的,需要手动生成jsc。执行可以看到如下输出:
是一个有用的命令行选项,支持将js编译成jsc。执行下面的命令生成jsc:
效果如图所示:
执行下面的命令查看是否生成成功:
效果如图所示:
很好很可以!一切都没有问题。执行如下面命令将未加密的js源文件删除:
完事以后,双击MyJSGame-desktop.app游戏程序,可以运行起来,没事没问题!
以上演示了完整的Cocos2dx+JavaScript创建与打包jsc游戏的完整过程。下面看看这些生成的jsc文件吧!
jsc反编译探索
我们来看下游戏的main.jsc文件。执行如下命令:
效果如图所示:
显然这是一个特定格式的十六进制文件!
在实际逆向分析过程中,遇到这类程序,该如何动手分析与破解呢这是一个值得思考的问题。
带着试一试的心态,在 络上搜索jsc反编译工具。结果找到了这个仓库:https://github.com/molnarg/dead0007。
编译好程序,执行反编译,提示:”[no source]”。
看来是失败了, 络上有 友的解释如下:
这种说法是否成立,还需要自己动手验证,但打算直接从 络上找工具这条路是失败了!
SpiderMonkey
查看dead0007.c文件中关于反编译相关的代码。代码不长,直接帖出来:
代码首先调用初始化JS环境;接着调用创建一个上下文环境;然后调用创建一个全局对象; 然后调用加载JS标准类;然后调用、、等函数生成内存script对象; 最后,调用进行反编译工作,然后调用获取反汇编的结果。
这一系列的流程,即使没有进行过Spidermonkey相关的接口调用开发,也能够从这些API的调用上,初步了解jsc反编译工作的流程。显然,是最重要的一环,由它完成所有的反编译工作。
到 上找到Spidermonkey的代码地址:https://github.com/cocos2d/Spidermonkey,下载下来后,查看它的源码。执行如下命令查找它的实现代码:
结果如图所示:
JS_DecompileScript
的实现代码位于js/src/jsapi.cpp文件中,实现如下:
看到“[no source]”了,发现当判断失败就返回这个值,看来与上面 友回复的是一样了。
可能也是一个需要注意的函数,它的代码如下:
内部调用了,后者的代码也需要搜一搜。执行如下命令:
结果如图所示:
实现代码位于js/src/jsfun.cpp文件中。代码比较长,我这里精减后的流程如下:
反汇编函数成功的前提是执行返回为真,即这个函数包括script,取出来后,还有这么一行:
当的值为真时,表示函数里面包括了程序打包时的源码,然后检查,只有包含了源码数据,故事才会往下演!可以看到,Spidermonkey反编译功能本质上只是取打包进jsc文件的源码数据!这与反编译关系本质上已经不大了!
那Cocos2dx编译出的jsc不能反编译,显然是打包时没有包括源码进jsc。这一点我们可以通过跟踪jsc代码的编译流程来验证。
jsc代码编译流程
Cocod2dx中关于jscompile的调用插件,位于cocos2d-x-3.16/tools/cocos2d-console/plugins/plugin_jscompile,它的底层是调用其目录下的bin/jsbcc程序来编译js脚本。后者在发布时以二进制形式打包进来,可以通过如下的Github PR记录看到它的实现代码:https://github.com/cocos2d/cocos2d-x/pull/2706/commits/96721466341d6e7e43087e7d8d4e31f5922062b2。
它的核心代码位于函数,精减代码如下:
负责处理JavaScript代码,在内存中生成好script对象;然后调用来编码生成jsc文件。值得注意的的编译选项options的设置有如下一行代码:
也就是编译的时候,不包含上代码,这意味着生成的jsc在反编译的时候,只会返回”[no source]”。
JS_DecodeScript
既然是表示将script脚本编译成二进制的jsc,那会不会有一个函数用来解码二进制呢根据函数名相关的原则,在jsapi.h中搜索,果不其然,有这么一个函数,而且还发现了另外一个函数,从名字上就可以判断它能完成jsc的反汇编工作。那么调用试试看吧。
编写代码函数如下:
然后编写一个,创建一个CMakeLists.txt文件,代码如下:
这代码看上去很正规,但编译运行,跑起来直接“code 11”返回错误!这让人揪心,难道接口没使用对吗
换个姿势,再写个测试代码:
同样的编译运行,直接“code 11”返回错误!别问我代码为什么是这么写,我 上抄的!别人给的代码就是这样,但跑不起来。于是,还是只能继续 上找怎么用这些接口们,因为它们的参数太多太细了,又没有文档。最终,我在https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/How_to_embed_the_JavaScript_engine这里发现了玄机!
奇葩的是,这SpiderMonkey每次更新都换接口!接口参数没设置对就得Die!我拿官 的样例代码进行测试,分别测试了31与38版本,当使用31版本时,代码能正常跑起来了。
使用解码指令后,还需要调用来反汇编代码。接下来,我在jsapi.cpp文件中添加了一个反汇编函数,它的代码如下:
下面是运行跑起来成功的效果:
仍需努力
到这里,jsc反编译工具编写的探索之路就暂时结束了。最后,我们完成了jsc文件的反汇编功能,但没有实现反编译功能,要基于jsc的机器码实现反编译功能是一个高级的话题,希望以后有机会与大家一起探讨这其中的原理与开发技术。
文章精美排版PDF与代码,小密圈会员可以在知识星球:【软件安全与逆向分析】(ID: 86753808)中下载。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!