[安全] Frida Labs 0x7

先讲一下 Frida 中一个类的引用的 $init$new 的关联与不同
$init 是对应 Java 类的构造函数, 返回 void
$new 对应了 Java 中的 new 操作, 负责 alloc 一块内存空间并对其调用 $init 方法

也就是说 通常 new 一个对象的实际调用如下

  1. $new 分配内存
  2. $new 调用 $init 初始化这块内存
  3. $new 返回对象

由于 $new 这里是我们 frida 这里的 new, 不对应着 Java 层里的函数, 因此不能 hook, 只能把它当成一个返回对象的操作
$init 是构造函数, 不需要返回值
使用 $new 的时候传递的参数要和 $init 的参数符合

反编译

public class Checker {
    int num1;
    int num2;
 
    Checker(int a, int b) {
        this.num1 = a;
        this.num2 = b;
    }
}
 
public class MainActivity extends AppCompatActivity {
 
    /* JADX INFO: renamed from: t1 */
    TextView f103t1;
 
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(C0535R.layout.activity_main);
        this.f103t1 = (TextView) findViewById(C0535R.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 BadPaddingException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeyException {
        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.f103t1.setText(decrypted);
        }
    }
}

根据之前学过的做法, 可以想到 hook onCreate() 在其之后再调用一个传入构造参数大于 512 的 Checkerflag 方法

import Java from "frida-java-bridge";
 
if (Java.available) {
    Java.perform(() => {
        const MainActivity = Java.use("com.ad2001.frida0x7.MainActivity");
        const Checker      = Java.use("com.ad2001.frida0x7.Checker");
        const checker      = Checker.$new(514, 514);
        MainActivity.onCreate.overload("android.os.Bundle").implementation = 
        function (savedInstanceState: any) {
            this.onCreate(savedInstanceState);
            this.flag(checker);
        };
    });
} else {
    console.log("No Java VM in this process");
}

当然, 也有另外一种做法, 我们可以 hook Checker 类的构造函数, 让其在 onCreate 时第一次调用 flag 时候构造出来的对象就能通过判断条件
那也就是 hook $init 函数

import Java from "frida-java-bridge";
 
if (Java.available) {
    Java.perform(() => {
        const Checker = Java.use("com.ad2001.frida0x7.Checker");
        Checker.$init.overload("int", "int").implementation = 
        function (a: number, b: number) {
            this.$init(a + 512, b + 512);
        };
    });
} else {
    console.log("No Java VM in this process");
}

以上的脚本均通过 frida -U -f com.ad2001.frida0x7 -l _agent.js 运行