Frida05 - 高级API用法

参考文档

api-caller.com/2019/03/30/...

frida.re/docs/javasc...

数组打印

测试代码:

ini 复制代码
private static class Bean {
    String a;
    int b;
    float c;
}

private void test() {
    Bean[] beans = new Bean[3];
    beans[0] = new Bean();
    beans[0].a = "a";
    beans[0].b = 1;
    beans[0].c = 1f;

    beans[1] = new Bean();
    beans[1].a = "b";
    beans[1].b = 2;
    beans[1].c = 2f;

    beans[2] = new Bean();
    beans[2].a = "c";
    beans[2].b = 2;
    beans[2].c = 3f;

    Arrays.toString(beans);
}

想要 hook Arrays.toString() 方法很简单:

javascript 复制代码
function main() {
    Java.perform(function () {

        Java.use("java.util.Arrays").toString.overload('[Ljava.lang.Object;').implementation = function (x) {
            var result = this.toString(x);
            console.log("params=", x);
            console.log("result=", result)
            return result
        }

    })
}

setImmediate(main)

输出的结果很多:

可以看到,输出的数组里是一个对象,那有没有什么好办法将对象转成字符串显示出来呢?

答案就是Gson,所以使用开发的思想来做逆向是很重要的。

项目里面不一定引入了Gson,所以我们需要自己编译一个gons库,放到手机里面,然后使用frida加载一下就可以使用了。

加载外部DEX

ini 复制代码
var dexPath = "/data/local/tmp/r0gson.dex";
Java.openClassFile(dexPath).load();

已经有大佬编译好了的dex,我们可以直接用:

github.com/r0ysue/Andr...

为了避免类重复,还特意换了包名,具体可看:

bbs.kanxue.com/thread-2591...

重新写脚本:

javascript 复制代码
function main() {
    Java.perform(function () {

        Java.use("java.util.Arrays").toString.overload('[Ljava.lang.Object;').implementation = function (x) {
            var result = this.toString(x);
            if (x.length > 0 && x[0].getClass().getName() == "com.example.demo2.MainActivity$Bean") {
                Java.openClassFile("/data/local/tmp/r0gson.dex").load();
                const gsonClass = Java.use('com.r0ysue.gson.Gson');
                for (var i=0; i<x.length; i++) {
                    console.log("entry=", gsonClass.$new().toJson(x[i]));
                }
            }
            return result;
        }

    })
}

setImmediate(main)

看下输出结果:

ini 复制代码
Spawned `com.example.demo2`. Resuming main thread!                      
[Pixel::com.example.demo2]-> entry= {"a":"a","b":1,"c":1.0}
entry= {"a":"b","b":2,"c":2.0}
entry= {"a":"c","b":2,"c":3.0}

构造数组

有时候为了替换返回值,需要一个数组类型,可以使用如下方式,构造一个数组:

ini 复制代码
const values = Java.array('int', [ 1003, 1005, 1007 ]);

const JString = Java.use('java.lang.String');
const str = JString.$new(Java.array('byte', [ 0x48, 0x65, 0x69 ]));

类型转换

测试代码:

ini 复制代码
Father father = new Father();
Son son = new Son();
Father father2 = new Son();

脚本:

javascript 复制代码
Java.choose('com.example.demo2.Father', {
    onMatch: function (instance) {
        console.log('found instance', instance);
        var son = Java.cast(instance, Java.use('com.example.demo2.Son'))
        console.log('cast instance', son.test());
    }, onComplete: function () { }

})

Java.choose('com.example.demo2.Son', {
    onMatch: function (instance) {
        console.log('found instance', instance);
        var father = Java.cast(instance, Java.use('com.example.demo2.Father'))
        console.log('cast instance', father.test());
    }, onComplete: function () { }

})

输出结果:

vbnet 复制代码
found instance com.example.demo2.Father@daf1aad
found instance com.example.demo2.Son@c7d41e2
cast instance Son
found instance com.example.demo2.Son@2341973
cast instance Son
Error: Cast from 'com.example.demo2.Father' to 'com.example.demo2.Son' isn't possible
    at cast (frida/node_modules/frida-java-bridge/lib/class-factory.js:131)
    at cast (frida/node_modules/frida-java-bridge/index.js:270)
    at onMatch (/demo2.js:20)
    at _chooseObjectsArtPreA12 (frida/node_modules/frida-java-bridge/lib/class-factory.js:298)
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/class-factory.js:250)
    at vt (frida/node_modules/frida-java-bridge/lib/android.js:573)

符合直觉,子类可以转成父类类型,但是调用的方法还是子类的。

注册一个类

有时候,我们想做一个AOPhook的时候,就需要实现一个接口,我们可以使用 registerClass 方法来做到。

测试代码:

java 复制代码
public interface IBook {

    String id();

    int size();

    boolean test(int input);

}

// -------------------------

public class SimpleBook implements IBook {

    @Override
    public String id() {
        return UUID.randomUUID().toString();
    }

    @Override
    public int size() {
        return 100;
    }

    @Override
    public boolean test(int input) {
        Log.e("SimpleBook", "input = " + input);
        return false;
    }

}

// -------------------------

IBook book = new SimpleBook();

脚本代码:

javascript 复制代码
Java.registerClass({
    name: 'com.example.demo2.SimpleBook2',
    implements: [Java.use('com.example.demo2.IBook')],
    fields: {
        proxy: 'com.example.demo2.IBook',
    },
    methods: {
        '<init>': [{
            returnType: 'void',
            argumentTypes: ['com.example.demo2.IBook'],
            implementation: function (proxy) {
                this.$super.$init();
                this.proxy.value = proxy;
            }
        }],
        id() {
            return this.proxy.value.id();
        },
        size() {
            return this.proxy.value.size();
        },
        test(input) {
            this.proxy.value.test(input);
            return true;
        },
    }
})

Java.choose('com.example.demo2.MainActivity', {
    onMatch: function (instance) {
        console.log('found MainActivity instance', instance);
        var oldBook = instance.book.value;
        instance.book.value = Java.use('com.example.demo2.SimpleBook2').$new(oldBook);
        console.log('book test id = ', instance.book.value.id());
        console.log('book test size = ', instance.book.value.size());
        console.log('book test result = ', instance.book.value.test(1));
    }, onComplete: function () { }

})

这里我们注册了一个类,com.example.demo2.SimpleBook2,并且实现了一个代理类,将 MainActivity 的字段替换之后,我们就可以让代理类来托管逻辑,做很多操作。

打印Map

与开发时的写法是一样的:

ini 复制代码
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;
}

Non-ASCII 方法名处理

比如说

arduino 复制代码
int ֏(int x) {
    return x + 100;
}

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

javascript 复制代码
var methods = Java.use('com.example.demo2.MainActivity').class.getDeclaredMethods();
for (var i in methods) {
    console.log('origin method name -> ' + methods[i].toString());
    console.log('encode method name ->' + encodeURIComponent(methods[i].toString().replace(/^.*?.([^\s.()]+)(.*?$/, "$1")));
}

Java.use('com.example.demo2.MainActivity')[decodeURIComponent("%D6%8F")].implementation = function() {
    console.log('method invoke');
    return 200;
}
相关推荐
一颗青果12 分钟前
【Linux】详解shell代码实现(上)
linux·运维·服务器·前端·chrome·算法·1024程序员节
琴~~27 分钟前
ant-design-vue中table某一列进行合并
前端·javascript·vue.js
sunly_1 小时前
Flutter:flutter_screenutil屏幕适配
前端·javascript·flutter
俸涛努力学前端1 小时前
ajax (一)
开发语言·前端·javascript·笔记·ajax
凌虚(失业了求个工作)2 小时前
Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人
前端·人工智能·python·whisper·llama
信息化未来2 小时前
odoo17 档案管理之翻译2
java·服务器·前端
川石课堂软件测试2 小时前
UI自动化测试|web端元素获取&元素等待实践
开发语言·前端·功能测试·算法·ui
糯米w2 小时前
【前端】excel文件对比
前端·javascript·excel
Ace_31750887762 小时前
微店商品详情接口技术实现详解及代码示例
前端
南城巷陌2 小时前
node.js中实现router模块化管理
前端·javascript·node.js·express.router