安卓逆向——Frida的基础用法(下)

五. .js脚本在现有实例上调用方法
1.拿到附件,还是老样子,先到模拟器运行一下

没什么有用的信息,就是一个提示词,没了。开jadx看看逻辑吧,

可以看到逻辑还是很清晰的,有一个flag方法,如果code的值是1337,那么就会输出flag,但是该方法没有在程序的任何位置被调用,我们需要借助Frida框架来调用这个方法,以获取flag。跟上一用法相同的是我们需要通过flag方法所在的MainActivity类的实例来调用该方法,但在使用Frida脚本创建MainActivity类的实例会出现错误。

原因:flag方法是属于MainActivity实例的,而上一题(4)中,check是单独的一个类实例,而MainActivity是Android组件,由于Android的生命周期和线程规则,Android组件需要依赖于应用程序上下文运行,在Frida中,我们缺少必要的上下文。例如:Android UI组件通常需要具有关联Looper的特定线程,如果涉及UI任务,需要在具有活动Looper的主线程上执行。总之,创建MainActivity的实例可能需要应用处于特定状态,并通过Frida管理整个生命周期,并不建议这样做。

解决方法:由于创建MainActivity实例是Android应用程序生命周期的一部分,当Android应用程序启动时,系统会创建MainActivity的一个实例(或AndroidManifest.xml文件中指定的启动器活动)。因此,我们可以使用Frida获取MainActivity的实例,然后调用flag方法来获取我们的标志。

脚本:

/*
Java.performNow是Frida中的一个函数,用于在Java运行时环境中执行代码。
*/

Java.performNow(function() {

  Java.choose('com.ad2001.frida0x5.MainActivity', {
    // Java.choose在运行时枚举作为第一个参数传入的Java类的实例。
    // 第二个参数需要传入包含onMatch和onComplete两个回调函数的选项对象。

      onMatch: function(instance) { 
        // 处理匹配到的类实例的回调函数
        // instance参数表示MainActivity类的每个匹配实例

        console.log("Instance found");
        // 找到实例时打印一条提示信息。
        instance.flag(1337); 
        // 调用flag方法,并传入参数1337。
    },
    onComplete: function() {}
    // 完成操作后的回调函数
  });
});

这个题和第二个题一样,需要在app运行起来,然后输入frida -U 'Frida 0x5' -l F:\桌面\5.js,就可以输出flag

总结:Frida 使用对象参数调用方法的脚本模板

Java.performNow(function() {
  Java.choose('<Package>.<class_Name>', {
    onMatch: function(instance) {
      var <class_reference> = Java.use("<package_name>.<class>");
      var <class_instance> = <class_reference>.$new(); // 创建类的实例
      /*
      设置实例参数
      */
      instance.<method>(class_instance); // 使用对象参数调用方法
    },
    onComplete: function() {}
    // 完成操作后的回调函数
  });
});

六. .js脚本 Hook构造函数
1.拿到apk安装包,还是先安装到模拟器中运行一下看看先,

还是一样,没有输入框,只有一句提示词,那就用jadx反编译看看吧,

package com.ad2001.frida0x7;

import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

/* loaded from: classes3.dex */
public class MainActivity extends AppCompatActivity {
    TextView t1;

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.t1 = (TextView) findViewById(R.id.textview);
        Checker ch = new Checker(123, 321);
        try {
            flag(ch);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e2) {
            throw new RuntimeException(e2);
        } catch (BadPaddingException e3) {
            throw new RuntimeException(e3);
        } catch (IllegalBlockSizeException e4) {
            throw new RuntimeException(e4);
        } catch (NoSuchPaddingException e5) {
            throw new RuntimeException(e5);
        }
    }

    public void flag(Checker A) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        if (A.num1 > 512 && 512 < A.num2) {
            Cipher cipher = Cipher.getInstance("AES");
            SecretKeySpec secretKeySpec = new SecretKeySpec("MySecureKey12345".getBytes(), "AES");
            cipher.init(2, secretKeySpec);
            byte[] decryptedBytes = Base64.getDecoder().decode("cL/bBqDmfO0IXXJCVFwYLeHp1k3mQr+SP6rlQGUPZTY=");
            String decrypted = new String(cipher.doFinal(decryptedBytes));
            this.t1.setText(decrypted);
        }
    }
}

分析代码逻辑,并不难,就是有一个Checker类的对象,调用flag方法传入该对象,然后对num1和num2的两个值分别进行判断,两个参数必须都大于512,那么就会对flag进行解密输出。

逻辑明白之后,我们就可以编写脚本进行hook,Hook Checker类对象的构造函数Checker(int a, int b),将参数a,b修改为大于512的值来绕过检验。

脚本:

Java.perform(function (){

  var a = Java.use("com.ad2001.frida0x7.Checker");
    // 声明了一个变量a来表示目标Android应用程序中的Java类。
    // Java.use函数指定要使用com.ad2001.frida0x7包中的Checker类。

  a.$init.implementation = function (a,b){
    // $init关键字Hook Checker类对象创建时执行的构造函数

    console.log("Origin num:",a,b);
    // 打印a,b变量初始化时设置的值

    this.$init(1000,1000);
    // 调用Checker类构造函数将a,b变量值修改为600
  }
})

运行脚本,然后利用jadx控制程序运行

拿到flag

总结:Frida Hook构造函数的脚本模板

Java.perform(function() {
  var <class_reference> = Java.use("<package_name>.<class>");
  <class_reference>.$init.implementation = function(<args>){

    /*
    我们自己的方法实现
    */

  }
});

结语
以上就是Frida的七种基础用法,也就是在Java层的一些操作,后续会继续更新在native层的操作,也就是相对进阶的一些用法

附件:
0 条评论
某人
表情
可输入 255
目录