Frida在安装时容易出现网络状况,两个小建议
- 使用镜像源,不要用豆瓣源
- 先pip install frida-tools --user,因为tools会一并尝试安装frida
Frida在环境搭建中会遇到各种问题
一、Frida版本问题
- 由于frida版本更新极快,不断修复bug,不断增加新特性,因此建议使用较新版本的server,较新版本的frida,较新版本的frida-tools。
- 手机上的server版本和电脑上的frida版本不一致也没关系,可以正常运行,但尽量一致。
- 在必要的时候使用pyenv,virtualenv等版本管理工具。即每个项目给予单独的Frida版本和环境,这样可以避免许多烦恼。比如Objection的最新版就因为相关原因不支持frida-tools的最新版,因此如果没有使用注入Pyenv一类的版本管理工具,就只能Objection/Frida-tools二选一版本降级。
二、编写Frida脚本相关问题
-
Frida编写脚本时无智能提示,这个真的很烦,严重影响开发体验,我们可以通过Frida官方提供的方案解决。首先需要电脑上有nodejs以及npm环境,新版的nodejs似乎自带npm,如果不在环境变量里就加上去,如图方式检测是否配置好环境。
需要注意的是,由于国内的网络状况,后续install很容易失败,这里建议使用阿里的cnpm镜像。命令行输入如下,安装好了就可以使用cnpm install xxx来替代npm install进行js依赖的下载了。
> npm install -g cnpm --registry=https://registry.npm.taobao.org
其次需要一个智能IDE,建议Webstorm,Jetbrain家的东西总是好用的。我们需要clone或者下载这个项目,在Webstorm中打开这个文件夹,terminal里cnpm install。(不用Webstorm的朋友可以直接在命令行终端里cd到相应文件夹)
一切就绪,在agent目录下编写的javascript/typescript代码就将拥有Frida相关api的智能提示。你可以以如下代码进行测试。function frida_Java() { Java.perform(function () { //作为判断用 if(Java.available) { //注入的逻辑代码 console.log("hello java vm"); }else{ //未能正常加载JAVA VM console.log("error"); } }); } setImmediate(frida_Java,0);
除此之外,它可以帮我们做更多的事。
agent目录中新建一个文件夹test,编写test1.js内容如下
var a = "测试var定义变量"; console.log(a); const b = "测试const定义变量"; console.log(b); let c = "测试let定义变量"; console.log(c);
根据ES6规范,Js中定义变量的方法由单一的 var 方式发展到了 var、let、const 三种之多。我们在Webstorm中测试一下。
启动手机上的frida server,将这个脚本随便注入一个应用,我这里注入了百度新闻。
可以发现,这里报了语法错误。注释掉let的两行,代码顺利运行。
即Frida的引擎只支持var,const这两种变量声明。如果我们使用别人的Frida脚本,无法运行,就可以看一下是否存在变量未定义或者使用let的情况。我们再编写test2.js,测试一下其他语法。let func = value => value+1; console.log(func(6));
这是ES6的箭头表达式,用于方便的定义函数,它等同于如下代码。
var func = function (value) { return value+1; };
Webstorm中运行顺利,我们试一下Frida
又是语法错误,Frida的引擎无法使用ES6很多方便的特性。除此之外,Typescript也是不被支持的。
Typescript是Javascript的超集,它增加了静态类型检查,这样你就能在运行代码之前发现错误了,更适合构建项目,很多基于Frida二次开发的项目都有Typescript的身影。
但Frida的Js引擎似乎不支持Ts,新建demo3.ts,编写ts代码如下,如果你想在WebStorm中运行,需要配置WebStorm Typescript环境。我们这里直接尝试Frida注入,同样报语法错误。
我们用三个demo说明了Frida的JS引擎似乎有很多缺陷,阻挠我们更高效的构建项目,可以开始谈谈Frida的JS运行引擎。Frida有两个Javascript运行引擎——Duktape和V8,原本使用的脚本引擎是V8,V8引擎功能完备,支持ES6诸多特性,但由于Frida曾经存在的一些问题,所以采用了Duktape引擎作为默认脚本引擎,Duk相比V8,缺失了非常多的Es6特性,比如箭头表达式,let等,没法充分释放JS的威力,但我们可以切换为V8,只需要在注入脚本时指定引擎“–runtime=v8/duk”。
但除此之外,我们还有更好的解决方案——frida-compile,它是解决问题的最好办法。
图来自https://www.slideshare.net/ssusercf6665/frida-107244825,这是一份关于Frida全面而深入的PPT资料。我们当前所处的模块已经配置了frida-compile,我们可以直接使用。
代码必须编写在index.ts中
Terminal运行npm run watch,它会监控代码修改,自动调用frida-compile,在目录中生成_agent.js,这个js脚本无需指定–runtime=v8,就可以被顺利的注入设备。
可以注意到,编译后得到的_agent.js代码,相比原先复杂了很多,而且可读性下降,但let被转成了var,可以被Frida的duk引擎识别。为什么npm run watch可以做到这样的事呢?实际上npm run watch 命令指的是监视项目的变化,具体怎么操作在于package.json中的定义,我们看一下。
我们是否能自己运行frida-compile呢,比如编译自己的脚本,或者编译别人的项目?只写在index.js中,或者每次修改package.json还是挺麻烦的,来试一下吧。
命令行或者任意Terminal中输入:cnpm install frida-compile -g cnpm install frida-compile
接下来我们就可以在任意位置compile项目了,格式如下
frida-compile agent -o _agent.js -w
agent:需要编译的脚本的路径,可不加文件后缀
_agent.js:编译后输出文件,可自由命名
-w:watch模式,持续检测原脚本改动并重新编译
三、调试Frida脚本
调试可以帮助我们检查脚本是否有误,又可以用于分析Frida源码实现。我们还是用这个简单的Frida脚本用于演示
function frida_Java() {
Java.perform(function () {
//作为判断用
if(Java.available)
{
//注入的逻辑代码
console.log("hello java vm");
}else{
//未能正常加载JAVA VM
console.log("error");
}
});
}
setImmediate(frida_Java,0);
启动时加上**–debug --runtime=v8**,两者缺一不可。
打开chrome浏览器,输入网址 chrome://inspect/#devices
稍等片刻,Remote Target会连接我们的Python进程,端口号并不一致,但不用管,我们点击inspect。
选择我们编写的脚本即可,后续debug操作应该大家都懂。
可能有的人会问,如果我基本都是通过Python脚本的方式运行Frida,那该如何操作?其实也一样,如果你想切换引擎,只需要修改runtime=“v8” 或者session.enable_jit(),如果想要debug,就再加上session.enable_debugger()。
import time
import frida
device = frida.get_usb_device(10)
session = device.attach("com.baidu.news")
session.enable_debugger()
# session.enable_jit()
with open("debugMyScript.js", encoding='UTF-8') as f:
script = session.create_script(f.read(), runtime="v8")
script.load()
input()
Python脚本方式debug更多细节参考这篇文章https://bbs.pediy.com/thread-254695.htm
我个人不建议使用Python+JS混合脚本方式Hook,Frida的Cli客户端实在是太丝滑了,JS脚本太好用了。