开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 1073|回复: 1
收起左侧

[转载教程] [转载]cocos2djsApp dump与hook,成功与失败

[复制链接]
结帖率:88% (22/25)
发表于 2023-7-16 02:31:36 | 显示全部楼层 |阅读模式   广西壮族自治区柳州市
没错,又是cocos2djs,先不要关,先看我道明事情原委。
某好友问我:Cocos2d有办法动态调试嘛
并且给我发了张图


我一看,想当然的,查看引用追回去不就行了。不过嘛,毕竟我比较懒,不想每次都去分析上下文。于是踏上了探索之路。
动态调试?(挨打)
先说结论:不行。除非App本身就是debug编译的,因为cocos打包的过程中不会把debug的js打包进去,虽然编译后的libcocos2djs.so里面包含了enableDebugger这个函数,然并软。
结论说完了,说说我的失败之路:自己建环境编译了个样本,想着用frida在适当的时机主动调用下enableDebugger….(此处省略一大波吐槽and废话)
贴贴Hook的代码:
[color=rgba(0, 0, 0, 0.87)][size=1.25em]function[size=1.25em] [size=1.25em]enableDebugger[size=1.25em]([size=1.25em])[size=1.25em]{[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]   

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] v8Start = Module.[size=1.25em]findExportByName[size=1.25em]([size=1.25em]"libcocos2djs.so"[size=1.25em], [size=1.25em]"_ZN13ScriptingCore5startEv"[size=1.25em])[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] basic_string = Module.[size=1.25em]findExportByName[size=1.25em]([size=1.25em]"libcocos2djs.so"[size=1.25em], [size=1.25em]"_ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcj"[size=1.25em])[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] enableDebuggerPtrs = Module.[size=1.25em]findExportByName[size=1.25em]([size=1.25em]"libcocos2djs.so"[size=1.25em], [size=1.25em]"_ZN2se12ScriptEngine14enableDebuggerERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEjb"[size=1.25em])[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] jsb_enable_debuggerPtrs = Module.[size=1.25em]findExportByName[size=1.25em]([size=1.25em]"libcocos2djs.so"[size=1.25em], [size=1.25em]"_Z19jsb_enable_debuggerRKNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEjb"[size=1.25em])[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]   

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]if[size=1.25em]([size=1.25em]v8Start == [size=1.25em]null[size=1.25em])[size=1.25em] [size=1.25em]{[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        [size=1.25em]// console.log("None evalString ptr");[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        [size=1.25em]setTimeout[size=1.25em]([size=1.25em]enableDebugger, [size=1.25em]5[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        [size=1.25em]return[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]}[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] newstr = [size=1.25em]new[size=1.25em] [size=1.25em]NativeFunction[size=1.25em]([size=1.25em]basic_string, [size=1.25em]"pointer"[size=1.25em], [size=1.25em][[size=1.25em]"pointer"[size=1.25em],[size=1.25em]"pointer"[size=1.25em], [size=1.25em]"int"[size=1.25em]][size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] jsb_enable_debugger = [size=1.25em]new[size=1.25em] [size=1.25em]NativeFunction[size=1.25em]([size=1.25em]jsb_enable_debuggerPtrs, [size=1.25em]"pointer"[size=1.25em], [size=1.25em][[size=1.25em]"pointer"[size=1.25em],[size=1.25em]"pointer"[size=1.25em], [size=1.25em]"int"[size=1.25em]][size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] stdString = Memory.[size=1.25em]alloc[size=1.25em]([size=1.25em]0x100[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]   

[color=rgba(0, 0, 0, 0.87)][size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]var[size=1.25em] strs = Memory.[size=1.25em]allocUtf8String[size=1.25em]([size=1.25em]"0.0.0.0"[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]newstr[size=1.25em]([size=1.25em]stdString, strs, [size=1.25em]0x7[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    Interceptor.[size=1.25em]attach[size=1.25em]([size=1.25em]v8Start, [size=1.25em]{[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        onEnter: [size=1.25em]function[size=1.25em]([size=1.25em]args[size=1.25em])[size=1.25em]{[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]            [size=1.25em]console[size=1.25em].[size=1.25em]log[size=1.25em]([size=1.25em]"ssss"[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]            [size=1.25em]jsb_enable_debugger[size=1.25em]([size=1.25em]stdString, [size=1.25em]new[size=1.25em] [size=1.25em]NativePointer[size=1.25em]([size=1.25em]5123[size=1.25em])[size=1.25em],[size=1.25em]0x0[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        [size=1.25em]}[size=1.25em],

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        onLeave: [size=1.25em]function[size=1.25em]([size=1.25em]arg[size=1.25em])[size=1.25em]{[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]            

[color=rgba(0, 0, 0, 0.87)][size=1.25em]        [size=1.25em]}[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]}[size=1.25em])[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em][size=1.25em]}[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em][size=1.25em]setImmediate[size=1.25em]([size=1.25em]function[size=1.25em]([size=1.25em])[size=1.25em]{[size=1.25em]

[color=rgba(0, 0, 0, 0.87)][size=1.25em]    [size=1.25em]setTimeout[size=1.25em]([size=1.25em]enableDebugger, [size=1.25em]5[size=1.25em])[size=1.25em];

[color=rgba(0, 0, 0, 0.87)][size=1.25em][size=1.25em]}[size=1.25em])

我选择了ScriptingCorestart执行前的时机,主动调用了jsb_enable_debugger,在开启了debug模式的样本中能够成功的将端口从默认的6086转到了5123,然而到了未开启debug的样本中….翻车了
插桩
俗话讲得好,退一步海阔天空(明明是被逼无奈)。我从Android中的smali插桩技术得到启发:是不是可以在jsc文件解密后运行前的时机进行Hook替换?
思路有了,下面动手干。
首先当然是找时机。翻阅了一下Cocos2djs的文档JSB 2.0 使用指南 · Cocos Creator ,jsc文件解密加载的过程就在AppDelegate::applicationDidFinishLaunching中,IDA查看伪代码
很明显,甚至xxtea的key都已经外露。解密后,可以看到加载的时机就在jsb_run_script,一步步跟进去,最终进行加载的时机在se::ScriptEngine::evalString
[color=rgba(0, 0, 0, 0.87)][size=1em][size=1.25em]// attributes: thunk[size=1.25em]

[size=1.25em]int __fastcall se::ScriptEngine::
[size=1.25em]evalString[size=1.25em]([size=1.25em]int a1, int a2, signed int a3, int a4, const char *a5[size=1.25em])[size=1.25em]

[size=1.25em][size=1.25em]{[size=1.25em]

[size=1.25em]  [size=1.25em]return[size=1.25em] [size=1.25em]_ZN2se12ScriptEngine10evalStringEPKciPNS_5ValueES2_[size=1.25em]([size=1.25em]a1, [size=1.25em]([size=1.25em]const char *[size=1.25em])[size=1.25em]a2, a3, a4, a5[size=1.25em])[size=1.25em];

[size=1.25em][size=1.25em]}





翻找了下源代码
[color=rgba(0, 0, 0, 0.87)][size=1em][size=1.25em]// ScriptingCore.h[size=1.25em]

[size=1.25em]
[size=1.25em]/**

[size=1.25em] * will eval the specified string

[size=1.25em] * @param string The string with the javascript code to be evaluated

[size=1.25em] * @param outVal The jsval that will hold the return value of the evaluation.

[size=1.25em] * Can be NULL.

[size=1.25em] */[size=1.25em]

[size=1.25em][size=1.25em]bool[size=1.25em] [size=1.25em]evalString[size=1.25em]([size=1.25em]const[size=1.25em] [size=1.25em]char[size=1.25em] *string, jsval *outVal, [size=1.25em]const[size=1.25em] [size=1.25em]char[size=1.25em] *filename = [size=1.25em]NULL[size=1.25em], JSContext* cx = [size=1.25em]NULL[size=1.25em], JSObject* global = [size=1.25em]NULL[size=1.25em])[size=1.25em];

[size=1.25em]

[size=1.25em]

[size=1.25em][size=1.25em]// ScriptingCore.cpp[size=1.25em]

[size=1.25em][size=1.25em]bool[size=1.25em] ScriptingCore::[size=1.25em]evalString[size=1.25em]([size=1.25em]const[size=1.25em] [size=1.25em]char[size=1.25em] *string, jsval *outVal, [size=1.25em]const[size=1.25em] [size=1.25em]char[size=1.25em] *filename, JSContext* cx, JSObject* global[size=1.25em])[size=1.25em]

[size=1.25em][size=1.25em]{[size=1.25em]

[size=1.25em]    [size=1.25em]if[size=1.25em] [size=1.25em]([size=1.25em]cx == [size=1.25em]NULL[size=1.25em])[size=1.25em]

[size=1.25em]        cx = _cx;

[size=1.25em]    [size=1.25em]if[size=1.25em] [size=1.25em]([size=1.25em]global == [size=1.25em]NULL[size=1.25em])[size=1.25em]

[size=1.25em]        global = _global.[size=1.25em]ref[size=1.25em]()[size=1.25em].[size=1.25em]get[size=1.25em]()[size=1.25em];

[size=1.25em]

[size=1.25em]    JSAutoCompartment [size=1.25em]ac[size=1.25em]([size=1.25em]cx, global[size=1.25em])[size=1.25em];

[size=1.25em]    [size=1.25em]return[size=1.25em] [size=1.25em]JS_EvaluateScript[size=1.25em]([size=1.25em]cx, JS::[size=1.25em]RootedObject[size=1.25em]([size=1.25em]cx, global[size=1.25em])[size=1.25em], string, [size=1.25em]strlen[size=1.25em]([size=1.25em]string[size=1.25em])[size=1.25em], [size=1.25em]"ScriptingCore::evalString"[size=1.25em], 1[size=1.25em])[size=1.25em];

[size=1.25em][size=1.25em]}




string参数就是要执行的js代码,Hook这一函数就能得到相应的代码或进行替换。
[color=rgba(0, 0, 0, 0.87)][size=1em][size=1.25em]function[size=1.25em] [size=1.25em]hook[size=1.25em]([size=1.25em])[size=1.25em] [size=1.25em]{[size=1.25em]

[size=1.25em]    Java.[size=1.25em]perform[size=1.25em]([size=1.25em]function[size=1.25em]([size=1.25em])[size=1.25em]{[size=1.25em]

[size=1.25em]        [size=1.25em]var[size=1.25em] evalString = Module.[size=1.25em]findExportByName[size=1.25em]([size=1.25em]"libcocos2djs.so"[size=1.25em], [size=1.25em]"_ZN2se12ScriptEngine10evalStringEPKciPNS_5ValueES2_"[size=1.25em])[size=1.25em]

[size=1.25em]        [size=1.25em]if[size=1.25em]([size=1.25em]evalString == [size=1.25em]null[size=1.25em])[size=1.25em] [size=1.25em]{[size=1.25em]

[size=1.25em]            [size=1.25em]setTimeout[size=1.25em]([size=1.25em]hook, [size=1.25em]100[size=1.25em])[size=1.25em];

[size=1.25em]            [size=1.25em]return[size=1.25em];

[size=1.25em]        [size=1.25em]}[size=1.25em]

[size=1.25em]        Interceptor.[size=1.25em]attach[size=1.25em]([size=1.25em]evalString, [size=1.25em]{[size=1.25em]

[size=1.25em]            onEnter: [size=1.25em]function[size=1.25em]([size=1.25em]args[size=1.25em])[size=1.25em]{[size=1.25em]

[size=1.25em]                [size=1.25em]var[size=1.25em] codeData = args[size=1.25em][[size=1.25em]1[size=1.25em]][size=1.25em].[size=1.25em]readCString[size=1.25em]([size=1.25em])[size=1.25em];

[size=1.25em]                [size=1.25em]var[size=1.25em] codeSize = args[size=1.25em][[size=1.25em]2[size=1.25em]][size=1.25em];

[size=1.25em]                [size=1.25em]var[size=1.25em] pathName = args[size=1.25em][[size=1.25em]4[size=1.25em]][size=1.25em].[size=1.25em]readCString[size=1.25em]([size=1.25em])[size=1.25em];

[size=1.25em]                [size=1.25em]send[size=1.25em]([size=1.25em]{[size=1.25em]Status:[size=1.25em]"hookOn"[size=1.25em], Data:codeData, Size:codeSize, Path:pathName[size=1.25em]}[size=1.25em])[size=1.25em];

[size=1.25em]            [size=1.25em]}[size=1.25em]

[size=1.25em]        [size=1.25em]}[size=1.25em])[size=1.25em]

[size=1.25em]    [size=1.25em]}[size=1.25em])[size=1.25em]

[size=1.25em][size=1.25em]}[size=1.25em]

[size=1.25em]

[size=1.25em][size=1.25em]setImmediate[size=1.25em]([size=1.25em]function[size=1.25em]([size=1.25em])[size=1.25em]{[size=1.25em]

[size=1.25em]    [size=1.25em]setTimeout[size=1.25em]([size=1.25em]hook, [size=1.25em]10[size=1.25em])[size=1.25em];

[size=1.25em][size=1.25em]}[size=1.25em])





jscHookR
借助frida赋予python与js强大的交互能力,我写了一份脚本。
GitHub
Mas0nShi/jscHookR
a reverse engineering tool for android cocos2d-js engine application.

★ 15


但是,此脚本也有未曾解决的问题:
替换时,不能够申请新的内存空间存放修改的js代码,只能在原来的内存地址上进行修改,导致修改后的文件大小不能超过原文件。这是此脚本最大的缺陷,目前并没有较好的办法解决,如果你有什么建议和思考,欢迎提出issue或联系我。
结语
失败乃成功之母!(无可奈何)
结语Plus
感觉最近写的文章都好水,开始不知道写什么了…让我想想下个月什么时候再写博客(逃了)


出处:https://blog.shi1011.cn/rev/android/1422


结帖率:100% (33/33)
发表于 2023-7-20 13:37:39 | 显示全部楼层   浙江省杭州市
ctrl c v大法好啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表