主要内容:
frida-gadget持久化研究
frida-gumjs脚本持久化研究
frida-inject脚本持久化研究
frida-gadget是一个动态共享库,可以在App中加载该动态库然后执行js代码功能。
frida-gadget动态库下载地址:
https://github.com/frida/frida/releases/tag/14.2.15
根据官方介绍,在Android中App中可以重打包方式将frida-gadget动态库放到lib下面对应的平台目录,然后编写对应的配置文件。例如我的一个Demo Apk,使用apktool反编译之后。可以像如下操作将frida-gadget动态库添加进去,并配置执行指定的脚本。参考如下:
# arm64-v8a加入对应的arm64-v8a版本的libfrida-gadget.so
DemoApp/lib/arm64-v8a/libfrida-gadget.so
DemoApp/lib/arm64-v8a/libfrida-gadget.config.so
# armeabi-v7a加入对应的armeabi-v7a版本的libfrida-gadget.so
DemoApp/lib/armeabi-v7a/libfrida-gadget.so
DemoApp/lib/armeabi-v7a/libfrida-gadget.config.so
libfrida-gadget.config.so中配置的内容如下:
{
"interaction": {
"type": "script",
"path": "/sdcard/test.js"
}
}
将以上内容配置到apk中之后,还需要将加载frida-gadget动态库的代码插入到App的启动代码中。由于Android App中启动首先执行Application相关类,所以可以通过反编译找到Applicatoin相关的类,然后插入如下smali代码进去。插入的加载动态库代码如下:
# direct methods
.method static constructor <clinit>()V
.registers 1 .prologue
.line 10
const-string v0, "frida-gadget"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
.line 11
return-void
.end method
根据以上frida-gadget重打包实现加载js的思路,可以在安卓系统源码中按照如下思路实现一个加载js的方案。
方案思路:
(1).寻找系统源码中App启动加载的合适时机加载frida-gadget动态库
安卓系统中App启动的时候主入口为ActivityThread.java。可以在该文件中找到一个合适的时机加载frida-gadget动态库,为了达到更好的hacking效果,最好在Application的attachBaseContext执行之前加载。比如该文件中handleBindApplication方法是一个不错的选择。
(2).在frida-gadaget动态库存放的目录同时添加相应的脚本配置规则文件
比如frida-gadget动态库文件名libtestgadget.so,那么需要在相同目录下面创建文件libtestgadget.config.so文件,并将如下内容加入(内容中的path值根据自己的脚本路径设置):
{
"interaction": {
"type": "script",
"path": "/sdcard/test.js"
}
}
该方案主要解决的问题:
(1).frida-gadget动态库集成到系统
(2).App读写权限配置,比如有权限读取配置的js文件路径
该方案参考项目:
https://github.com/hanbinglengyue/FridaManager
frida-gumjs是frida中核心模块frida-gum的脚本执行接口封装。以下是frida整个架构图:
从以上架构中分析出平时PC端使用frida 命令执行执行App脚本加载的时候,实际上在App端加载了一个frida-agent-64.so或者frida-agent-32.so动态库,该动态库中使用了frida-gumjs封装的接口来执行js内容。官方提供了libfrida-gumjs.a的下载,可以下载集成到App工程中使App直接调用对应的接口来执行js脚本。下载地址:
https://github.com/frida/frida/releases/tag/14.2.15
比如frida-gumjs中提供的一个接口:
//source参数指定了执行的js脚本内容
GUM_API GumScript * gum_script_backend_create_sync (GumScriptBackend * self,
const gchar * name, const gchar * source, GCancellable * cancellable,
GError ** error);
从以上接口可以看出直接调用接口执行js脚本非常的方便。
有了frida-gumjs提供的接口,可以设计如下的一个方案来进行系统中App的持久化运行。
方案如下:
(1).将frida-gumjs链接到开发的动态库中,并提供封装jni接口,提供Java api对外调用。
(2).将开发的动态库以及提供的Java api接口集成到系统
(3).在Android App启动入口ActivityThread.java中找一个合适的位置调用开发的Java api接口,传入配置的js文件路径
该方案主要解决的问题:
(1).frida-gumjs封装为Java api接口
(2).系统集成开发的so以及Java api
(3).App读写权限配置,比如有权限读取配置的js文件路径
frida-gumjs集成接口封装开发参考项目:
https://github.com/svengong/xcubebase
frida-inject是一个可执行程序,执行的时候可以传入进程pid以及执行的js文件路径实现对app js载入。使用frida-inject需要超级Root权限。在之前我们已经实现了通过socket连接到超级Root权限进程中去执行命令。所以系统中只需要在App入口的地方找到合适的调用点,将要执行的命令通过socket连接发送到超级Root权限进程执行,从而实现js载入。
frida-inject持久化方案:
在App入口ActivityThread.java中找到一个调用点,比如函数handleBindApplication方法。然后socket连接到超级Root权限去执行frida-inject命令。
该方案主要解决的问题:
(1).frida-injec集成到系统
(2).开发配置超级Root权限后台进程
(3).封装socket连接超级Root进程的Java Api接口
Application**方法。然后socket连接到超级Root权限去执行frida-inject命令。
该方案主要解决的问题:
(1).frida-injec集成到系统
(2).开发配置超级Root权限后台进程
(3).封装socket连接超级Root进程的Java Api接口