初步了解题目
先打开题目,下载附件,是一个 apk 文件,然后直接拖动到 JADX-gui 中去:
然后直接保存到文件夹里去,我们用 IDEA 打开,方便我们编辑
简单看看 AndroidManifest.xml ,直接看 MainActivity 吧
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(getApplicationContext());
tv.setText("Select the activity you wish to interact with.To-Do: Add buttons to select activity, for now use Send_to_Activity");
setContentView(tv);
IntentFilter filter = new IntentFilter();
filter.addAction("com.ctf.INCOMING_INTENT");
Send_to_Activity receiver = new Send_to_Activity();
registerReceiver(receiver, filter, Manifest.permission._MSG, null);
}
代码的意思是,将 Send_to_Activity 类注册成了一个广播接收器,接受的广播动作是 com.ctf.INCOMING_INTENT 而且设定了 Manifest.permission._MSG 权限,只有拥有这个权限的广播发送者发出的广播,当前的这个广播接受者才能接受广播。那我们看看这个权限是什么,能不能伪造。
<permission android:name="ctf.permission._MSG" android:protectionLevel="signature" android:description="@string/android_permission__msg"/>
观察 AndroidManifest.xml 里的关于 ctf.permission._MSG 的定义,发现,我们好像无法伪造,因为保护级别是 signature,(大概是这个意思,有知道的师傅,还请指出)
尴尬,线索到这里其实就断了,因为我们无法发出广播给这个 Send_to_Activity 广播接受者。
但是先不管了,我们看看这个 Send_to_Activity 的实现。
public void onReceive(Context context, Intent intent) {
String msgText = intent.getStringExtra("msg");
if (msgText.equalsIgnoreCase("ThisIsTheRealOne")) {
Intent outIntent = new Intent(context, ThisIsTheRealOne.class);
context.startActivity(outIntent);
} else if (msgText.equalsIgnoreCase("IsThisTheRealOne")) {
Intent outIntent2 = new Intent(context, IsThisTheRealOne.class);
context.startActivity(outIntent2);
} else if (msgText.equalsIgnoreCase("DefinitelyNotThisOne")) {
Intent outIntent3 = new Intent(context, DefinitelyNotThisOne.class);
context.startActivity(outIntent3);
} else {
Toast.makeText(context, "Which Activity do you wish to interact with?", 1).show();
}
}
其实就是打开一个又一个 Activity ,那么思路就有了,我们虽然无法发送广播,但是我们直接使用工具,打开对应的 Activity 就行了。
然后再观察一下这三个 Activity 的内容
public native String definitelyNotThis(String str, String str2);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Activity - Is_this_the_real_one");
Button button = new Button(this);
button.setText("Broadcast Intent");
setContentView(button);
button.setOnClickListener(new View.OnClickListener() { // from class: com.example.application.DefinitelyNotThisOne.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.ctf.OUTGOING_INTENT");
DefinitelyNotThisOne.this.getResources().getString(R.string.str1);
String b = Utilities.doBoth(DefinitelyNotThisOne.this.getResources().getString(R.string.test));
String c = Utilities.doBoth("Test");
intent.putExtra("msg", DefinitelyNotThisOne.this.definitelyNotThis(b, c));
DefinitelyNotThisOne.this.sendBroadcast(intent, Manifest.permission._MSG);
}
});
}
其他两个类我就不继续粘贴了,都和这个一样,都是调用 Native 方法,所以这道题要么用 IDA 去分析 Native 实现,要么去 Hook 这些方法。 我们这里尝试使用 frida 去 hook 这些方法。
下面简单介绍一下工具安装
工具安装
frida 和 objection 的简单安装及在 android 渗透测试中的入门级教程
frida 是一个 hook 框架,可运行在android、ios、linux、win、osx等各平台,主要使用动态二进制插桩技术。
你可以通过 frida 来注入安卓代码,进而获取特定函数的输入值,输出值,返回值,或者直接更改这些值等等。
Frida 安装
因为 frida 是基于 python 的,所以这里默认已经搭建好了 python 环境。
直接一键安装即可
pip install -i https://pypi.doubanio.com/simple/ frida-tools
% pip list | grep frida
frida 16.2.1
frida-tools 12.3.0
这个时候,就可以看到已经帮你安装好了 frida 和 frida-tools
然后顺便安装一下 objection 一款基于 frida 的安卓应用渗透框架
pip install objection
安装 frida 安卓服务端
% adb shell
$ getprop ro.product.cpu.abi
arm64-v8a
获取一下你的安卓的架构,然后去下载对应的服务端文件
Github:Releases · frida/frida (github.com)
记得点击 Show all 257 assets,然后搜索 server 字样,找一下自己对应的架构的 安卓包
然后解压,传输到安卓端
adb push ~/Downloads/frida-server-16.2.1-android-arm64 /data/local/tmp/
请注意!:如果你的模拟器使用的是带 play store 的,那么你是无法获取 root 权限的, 而且传入到文件夹也是不能随便传,有的文件夹是无法设置运行权限的
继续使用 adb 操作安卓系统,提升到管理员权限并运行
adb root
adb shell
cd /data/local/tmp/
mv frida-server-16.2.1-android-arm64 frida-server
chmod 777 frida-server && ls -al
./frida-server
这个时候如果没报错,那说明安卓端的就安装好了,再测试一下,电脑端执行
frida-ps -U
如果输出安卓端的一些信息,那么就成功了
尝试解题
回到解题环节,因为这部分设计到各个工具的使用,所以就简单演示一下,至于为什么要这样写,还需要各位去自行学习工具使用。 我们先编写这三个函数的 hook 函数
function main() {
Java.perform(function() {
var DefinitelyNotThisOneHandler = Java.use('com.example.application.DefinitelyNotThisOne')
DefinitelyNotThisOneHandler.definitelyNotThis.implementation = function(arg0, arg1) {
console.log('进入 DefinitelyNotThisOneHandler 函数,参数1: ' + arg0 + " 参数2: " + arg1)
var ret = this.definitelyNotThis(arg0, arg1)
console.log('完成 DefinitelyNotThisOneHandler 函数,返回值: ' + ret )
return ret
}
var ThisIsTheRealOneHandler = Java.use('com.example.application.ThisIsTheRealOne')
ThisIsTheRealOneHandler.orThat.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(arg0, arg1, arg2) {
console.log('进入 ThisIsTheRealOneHandler 函数,参数1: ' + arg0 + " 参数2: " + arg1 + " 参数3: " + arg2)
var ret = this.orThat(arg0, arg1, arg2)
console.log('完成 ThisIsTheRealOneHandler 函数,返回值:' + ret )
return ret
}
var IsThisTheRealOneHandler = Java.use('com.example.application.IsThisTheRealOne')
IsThisTheRealOneHandler.perhapsThis.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(arg0, arg1, arg2) {
console.log('进入 IsThisTheRealOneHandler 函数,参数1: ' + arg0 + " 参数2: " + arg1 + " 参数3: " + arg2)
var ret = this.perhapsThis(arg0, arg1, arg2)
console.log('完成 IsThisTheRealOneHandler 函数,返回值: ' + ret )
return ret
}
})
}
setImmediate(main)
将文件保存为 hook.js 将 题目的 apk 安装到安卓上,点击运行
开启 frida 注入
frida -U -f com.example.hellojni -l hook.js
# 然后再开个命令行输入:
adb shell am start -n com.example.hellojni/com.example.application.IsThisTheRealOne
经过一下午的研究,发现 objection 的版本太老了,已经和最新的 frida 产生了不兼容,而且我安装老版本的 frida 的时候遇到了很奇葩的错误,所以这里没法使用 objection 了,我就使用 adb 调用 activity 吧
这个时候点击一下 Broadcast Intent 按钮即可发布广播,frida 成功 hook 数据。其他两个 activity 试了一下是干扰项。