Frida常用方法

基础语法

符号作用
$init 构造方法 Hook 的时候用
$new() 实例化对象的时候用
Hook重载语法
int类型 int
float类型 float
boolean类型 boolean
string类型 java.lang.String
byte类型 [B
char类型 [C
list结构 java.util.List
安卓上下文结构 android.content.Context

主动调用函数

  • 静态函数 static 可以直接调用
  • 动态函数要用choose找到实例才能操作

静态函数主动调用

Java.perform(function x(){
    var LoginActivity = Java.use("com.xx.xx.xx.xx");
    LoginActivity.function();
}
)
 
JavaScript

动态函数主动调用

Java.perform(function x(){
    Java.choose("com.xx.xx.xx.xx",{
        onMatch: function(instance){
            instance.function();
        },
        onComplete: function(){

        }
    });
}
)
 
JavaScript

修改变量

APP 代码如下

public class FridaTest extends BaseFridaTest{
    private static boolean static_bool_var = false;
    private boolean bool_var = false;
    private boolean same_name_bool_var = false;
}
 
Java
  • 静态变量 static 可以直接设置值
  • 动态变量要用choose找到实例才能操作

静态变量

道理和调用函数相同

var LoginActivity3 = Java.use("com.xx.xx.xx.xx");

// 设置变量值后面必须加 `.value` 才能设置
LoginActivity3.static_bool_var.value = true;
 
JavaScript

动态变量

// 动态变量必须 choose 找到示例才能操作
Java.choose("com.xx.xx.xx.xx",{
    onMatch: function(instance){
        // 设置变量值后面必须加 `.value` 才能设置
        instance.bool_var.value = true;
        
        // 注意! 如果动态变量名与函数名重名了,就需要在前面加 _ 下划线,如下:
        instance._same_name_bool_var.value = true;
    },
    onComplete: function(){
    }
});
 
JavaScript

枚举

枚举类中方法

有的情况下我们要hook一个类下所有的方法(不知道他的方法类型和数量),这个时候我们就要用到 java 的反射 getDeclaredMethods()

//Hook类的所有方法
Java.perform(function(){
    var md5 = Java.use("com.xxx.xxx.xxx");
    var methods = md5.class.getDeclaredMethods();
    for(var j = 0; j < methods.length; j++){
        var methodName = methods[j].getName();
        console.log(methodName);
        // hook methodNmae 这个类的所有方法(难点在于每个方法的参数是不同的)
        for(var k = 0; k < md5[methodName].overloads.length; k++){
            md5[methodName].overloads[k].implementation = function(){
                // 这是 hook 逻辑
                for(var i = 0; i < arguments.length; i++){
                    console.log(arguments[i]);
                }
                return this[methodName].apply(this, arguments);  // 重新调用
            }
        }

    }
});
 
JavaScript

枚举所有类

setTimeout(function (){
  Java.perform(function (){
    console.log("\n[*] enumerating classes...");
    Java.enumerateLoadedClasses({
      onMatch: function(_className){
        console.log("[*] found instance of '"+_className+"'");
      },
      onComplete: function(){
        console.log("[*] class enuemration complete");
      }
    });
  });
});
 
JavaScript

Hook 构造对象(自定义参数)

 

参数是一个自定义类

类是这样的

 

Java.perform(function () {
    var money = Java.use('com.xx.app.Money')  // 如果要自定义实例化就要获取并重写
    var utils = Java.use('com.xx.app.Utils');
    utils.test.overload("com.xx.app.Money").implementation = function (obj) {
        console.log("参数自定义类Hook中...");
        // 重新实例化  $new()
        var mon = money.$new(999,'我的天')
        send(mon.getInfo());  // 调用 这个对象的 getInfo 
        return mon.getInfo();  // 根据需求return
    }
});
 
JavaScript

Hook interface 接口类

目前在app逆向中遇到interface搜索其实现还是一顿乱搜。
可以使用反射得到实现的接口数组,然后打印出来即可,这个问题终于可以解决了。

 

Hook 构造函数

 

类的内部如下

 

Java.perform(function () {
    var Money = Java.use('com.xx.xx.xx');
    Money.$init.implementation = function (a, b) {
        console.log("构造函数Hook中...");
        send(a);
        send(b);
        send("Success!");
        return this.$init(a, b);
    }
});
 
JavaScript

解析:

  • $init 构造函数 和 python语法类似
  • this.$init(a, b) 这里的 this 指代,原始app中的函数,$init() 表示该类的实例化

Hook 数组(char 和 byte)

有很多方法我这里直接用 gson.dex 方法,再肉丝的星球中下载

打印 CharArray 和 byteArray

Java.perform(function () {
    // 调用 自写dex
    Java.openClassFile("/data/local/tmp/r0gson.dex").load();
    const gson = Java.use('com.r0ysue.gson.Gson');

    // CharArray
    Java.use("java.util.Arrays").toString.overload('[C').implementation = function(charArray){
        var result = this.toString(charArray);
        console.log("charArray,result:",charArray,result)
        console.log("charArray Object Object:",gson.$new().toJson(charArray));
        return result;
    }

    // byteArray
    Java.use("java.util.Arrays").toString.overload('[B').implementation = function(byteArray){
        var result = this.toString(byteArray);
        console.log("byteArray,result):",byteArray,result)
        console.log("byteArray Object Object:",gson.$new().toJson(byteArray));
        return result;
    }
});
 
JavaScript

生成数组替换结果

java代码和上面例子相同

Java.perform(function () {
    // 调用 自写dex
    Java.openClassFile("/data/local/tmp/r0gson.dex").load();
    const gson = Java.use('com.r0ysue.gson.Gson');

    // CharArray 替换
    Java.use("java.util.Arrays").toString.overload('[C').implementation = function(charArray){
        var newCharArray = Java.array('char', [ '一','去','二','三','里' ]);
        var result = this.toString(newCharArray);
        console.log("newCharArray,result:",newCharArray,result)
        
        // 利用 gson.dex 来修改
        console.log("newCharArray Object Object:",gson.$new().toJson(newCharArray));
        
        // 官方api方法
        var newResult = Java.use('java.lang.String').$new(Java.array('char', [ '烟','村','四','五','家']))
        return newResult;
    }

});
 
JavaScript

Hook 重载方法

例两个同名的函数。给多少个参数,调用有多少参数的对应方法 必须使用 overload()方法!!!

  • function test(a)
  • function test(a,b,c)

解决方法 overload() 指定

  • 如果是一个 int 类型的参数那么 overload("int") 要指定参数与类型
  • 如果是 string 类型 overload("java.lang.String") 全路径
var Utils = Java.use('com.xx.app.Utils');
Utils.test.overload("int").implementation = function () {
    console.log("重写方法Hook中...");
    send("重写方法 Success!");
    return this.test(55555555);
}
 
Python

Hook 类中的类

com.xxx.xxx.xxx.xxx$InnerClasses

利用符号 $ 来操作

Hook 被混淆的函数名

有的代码混淆,函数名已经是乱码符号

// 比如说这
int ֏(int x) {
    return x + 100;
}
 
Java

甚至有一些不可视, 所以可以先编码打印出来, 再用编码后的字符串去 hook.

Java.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[i].toString());
            console.log(encodeURIComponent(methods[i].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;
            }
    }
)
 
JavaScript

Hook 函数的参数为 map 等特殊类型

 

Java.perform(function () {
    /*
    var ShufferMap = Java.use('com.xx.xx.ShufferMap');
    ShufferMap.show.implementation = function (map) {
        
        var result = "";
        var keyset = map.keySet(); // 
        var it = keyset.iterator();
        while(it.hasNext()){
            var keystr = it.next().toString();
            var valuestr = map.get(keystr).toString();
            result += valuestr;
        }
        send(result);
        return this.show(map);
    }
    */
    var HashMap = Java.use('java.util.HashMap');
    var ShufferMap = Java.use('com.xx.app.ShufferMap');
    ShufferMap.show.implementation = function (map) {
        var hm = HashMap.$new();
        hm.put("user","dajianbang");
        hm.put("pass","87654321");
        hm.put("code","123456");
        return this.show(hm);
    }
});
 
JavaScript

方法2

Java.perform(function(){
    var ShufferMap = Java.use("com.xx.app.ShufferMap");
    console.log(ShufferMap);
    ShufferMap.show.implementation = function(map){
        console.log(JSON.stringify(map));
        //Java map的遍历
        // var key = map.keySet();
        // var it = key.iterator();
        // var result = "";
        // while(it.hasNext()){
        //     var keystr = it.next();
        //     var valuestr = map.get(keystr);
        //     result += valuestr;
        // }
        // console.log(result);
        // return result;

        map.put("pass", "wawa");
        map.put("guanwang", "666");

        var retval = this.show(map);
        console.log(retval);
        return retval;

    }
});
 
Java

Hook 动态加载的 dex

先枚举到类, 然后利用Java.classFactory.loader = loader; 切换 classloader

// 先枚举到类, 然后利用Java.classFactory.loader = loader; 切换 classloader
 Java.perform(function () {
        //hook 动态加载的dex
        Java.enumerateClassLoaders({  // 枚举当前加载的 Java VM类加载器
            onMatch: function (loader) {
                try {
                    if (loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")) {
                        console.log(loader);
                        Java.classFactory.loader = loader;      //切换 classloader, 切换好了就可以正常hook了
                    }
                } catch (error) {
                }
            }, onComplete: function () {
            }
        });
 
        var DynamicCheck = Java.use("com.example.androiddemo.Dynamic.DynamicCheck");
        console.log(DynamicCheck);
        DynamicCheck.check.implementation = function () {
            console.log("DynamicCheck.check");
            return true;
        }
    });
 
JavaScript

Hook 找不到包名的类

 

我们要hook类似这种代码的时候,找不到引用包,我们可以通过查看 smali 代码来看到她的引用

输出调用栈

function showStacks() {
    send('调用栈输出\n\t' + Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
}
 
Java

调用外部 dex

dex 中变量名尽量取得特殊一点,防止重名。

使用案例 再上面《Hook 数组(char 和 byte)》 中就有引用肉丝的 dex 例子

手动注册类

frida 用 registerClass 自己构造一个类

Java.perform(function(){
    var liquid = Java.use("com.xx.xx.xx");
    var beer = Java.registerClass({
    name: 'com.xx.xx.xx',
    implements: [liquid],
    methods: {
        flow: function () {
            return "look, beer is flowing!";
        }
    }
    });
    console.log("beer.bubble:",beer.$new().flow())      
})
posted @ 2021-05-06 11:14  koflfy  阅读(569)  评论(0编辑  收藏  举报