frida hook native so

1 转向native

接触frida以来,基本的hook操作都在java层开展。其实java层的hook只是基操,在更高层次的对抗,都会对so进行分析,这里就需要使用到frida hook native的知识,包括模块、函数地址、参数替换等。

1.0.1 模块定位

模块定位比较简单,就是根据so名字找出so在内存中的加载地址,对应的frida api为Module.findBaseAddress。后续在做非导出函数定位的时候需要。

1.0.2 函数定位

  • 导出函数

    导出函数,直接在导出表里找到符号,然后通过Module.findExportByName即可定位函数地址。

  • 非导出函数

    非导出函数,需要通过反编译获取函数相对地址,然后加上so模块加载的内存基地址即可。

  • 符号定位

    符号定位,通过Process.findModuleByName().enumerateSymbols()枚举符号,然后通过对比符号获取地址。

1.0.3 Intercept

通过Intercept接口,可以使用attach或者replace来hook或者替换。attach会有两个回调地址,onEnter和onLeave。注意的是onLeave中可以修改返回值,而onEnter中无法修改函数参数。如果要修改参数,通常是使用replace配合NativeFunction和NativeCallback替换原函数,增加自己的逻辑。

function find_openvpn_so() {
    var base_addr = Module.findBaseAddress("libopenvpn.so");
    var send_func_addr = Module.findExportByName("libopenvpn.so", "send_control_channel_string");
    var management_android_control_addr = Module.findExportByName("libopenvpn.so", "management_android_control");
    var management_io_addr = Module.findExportByName("libopenvpn.so", "management_io");
    var command_line_get_addr = Module.findExportByName("libopenvpn.so", "command_line_get");
    var auth_user_pass_setup_addr = Module.findExportByName("libopenvpn.so", "auth_user_pass_setup");
    var x_msg_addr = Module.findExportByName("libopenvpn.so", "x_msg");
    if (auth_user_pass_setup_addr != null) {
        // var my_auth_user_pass_setup = new NativeFunction(ptr(auth_user_pass_setup_addr), 'bool', ['pointer','pointer'])
    }
    console.log("send_func_addr is : ", send_func_addr);
    console.log("management_android_control_addr is : ", management_android_control_addr);
    console.log("auth_user_pass_setup_addr is : ", auth_user_pass_setup_addr);
    // 添加拦截器
    if (send_func_addr != null) {
        Interceptor.attach(send_func_addr, {
            // 打印入参
            onEnter: function (args) {
                console.log("send_control_channel_string send string is : ", args[1].readCString());
            },
            // 打印返回值
            onLeave: function (returnValue) {

            }
        })
    }
    if (management_android_control_addr != null) {
        Interceptor.attach(management_android_control_addr, {
            // 打印入参
            onEnter: function (args) {
                // console.log('management_query_user_pass called from:\\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n');
                console.log("management_android_control cmd is " + args[1].readCString())
            },
            // 打印返回值
            onLeave: function (returnValue) {

            }
        })
    }
    if (management_io_addr != null) {
        Interceptor.attach(management_io_addr, {
            // 打印入参
            onEnter: function (args) {
                // console.log("management_io_addr called");
            },
            // 打印返回值
            onLeave: function () {
                // console.log("management_io_addr result is void");
            }
        })
    }
    if (command_line_get_addr != null) {
        Interceptor.attach(command_line_get_addr, {
            // 打印入参
            onEnter: function (args) {
                // console.log("command_line_get_addr called");
            },
            // 打印返回值
            onLeave: function (returnValue) {
                console.log("command_line_get_addr result is ", returnValue.readCString());
            }
        })
    }
    if (auth_user_pass_setup_addr != null) {
        Interceptor.attach(auth_user_pass_setup_addr, {
            // 打印入参
            onEnter: function (args) {
                var str = Memory.allocAnsiString('stdin')
                my_auth_user_pass_setup(str, args[1])
                console.log("auth_user_pass_setup_addr called path is ", Memory.readCString(args[0]));
            },
            // 打印返回值
            onLeave: function () {
                // console.log("command_line_get_addr result is ", returnValue.readCString());
            }
        })
    }
    if (x_msg_addr != null) {
        Interceptor.attach(x_msg_addr, {
            // 打印入参
            onEnter: function (args) {
                console.log("x_msg_addr called path is ", args[1].readCString(), args[2].readCString());
            },
            // 打印返回值
            onLeave: function () {
                // console.log("command_line_get_addr result is ", returnValue.readCString());
            }
        })
    }
}

function hook_java_vpn_management() {
    if (Java.available) {
        Java.perform(function () {
            console.log('ready to hook normal vpn mobile java layer!')
            var management_thread_cls = Java.use("de.blinkt.openvpn.core.OpenVpnManagementThread");
            management_thread_cls.processCommand.implementation = function (cmd) {
                console.log('process cmd is ' + cmd)
                return this.processCommand(cmd)
            }
            management_thread_cls.managmentCommand.implementation = function (cmd) {
                console.log('send cmd is ' + cmd)
                return this.managmentCommand(cmd)
            }
        });
    }
}

// setTimeout(find_openvpn_so, 100)
find_openvpn_so()