五. .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层的操作,也就是相对进阶的一些用法