LOADING

加载过慢请开启缓存 浏览器默认开启

frida的初步学习

运行frida常用命令

运行

adb push 名 /data/local/tmp
adb root
adb shell chmod +x /data/local/tmp/fridaad64
adb shell /data/local/tmp/frida-server -l 0.0.0.0:27042 #默认27042端口
adb forward tcp:27042 tcp:27043
Frida -U -f 包 -l hookbool.js

-U 指定USB设备

-f 用app包名spwn方式启动

-P 指定APP的pid,先要自行启动

-pause 暂停

-l 加载hook脚本

hookjs

对fridahook脚本的一点理解

我们用fridahook一个函数时可以说是我们从apk里面钩住了一个函数,我们可以替换这个函数的任何内容。也可以说我们建立了一个管道在这个函数方法上,代码执行就像是一个水流,当水流到这个函数时,我们把水引到了我们的js这里,让它流经我们想要流过的地方。

一些frida方法的收集

send(); //发送信息到控制台.

对hook脚本的初步解析

//在启动时就被hook的方法,通常用于绕过反调试,java.perform()是一个frida的接口
//几乎一切操作都在这个函数执行
Java.perform(function(){  
    let MainActivity = Java.use("packname.MainActivity"); //实例化一个类
    MainActivity["isEmu"].implementation = function () {
        console.log(`MainActivity.isEmu is called`);
        let result = this["isEmu"]();
        console.log(`MainActivity.isEmu result=${result}`);
        return 0;  //一般可以修改返回值如果报错用false,修改返回值
    };
    //调用方法并返回值。
    MainActivity["g4tk4y"].implementation = function () {
    console.log(`MainActivity.g4tk4y is called`);
    let result = this["g4tk4y"]();
    console.log(`MainActivity.g4tk4y result=${result}`);
    return result; //修改返回值
};
//java.choose会遍历类的实例,调用方法,用于无法获得实例时动态引用,
//修改成员变量。我的理解是寻找一个系统自己的实例,而不是我们自己去实例化。
 Java.choose("packname.MainActivity",{  
        onMatch:
        function(x){
            console.log("ok" + x);
            let result = x.g4tk4y();
            console.log(result);
        },
        onComplete: function () {
            console.log("end");
        }

});
var MainActivity = Java.use("packname.MainActivity");
        //overload 选择被重载的对象,funname是方法名,int是要重载的类型
        MainActivity.funname.overload('int').implementation = function (x) {
            console.log("ok" + x);
            //可修改结果,另一种修改返回值的方法
            var result = "";
            return result;
        };
})

 

function hook() {   //把方法封装为一个函数,在运行起来后可以直接调用执行
Java.perform(function(){
    let MainActivity = Java.use("packname.MainActivity");
    MainActivity["g4tk4y"].implementation = function () {
        console.log(`MainActivity.g4tk4y is called`);
        let result = this["g4tk4y"]();
        console.log(`MainActivity.g4tk4y result=${result}`);
        return result;
        };
    MainActivity.aaa("x"); //调用函数并传参
})
};

(function () {    //(function(){..})();这样的形式会直接执行函数,  
                  //以下函数用dia提取,用于hookso层的函数

    // @ts-ignore
    function print_arg(addr) {
        try {
            var module = Process.findRangeByAddress(addr);
            if (module != null) return "\n"+hexdump(addr) + "\n";
            return ptr(addr) + "\n";
        } catch (e) {
            return addr + "\n";
        }
    }

    // @ts-ignore
    function hook_native_addr(funcPtr, paramsNum) {
        var module = Process.findModuleByAddress(funcPtr);
        try {
            Interceptor.attach(funcPtr, {
                onEnter: function (args) {
                    this.logs = "";
                    this.params = [];
                    // @ts-ignore
                    this.logs=this.logs.concat("So: " + module.name + "  Method: Java_work_pangbai_debugme_MainActivity_g4tk4y offset: " + ptr(funcPtr).sub(module.base) + "\n");
                    for (let i = 0; i < paramsNum; i++) {
                        this.params.push(args[i]);
                        this.logs=this.logs.concat("this.args" + i + " onEnter: " + print_arg(args[i]));
                    }
                }, onLeave: function (retval) {
                    for (let i = 0; i < paramsNum; i++) {
                        this.logs=this.logs.concat("this.args" + i + " onLeave: " + print_arg(this.params[i]));
                    }
                    this.logs=this.logs.concat("retval onLeave: " + print_arg(retval) + "\n");
                    console.log(this.logs);
                }
            });
        } catch (e) {
            console.log(e);
        }
    }
    // @ts-ignore
    hook_native_addr(Module.findBaseAddress("libdebugme.so").add(0xff0), 0x1);
})();

//重载函数的其他类型
.overload()
.overload('int')
.overload('java.lang.Exception')
.overload('android.content.Context')
.overload('java.lang.String')
.overload('android.content.Context', 'java.lang.String')
.overload('java.io.BufferedInputStream', 'java.io.BufferedInputStream', 'int')
.overload('android.content.Context', 'java.lang.String', 'java.lang.String', 'java.lang.String')

上面的方法都是被动调用,下面一段脚本是主动调用脚本

Java.perform(function(){
        var main =Java.use("com.moible.r15.main").$new();
        var input = "66.666s";
        var result = main.getit(input);
        console.log(result);
    })

有时候我们想要把一个调用方法封装在一个函数里面,在之后手动调用,然而在我们后面调用时可能会出现报错

这个时候我们要使用一下代码使handle能够在别的实例中运行。

 send(Java.available); 
function get(){
    Java.perform(function () { 
        send(Java.androidVersion); 
        send(Java.isMainThread());
    
        Java.scheduleOnMainThread(function () { 
            send(Java.isMainThread());
            
            var main = Java.use("com.moible.r15.main").$new();  //记得实例化new
            var input = "66.666s";  //设置参数
            var result = main.getit(input);
            console.log(result);       
        });
    });
}

一些常见错误

关于雷电模拟器spawn启动时卡在waitdebug界面的的原因解决方案

在用雷电模拟器调试时,有可能会卡在wait for debug,这是因为雷电的adb调试会给我们自动设置调试的应用,从而卡在wait界面。只要在开发者选项中把选择调试的应用改成”无”就行了。

关于frida调试应用闪退的解决方案

端口没有设置好.设置一下端口就行。

adb forward tcp:27042 tcp:27043

脚本运行过程中报错

查找报错点,找到报错的方法,分析,有必要时直接hook下来,修改函数的返回值等内容。