Frida用于生产部署实践
Frida用于生产部署实践----续作(Frida-Inject)
此文为这篇文章的续作,在前文中,生产部署时除了手机外,还要有一台另外的设备用于rpc交互(前文用的是树莓派)。在本文中,我们将使用frida-inject去实现满足生产需要的部署。
一、准备工作
- 安卓设备 真机或模拟器都可,需要root权限
- frida-inject模块
- 用于hook的 js脚本
- 目标app
没错,只需要上述资源即可完成,成功部署之后可以完全脱离PC去使用。
二、开始部署
将frida-inject和js脚本推送到手机,例如/data/local/tmp目录中
frida-inject下载地址,注意不要下错了,根据自己设备的cpu架构选择对应的版本,如下图,我的设备是arm64架构的,就是下图圈出来这个。下载完之后先解压,里面的文件才是我们需要的,这一点和frida-server相同,熟悉frida 的朋友应该不会搞错。
接着给frida-inject和js脚本赋予可执行权限,即:
//frida inject模块
chmod 777 frida-injetmodule
//xxx.js为你的jshook脚本
chmod 777 xxx.js
然后,运行即可
//fi1422-arm64为frida-inject模块 我这里重新命名了
//pkgname为需要hook的目标app包名
//xxx.js为hook脚本
./fi1422-arm64 -f pkgname -s xxx.js
确认启动没有问题后(如有问题查看下文),再使用nohup命令使其在后台运行,代码如下:
nohup ./fi1422-arm64 -f pkgname -s xxx.js --runtime=v8 -e &
三、问题解决
1.启动失败
需要注意的是,部分设备首次执行这条命令会自动重启,属于正常现象,待重启完毕之后再次执行即可。如果出现目标app崩溃且多次重试无效时,尝试修改js代码,延迟启动,如下:
//xxxx为hook代码
//延迟时间根据实际情况调整
setTimeout(xxxx,1000);
如果上述操作之后还是无法使用,则修改命令,在目标app启动之后再attch,将-f 替换成-n即可,如下
./fi1422-arm64 -n pkgname -s xxx.js --runtime=v8 -e
2.原生js功能欠缺
由于去掉了python部分,所以的功能都需要用js去实现,但是原生js对例如http请求的功能支持比较差,而有时我们的确需要这些功能。解决这一问题,有两个笔者认为比较合适的方法:
1).使用frida-compile
使用frida-compile,可以将js代码打包成frida能够执行的样式,同时也支持typescript
安装
npm install frida-compile
打包
frida-compile -o output.js input.js
但是实际使用过程中,由于需要用到网络请求,便引入了axios这个模块,打包完毕后执行报错,而用于加解密的crpyto模块则正常,由此可见frida-compile可能有一些bug,由于本人并非专攻js方向,因此没有继续研究而是采用了其他方法。
2).使用hook方式
以okhttp为例,以下代码既可以简单的发送get、post请求
function sendbyokhttp(url, postdata) {
try {
var OkHttpClient = Java.use('okhttp3.OkHttpClient').$new();
var requestbuild = Java.use('okhttp3.Request$Builder').$new();
var request;
if (postdata == undefined || postdata == "" || postdata == null) {
request = requestbuild.url(url).build();
} else {
var body = Java.use('okhttp3.RequestBody').create(Java.use('okhttp3.MediaType').parse('application/json'), postdata);
request = requestbuild.url(url).post(body).build();
}
var response = OkHttpClient.newCall(request).execute();
var result = response.body().string();
log("http request:" + url)
log("http response:" + result)
return result;
} catch (error) {
log(error)
}
return "fail";
}
使用这种方式的优点是不需要用js去发送请求,打包的代码体积也大大减少,缺点就是不同的app可能使用的是不同的http请求框架,有的或许也有混淆,导致无法找到正确的hook目标。部分场景可能因为hook位置在主线程而导致发送http请求报错,这时可以使用异步方法,使用frida去注册一个实现Callback的类即可,代码如下:
var MyCallbBack = null;
function sendbyokhttpasync(url, postdata) {
try {
if (MyCallbBack == null) {
//注册callback
MyCallbBack = Java.registerClass({
name: 'okhttp3.MyCallbBack ',
implements: [Java.use('okhttp3.Callback')],
methods: {
onFailure(call, e) {
log("请求失败:" + e.getMessage());
},
onResponse(call, re) {
log("请求完毕:" + re.request().url().toString());
var re = re.body().string();
log("http request:" + re);
}
}
});
}
if (OkHttpClient == "" || OkHttpClient == null) {
OkHttpClient = Java.use('okhttp3.OkHttpClient').$new();
}
var requestbuild = Java.use('okhttp3.Request$Builder').$new();
var request;
if (postdata == undefined || postdata == "" || postdata == null) {
request = requestbuild.url(url).build();
} else {
var body = Java.use('okhttp3.RequestBody').create(Java.use('okhttp3.MediaType').parse('application/json'), postdata);
request = requestbuild.url(url).post(body).build();
}
var callbackins = MyCallbBack.$new();
OkHttpClient.newCall(request).enqueue(callbackins);
} catch (error) {
log(error)
}
return failmessage;
}
3.外部调用
笔者在做手上的项目时暂时没有此需求,但是有两种思路,1.即是用node模块起一个http服务,使用frida-compile打包之后随hook代码一同注入到目标app中。2.用java实现一个http服务,编译成dex文件,然后用frida去加载这个dex文件来开启http服务。在局域网环境下,设置端口转发即可局域网访问。如果需要外网访问,配置内网穿透即可。
四、总结
frida-inject与上一篇文章中的rpc方法相比,硬件上只需要一台安卓设备,软件上剔除了python模块,删除了rpc通讯,整套系统复杂度降低,稳定性大大提升。