Frida Hook初探
前置
安装环境
想要快乐地进行frida hook,就需要先准备好一部安卓机(最好是真机)和adb环境,这一部分就不细说了。
安装frida的话,先在https://github.com/frida/frida/releases
找好一个版本,然后下载手机对应架构的frida-server
比如我这里是
所以选择下载了frida-server-16.0.1-android-arm64
然后使用adb push ./frida-server-16.0.1-android-arm64 /data/local/tmp/
将这个binary传到手机里
这样就是上传成功了,要用的时候只需要在adb起的shell中cd过去然后运行一下就行了(记得给运行权限)
在PC端用pip装一下frida这个库(frida版本要和安卓上的一样)
pip install frida-16.0.1.dev7-cp34-abi3-win_amd64.whl
pip install frida-tools
装好之后可以frida-ps -U
测试一下
这样就是正常工作了
测试环境
简单测试一下脚本的使用
- test.py
import frida
# print(frida.__version__)
device = frida.get_usb_device()
session = device.attach(22576)
print(device)
print(session)
with open("./hook.js") as f:
script = session.create_script(f.read())
script.load()
input()
- hook.js
console.log("hook success!")
Java.perform(
function x(){
console.log("Inside java perform function")
}
)
- 运行结果
利用
对原有方法进行覆盖
例题001
NewstarCTF上的一题,先把apk装到安卓机上
adb install ./apk.apk
浅浅运行一下
发现貌似逻辑不在MainActivity
里,jadx打开果然发现了FlagActivity
所以需要指定加载到这里面来运行,在adb起的shell中执行
am start -n com.droidlearn.activity_travel/com.droidlearn.activity_travel.FlagActivity
然后就能看到进入了这个地方,但是需要点击10000次才能拿到flag,有点小离谱()
这里就可以用到frida来hook一下这个方法了
FlagActivity
的源码在jadx中可以看到是这样的(图片不清楚的话可以放大看)
其中比较重要的片段是
...
private int cnt = 0;
static int access$004(FlagActivity flagActivity) {
int i = flagActivity.cnt + 1;
flagActivity.cnt = i;
return i;
}
...
public void onCreate(Bundle bundle) {
...
public void onClick(View view) {
textView.setText(Integer.toString(FlagActivity.access$004(FlagActivity.this)));
if (FlagActivity.this.cnt >= 10000) {
Toast.makeText(FlagActivity.this, editText.getText().toString(), 0).show();
}
}
...
}
每次监听到点击事件过后,就会使用access$004
方法对cnt
变量进行递增,并打印在屏幕上
那么我们可以hook到java层,重新实现access$004
这个方法,让返回值直接大于10000
- hook.js
Java.perform(
function () {
console.log("Inside java perform function");
console.log("process pid = " + Process.id);
var my_class = Java.use("com.droidlearn.activity_travel.FlagActivity");
//console.log(my_class.access$004)
my_class.access$004.implementation= function (x){
console.log("cnt=" + x.cnt.value);
x.cnt.value = 10001;
console.log("cnt=" + x.cnt.value);
return 10001;
}
}
);
- exp.py
import frida
device = frida.get_usb_device()
session = device.attach(4180)
print(device)
print(session)
with open("./hook.js") as f:
script = session.create_script(f.read())
script.load()
input()
成功修改cnt为10001,拿到flag
通过类名获取实例
例题001-REsolve
这里使用Java.choose(完整类名)
的方法来解例题001
- hook.js
// Java.perform方法:当 js 附加到目标的进程中时被执行,运行其中定义的函数
// Java.choose方法:通过完整类名,获取它的实例,从而对实例中的数据进行修改
// onMatch 对应的函数在命中一个实例的时候被调用,传入函数中的参数 instance 就是被命中的实例
// onComplete 函数会在所有实例遍历完毕之后被调用,可以做一些后续处理操作
Java.perform(
function () {
console.log("Inside java perform function");
console.log("process pid = " + Process.id);
var my_class = Java.use("com.droidlearn.activity_travel.FlagActivity");
//console.log(my_class.access$004)
// my_class.access$004.implementation= function (x){
// console.log("cnt=" + x.cnt.value);
// x.cnt.value = 10001;
// console.log("cnt=" + x.cnt.value);
// return 10001;
// }
Java.choose("com.droidlearn.activity_travel.FlagActivity",{
onMatch:function(instance){
console.log("cnt = " + instance.cnt.value);
instance.cnt.value = 114514;
console.log("cnt = " + instance.cnt.value);
},
onComplete:function(){
console.log("finish")
}
});
}
);
- exp.py
import frida
device = frida.get_usb_device()
session = device.attach(4180)
print(device)
print(session)
with open("./hook.js") as f:
script = session.create_script(f.read())
script.load()
input()
依然可以成功