Frida Hook方法1

简单使用入门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 推送到服务器
adb root
adb push frida-server-17.24.3-android-x86_64 /data/local/tmp
adb shell

# 启动frida服务端
cd /data/local/tmp
chmod 755 frida-server-17.24.3-android-x86_64 /data/local/tmp
./frida-server-17.24.3-android-x86_64 /data/local/tmp

# adb建立端口映射
# frida-server 启动后,默认监听127.0.0.1:27042

# 情况一:USB 直连(`frida -U`)—— 不需要端口映射
frida-ps -U
验证是否能列出进程

# 情况二:网络连接(`frida -H`)—— 需要端口映射或直连
# 建立转发:PC 的 27042 → 设备的 27042
adb forward tcp:27042 tcp:27042

adb -s 127.0.0.1:16416 forward --list
通过本地 27042 端口连接设备上的 Frida-server
frida-ps -H 127.0.0.1:27042

基础语法

API名称 描述
Java.use(className) 获取指定的Java类并使其在JavaScript代码中可用。
Java.perform(callback) 确保回调函数在Java的主线程上执行。
Java.choose(className, callbacks) 枚举指定类的所有实例。
Java.cast(obj, cls) 将一个Java对象转换成另一个Java类的实例。
Java.enumerateLoadedClasses(callbacks) 枚举进程中已经加载的所有Java类。
Java.enumerateClassLoaders(callbacks) 枚举进程中存在的所有Java类加载器。
Java.enumerateMethods(targetClassMethod) 枚举指定类的所有方法。

日志输出

日志方法 描述 区别
console.log() 使用JavaScript直接进行日志打印 多用于在CLI模式中,console.log()直接输出到命令行界面,使用户可以实时查看。在RPC模式中,console.log()同样输出在命令行,但可能被Python脚本的输出内容掩盖。
send() Frida的专有方法,用于发送数据或日志到外部Python脚本 多用于RPC模式中,它允许JavaScript脚本发送数据到Python脚本,Python脚本可以进一步处理或记录这些数据。

常用API

hook框架模板

1
2
3
4
5
6
7
function main(){
Java.perform(function(){
hookTest1();
});
}
setImmediate(main);

  1. Hook普通方法、打印参数和修改返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//定义一个名为hookTest1的函数
function hookTest1(){
//获取一个名为"类名"的Java类,并将其实例赋值给JavaScript变量utils
var utils = Java.use("类名");
//修改"类名"的"method"方法的实现。这个新的实现会接收两个参数(a和b).implementation 是它的一个属性,专门用来替换方法体。
utils.method1.implementation = function(a, b){
//将参数a和b的值改为123和456。
a = 123;
b = 456;
//调用修改过的"method"方法,并将返回值存储在`retval`变量中
var retval = this.method1(a, b);
//在控制台上打印参数a,b的值以及"method"方法的返回值
console.log(a, b, retval);
//返回"method"方法的返回值
return retval;
}
}
  1. Hook重载参数
    这里需要注意,hook重载函数的时候需要加overload指定,不知道也可以直接运行,frida的报错会给出提示。
1
2
3
4
5
6
7
8
9
10
11
12
// .overload()        
// .overload('自定义参数')
// .overload('int')
function hookTest2(){
var utils = Java.use("com.zj.wuaipojie.Demo");
//overload定义重载函数,根据函数的参数类型填
utils.Inner.overload('com.zj.wuaipojie.Demo$Animal','java.lang.String').implementation = function(a,b){
b = "aaaaaaaaaa";
this.Inner(a,b);
console.log(b);
}
}
  1. Hook构造函数
1
2
3
4
5
6
7
8
9
function hookTest3(){
var utils = Java.use("com.zj.wuaipojie.Demo");
//修改类的构造函数的实现,$init表示构造函数
utils.$init.overload('java.lang.String').implementation = function(str){
console.log(str);
str = "52";
this.$init(str);
}
}
  1. Hook字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function hookTest5(){
Java.perform(function(){
//静态字段的修改
var utils = Java.use("com.zj.wuaipojie.Demo");
//修改类的静态字段"flag"的值
utils.staticField.value = "我是被修改的静态变量";
console.log(utils.staticField.value);
//非静态字段的修改
//使用`Java.choose()`枚举类的所有实例
Java.choose("com.zj.wuaipojie.Demo", {
onMatch: function(obj){
//修改实例的非静态字段"_privateInt"的值为"123456",并修改非静态字段"privateInt"的值为9999。
obj._privateInt.value = "123456"; //字段名与函数名相同 前面加个下划线
obj.privateInt.value = 9999;
},
onComplete: function(){

}
});
});

}
  1. Hook内部类
1
2
3
4
5
6
7
8
9
10
11
function hookTest6(){
Java.perform(function(){
//内部类
var innerClass = Java.use("com.zj.wuaipojie.Demo$innerClass");
console.log(innerClass);
innerClass.$init.implementation = function(){
console.log("eeeeeeee");
}

});
}
  1. 枚举所有的类与类的所有方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function hookTest7(){
Java.perform(function(){
//枚举所有的类与类的所有方法,异步枚举
Java.enumerateLoadedClasses({
onMatch: function(name,handle){
//过滤类名
if(name.indexOf("com.zj.wuaipojie.Demo") !=-1){
console.log(name);
var clazz =Java.use(name);
console.log(clazz);
var methods = clazz.class.getDeclaredMethods();
console.log(methods);
}
},
onComplete: function(){}
})
})
}
  1. 枚举所有方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function hookTest8(){
Java.perform(function(){
var Demo = Java.use("com.zj.wuaipojie.Demo");
//getDeclaredMethods枚举所有方法
var methods =Demo.class.getDeclaredMethods();
for(var j=0; j < methods.length; j++){
var methodName = methods[j].getName();
console.log(methodName);
for(var k=0; k<Demo[methodName].overloads.length;k++){
Demo[methodName].overloads[k].implementation = function(){
for(var i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
return this[methodName].apply(this,arguments);
}
}
}
})
}
  1. 主动调用
    静态方法
1
2
var ClassName=Java.use("com.zj.wuaipojie.Demo"); 
ClassName.privateFunc("传参");

非静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
var ret = null;
Java.perform(function () {
Java.choose("com.zj.wuaipojie.Demo",{ //要hook的类
onMatch:function(instance){
ret=instance.privateFunc("aaaaaaa"); //要hook的方法
},
onComplete:function(){
//console.log("result: " + ret);
}
});
})
//return ret;

FridaHook辅助算法分析

  1. 找到一些疑似关键函数,可以通过hook来确认app执行某个操作的时候,是否调用了它们
  2. 如果没有触发这些函数,考虑以下问题
    1. app在执行这个操作的时候,真的没有调用这个函数,换一个其他的关键函数
    2. 代码写错了,导致hook函数没执行,比如.implementation写成了.implementations,不报错,但是不执行。
    3. 一般可以通过主动调用上层函数,来触发这些hook函数
  3. 如果触发了这些函数,可以通过hook来打印执行过程中传入函数的参数和返回值
  4. frida -U -F -I HookDemo.js-U代表远程USB设备-F代表附加到最前的这个app-|后面指明需要加载的S脚本
  5. 写好的js脚本要注入手机端,并不是在Node.js中使用,所以只能用v8和fridaAPI支持的代码

Hook可以做什么

可以用来判断app执行某个操作的时候,是否经过我们的怀疑的这个函数
可以用来修改被hook函数的运行逻辑
可以用来在运行过程中,获取被hook的函数传入的具体的参数和返回值
可以用来主动调用app中的某些函数

作者

纹云

发布于

2026-11-07

更新于

2026-11-07

许可协议

豫ICP备2023004969号-2 | 公安备案 川公网安备51010702042859号