Android使用Frida挂钩抽象类方法调用

Posted

技术标签:

【中文标题】Android使用Frida挂钩抽象类方法调用【英文标题】:Android hooking of abstract class method calls using Frida 【发布时间】:2017-12-05 19:13:49 【问题描述】:

我正在努力学习Frida 并且到目前为止已经做了一些实验。幸运的是,我可以找到足够的示例和教程来帮助我完成任务。 然而,此时此刻,我手头有一项非常具体的任务。

所以我们说下面是我所指的 Frida 钩子:

Java.perform(function () 

var Activity = Java.use("myPack.myClass");

Activity.methodM1.overload('[B', 'java.lang.String').implementation = function (a, str) 

    var retval = this.methodM1(a, str);

    console.log("[*] return value4: "+retval);

    return retval;
;
);

现在根据我目前的理解,对于上面的 Java.use,我的意思是每当创建 myPackage.myClass 的对象并且如果该对象调用方法 methodM1,则获得控制权改为我的javascript函数并执行其中提到的任何操作。

按预期完成工作。然而,重点(为了这个讨论而感兴趣)是:如果对象被制造出来,那么就会发生这种情况。

同样,如果我们也讨论 Java.choose() 而不是 Java.use,情况也会是一样的。所以即使在这种情况下,我们说如果对象被制作,然后调用我的回调。

现在,如果我试图挂钩到抽象类的方法会发生什么所以假设我正在尝试挂钩到方法

'静态获取实例(字符串)' 的 java.security.KeyPairGenerator(这是一个抽象类)。

这个类是抽象的,它的对象永远不会真正被制作出来。而方法为static,直接使用类名本身调用。所以在这种情况下,Java.use() 和 Java.choose() 都无法提供帮助(如果我的上述理解是正确的)。

那么在这种情况下,我该如何挂钩 getInstance() 呢?

这是我已经尝试过的东西:

Java.perform(
  function()
  
    Java.enumerateLoadedClasses(
     
      onMatch: function(className)
      
        if(className == "java.security.KeyPairGenerator")
        
          var item = Java.use(className); 

          console.log("the PrivateKey class was just loaded");
          item.getInstance.overload('java.lang.String').implementation = function(str)
          
            console.log("[*] This got called ");
            var ret = item.getInstance(str);
            console.log("[*] return value4: "+retval);
            return retval;
          
        
      ,
      onComplete:function()
    );
  
);

但这不起作用。同样,我在这里的假设是,每当创建 Object 并调用 getInstance() 时,就挂钩它。但是在这里,KeyPairGenerator 是一个抽象类,它本身从来没有真正被实例化过。我也试过:

className.getInstance()

而不是

item.getInstance()

这也不起作用。

【问题讨论】:

您是否尝试直接从 Java.use("java.security.KeyPairGenerator") 挂钩 getInstance?我想知道这是否行不通。我的意思是,如果你看一下生成的 smali 代码,它会从 KeyPairGenerator 调用 getInstance,对吧? 是的,这正是我的思考过程。是的,我也试过了。但它不知何故不起作用。更新了问题供您参考。 【参考方案1】:

从 Frida 10.1.2 开始,早期的检测工作非常好,可以在您的案例中使用以达到您的目标。

我在我的设备(Huwaei P8 lite \w android 6.0)上尝试了您的代码。我正在使用最新的 Frida (10.1.4)。结果,使用 Java.enumerateLoadedClass(在您的情况下)会使应用程序挂起,几秒钟后,frida 崩溃。

Error: abort was called
at u (frida/node_modules/frida-java/lib/android.js:512)
at p (java.js:2054)
at frida/node_modules/frida-java/index.js:105
at [anon] (repl1.js:28)
at frida/node_modules/frida-java/lib/vm.js:39
at y (frida/node_modules/frida-java/index.js:325)
at frida/node_modules/frida-java/index.js:305
at call (native)
at getPackageInfoNoCheck (Input:1)
[...]

可行的解决方案是依靠 Frida 的早期检测能力:

/*
Working code. 
No need of Java.enumerateLoadedClasses
The following application https://github.com/obaro/SimpleKeystoreApp has been installed  on the target device for testing.

Call the current javascript script like so:
frida -U -f com.sample.foo.simplekeystoreapp -l myscript.js --no-pause
*/

function monitorKPG2()

    console.log("Starting early instrumentation test...");

    Java.perform(function () 
        var target = Java.use("java.security.KeyPairGenerator");

        console.log("Target = " + target);

        target.getInstance.overload("java.lang.String", "java.lang.String").implementation = function(alg, prov) 
            console.log("getInstance " + alg);

            this.getInstance(alg, prov);
        ;
    ); 



console.log("Call me may be");
monitorKPG2();

【讨论】:

【参考方案2】:

除了@D4l3k 的精彩回答,以防万一有人使用旧版本的 Frida(无论出于何种原因),就像我在 10.0.5 上一样,仍然可以使用以下方法实现早期检测: Java.performNow() 而不是 Java.perform()

以下是使用 Java.performNow() 的工作示例:

Java.performNow(
  function()
  
    var item = Java.use("java.security.KeyPairGenerator"); 
    console.log("the PrivateKey class was just loaded");
    item.getInstance.overload('java.lang.String').implementation = function(str)
    
      console.log("[*] This got called " + str);
      var ret = this.getInstance(str);
      console.log("[*] return value4: "+ret);
      return ret;
    
  
);

【讨论】:

以上是关于Android使用Frida挂钩抽象类方法调用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Frida 在 Android 中从挂钩的本机函数中打印变量

在 Frida 拦截方法中读取结构/对象的值

初识Frida--Android逆向之Java层hook

你如何使用 frida 挂钩一个原生的剥离库?

使用Frida打印Java类函数调用关系

从 Frida 的非主线程调用 API 来修改应用程序的 GUI