首先frida的hook代码是通关JavaScript进行实现的,而且调用是通关python进行调用的
如果单独写一个js,就需要通关frida 命令进行启动了
首先聊一下frida的几个常用命令:
所以frida再dos窗口调用test.js 文件hook app如下
frida -U -f app的进程包名 -l test.js -o 窗口输出信息文件 -no-pause
但是习惯用python开发,所以再python中调用,具体如下:
一般其格式如下:
js_hook='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("包名+类名");
// hook 目标方法
clazz.方法名.implementation=function([参数]){
// 对方中的数据进行修改 一般还会再使用 this.方法名 运行程序本身的方法,这样不会影响程序正常运行
}
)
'''
因在python中写多行会方便一些,所以采用字符串多行模式标记:
'''字符串内容'''
Java.perform() :这个是固定写法
Java.use(“包名+类名”) : 也是固定写法 首先找到目标类,才能hook方法
clazz.方法名.implementation=function([参数]){}: 这个也是固定方法
然后再通关两种pyhon进行调用
具体格式如下:
一般会有一个方法
def on_message(message,dada):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
也就是一个监控,注入进程的任何信息。一般的时候,都写上。
import frida,sys
def on_message(message,dada):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
#hook js
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("包名+类名");
// hook 目标方法
clazz.方法名.implementation=function([参数]){
// 对方中的数据进行修改 一般还会再使用 this.方法名 运行程序本身的方法,这样不会影响程序正常运行
}
)
'''
# 启动方式1
process = frida.get_usb_device(-1).attach('app的包名')
script = process.create_script(test)
script.on('message', on_message)
script.load()
sys.stdin.read()
# 启动方式2 spawn 重启APP 可以hook APP启动阶段
device = frida.get_usb_device(-1)
pid = device.spawn(['app的包名'])
process = device.attach(pid)
script = process.create_script(test)
script.on('message', on_message)
script.load()
device.resume(pid)
sys.stdin.read()
格式如下:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("包名+类名");
// hook 目标方法 如果有参数,参数不需要写类型
clazz.方法名.implementation=function([参数]){
// 对方中的数据进行修改 一般还会再使用 this.方法名 运行程序本身的方法,这样不会影响程序正常运行
}
)
'''
来一个例子:
目标代码:
com.xiaozhudi
class A{
public static void testA(){
}
}
hook的js
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("com.xiaozhudi.A");
// hook 目标方法 如果有参数,参数不需要写类型
clazz.testA.implementation=function(){
// 如果是 有返回值 记得使用 return this.方法名()
this.testA();
}
)
'''
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("包名+类名");
// hook 目标方法 如果有参数,参数不需要写类型
clazz.$init.implementation=function([参数]){
}
)
'''
来一个例子:
com.xiaozhudi
class A{
private String a1;
public A (String a1){
this.a1=a1;
}
public String getA1(){
return this.a1
}
}
写的hook js如下:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("com.xiaozhudi.A");
// hook 目标方法 如果有参数,参数不需要写类型
clazz.$init.implementation=function(a1){
// 因为这个是js 所以用console.log 打印数据
console.log('a1参数在实例化时值为',a1) ;
return this.$init('可以传入自己想实例化的值或者使用a1')
}
)
'''
比如这样比如下面B类调用了A类:
com.xiaozhudi
class A{
private String a1;
public A (String a1){
this.a1=a1;
}
public String getA1(){
return this.a1
}
}
class B{
//这个传递的类A
public String getB1 (A a){
return a.getA1();
}
}
如果只是单纯的hookB中的getA1方法可以如下操作:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzzb=Java.use("com.xiaozhudi.B");
clazzb.getB1.implementation=function(a){
// 因为a本身就是一个对象可以可可以直接调用直接的方法
console.log('a1实例化时值为',a.getA1()) ;
return this.getB1(a);
}
)
'''
但是如果如果想修改A的对象可以如下操作,一般对象类中有set方法比如setA1(String a1),但是我估计不写是了为引出另一个关键字$new
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzza=Java.use("com.xiaozhudi.A");
var calzzb=Java.use("com.xiaozhudi.B");
clazzb.getB1.implementation=function(a){
// 因为a本身就是一个对象可以可可以直接调用直接的方法
console.log('a1实例化时值为',a.getA1()) ;
//如果A 有set方法可以如下写:
//a.setA1('新的值');
//return this.getB1(a);
// 估计不写 所以需要这样写 签名也需要得到这个类 var calzza=Java.use("com.xiaozhudi.A");
return this.getB1(calzza.$new('新的值'));
}
)
'''
对于静态的类,不会使用这种方式,对于实例可能就需要中方式了,
得到实例有两种方式:
创建对象:这种需要$new 创建一个新的实例
获得以后的实例,这个就需要Java.choose
具体如下:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzza=Java.use("com.xiaozhudi.A");
var aobject= calzza.choose("com.xiaozhudi.A",{
// 这个里面有两个回调函数 第一个如果找到实例:
onMathch:function(obj){
// 找到了可以进行操作
console.log(obj)
},
// 当然还有一种情况,那就是找不到,这个还是就调用这个方法
onComplete:function(){
console.log('找不到啊')
}
})
)
'''
安卓和java其实溯本同源是一样,所以自然多态的一个特性:方法重载。
简单说,就是一个类中有两个或两个以上的相同方法名的方法,如下:
com.xiaozhudi
class A{
public static void testA(){
}
public static void testA(int a1){
}
}
如果按照java的理解如下写:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("com.xiaozhudi.A");
//
clazz.testA.implementation=function( ){
return this.testA();
}
)
'''
这个不会自动选择调用无参的构造方法,而是会报错:
其中最重要的是:
Error: testA(): has more than one overload,use overload ( < signature > ) to choose from :
.overload()
.overload('int')
…………
不过根据报错,如何hook 有参的testA方法如下:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("com.xiaozhudi.A");
// hook 有参的方法
clazz.testA.overload('int').implementation=function(a){
return this.testA(a);
}
)
'''
最笨的方法,那就是 将所有的重载方法,都写一遍:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("com.xiaozhudi.A");
clazz.testA.overload().implementation=function(){
return this.testA();
}
// hook 有参的方法
clazz.testA.overload('int').implementation=function(a){
return this.testA(a);
}
)
'''
使用循环方式:
需要知道三个点知识:
方法.overloads : 这个返回一个重载方法的数组
在方法体中使用 arguments : 这个是js中常用的一个方式,如果想了解可以看我另一篇文章:https://blog.csdn.net/u011863822/article/details/121062463
还有一个js中可以改变this的关键字apply : 如果了解详情可以看我另一篇文章:https://blog.csdn.net/u011863822/article/details/121255682
因此可以将hook的全部重载方法,如下写:
test='''
Java.perform(
// 也就是增加需要hook的方法所在的类
var calzz=Java.use("com.xiaozhudi.A");
// 得到所有重载方法 返回一个数组
var overload_arr=clazz.testA.overloads;
// 得到数组的长度
var len=overload_arr.length;
for(var i=0;i