2020年6月11日星期四

andorid jar/库源码解析之frida体验

andorid jar/库源码解析之frida体验


目录:andorid jar/库源码解析 

Frida体验:

  作用:

    android手机上可以对,java和so层代码,进行hook.监控数据和处理内存数据。

    官译:面向开发人员、逆向工程师和安全研究人员的动态工具工具包。

  栗子:

    运行步骤:

    1、https://github.com/frida/frida/releases 下载适合需要运行环境的可执行程序。我这里是arm64,所以下载了一个最新版本的frida64位。

    2、PC端,安装python环境,直接从官网下载一个python安装包安装即可,我这里安装的是python3, 安装包会自己配置环境变量,cmd运行 python,看看有没有,有就是安装上了环境变量了。

    3、使用 pip install frida 安装 frida 环境,基于 python的。  再安装  pip install frida-tools ,我看大部分都是按照了。tools的。

    4、一切ok。开始跑了,,,把步骤1中得到的,可执行文件,拷贝到手机上面  adb push D:\xxx\xxx\frixxxx   /data/local/tmp/

    5、因为push上去的可执行文件默认没有权限,下一步授权。。adb shell 进入手机  su,得到root权限。。cd /data/local 进入 local文件夹  chmod 777 -R *  授权可执行。。 再  cd tmp  进入 tmp  执行 :./frXXX回车运行exe

效果如下图:

    

    6、端口转发,因为要把手机的数据和本地电脑互通,需要设置端口转发,两个端口:执行两条命令

    

adb forward tcp:27042 tcp:27042adb forward tcp:27043 tcp:27043

    7、接着就可以允许python了。

    8、代码示例:

import frida, sysjsCode = """Java.perform(function () {    var impl = Java.use("com.android.test.TestUtil");    impl.test1.implementation = function () {        send("test1 called!");        this.test1();    }; impl.test2.implementation = function () {        send("test2 called!");    }; impl.test3.implementation = function (a) {        send("test3 called!");    }; impl.test4.implementation = function (a,b,c) {        send("test4 called!");  return this.test4(a,b,c);    }; impl.test5.overload("int").implementation = function (a) {        send("test5 1 called!");    }; impl.test5.overload("int", "java.lang.String").implementation = function (a,b) {        send("test5 2 called!");    };});"""def message(message, data): if message["type"] == 'send':  print(u"[*] {0}".format(message['payload'])) else:  print(message)process = frida.get_remote_device().attach("com.android.test")script= process.create_script(jsCode)script.on("message", message)script.load()sys.stdin.read()

  代码中,把js写到了一个string变量中。多行都是用这个固定格式。

  对test1方法进行了hook同时,在后面也对 test1方法进行了调用,如果不调用,方法就不会执行了。参考 test2

  test3针对单个参数的情况,test4针对多个参数。test5,针对不同参数进行了重载,需要指明参数类型,上面做了处理。

  执行js的send方法,内容回呗,发往,scritp的绑定方法 。def message(message, data)在里面,进行输出,你也可以在js中使用 console.log进行输出参数。

  针对是复杂类型的情况,可以直接a.XXXX拿到复杂类型的变量。

  8.2、其他js

// 遍历所有js.指定名称,过滤Java.perform(function(){ Java.enumerateLoadedClasses({  onMatch: function(className) {   if(className.toString().indexOf("down") >= 0){    send(className+'\"));');   }  },  onComplete:function(){   send("done");  } });});

  9:so,hook处理。

  

import frida, sysjsCode3 = """Java.perform(function(){  var exports = Module.enumerateExportsSync("xxx.so"); for(var i = 0; i < exports.length; i++) {  if(exports[i] && exports[i].name != undefined){   if(exports[i].name.indexOf("rapidjson")>=0){    var nativePointer = new NativePointer(exports[i].address);    send("exports " + exports[i].name + " nativePointer " + nativePointer);    Interceptor.attach(nativePointer, {     onEnter: function(args) {      send(this.context.pc + " called! ");      send("context " + JSON.stringify(this.context));            // 保存长度,在返回方法进行调用      this.fd = args[1];      // send(nativePointer + " arg0 " +args[0] + " arg1 " +args[1] + " arg2 " +args[2]);     },     onLeave:function(retval){      send(this.context.pc + " retval " +retval);            // dump出内容      var size = parseInt(this.fd);      if(size > 0){       const r = Memory.alloc();               // 复制以module.base地址开始的10个字节 那肯定会是7F 45 4C 46...因为一个ELF文件的Magic属性如此。       Memory.copy(r,ptr(retval),size);       console.log(hexdump(r, {        offset: 0,        length: size,        header: true,        ansi: false       }));      }     }    });   }  } }});""";jsCode2 = """Java.perform(function(){ // 遍历所有模块 Process.enumerateModules({  onMatch: function(exp){   //先获取so的module对象   var module = Process.findModuleByName(exp.name);       //??是通配符   var pattern = "11 22 33 44 55 66"; //   //基址   // console.log("base:" + module.base)   //从so的基址开始搜索,搜索大小为so文件的大小,搜指定条件03 49 ?? 50 20 44的数据   var res = Memory.scan(module.base, module.size, pattern, {    onMatch: function(address, size){     //搜索成功     console.log('搜索到 ' + pattern +" 地址是:"+ address.toString());     },     onError: function(reason){     //搜索失败     // console.log('搜索失败 ' + reason);    },    onComplete: function(){     //搜索完毕     // console.log("搜索完毕")    }   });  },  onComplete: function(){   send('stop');  } }); // 导入函数 var imports = Module.enumerateImportsSync("xxx.so"); for(var i = 0; i < imports.length; i++) {  if(imports[i].name == 'strncat'){   send(imports[i].name + ": " + imports[i].address);   break;  } }  // 导出函数 var exports = Module.enumerateExportsSync("xxx.so"); for(var i = 0; i < exports.length; i++) {  if(exports[i].name.indexOf('add') != -1){   send(exports[i].name + ": " + exports[i].address);   break;  } }});"""; jsCode = """var module = Process.findModuleByName("xxx.so"); var nativePointer = new NativePointer(module.base.add(0x1740));send("nativePointer " + nativePointer);Interceptor.attach(nativePointer, { onEnter: function(args) {  send("mou sub_method called!"); }, onLeave:function(retval){  }});var nativePointer = new NativePointer(ptr(0x00001122));send("nativePointer " + nativePointer);Interceptor.attach(nativePointer, { onEnter: function(args) {  send("mou sub_method 2 called!"); }, onLeave:function(retval){  }});"""def message(message, data): if message["type"] == 'send':  print(u"[*] {0}".format(message['payload'])) else:  print(message)process = frida.get_remote_device().attach("com.android.test")script= process.create_script(jsCode2)script.on("message", message)script.load()sys.stdin.read()

  提供了多种方法:

  a>遍历所有so模块,查找指定关键字。

  b>遍历某个模块的所有导出函数,名称包含

  c>遍历某个模块的所有导入函数,名称包含。

  d>直接通过,模块得到内存地址和偏移,进行hook.

  e>通过利用 this.的成员变量,在结果中,dump出,入参的参数的某个值进行dump内容。

  f>输出 this.context对象。

  源码解读:

  待补充

  参考:

        https://www.anquanke.com/post/id/195215

  https://www.anquanke.com/member/131652

  源码:https://frida.re/

  引入:

 

没有评论:

发表评论

注意:只有此博客的成员才能发布评论。