autojs(后面简称aj)是一款基于rhino引擎依赖无障碍进行自动点击操作的安卓APP,类似电脑上的按键精灵,不过功能更加强大,可以打包为独立的APP。因此有许多人在使用它开发一些小程序,免去了AndroidStudio复杂的开发流程。
但是本来aj对源码的保护并不强,于是很多人为了防止别人获取源码,有了加密的需求,先是出现了庖丁用于编译为dex进行加密,后面aj官方也推出了dex加密与快照加密。
Dex加密
将js编译为直接操作rhino运行的java字节码,运行效率高,且不易被还原为js源代码。
快照加密
将js编译为只可被rhino解析运行的二进制字节码,这个加密比较新颖,所以很难找到现成的工具对其进行有效分析还原。
前言
刚开始接触aj的时候是玩游戏,某位好友使用aj去执行一些简单的重复操作,然后知道js可以被编译为dex很是新奇,便开始研究其中的原理。
在对比了多个js的源代码与编译结果后,发现了一些规律,开始尝试对其进行还原。刚开始并不会AST,在还原了一些dex为等价js,逐渐熟练java与js的AST后,继续攻克了快照的还原。
还原过程
所需工具
[ol]
rhino(需与autojs内置版本一致,可从apk提取)
javaparser
rhino源码
idea或eclipse
[/ol]
创建样本
source.jpg (15.91 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
由于只是说明原理,就不创建过于复杂的了,容易看到眼花。
pack.jpg (24.98 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
在这里,分别使用dex与快照进行加密。
Dex样本提取
package.jpg (29.59 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
将apk内的classes.dex提取出来,用MT打开提取的classes.dex,找到这个包名。
pure.jpg (13.45 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
选中这个包名,然后反选删掉多余的类,得到纯粹带js逻辑的dex。
dex_example.png (12.07 KB, 下载次数: 0)
下载附件
2021-7-18 09:54 上传
快照样本提取
snapshot_dump.jpg (17.64 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
将apk中/assets/project目录整个复制出来。
pao.jpg (40.77 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
为了节省时间,使用庖丁的兼容方式对其进行第一层的解密。
snapshot_content.jpg (92.05 KB, 下载次数: 0)
下载附件
2021-7-18 10:23 上传
样本
examples.png (15.92 KB, 下载次数: 0)
下载附件
2021-7-18 09:50 上传
Dex加密还原
java.png (13.3 KB, 下载次数: 0)
下载附件
2021-7-18 09:51 上传
先使用jadx等反编译器将其反编译为java。
java_analysis.png (103.38 KB, 下载次数: 0)
下载附件
2021-7-18 09:51 上传
经过分析,call方法为脚本入口点,_c_script_0为脚本根节点,正则表达式被放置在_reInit方法内动态初始化。
dex_code.png (269.8 KB, 下载次数: 0)
下载附件
2021-7-18 09:51 上传
分析完毕后,便开始模拟运行过程,缓存全局变量、正则表达式、函数id映射表(多函数时出现,call中将出现大型switch),通过递归解析java的AST同步生成js的AST,即可得到一个完整的js。
快照加密还原
如何解析快照,可参考我之前的文章
dumpICode.png (115.46 KB, 下载次数: 0)
下载附件
2021-7-18 09:53 上传
使用dumpICode之后,可以看到如上字节码信息,js被编译之后只有顺序与跳转两种运行逻辑,类似汇编。在与源代码对照之后,可以大概分析出每个语句块的含义(已在图中标注)。
至于如何还原字节码为js代码,首先必定是需要先拼凑出一个完整的AST,最终选定的方法为模拟解释器运行,栈的存储内容改为AST节点。
snapshot_code.png (214.52 KB, 下载次数: 0)
下载附件
2021-7-18 09:55 上传
由此进行不断地入栈出栈,即可拼凑出一个完整的AST,最终生成结果与dex没有任何区别。
结束语
随着变量与函数的增加,实际情况远比样本复杂得多(例如dex会出现大量多余的逻辑,快照会出现很多跳转与偏门的字节码),知道原理之后其实大同小异,只是如何优化的问题。
由于并不清楚所有指令对应的结构,这两种加密的还原都没法一步到位,只能通过多种js的源码与加密后的指令进行对照一步步完善。(或许有大佬能直接对照rhino的编译部分写)
本人并非专业逆向爱好者,llvm和antlr等汇编工具根本不会,刚开始AST都不会,整个过程都是从零开始瞎鼓捣出来的,恕本人才疏学浅,请各位大佬轻喷。