js 写hook格式

首先frida的hook代码是通关JavaScript进行实现的,而且调用是通关python进行调用的

如果单独写一个js,就需要通关frida 命令进行启动了

首先聊一下frida的几个常用命令:

  • -U:连接USB设备。
  • -F:附加最前面的应用。
  • -f:主动启动进程。
  • -l:加载script脚本文件。
  • -o:输出日志。
  • -no-pause:启动主线程运行应用。

所以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()

hook 各种方法

hook 静态方法或者实例方法

格式如下:

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();
   
   }

  )

'''

hook 构造方法

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')
   
   }

  )

'''
hook的方法 参数是一个对象

比如这样比如下面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('新的值')); 
   
   }

  )

'''
补充 :对已有的对象查找 Java.choose

对于静态的类,不会使用这种方式,对于实例可能就需要中方式了,

得到实例有两种方式:

  • 创建对象:这种需要$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('找不到啊')
         
       }
         
         }) 
     
    
    
      )
    
    '''
    

hook 重载方法

安卓和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);
   
   }

  )

'''
hook 所有的重载方法
  • 最笨的方法,那就是 将所有的重载方法,都写一遍:

    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<len;i++){
             overload_arr[i],implementation=function(){
               // 如果想知道参数的每个值可以如下操作
               var params="";
               for(var j=0;j<arguments.length;j++){
                   params+=arguments[j]+"   "
                   }
               console.log('调用的参数值是',params) 
               // 这里如果还需要运行正确的方法可以如下
               
               this.testA.apply(this,arguments)
               
             }
    
         }
      
       
       }
    
      )
    
    
    
    '''
    

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐