XCTF - IllIntentions wp
做 ctf 每天都是踩坑的一天
文章目录
- 题目概述
- 我的做法
- frida hook
题目概述
这道题本身逻辑不复杂,有一个 MainActivity
和三个二级 Activity IsThisTheRealOne
, ThisIsTheRealOne
, DefinitelyNotThis
。主 activity 是空白页面,注册了一个 Receiver Send_to_Activity
,在接收到特定 Action 后会根据参数选择一个 activity 启动。
每个 activity 内部会调用 jni 计算一个字符串,从返回值拿到结果,最后将该字符串用 broadcast 广播成一个 Intent。例如,IsThisTheRealOne 的成员函数有 jni 的接口,和一个 OnCreate 入口函数
我的做法
由于题目逻辑其实不复杂,我做的时候也不太会 hook,所以我选择复现加密函数。但是连续踩了三个坑 xs。
- Java 部分,Utilities 类可以直接粘贴到新文件里在本地跑,这样 jni 的入参就知道了。
- jni 里面其实就是 load 内存中预定义的字符串拼接到 arg0,然后和 s, s1 异或一下。把这段代码用 python 复现一下就好了。
jni 这里要注意字节序的问题,只有
strcpy
是保证相同字节顺序的,剩下两个*(QWORD*)v11 = ""
的赋值,右边的字符串常量是 ida 按照数字的字节顺序直接翻译过来的,相当于数字的小端是字符串末尾。在小端序字符串的末尾会被放到内存低位。
踩了很多坑。首先是我之前以为单独的 java 文件不能写 pkg name,但事实上写了 pkg name 也能单独跑,不写 pkgname 反而会造成误导,例如本题
class.getName() = "com.example. ...."
会返回从包名开始的全限定名,但不写包名相当于是空,在本地测试会以为getName
只有类名
匿名函数(匿名类)本质上是个内部类,他的 this 指向的是匿名类的 this,不再是外部类了。只是编译器会把内部匿名类命名为
"外部类名" + "$1"(or ".1")
.
图 2 的subString(0, s.length() -2)
就是在处理这个问题。
注意:jeb 不会在反编译结果中以注释的形式显示匿名类的全限定名,需要鼠标 hover 在符号上方显示详细信息才看得到。相对的,jadx 默认就会显示。
frida hook
在模拟器里安装 frida server 后可以用 frida hook 安卓程序的过程,感觉这个可能是预期解法,学习一下。
首先参考了 这篇 (参考 1) 稀土的博客,里面记录了安装 frida server 的操作,然后 hook 了三个 jni 接口
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)
在 这篇 (参考 2) 博客里,作者 hook 了 Java 的 Intent.putExtra
函数,从而拦截发送。此外,作者没用 am broadcast
发送 Intent 触发二级 activity,而是使用的 objection 的 android intent
function main() {
function getjstring(jstr) {
return Java.vm.getEnv().getStringUtfChars(jstr, null).readCString();
}
Java.perform(function () {
var so_addr = Module.findBaseAddress("libhello-jni.so");
var perhapsThis_addr = Module.findExportByName("libhello-jni.so", "Java_com_example_application_IsThisTheRealOne_perhapsThis");
console.log("perhapsThis_addr", perhapsThis_addr);
Interceptor.attach(perhapsThis_addr, {
onEnter: function (args) {
console.log("perhapsThis_args:[1]", getjstring(args[2]), "\n [2]", getjstring(args[3]), "\n [3]", getjstring(args[4]), "\n");
},
onLeave: function (retval) {
console.log("perhapsThis_result:", getjstring(retval));
},
});
Interceptor.attach(Module.findExportByName("libhello-jni.so", "Java_com_example_application_ThisIsTheRealOne_orThat"), {
onEnter: function (args) {
console.log("orThat_args:[1]", getjstring(args[2]), "\n [2]", getjstring(args[3]), "\n [3]", getjstring(args[4]), "\n");
},
onLeave: function (retval) {
console.log("orThat_result:", getjstring(retval));
},
});
Interceptor.attach(Module.findExportByName("libhello-jni.so", "Java_com_example_application_DefinitelyNotThisOne_definitelyNotThis"), {
onEnter: function (args) {
console.log("definitelyNotThis_args:[1]", getjstring(args[2]), "\n [2]", getjstring(args[3]), "\n");
},
onLeave: function (retval) {
console.log("definitelyNotThis_result:", getjstring(retval));
},
});
});
}
setImmediate(main);