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()