查看: 21|回复: 0

[公众号] fridahookjava

[复制链接]

1

主题

0

回帖

0

积分

积极分子

金币
0
阅读权限
220
精华
0
威望
0
贡献
0
在线时间
0 小时
注册时间
2010-4-13
发表于 2021-9-16 18:57:00 | 显示全部楼层 |阅读模式

目录
  • Frida 启动
    • attach 启动
    • spawn 启动
  • frida-server 自定义端口
    • frida server
    • frida
    • python
  • Frida rpc 远程调用
    • python
    • js
    • 压力测试
    • nps 进行内网穿透
  • Hook 普通方法
  • Hook 重载方法
  • Hook 构造方法
  • Hook 对象
  • Hook 动静态成员属性
  • Hook 内部类
  • Hook 匿名类
  • Hook 类的所有方法
  • Hook 类的所有方法及重载
  • Hook 动态加载的 dex
  • Hook 主动构造数组
  • Hook cast 强制类型转换
  • Hook 打印类实现的接口
  • Hook enum 枚举
  • Hook 获取 context
  • Hook 主动调用构造方法
  • Hook 主动调用静态方法
  • Hook 主动调用动态方法
  • Hook frida 和 python 交互
  • Hook 打印 char
  • Hook 打印 char 数组
  • Hook 打印和修改 HashMap
  • Hook 打印 byte 数组
  • Hook 打印调用栈
  • Hook gson 打印
  • Hook 打印 non-ascii 和特殊字符
  • 简易 wallbreaker 内存打印
  • hook frida 实现 runnable
  • Hook 监控控件 onClick
  • Hook startActivity
  • Hook frida 绕过 root 检测
  • Hook frida 强制在主线程运行
  • Hook frida 指定方法中过滤打印
  • Hook 禁止 app 退出
  • Hook 修改设备参数
  • Hook 打印请求调用栈
  • Hook UI thread 注入
  • 常用打印转换

Frida 启动

attach 启动

直接附加到指定包名的应用中

BASH
frida -U com.kevin.android -l hook.js --no-pause

直接附加到当前应用中

BASH
frida -UF -l hook.js --no-pause
import sys
import time
import frida

def on_message(message,data):
    print("message",message)
    print("data",data)

device = frida.get_usb_device()
session = device.attach("com.kevin.demo1")

with open("./demo1.js","r") as f:
    script = session.create_script(f.read())

script.on("message",on_message)
script.load()
sys.stdin.read()

spawn 启动

BASH
frida -U -f com.kevin.android -l demo1.js --no-pause
import sys
import time
import frida

def on_message(message,data):
    print("message",message)
    print("data",data)

device = frida.get_usb_device()
pid = device.spawn(["com.kevin.demo1"])
device.resume(pid)
session = device.attach(pid)

with open("./rpc_demo.js",'r') as f:
    script = session.create_script(f.read())

script.on("message",on_message)
script.load()

sys.stdin.read()

frida-server 自定义端口

frida server

更改 frida server 默认端口: 27042 并开启远程连接

BASH
adb shell
su -
cd /data/local/tmp

# 输入 wifiadb 对应的 ip 和自定义端口
./frida-server -l 192.168.0.1:6666

# 也可以使用默认端口启动
./frida-server -l 192.168.0.1

frida

frida 远程连接自定义端口

BASH
# 连接指定 6666 端口
frida -H 192.168.0.1:6666 com.demo1.app -l demo1.js

# 默认使用端口 27042
frida -H 192.168.0.1 -l demo1.js

python

PYTHON
# -*- coding: UTF-8 -*-

import frida, sys

jsCode = """
console.log("test");
"""

def message(message, data):
    if message['type'] == 'send':
        print(f"
  • {message['payload']}") else: print(message) # ./fs120800 -l "0.0.0.0:6666" # adb wifi 10.0.0.23 process = frida.get_device_manager().add_remote_device('127.0.0.1:6666').attach('com.kevin.app') script = process.create_script(jsCode) script.on("message",message) script.load() input()
  • Frida rpc 远程调用

    python

    PYTHON
    import frida
    import json
    from flask import Flask, jsonify, request
    
    def message(message, data):
    	if message['type'] == 'send':
    		print(f"
  • {message['payload']}") else: print(message) # ./fs120800 -l "0.0.0.0:6666" # adb wifi 10.0.0.123 # 远程 frida-server 路径 adb wifi 的 ip : frida-server 启动的端口 session = frida.get_device_manager().add_remote_device('10.0.0.123:6666').attach('com.example.demoso1') with open("/Users/zhangyang/codes/fridaProject/rpcDemo/hook.js") as f: jsCode = f.read() # print("加载代码", jsCode) script = session.create_script(jsCode) script.on("message",message) script.load() # print("加密","1213") # encodeResult = script.exports.invokemethod01("123") # decodeResult = script.exports.invokemethod02(encodeResult) # print(decodeResult) app = Flask(__name__) @app.route('/encrypt', methods=['POST'])#data解密 def decrypt_class(): data = request.get_data() json_data = json.loads(data.decode("utf-8")) postdata = json_data.get("data") res = script.exports.invokemethod01(postdata) return res @app.route('/decrypt', methods=['POST'])#url加密 def encrypt_class(): data = request.get_data() json_data = json.loads(data.decode("utf-8")) postdata = json_data.get("data") print(postdata) res = script.exports.invokemethod02(postdata) return res if __name__ == "__main__": app.run()
  • js

    JSX
    ///<reference path='/Users/zhangyang/node_modules/@types/frida-gum/index.d.ts'/>
    
    // 先 hook 方法 method01
    // function hookmethod1(){
    //     Java.perform(function(){
    //         var targetClass = Java.use("com.example.demoso1.MainActivity");
    //         targetClass.method01.implementation = function(str){
    //             console.log("str is ", str);
    //             var result = this.method01(str);
    //             console.log("result is ", result);
    //             return result;
    //         }
    //     })
    // };
    
    // 主动调用
    function fridamethod01(inputStr){
        var result = null;
        Java.perform(function(){
            var targetClass = Java.use("com.example.demoso1.MainActivity");
            result = targetClass.method01(inputStr);
        });
        return result;
    }
    
    function fridamethod02(inputStr){
        var result = null;
        // public native String method02(String str);
        Java.perform(function(){
            Java.choose("com.example.demoso1.MainActivity",{
                onMatch: function(ins){
                    result = ins.method02(inputStr);
                },
                onComplete: function(){}
            })
        });
        return result;
    }
    
    // 优先测试 js 中的主动调用
    // function main(){
    //     console.log("你好 -> 结果为:", fridamethod01("你好"));
    //     console.log("27cae29a0913f6791705ca10be31a3e0 -> 结果为", fridamethod02("27cae29a0913f6791705ca10be31a3e0"))
        
    // }
    // setImmediate(main);
    
    // 基于主动调用设置 rpc
    rpc.exports = {
        invokemethod01: fridamethod01,
        invokemethod02: fridamethod02,
    }
    

    压力测试

    tmp.json

    JSON{"data": "62feb9a98a01945ab06c0dd7823adc57"}
    

    命令

    BASHsiege -c30 -r1 "<http://127.0.0.1:5000/encrypt> POST < tmp.json"
    

    nps 进行内网穿透

    1. nps server 启动

      mac: sudo nps start

    2. 新建客户端

      https://kevinspider-1258012111.cos.ap-shanghai.myqcloud.com/2021-01-14-032324.png

      安卓手机连接客户端 ./npc -server=10.0.0.124:8024 -vkey=hm40rtjpf2j3c1up -type=tcp

    3. 给客户端添加和 frida server 的端口映射

      安卓手机启动 frida-server: ./fs12800 -l 0.0.0.0:6666

      https://kevinspider-1258012111.cos.ap-shanghai.myqcloud.com/2021-01-14-032703.png

      将目标 frida-server 的端口映射到 56666 端口上

    4. python 脚本更改和 frida-server 的连接

      PYTHONsession = frida.get_device_manager().add_remote_device('10.0.0.124:56666').attach('com.example.demoso1')
      

      此时就可以将 frida-server 开放到公网了;

    Hook 普通方法

    function main(){    
      Java.perform(function(){        
        var UtilsClass = Java.use("com.kevin.app.Utils");        
        UtilsClass.getCalc.implementation = function (a,b){        	
          // 打印信息	        
          console.log('a:' + a + ' ' + 'b:' + b);    	    
          // 调用原方法获取结果        	
          var value = this.getCalc(a, b);	        
          console.log('result:',value);            
          // 修改返回值    	   
          return 123456;           
        }    
      })
    }
    setImmediate(main);
    

    Hook 重载方法

    function main(){    
      Java.perform(function(){        
        var UtilsClass = Java.use("com.kevin.app.Utils");
        // 重载无参方法       
        UtilsClass.test.overload().implementation = function () {            
          console.log("hook overload no args");            
          return this.test();       
        }                
        // 重载有参方法 - 基础数据类型		
        UtilsClass.test.overload('int').implementation = function(num){            
          console.log("hook overload int args");            
          var myNum = 9999;            
          var oriResult = this.test(num);            
          console.log("oriResult is :" + oriResult);            
          return this.test(myNum);       
        }                
        // 重载有参方法 - 引用数据类型        
        UtilsClass.test.overload('com.kevin.app.Money').implementation = function(money){
          console.log("hook Money args"); 
          return this.test(money);
        }                
        // hook 指定方法的所有重载        
        var ClassName = Java.use("com.xiaojianbang.app.Utils");
        var overloadsLength = ClassName.test.overloads.length;
        for (var i = 0; i < overloadsLength; i++){
          ClassName.test.overloads.implementation = function () {                
            // 遍历打印 arguments                 
            for (var a = 0; a < arguments.length; a++){
              console.log(a + " : " + arguments[a]);
            }                
            // 调用原方法                
            return this.test.apply(this,arguments);            
          }        
        }   
      })
    }
    setImmediate(main);
    

    Hook 构造方法

    function main(){    
      Java.perform(function (){
        // hook 构造方法 $init 
        var MoneyClass = Java.use("com.kevin.app.Money");
        MoneyClass.$init.overload().implementation = function(){            
          console.log("hook Money $init");            
          this.$init();        }    
      })
    }
    setImmediate(main);
    

    Hook 对象

    function main(){    
      Java.perform(function(){        
        // hook instance        
        Java.choose("com.xiaojianbang.app.Money",{            
          onMatch : function(instance){                
            console.log("find it!!", instance.getInfo());
            // something to do...           
          },onComplete: function(){
            console.log("compelete!!!");
          }        
        })    
      })
    }
    setImmediate(main);
    

    Hook 动静态成员属性

    function main(){    
      Java.perform(function(){        
        var MoneyClass = Java.use("com.xiaojianbang.app.Money"); 
        // get static properties 
        // need to use .value 
        var ori_property = MoneyClass.flag.value;        
        console.log("ori_property: ", ori_property); 
        // change static properties         
        MoneyClass.flag.value = "change the value";       
        console.log("change to : ", MoneyClass.flag.value);                
        // get dynamic properties         
        Java.choose("com.xiaojianbang.app.Money",{            
          onMatch: function(instance){                
            instance.num.value = 50000;                
            // 当对象的成员属性和成员方法名重复时,成员属性前加`_`,进行区分
            instance._name.value = "ouyuan";
            console.log(instance._name.value, instance.num.value, instance.flag.value);
          },onComplete: function(){ 
            console.log("complete!!")
          }        
        })    
      })
    }
    setImmediate(main);
    

    Hook 内部类

    function main(){   
      Java.perfor(function(){
        // hook 内部类
        // 内部类使用$进行分隔 不使用.  
        var InnerClass = Java.use("com.xiaojianbang.app.Money$innerClass"); 
        // 重写内部类的 $init 方法        
        InnerClass.$init.overload("java.lang.String","int").implementation = function(x,y){ 
          console.log("x: ",x);            
          console.log("y: ",y);
          this.$init(x,y); 
        }   
      })
    }setImmediate(main)
    

    Hook 匿名类

    // 接口, 抽象类, 不可以被new
    // 接口, 抽象类 要使用必须要实例化, 实例化不是通过new, 而是通过实现接口方法, 继承抽象类等方式
    // new __接口__{} 可以理解成 new 了一个实现接口的匿名类, 在匿名类的内部(花括号内),实现了这个接口
    function main(){    
      Java.perform(function(){
        // hook 匿名类        
        // 匿名类在 smail中以 $1, $2 等方式存在, 需要通过 java 行号去 smail 找到准确的匿名类名称         
        var NiMingClass = Java.use("com.xiaojianbang.app.MainActivity$1");        
        NiMingClass.getInfo.implementation = function (){           
          return "kevin change 匿名类";       
        }   
      })
    }
    setImmediate(main)
    

    Hook 类的所有方法

    • Java.enumerateLoadedClasses()
    function main(){    
      Java.perform(function(){        
        Java.enumerateLoadedClasses({ 
          onMatch: function(name,handle){   
            if (name.indexOf("com.xiaojianbang.app.Money") != -1){ 
              console.log(name,handle);
              // 利用反射 获取类中的所有方法
              var TargetClass = Java.use(name); 
              // return Method Object List
              var methodsList = TargetClass.class.getDeclaredMethods();
              for (var i = 0; i < methodsList.length; i++){
                // Method Objection getName()
                console.log(methodsList.getName()); 
              }                
            }            
          },
          onComplete: function(){
            console.log("complete!!!")
          }
        })
      })}
    
    • Java.enumerateLoadedClassesSync()
    function main(){    
      Java.perform(function(){ 
        // return String[] class name 
        var classList = Java.enumerateLoadedClassesSync(); 
        for (var i=0; i < classList.length; i++){            
          var targetClass = classList;            
          if (targetClass.indexOf("com.xiaojianbang.app.Money") != -1){
            console.log("hook the class: ", targetClass);
            var TargetClass = Java.use(targetClass);
            // 利用反射获取类中的所有方法
            var methodsList = TargetClass.class.getDeclaredMethods();
            for (var k=0; k < methodsList.length; k++){
              console.log(methodsList[k].getName());
            }                          
          }       
        }   
      })
    }
    setImmediate(main)
    

    Hook 类的所有方法及重载

    function main(){    
      Java.perform(function(){        
        // hook md5 class in app        
        // 1. iterate classes
        var classList = Java.enumerateLoadedClassesSync();
        for (var i = 0; i < classList.length; i++){
          // 筛选过滤 只遍历 MD5 下面的方法
          if (classList.indexOf("com.xiaojianbang.app.MD5") != -1){
            var className = classList;
            console.log("class name is :", className);
            // 2. get methods of the class
            // 返回一个 Methods对象的数组
            var methodsList = Java.use(className).class.getDeclaredMethods();
            for (var k=0; k<methodsList.length; k++){
              console.log("method is :",methodsList[k],typeof(methodsList[k]));
              // 3. Method object.getName() --> methodName and class[methodName] to hook method 
              var methodName = methodsList[k].getName(); 
              console.log('methodName',methodName); 
              // 4. use apply and arguments to implementation
              var hookClass = Java.use(className);
              // 5. overloads                   
              for (var o = 0; o< hookClass[methodName].overloads.length; o++){
                hookClass[methodName].overloads[o].implementation = function(){
                  for (var a=0; a<arguments.length; a++){
                    console.log('argument ',a,arguments[a]);
                  }                            
                  // return this[methodName].apply(this,arguments);
                  return "fucking the md5"                        
                }                    
              }                
            }            
          }        
        }    
      })
    }
    

    Hook 动态加载的 dex

    function main(){    
      Java.perform(function(){
        Java.enumerateClassLoaders({
          onMatch : function(loader){ 
            try {                    
              // loadClass or findClass
              if (loader.loadClass("com.xiaojianbang.app.Dynamic")){
                Java.classFactory.loader = loader;
                var hookClass = Java.use("com.xiaojianbang.app.Dynamic");    
                console.log("success hook it :", hookClass); 
                // something to do;
              }                
            } catch (error) {
              // pass               
            }
          }, 
          onComplete: function () {               
            console.log("complete !!! ")
          }       
        })    
      })
    }
    setImmediate(main);
    

    经常在加壳的 app 中, 没办法正确找到正常加载 app 类的 classloader, 可以使用以下代码:

    function hook() {    
      Java.perform(function () {
        Java.enumerateClassLoadersSync().forEach(function (classloader) { 
          try {
            console.log("classloader", classloader);
            classloader.loadClass("com.kanxue.encrypt01.MainActivity");                
            Java.classFactory.loader = classloader;                
            var mainActivityClass = Java.use("com.kanxue.encrypt01.MainActivity");
            console.log("mainActivityClass", mainActivityClass);
          } catch (error) {                
            console.log("error", error);
          }        
        });    
      })
    }
    

    Hook 主动构造数组

    function mainArray(){    
      Java.perform(function(){
        var myCharList = Java.array("char",['一','去','二','三','里']);
        var myStringList = Java.array("java.lang.String",["一","二","三"]);
        var ArrayClass = Java.use("java.util.Arrays");
        console.log(ArrayClass.toString(myCharList));       
        console.log(ArrayClass.toString(myStringList));   
      })
    }
    

    Hook cast 强制类型转换

    // Java.cast() 子类可以强转成父类, 父类不能转成子类
    // 可以使用Java.cast()将子类强转成父类, 再调用父类的动态方法
    function castDemo(){    
      Java.perform(function(){        
        var JuiceHandle = null; 
        // 用来存储内存中找到的Juice对象        
        var WaterClass = Java.use("com.r0ysue.a0526printout.Water");                     Java.choose("com.r0ysue.a0526printout.Juice",{	
          onComplete: function(){},            
          onMatch: function(instance){
            JuiceHandle = instance;
            console.log("instance:", instance);
            // 调用Juice对象的方法               
            console.log(JuiceHandle.fillEnergy());                
            // 子类Juice转父类Water 并调用父类的动态方法               
            var WaterInstance = Java.cast(JuiceHandle,WaterClass);  
            console.log(WaterInstance.still(WaterInstance));           
          }        
        })    
      })
    }
    

    Hook 打印类实现的接口

    function searchInterface(){    
      Java.perform(function(){       
        Java.enumerateLoadedClasses({            
          onComplete: function(){},            
          onMatch: function(name,handle){ 
            if (name.indexOf("com.r0ysue.a0526printout") > -1) {
              // 使用包名进行过滤                   
              console.log("find class");
              var targetClass = Java.use(name);
              var interfaceList = targetClass.class.getInterfaces(); 
              // 使用反射获取类实现的接口数组
              if (interfaceList.length > 0) {
                console.log(name) 
                // 打印类名
                for (var i in interfaceList) { 
                  console.log("\t", interfaceList.toString());
                  // 直接打印接口名称
                }                    
              }                
            }            
          }        
        })    
      })
    }
    

    Hook enum 枚举

    function enumPrint(){    
      Java.perform(function(){
        Java.choose("com.r0ysue.a0526printout.Signal",{ 
          onComplete: function(){},
          onMatch: function(instance){
            console.log('find it ,',instance);
            console.log(instance.class.getName());
          }
        })  
      })
    }
    

    Hook 获取 context

    function getContext(){    
      Java.perform(function(){
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();        
        console.log(currentApplication);
        var context = currentApplication.getApplicationContext();
        console.log(context);
        var packageName = context.getPackageName(); 
        console.log(packageName);
        console.log(currentApplication.getPackageName());
      })
    }
    

    Hook 主动调用构造方法

    function main(){    
      Java.perform(function(){        
        var StringClass = Java.use("java.lang.String");
        var MoneyClass = Java.use("com.xiaojianbang.app.Money"); 
        MoneyClass.$init.overload('java.lang.String','int').implementation = function(x,y){
          console.log('hook Money init');            
          var myX = StringClass.new("Hello World!");            
          var myY = 9999;            
          this.$init(myX,myY);
        }    
      })
    }
    setImmediate(main);
    

    Hook 主动调用静态方法

    function main_rsa(){
      Java.perform(function(){
        var RSA = Java.use("com.xiaojianbang.app.RSA"); 
        var StringClass = Java.use("java.lang.String");
        var base64Class = Java.use("android.util.Base64"); 
        var myBytes = StringClass.$new("Hello World").getBytes();
        var result = RSA.encrypt(myBytes);       
        console.log("result is :", result);       
        console.log("json result is: ",JSON.stringify(result));        
        console.log("base64 result is :", base64Class.encodeToString(result,0));
        // console.log("new String is : ", StringClass.$new(result)); 
        // 加密之后的内容有很多不可见字符, 不能直接 new String()    
      })
    }setImmediate(main_rsa);
    

    Hook 主动调用动态方法

    // 非静态方法的主动调用 自定义instance 并调用 非静态方法
    function main_getInfo(){    
      Java.perform(function(){ 
        var instance = Java.use("com.xiaojianbang.app.Money").$new("日元",300000); 
        console.log(instance.getInfo());    
      })
    }
    // 遍历所有的对象并调用 需要进行过滤
    function main_instance_getInfo(){    
      Java.perform(function(){        
        Java.choose("com.xiaojianbang.app.Money",{
          onComplete: function(){},            
          onMatch: function(instance){                
            console.log(instance.getInfo());
          }      
        })
      })
    }
    

    Hook frida 和 python 交互

    frida 传递参数
    function main(){    
      Java.perform(function () {        
        console.log("enter perform");
        // 获取要hook的类 
        var TextViewClass = Java.use("android.widget.TextView"); 
        // 要hook的方法        
        TextViewClass.setText.overload('java.lang.CharSequence').implementation = function (ori_input) {  
          console.log('enter', 'java.lang.CharSequence');  
          console.log('ori_input',ori_input.toString());
          // 定义用于接受python传参的data 
          var receive_data; 
          // 将原参数传递给python 在python中进行处理
          send(ori_input.toString());
          // recv 从python接收传递的内容 默认传过来的是个json对象
          recv(function (json_data) {
            console.log('data from python ' + json_data.data); 
            receive_data = json_data.data;
            console.log(typeof (receive_data)); 
          }).wait(); 
          //wait() 等待python处理 阻塞            
          // 转java字符串
          receive_data = Java.use("java.lang.String").$new(receive_data);
          this.setText(receive_data); 
        };
      })
    }
    setImmediate(main);
    
    

    Python代码

    python 处理收到的参数
    # -*- coding: utf-8 -*-
    import sysimport time
    import base64
    import frida 
    from loguru import logger
    def on_message(message,data):    
      logger.info(str(message)) 
      # dict    
      logger.info(str(data) if data else "None")    
      if message['type'] == 'error': 
        logger.error('error:' + str(message['description']))
        logger.error('stack: ' + str(message['stack'])) 
        if message['type'] == 'send':       
          logger.info('get message 
  • --> ' + message['payload']) payload = message['payload'] # 处理逻辑 sending to the server: YWFhOmJiYg== tmp = payload.split(':') sts = tmp[0] need_to_db64 = tmp[1] user_pass = base64.b64decode(need_to_db64.encode()).decode() mine_str = 'admin' + ':' + user_pass.split(':')[-1] mine_b64_str = base64.b64encode(mine_str.encode()).decode() mine_b64_str = sts + mine_b64_str logger.info(mine_b64_str) # python返回数据给js script.post script.post({'data':mine_b64_str}) logger.info('python complete') device = frida.get_usb_device() # pid = device.spawn(['com.kevin.demo04']) # time.sleep(1) session = device.attach('com.kevin.demo02') with open('./hulianhutong.js','r') as f: script = session.create_script(f.read()) script.on("message",on_message) script.load() input()
  • Hook 打印 char

    // 打印char字符, 直接调用java.lang.Character toString()即可
    function main(){    
      Java.perform(function(){       
        var CharClass = Java.use("java.lang.Character");        
        CharClass.toString.overload("char").implementation = function(inputChar){           
          var result = this.toString(inputChar);
          console.log("inputChar, result: ", inputChar, result);
          return result; 
        }    
      })
    }
    

    Hook 打印 char 数组

    // 1. 使用 java.util.Arrays 的 toString 方法 打印 [C 
    // 2. 使用 js 的 JSON.stringify 打印 [C
    function printCharArray(){    
      Java.perform(function(){
        var ArrayClass = Java.use("java.util.Arrays");
        ArrayClass.toString.overload('[C').implementation = function(charArray){
          // 1. java.util.Arrays.toString()           
          var result = this.toString(charArray); 
          // 2. javascript JSON.stringify() 
          var result1 = JSON.stringify(charArray); 
          console.log('charArray, result : ', charArray, result); 
          console.log('charArray, result :', charArray, result1);
        }   
      })
    }
    

    Hook 打印和修改 HashMap

    //遍历打印
    function main(){	
      Java.perform(function(){
        var targetClass = Java.use("com.xiaojianbang.app.ShufferMap");
        targetClass.show.implementation = function(map){ 
          // 遍历 map
          var result = "";	
          var it = map.keySet().iterator(); 
          while (it.hasNext()){ 
            var keyStr = it.next();
            var valueStr = map.get(keyStr); 
            result += valueStr;	
          } 
          console.log("result :", result);    
          // 修改 map 
          map.put("pass","fxxk"); 
          map.put("code","Hello World");
          console.log(JSON.stringify(map));
          this.show(map);
          return this.show(map);
        }  
      })    
    }
    setImmediate(main)
    //cast打印 HashMap
    function main(){    
      Java.perform(function(){
        var HashMapNode = Java.use("java.util.HashMap$Node"); 
        var targetClass = Java.use("com.xiaojianbang.app.ShufferMap"); 
        var targetClass.show.implementation = function(map){
          var result = "";           
          var iterator = map.entrySet().iterator();           
          while (iterator.hasNext()) {  
            console.log("entry", iterator.next()); 
            var entry = Java.cast(iterator.next(), HashMapNode); 
            console.log(entry.getKey()); 
            console.log(entry.getValue()); 
            return += entry.getValue();  
          }                        
          console.log("result is :", result);
        }   
      })
    }
    setImmediate(main);
    

    toString()打印

    function main(){    
      Java.perform(function(){  
        var targetClass = Java.use("com.xiaojianbang.app.ShufferMap");  
        targetClass.show.implementation = function(map){ 
          // 直接调用 toString() 
          console.log("打印hashmap: -> " + map.toString());
          return this.show.apply(this,arguments);
        }  
      })
    }
    setImmediate(main)
    
    ;function printHashMap(flag, param_hm) {    
      Java.perform(function () {     
        var HashMap = Java.use('java.util.HashMap');  
        var args_map = Java.cast(param_hm, HashMap);  
        send(flag +":" + args_map.toString()); 
      })
    }
    

    Hook 打印 byte 数组

    //方法 1
    function main(){   
      Java.perform(function(){  
        var StringClass = Java.use("java.lang.String");   
        var byteArray = StringClass.$new("Hello World").getBytes();            
        // load r0gson	     
        // openClassFile 返回 dex对象, dex对象.load()加载dex文件内容    
        Java.openClassFile("/data/local/tmp/r0gson.dex").load(); 
        var gson = Java.use("com.r0ysue.gson.Gson");
        console.log(gson.$new().toJson(byteArray));
        // // console byte[]
        // var ByteString = Java.use("com.android.okhttp.okio.ByteString"); 
        // console.log(ByteString.of(byteArray).hex()); 
        // byte转16进制字符串 
        // // 创建自定义Java数组 并打印 
        // var MyArray = Java.array("byte",[13,4,4,2]); 
        // console.log(gson.$new().toJson(MyArray)); 
        var TargetClass = Java.use("com.xiaojianbang.app.ShufferMap");  
        TargetClass.show.implementation =  function(map){                
          console.log(gson.$new().toJson(map));
          return this.show(map);           
        }
      })
    }
    setImmediate(main);
    //方法 2
    // 1. 使用 java.util.Arrays.toString() 打印 [B
    // 2. 使用 javascript JSON.stringify() 打印 [B
    function printByteArray(){  
      Java.perform(function(){    
        var ArrayClass = Java.use("java.util.Arrays");  
        ArrayClass.toString.overload('[B').implementation = function(byteArray){	
          // 1. 使用 java.util.Arrays.toString() 打印 [B            
          var result = this.toString(byteArray);	
          // 2. 使用 javascript JSON.stringify() 打印 [B 
          var result1 = JSON.stringify(byteArray); 
          console.log('byteArray,result: ', byteArray, result);   
          console.log('byteArray,result1 :', byteArray, result1); 
          return result       
        }
      })
    }
    //方法 3
    function printByteArray(byteArray){
      Java.perform(function(){	
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");		
        console.log(ByteString.of(byteArray).hex())
      })
    }
    

    Hook 打印调用栈

    function printStacks(name){    
      console.log("====== printStacks start ====== " + name + "==============================") 
      // sample 1    
      var throwable = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()); 
      console.log(throwable);    
      // sample 2    
      var exception = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());  
      console.log(exception);       
      console.log("====== printStacks end ======== " + name + "==============================")}
    

    Hook gson 打印

    function main(){    
      Java.perform(function(){  
        var StringClass = Java.use("java.lang.String");   
        var byteArray = StringClass.$new("Hello World").getBytes();
        // load r0gson	        
        // openClassFile 返回 dex对象, dex对象.load()加载dex文件内容  
        Java.openClassFile("/data/local/tmp/r0gson.dex").load();   
        var gson = Java.use("com.r0ysue.gson.Gson");  
        console.log(gson.$new().toJson(byteArray)); 
        // // console byte[] 
        // var ByteString = Java.use("com.android.okhttp.okio.ByteString");   
        // console.log(ByteString.of(byteArray).hex());
        // byte转16进制字符串     
        // // 创建自定义Java数组 并打印  
        // var MyArray = Java.array("byte",[13,4,4,2]);   
        // console.log(gson.$new().toJson(MyArray));  
        var TargetClass = Java.use("com.xiaojianbang.app.ShufferMap");  
        TargetClass.show.implementation =  function(map){ 
          console.log(gson.$new().toJson(map)); 
          return this.show(map);
        }
      })
    }
    setImmediate(main);
    

    Hook 打印 non-ascii 和特殊字符

    一些特殊字符和不可见字符, 可以先通过编码再解码的方式进行 hook

    int ֏(int x) {
      return x + 100;
    }
    

    针对上面的֏, 直接用js编码, 在通过类名[js解码的方法名]进行implementation

    JSJava.perform(       
      function x() {     
        var targetClass = "com.example.hooktest.MainActivity";    
        var hookCls = Java.use(targetClass);   
        var methods = hookCls.class.getDeclaredMethods(); 
        for (var i in methods) {
          console.log(methods.toString());  
          console.log(encodeURIComponent(methods.toString().replace(/^.*?\.([^\s\.\(\)]+)\(.*?$/, "$1")));   
        }            
        hookCls[decodeURIComponent("%D6%8F")].implementation = function (x) {   
          console.log("original call: fun(" + x + ")"); 
          var result = this[decodeURIComponent("%D6%8F")](900); 
          return result;
        }
      } 
    )
    

    简易 wallbreaker 内存打印

    内存漫游, 打印实例的字段和方法

    function main(){    
      Java.perform(function(){ 
        var Class = Java.use("java.lang.Class"); 
        function inspectObject(obj){
          var obj_class = Java.cast(obj.getClass(), Class); 
          var fields = obj_class.getDeclaredFields();
          var methods = obj_class.getMethods(); 
          console.log("Inspectiong " + obj.getClass().toString()); 
          console.log("\t Fields:") 
          for (var i in fields){ 
            console.log("\t\t" + fields.toString()); 
          }           
          console.log("\t Methods:")  
          for (var i in methods){ 
            console.log("\t\t" + methods.toString()) 
          } 
        }
        
        Java.choose("com.baidu.lbs.waimai.WaimaiActivity",{ 
          onComplete: function(){
            console.log("complete!"); 
          },  
          onMatch: function(instance){ 
            console.log("find instance", instance);  
            inspectObject(instance); 
          }        
        })    
      })}
    setImmediate(main)
    

    hook frida 实现 runnable

    Java.perform(function() {  
      // https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_SECURE  
      var FLAG_SECURE = 0x2000;   
      var Runnable = Java.use("java.lang.Runnable"); 
      var DisableSecureRunnable = Java.registerClass({      
        name: "me.bhamza.DisableSecureRunnable", 
        implements: [Runnable], 
        fields: {
          activity: "android.app.Activity", 
        },  
        methods: { 
          $init: [{ 
            returnType: "void", 
            argumentTypes: ["android.app.Activity"],
            implementation: function (activity) {  
              this.activity.value = activity;
            }
          }],  
         run: function() { 
           var flags = this.activity.value.getWindow().getAttributes().flags.value; 
           // get current value             
           flags &= ~FLAG_SECURE; 
           // toggle it
           this.activity.value.getWindow().setFlags(flags, FLAG_SECURE);
           // disable it!            
           console.log("Done disabling SECURE flag...");
         }
        } 
      });
      
      Java.choose("com.example.app.FlagSecureTestActivity", {
        "onMatch": function (instance) { 
          var runnable = DisableSecureRunnable.$new(instance); 
          instance.runOnUiThread(runnable);  
        }, 
        "onComplete": function () {}   
      });
    });
    

    Hook 监控控件 onClick

    var jclazz = null;
    var jobj = null;
    function getObjClassName(obj) {
      if (!jclazz) { 
        var jclazz = Java.use("java.lang.Class");  
      }
      if (!jobj) {
        var jobj = Java.use("java.lang.Object");  
      } 
      return jclazz.getName.call(jobj.getClass.call(obj));
    }
    
    function watch(obj, mtdName) {   
      var listener_name = getObjClassName(obj);  
      var target = Java.use(listener_name); 
      if (!target || !mtdName in target) { 
        return;
      }
      // send("[WatchEvent] hooking " + mtdName + ": " + listener_name);    
      target[mtdName].overloads.forEach(function (overload) {        
        overload.implementation = function () { 
          //send("[WatchEvent] " + mtdName + ": " + getObjClassName(this)); 
          console.log("[WatchEvent] " + mtdName + ": " + getObjClassName(this))
          return this[mtdName].apply(this, arguments);        
        };
      })
    }
    
    function OnClickListener() {    
      Java.perform(function () {  
        //以spawn启动进程的模式来attach的话   
        Java.use("android.view.View").setOnClickListener.implementation = function (listener) {   
          if (listener != null) {  
            watch(listener, 'onClick');
          }
          return this.setOnClickListener(listener);
        };  
        //如果frida以attach的模式进行attch的话 
        Java.choose("android.view.View$ListenerInfo", {   
          onMatch: function (instance) {              
            instance = instance.mOnClickListener.value;    
            if (instance) { 
              console.log("mOnClickListener name is :" + getObjClassName(instance));   
              watch(instance, 'onClick');  
            }          
          },      
          onComplete: function () {   
          }
        })
      })
    }
    setImmediate(OnClickListener);
    

    Hook startActivity

    Java.perform(function () {  
      var Activity = Java.use("android.app.Activity");  
      //console.log(Object.getOwnPropertyNames(Activity)); 
      Activity.startActivity.overload('android.content.Intent').implementation=function(p1){    
        console.log("Hooking android.app.Activity.startActivity(p1) successfully,p1="+p1);   
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));  
        console.log(decodeURIComponent(p1.toUri(256)));
        this.startActivity(p1);
      }   
      Activity.startActivity.overload('android.content.Intent', 'android.os.Bundle').implementation=function(p1,p2){
        console.log("Hooking android.app.Activity.startActivity(p1,p2) successfully,p1="+p1+",p2="+p2);     
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));  
        console.log(decodeURIComponent(p1.toUri(256)));  
        this.startActivity(p1,p2);
      }   
      Activity.startService.overload('android.content.Intent').implementation=function(p1){ 
        console.log("Hooking android.app.Activity.startService(p1) successfully,p1="+p1);    
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));   
        console.log(decodeURIComponent(p1.toUri(256)));     
        this.startService(p1); 
      }}
                )
    

    Hook frida 绕过 root 检测

    // $ frida -l antiroot.js -U -f com.example.app --no-pause
    // CHANGELOG by Pichaya Morimoto (p.morimoto@sth.sh): 
    //  - I added extra whitelisted items to deal with the latest versions 
    // 						of RootBeer/Cordova iRoot as of August 6, 2019
    //  - The original one just fucked up (kill itself) if Magisk is installed lol
    // Credit & Originally written by: https://codeshare.frida.re/@dzonerzy/fridantiroot/
    // If this isn't working in the future, check console logs, rootbeer src, or libtool-checker.so
    Java.perform(function() {
    
        var RootPackages = ["com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu",
            "com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager",
            "com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch",
            "com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.devadvance.rootcloak", "com.devadvance.rootcloakplus",
            "de.robv.android.xposed.installer", "com.saurik.substrate", "com.zachspong.temprootremovejb", "com.amphoras.hidemyroot",
            "com.amphoras.hidemyrootadfree", "com.formyhm.hiderootPremium", "com.formyhm.hideroot", "me.phh.superuser",
            "eu.chainfire.supersu.pro", "com.kingouser.com", "com.android.vending.billing.InAppBillingService.COIN","com.topjohnwu.magisk"
        ];
    
        var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk","magisk"];
    
        var RootProperties = {
            "ro.build.selinux": "1",
            "ro.debuggable": "0",
            "service.adb.root": "0",
            "ro.secure": "1"
        };
    
        var RootPropertiesKeys = [];
    
        for (var k in RootProperties) RootPropertiesKeys.push(k);
    
        var PackageManager = Java.use("android.app.ApplicationPackageManager");
    
        var Runtime = Java.use('java.lang.Runtime');
    
        var NativeFile = Java.use('java.io.File');
    
        var String = Java.use('java.lang.String');
    
        var SystemProperties = Java.use('android.os.SystemProperties');
    
        var BufferedReader = Java.use('java.io.BufferedReader');
    
        var ProcessBuilder = Java.use('java.lang.ProcessBuilder');
    
        var StringBuffer = Java.use('java.lang.StringBuffer');
    
        var loaded_classes = Java.enumerateLoadedClassesSync();
    
        send("Loaded " + loaded_classes.length + " classes!");
    
        var useKeyInfo = false;
    
        var useProcessManager = false;
    
        send("loaded: " + loaded_classes.indexOf('java.lang.ProcessManager'));
    
        if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) {
            try {
                //useProcessManager = true;
                //var ProcessManager = Java.use('java.lang.ProcessManager');
            } catch (err) {
                send("ProcessManager Hook failed: " + err);
            }
        } else {
            send("ProcessManager hook not loaded");
        }
    
        var KeyInfo = null;
    
        if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) {
            try {
                //useKeyInfo = true;
                //var KeyInfo = Java.use('android.security.keystore.KeyInfo');
            } catch (err) {
                send("KeyInfo Hook failed: " + err);
            }
        } else {
            send("KeyInfo hook not loaded");
        }
    
        PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pname, flags) {
            var shouldFakePackage = (RootPackages.indexOf(pname) > -1);
            if (shouldFakePackage) {
                send("Bypass root check for package: " + pname);
                pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it";
            }
            return this.getPackageInfo.call(this, pname, flags);
        };
    
        NativeFile.exists.implementation = function() {
            var name = NativeFile.getName.call(this);
            var shouldFakeReturn = (RootBinaries.indexOf(name) > -1);
            if (shouldFakeReturn) {
                send("Bypass return value for binary: " + name);
                return false;
            } else {
                return this.exists.call(this);
            }
        };
    
        var exec = Runtime.exec.overload('[Ljava.lang.String;');
        var exec1 = Runtime.exec.overload('java.lang.String');
        var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;');
        var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;');
        var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File');
        var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File');
    
        exec5.implementation = function(cmd, env, dir) {
            if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
                var fakeCmd = "grep";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
            if (cmd == "su") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
            if (cmd == "which") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass which command");
                return exec1.call(this, fakeCmd);
            }
            return exec5.call(this, cmd, env, dir);
        };
    
        exec4.implementation = function(cmdarr, env, file) {
            for (var i = 0; i < cmdarr.length; i = i + 1) {
                var tmp_cmd = cmdarr;
                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
                    var fakeCmd = "grep";
                    send("Bypass " + cmdarr + " command");
                    return exec1.call(this, fakeCmd);
                }
    
                if (tmp_cmd == "su") {
                    var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                    send("Bypass " + cmdarr + " command");
                    return exec1.call(this, fakeCmd);
                }
            }
            return exec4.call(this, cmdarr, env, file);
        };
    
        exec3.implementation = function(cmdarr, envp) {
            for (var i = 0; i < cmdarr.length; i = i + 1) {
                var tmp_cmd = cmdarr;
                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
                    var fakeCmd = "grep";
                    send("Bypass " + cmdarr + " command");
                    return exec1.call(this, fakeCmd);
                }
    
                if (tmp_cmd == "su") {
                    var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                    send("Bypass " + cmdarr + " command");
                    return exec1.call(this, fakeCmd);
                }
            }
            return exec3.call(this, cmdarr, envp);
        };
    
        exec2.implementation = function(cmd, env) {
            if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
                var fakeCmd = "grep";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
            if (cmd == "su") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
            return exec2.call(this, cmd, env);
        };
    
        exec.implementation = function(cmd) {
            for (var i = 0; i < cmd.length; i = i + 1) {
                var tmp_cmd = cmd;
                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
                    var fakeCmd = "grep";
                    send("Bypass " + cmd + " command");
                    return exec1.call(this, fakeCmd);
                }
    
                if (tmp_cmd == "su") {
                    var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                    send("Bypass " + cmd + " command");
                    return exec1.call(this, fakeCmd);
                }
            }
    
            return exec.call(this, cmd);
        };
    
        exec1.implementation = function(cmd) {
            if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
                var fakeCmd = "grep";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
            if (cmd == "su") {
                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
                send("Bypass " + cmd + " command");
                return exec1.call(this, fakeCmd);
            }
            return exec1.call(this, cmd);
        };
    
        String.contains.implementation = function(name) {
            if (name == "test-keys") {
                send("Bypass test-keys check");
                return false;
            }
            return this.contains.call(this, name);
        };
    
        var get = SystemProperties.get.overload('java.lang.String');
    
        get.implementation = function(name) {
            if (RootPropertiesKeys.indexOf(name) != -1) {
                send("Bypass " + name);
                return RootProperties[name];
            }
            return this.get.call(this, name);
        };
    
        Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
            onEnter: function(args) {
                var path1 = Memory.readCString(args[0]);
                var path = path1.split("/");
                var executable = path[path.length - 1];
                var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)
                if (shouldFakeReturn) {
                    Memory.writeUtf8String(args[0], "/ggezxxx");
                    send("Bypass native fopen >> "+path1);
                }
            },
            onLeave: function(retval) {
    
            }
        });
    
        Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
            onEnter: function(args) {
                var path1 = Memory.readCString(args[0]);
                var path = path1.split("/");
                var executable = path[path.length - 1];
                var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)
                if (shouldFakeReturn) {
                    Memory.writeUtf8String(args[0], "/ggezxxx");
                    send("Bypass native fopen >> "+path1);
                }
            },
            onLeave: function(retval) {
    
            }
        });
    
        Interceptor.attach(Module.findExportByName("libc.so", "system"), {
            onEnter: function(args) {
                var cmd = Memory.readCString(args[0]);
                send("SYSTEM CMD: " + cmd);
                if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id") {
                    send("Bypass native system: " + cmd);
                    Memory.writeUtf8String(args[0], "grep");
                }
                if (cmd == "su") {
                    send("Bypass native system: " + cmd);
                    Memory.writeUtf8String(args[0], "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled");
                }
            },
            onLeave: function(retval) {
    
            }
        });
    
        /*
        TO IMPLEMENT:
        Exec Family
        int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
        int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
        int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);
        int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
        int execv(const char *path, char *const argv[]);
        int execve(const char *path, char *const argv[], char *const envp[]);
        int execvp(const char *file, char *const argv[]);
        int execvpe(const char *file, char *const argv[], char *const envp[]);
        */
    
    
        BufferedReader.readLine.overload().implementation = function() {
            var text = this.readLine.call(this);
            if (text === null) {
                // just pass , i know it's ugly as hell but test != null won't work :(
            } else {
                var shouldFakeRead = (text.indexOf("ro.build.tags=test-keys") > -1);
                if (shouldFakeRead) {
                    send("Bypass build.prop file read");
                    text = text.replace("ro.build.tags=test-keys", "ro.build.tags=release-keys");
                }
            }
            return text;
        };
    
        var executeCommand = ProcessBuilder.command.overload('java.util.List');
    
        ProcessBuilder.start.implementation = function() {
            var cmd = this.command.call(this);
            var shouldModifyCommand = false;
            for (var i = 0; i < cmd.size(); i = i + 1) {
                var tmp_cmd = cmd.get(i).toString();
                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd.indexOf("mount") != -1 || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd.indexOf("id") != -1) {
                    shouldModifyCommand = true;
                }
            }
            if (shouldModifyCommand) {
                send("Bypass ProcessBuilder " + cmd);
                this.command.call(this, ["grep"]);
                return this.start.call(this);
            }
            if (cmd.indexOf("su") != -1) {
                send("Bypass ProcessBuilder " + cmd);
                this.command.call(this, ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]);
                return this.start.call(this);
            }
    
            return this.start.call(this);
        };
    
        if (useProcessManager) {
            var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean');
            var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean');
    
            ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) {
                var fake_cmd = cmd;
                for (var i = 0; i < cmd.length; i = i + 1) {
                    var tmp_cmd = cmd;
                    if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {
                        var fake_cmd = ["grep"];
                        send("Bypass " + cmdarr + " command");
                    }
    
                    if (tmp_cmd == "su") {
                        var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];
                        send("Bypass " + cmdarr + " command");
                    }
                }
                return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);
            };
    
            ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) {
                var fake_cmd = cmd;
                for (var i = 0; i < cmd.length; i = i + 1) {
                    var tmp_cmd = cmd;
                    if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {
                        var fake_cmd = ["grep"];
                        send("Bypass " + cmdarr + " command");
                    }
    
                    if (tmp_cmd == "su") {
                        var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];
                        send("Bypass " + cmdarr + " command");
                    }
                }
                return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect);
            };
        }
    
        if (useKeyInfo) {
            KeyInfo.isInsideSecureHardware.implementation = function() {
                send("Bypass isInsideSecureHardware");
                return true;
            }
        }
    
    });
    

    Hook frida 强制在主线程运行

    针对使用一些方法的时候出现报错 on a thread that has not called Looper.prepare()

    强制让代码运行在主线程中

    JSJava.perform(function() {  var Toast = Java.use('android.widget.Toast');  var currentApplication = Java.use('android.app.ActivityThread').currentApplication();   var context = currentApplication.getApplicationContext();  Java.scheduleOnMainThread(function() {    Toast.makeText(context, "Hello World", Toast.LENGTH_LONG.value).show();  })})
    

    Hook frida 指定方法中过滤打印

    JSfunction hook_lnf() {    var activate = false;    Java.perform(function(){        var hashmapClass = Java.use("java.util.HashMap");        hashmapClass.put.implementation = function(key,value){            if (activate){                console.log("key:", key, "value:", value);            }            return this.put(key,value);        };    });    Java.perform(function () {        var lnfClazz = Java.use("tb.lnf");        lnfClazz.a.overload('java.util.HashMap', 'java.util.HashMap', 'java.lang.String',            'java.lang.String', 'boolean').implementation = function (hashmap, hashmap2, str, str2, z) {                printHashMap("hashmap", hashmap);                printHashMap("hashmap2", hashmap2);                console.log("str", str);                console.log("str2", str2);                console.log("boolean", z);                activate = true;                var result = this.a(hashmap, hashmap2, str, str2, z);                activate = false                printHashMap("result", result);                return result;            };    })}
    

    Hook 禁止 app 退出

    function hookExit(){  
      Java.perform(function(){     
        console.log("
  • Starting hook exit"); var exitClass = Java.use("java.lang.System"); exitClass.exit.implementation = function(){ console.log("
  • System.exit.called"); } console.log("
  • hooking calls to System.exit"); }) } setImmediate(hookExit);
  • Hook 修改设备参数

    // frida hook 修改设备参数
    Java.perform(function() {	
      var TelephonyManager = Java.use("android.telephony.TelephonyManager");  
      //IMEI hook 
      TelephonyManager.getDeviceId.overload().implementation = function () { 
        console.log("
  • Called - getDeviceId()"); var temp = this.getDeviceId(); console.log("real IMEI: "+temp); return "867979021642856"; }; // muti IMEI TelephonyManager.getDeviceId.overload('int').implementation = function (p) { console.log("
  • Called - getDeviceId(int) param is"+p); var temp = this.getDeviceId(p); console.log("real IMEI "+p+": "+temp); return "867979021642856"; }; //IMSI hook TelephonyManager.getSimSerialNumber.overload().implementation = function () { console.log("
  • Called - getSimSerialNumber(String)"); var temp = this.getSimSerialNumber(); console.log("real IMSI: "+temp); return "123456789"; }; ////////////////////////////////////// //ANDOID_ID hook var Secure = Java.use("android.provider.Settings$Secure"); Secure.getString.implementation = function (p1,p2) { if(p2.indexOf("android_id")<0) return this.getString(p1,p2); console.log("
  • Called - get android_ID, param is:"+p2); var temp = this.getString(p1,p2); console.log("real Android_ID: "+temp); return "844de23bfcf93801"; } //android的hidden API,需要通过反射调用 var SP = Java.use("android.os.SystemProperties"); SP.get.overload('java.lang.String').implementation = function (p1) { var tmp = this.get(p1); console.log("
  • "+p1+" : "+tmp); return tmp; } SP.get.overload('java.lang.String', 'java.lang.String').implementation = function (p1,p2) { var tmp = this.get(p1,p2) console.log("
  • "+p1+","+p2+" : "+tmp); return tmp; } // hook MAC var wifi = Java.use("android.net.wifi.WifiInfo"); wifi.getMacAddress.implementation = function () { var tmp = this.getMacAddress(); console.log("
  • real MAC: "+tmp); return tmp; } })
  • Hook 打印请求调用栈

    var class_Socket = Java.use("java.net.Socket");
    class_Socket.getOutputStream.overload().implementation = function(){ 
      send("getOutputSteam"); 
      var result = this.getOutputStream();
      var bt = Java.use("android.util.Log").getStackTraceString(  
        Java.use("java.lang.Exception").$new(); 
      )  
      console.log("Backtrace:" + bt); 
      send(result);  
      return result;
    }
    

    Hook UI thread 注入

    Java.perform(function() { 
      var Toast = Java.use('android.widget.Toast'); 
      var currentApplication = Java.use('android.app.ActivityThread').currentApplication(); 
      var context = currentApplication.getApplicationContext(); 
      Java.scheduleOnMainThread(function() {  
        Toast.makeText(context, "Hello World", Toast.LENGTH_LONG.value).show();
      
      } 
        )}
            )
    

    常用打印转换

    JS
    //工具相关函数
    var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
        base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, (-1), (-1), (-1), (-1), (-1), (-1), 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, (-1), (-1), (-1), (-1), (-1));
    
    function stringToBase64(e) {
        var r, a, c, h, o, t;
        for (c = e.length, a = 0, r = ''; a < c;) {
            if (h = 255 & e.charCodeAt(a++), a == c) {
                r += base64EncodeChars.charAt(h >> 2),
                    r += base64EncodeChars.charAt((3 & h) << 4),
                    r += '==';
                break
            }
            if (o = e.charCodeAt(a++), a == c) {
                r += base64EncodeChars.charAt(h >> 2),
                    r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                    r += base64EncodeChars.charAt((15 & o) << 2),
                    r += '=';
                break
            }
            t = e.charCodeAt(a++),
                r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
                r += base64EncodeChars.charAt(63 & t)
        }
        return r
    }
    
    function base64ToString(e) {
        var r, a, c, h, o, t, d;
        for (t = e.length, o = 0, d = ''; o < t;) {
            do
                r = base64DecodeChars[255 & e.charCodeAt(o++)];
            while (o < t && r == -1);
            if (r == -1)
                break;
            do
                a = base64DecodeChars[255 & e.charCodeAt(o++)];
            while (o < t && a == -1);
            if (a == -1)
                break;
            d += String.fromCharCode(r << 2 | (48 & a) >> 4);
            do {
                if (c = 255 & e.charCodeAt(o++), 61 == c)
                    return d;
                c = base64DecodeChars[c]
            } while (o < t && c == -1);
            if (c == -1)
                break;
            d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2);
            do {
                if (h = 255 & e.charCodeAt(o++), 61 == h)
                    return d;
                h = base64DecodeChars[h]
            } while (o < t && h == -1);
            if (h == -1)
                break;
            d += String.fromCharCode((3 & c) << 6 | h)
        }
        return d
    }
    
    function hexToBase64(str) {
        return base64Encode(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
    }
    
    function base64ToHex(str) {
        for (var i = 0, bin = base64Decode(str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) {
            var tmp = bin.charCodeAt(i).toString(16);
            if (tmp.length === 1)
                tmp = "0" + tmp;
            hex[hex.length] = tmp;
        }
        return hex.join("");
    }
    
    function hexToBytes(str) {
        var pos = 0;
        var len = str.length;
        if (len % 2 != 0) {
            return null;
        }
        len /= 2;
        var hexA = new Array();
        for (var i = 0; i < len; i++) {
            var s = str.substr(pos, 2);
            var v = parseInt(s, 16);
            hexA.push(v);
            pos += 2;
        }
        return hexA;
    }
    
    function bytesToHex(arr) {
        var str = '';
        var k, j;
        for (var i = 0; i < arr.length; i++) {
            k = arr;
            j = k;
            if (k < 0) {
                j = k + 256;
            }
            if (j < 16) {
                str += "0";
            }
            str += j.toString(16);
        }
        return str;
    }
    
    function stringToHex(str) {
        var val = "";
        for (var i = 0; i < str.length; i++) {
            if (val == "")
                val = str.charCodeAt(i).toString(16);
            else
                val += str.charCodeAt(i).toString(16);
        }
        return val
    }
    
    function stringToBytes(str) {
        var ch, st, re = [];
        for (var i = 0; i < str.length; i++) {
            ch = str.charCodeAt(i);
            st = [];
            do {
                st.push(ch & 0xFF);
                ch = ch >> 8;
            }
            while (ch);
            re = re.concat(st.reverse());
        }
        return re;
    }
    
    //将byte[]转成String的方法
    function bytesToString(arr) {
        var str = '';
        arr = new Uint8Array(arr);
        for (var i in arr) {
            str += String.fromCharCode(arr);
        }
        return str;
    }
    
    function bytesToBase64(e) {
        var r, a, c, h, o, t;
        for (c = e.length, a = 0, r = ''; a < c;) {
            if (h = 255 & e[a++], a == c) {
                r += base64EncodeChars.charAt(h >> 2),
                    r += base64EncodeChars.charAt((3 & h) << 4),
                    r += '==';
                break
            }
            if (o = e[a++], a == c) {
                r += base64EncodeChars.charAt(h >> 2),
                    r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                    r += base64EncodeChars.charAt((15 & o) << 2),
                    r += '=';
                break
            }
            t = e[a++],
                r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
                r += base64EncodeChars.charAt(63 & t)
        }
        return r
    }
    
    function base64ToBytes(e) {
        var r, a, c, h, o, t, d;
        for (t = e.length, o = 0, d = []; o < t;) {
            do
                r = base64DecodeChars[255 & e.charCodeAt(o++)];
            while (o < t && r == -1);
            if (r == -1)
                break;
            do
                a = base64DecodeChars[255 & e.charCodeAt(o++)];
            while (o < t && a == -1);
            if (a == -1)
                break;
            d.push(r << 2 | (48 & a) >> 4);
            do {
                if (c = 255 & e.charCodeAt(o++), 61 == c)
                    return d;
                c = base64DecodeChars[c]
            } while (o < t && c == -1);
            if (c == -1)
                break;
            d.push((15 & a) << 4 | (60 & c) >> 2);
            do {
                if (h = 255 & e.charCodeAt(o++), 61 == h)
                    return d;
                h = base64DecodeChars[h]
            } while (o < t && h == -1);
            if (h == -1)
                break;
            d.push((3 & c) << 6 | h)
        }
        return d
    }
    

    文章作者: Kevin
    文章链接: http://example.com/fridahookjava/
    版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 凡墙总是门!



    来源:https://www.cnblogs.com/c-x-a/p/15294911.html
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

    Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

    在本版发帖返回顶部