查看原文
其他

分享|Frida在安卓逆向中使用的脚本以及延时Hook手法

lykseek 看雪学院 2019-05-25

0x00 frida简介


frida是近几年才推出的一款全平台的逆向神器。功能上主要采用动态hook的方式,加入log,修改逻辑等。可以对java,native等hook。


具体使用情况,谁用谁知道。废话不多说,直接上干货。


这里仅仅讨论安卓上面的情况,其他平台的咱不做研究。



0x01 在java中的一些应用


1、延时Hook


安卓有一些多包的问题,另外有一些类是通过动态加载的方式来加载的。可能在hook触发的那个时间点,不会找到未加载的代码。


这个时候,可以通过在class loader上面加hook的方式,在hook的代码下进行二次绑定加载。


这里没有代码,需要各位同学自己尝试一下。



2、打印调用栈


调用栈,这个很有用。在分析的过程中,不一定会一定找到需要分析或者hook的函数。可能根据字符串等蛛丝马迹,仅仅找到一部分信息。


使用java调用栈,就可以找到方法的调用关系。


代码如下:

Java.perform(function () {                                      
  var thread = Java.use('java.lang.Thread');
  var instance = thread.$new();

  function where(stack){
    var at = ""
    for (var i = 0; i < stack.length; i++){
        at += stack[i].toString() + "\n";
    }

    return at;
  }

  var ConnectionErrorMessages = Java.use("com.google.android.gms.common.internal.ConnectionErrorMessages");
  ConnectionErrorMessages.getErrorMessage.overload('android.content.Context','int').implementation = function(mContext,mI){

        console.log("gms i:"+ mI);

        var ret = this.getErrorMessage(mContext,mI);

        console.log("return:" + ret);

        var stack = instance.currentThread().getStackTrace();
        var full_call_stack = where(stack);

        console.log(full_call_stack);

        return ret;
  };
});

      

如上所示,可以把所用调用了ConnectionErrorMessages.getErrorMessage这个方法的栈给打印出来。



3、关于java的重载 


这个载frida中设计比较友好,如果不知道重载方法如何写。只需要写上方法名,运行一次,frida就会把所有的方法,通过错误日志的形式给打印出来。照抄即可。

// overload 是用于定位hook哪一个方法的

   .overload()
   .overload('java.lang.String')
   .overload('android.app.Activity')
   .overload('int')
   .overload('[B') // byte array
   .overload('float')
   .overload('android.content.Context')
   .overload('[C')
   .overload('android.content.Context', 'android.view.View')
   .overload('android.app.Activity', 'com.cherrypicks.hsbcpayme.model.object.PayMeNotification')
   .overload('android.content.Context', 'boolean')
   .overload('android.content.Context', 'int')
   .overload('android.content.Context', 'java.lang.String')
   .overload('android.app.Activity', 'int')
   .overload('java.lang.String', 'java.lang.String')
   .overload('android.content.Context', 'android.graphics.Bitmap')
   .overload('java.lang.String', 'java.io.File')
   .overload('android.content.Context', 'java.lang.String', 'java.util.List')
   .overload('java.lang.String', 'java.lang.String', 'java.lang.String')
   .overload('java.lang.String', '[B', '[B')
   .overload('java.lang.String', 'java.lang.String', 'android.content.Context')
   .overload('android.app.Activity', 'com.cherrypicks.hsbcpayme.model.object.PayMeNotification', 'int')
   .overload('[B', '[B', '[B')
   .overload('android.content.Context', 'java.lang.String', 'java.lang.String')
   .overload('android.app.Activity', 'int', 'int', 'int', 'boolean')


// 一个列子
Java.perform(function () {
   var AssetManager = Java.use("android.content.res.AssetManager");
   var FileInputStream = Java.use("java.io.FileInputStream");
   AssetManager.open.overload("java.lang.String").implementation = function(str) {
       send("hook asset")
       if(str.endsWith(".xxx")){
           return FileInputStream.$new("/data/local/tmp/xxxxx");
       }
       return this.open(str)
   }
});


如上图所示,就是AssetManager 的 open方法的各种方法。



0x02 在C语言中的Hook


1、同样的延时Hook 


这里的Hook可以绑定到程序启动时,这个时候可以针对脱壳以及一些其他只有在启动时才会触发的逻辑起作用。如下面的代码所示,可以先把hook的代码,放在libc.so 的open方法上面,等到指定的so加载的时刻,在触发自需要hook的逻辑。

function hookopen(){
   var openPtr = Module.findExportByName("libcrypt-lib.so", ".open");
   console.log("openPtr:",JSON.stringify(openPtr));
}

function hookfopen(){
   var fopenPtr = Module.findExportByName("libcrypt-lib.so", ".fopen");
   console.log("fopenPtr:",JSON.stringify(fopenPtr));
}


function hookOpen(){
   var openPtr = Module.findExportByName("libc.so", "open");
   var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
   Interceptor.replace(openPtr, new NativeCallback(function (pathPtr, flags) {
   var path = Memory.readUtf8String(pathPtr);
   console.log("Opening '" + path + "'");
   var fd = open(pathPtr, flags);
   console.log("Got fd: " + fd);
   return fd;
}, 'int', ['pointer', 'int']));
}


var libc=Module.findExportByName(null,"dlopen");
var find = 0;
Interceptor.attach(libc,{
       
       onEnter: function(args) {

           hookOpen();

           var addr = args[0];
           var str = Memory.readCString(addr);
           // console.log("dlopen ",str);
           if (str.indexOf("libcrypt-lib.so") > 0){
               find = 1;
           }else{
               find = 0;
           }
       },
       onLeave:function(retval){
           if (find > 0){          

           }
       }
});借宿把

      


2、C语言中打印调用关系


c中可以打印到该方法,是由那个so调用的。如open函数,在这里就可以知道是由那个so调用了,然后打印出该so具体的打开了那几个文件。根据打开的文件,进而可以猜测出使用了那些设备的信息以及一些其他操作。


关键的打印调用 就是这一行代码:Thread.backtrace

var openFile = new File("/sdcard/openFile.txt","a+");
function hookOpen(){
   var openPtr = Module.findExportByName("libc.so", "open");
   var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
   Interceptor.replace(openPtr, new NativeCallback(function (pathPtr, flags) {
   var path = Memory.readUtf8String(pathPtr);

   var fd = open(pathPtr, flags);
   // console.log("Got fd: " + fd);

   var trace = Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n");
   if (trace.indexOf("libcrypt-lib.so") > 0){
       console.log("trace:"+trace);
       console.log("Opening '" + path + "'");

       openFile.write(path+"\n");
       openFile.flush();
   }

   return fd;
}, 'int', ['pointer', 'int']));
}

 

    

0x03 结语


如果纰漏,请各位同学加以指出。


最后放上脚本的git地址:

  

https://github.com/lykmoon/frida-tools.git



- End -


看雪ID: lykseek                         

https://bbs.pediy.com/user-623313.htm



本文由看雪论坛 lykseek 原创

转载请注明来自看雪社区


长按识别下方图中的二维码,为Ta投票!



热门图书推荐:

立即购买!



热门技术文章:        



公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com


点击下方“阅读原文”

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存