当前位置: 首页 > article >正文

XCTF - IllIntentions wp

做 ctf 每天都是踩坑的一天

文章目录

  • 题目概述
  • 我的做法
  • frida hook

题目概述

这道题本身逻辑不复杂,有一个 MainActivity 和三个二级 Activity IsThisTheRealOne, ThisIsTheRealOne, DefinitelyNotThis。主 activity 是空白页面,注册了一个 Receiver Send_to_Activity,在接收到特定 Action 后会根据参数选择一个 activity 启动。

MainActivity 注册 Send_to_Activity

每个 activity 内部会调用 jni 计算一个字符串,从返回值拿到结果,最后将该字符串用 broadcast 广播成一个 Intent。例如,IsThisTheRealOne 的成员函数有 jni 的接口,和一个 OnCreate 入口函数
jni

IsThisTheRealOne 的 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);

http://www.kler.cn/a/524634.html

相关文章:

  • 【C++】特殊类设计
  • 二叉树-堆(补充)
  • 2023年吉林省职业院校技能大赛网络系统管理样题-网络配置(华三代码)
  • mybatis(112/134)
  • Luzmo 专为SaaS公司设计的嵌入式数据分析平台
  • 汇编的使用总结
  • python实现一个完整的智能教室能耗监测与管理系统的实现方案
  • (2)SpringBoot自动装配原理简介
  • CSS语言的区块链
  • Vue 3 30天精进之旅:Day 08 - 组件通信
  • 锁升级过程与优化操作
  • 消息队列篇--通信协议篇--STOMP(STOMP特点、格式及示例,WebSocket上使用STOMP,消息队列上使用STOMP等)
  • 大屏 UI 设计风格的未来趋势
  • FreeRTOS从入门到精通 第十四章(队列集)
  • [NOI1995] 石子合并
  • Antd React Form使用Radio嵌套多个Select和Input的处理
  • 架构技能(六):软件设计(下)
  • 用户创建命令的详细使用与参数说明
  • 深度学习每周学习总结R5(LSTM-实现糖尿病探索与预测-模型优化)
  • Origami Agents:通过AI驱动的研究工具提升B2B销售效率
  • 网络工程师 (8)存储管理
  • docker运行Open-Webui 界面化展示 deepseek-r1大模型
  • 【新春特辑】2025年春节技术展望:蛇年里的科技创新与趋势预测
  • CUDA学习-内存访问
  • 飞鸟小目标检测数据集VOC+YOLO格式1657张2类别
  • 解锁豆瓣高清海报:深度爬虫与requests进阶之路