国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

admin 2025年6月4日09:02:44评论11 views字数 4480阅读14分56秒阅读模式

国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

嗨👋,最近工作有亿点忙,难得请了假,终于有机会能写点有趣的东西啦。之前的文章大部分都是实战挖洞思路,所以今天还是想写点逆向相关的内容,顺便充实一下我的安卓逆向专栏🚩

0x01 前言

Frida,光看理论可不行,还是得找个 App 练练手。商业应用的复杂性往往令人望而却步,而我自己编写的演示 App 又因能力所限,逻辑过于简单,缺乏挑战性,没什么实战意义。(想看之前的逆向文章,可以看看公众号的主页底部的动态,找到逆向专栏)所以,我更喜欢用 CTF 题目来练一下Frida,顺便提高自己的逆向思维。可惜国内这方面的优质题目不多,我只好找找国外的。真巧,今天就找到一个超级有意思的 APK,所以记录一下解体思路📝

0x02 Oh,Bugger(噢,讨厌鬼)

题目描述:

Hello agent,Our field operatives========巴拉巴拉讲了一大堆废话(省略)=========to find a way to retrieve it.Good luck!

题目原名就是标题“Oh,Bugger”,先把apk下载到手机上:

国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag
安装完成之后,可以看到主页,很朴实无华的一个app:
国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag
只有一个按钮“TAP”可以点,上面写着“Get Your Flag Here”,意思就是说,从这里获取你的Flag,很明显,CTF出题人都是骗子,不可能白给的🤡。不出意外,点击之后显示“bugger off!”。
国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

0x03 源码分析

JEB启动!!

国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

因为刚刚点击按钮的时候,出现了一个字符提醒“bugger off”,所以直接搜索这个字符串,看看是哪段代码触发了这个提示。

国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

在MainActivity类⬇️

也就是(com.w.buggeroff.MainActivity)的onCreat方法中找到了这个字符串。关键代码1:

if(!MainActivity.setOperation(0)) {                Toast.makeText(context0, "bugger off!"0).show();                return;            }
如果setOperation(0)返回false
(即!setOperation(0)为真) ,则会显示一个短暂的提示信息 (Toast) "bugger off!" 给用户。
然后方法立即返回,后续的加密操作不会执行。
关键代码2:
try {         this.cipher = Cipher.getInstance(this.alg);         byte[] arr_b = GenerateKeys.getKey(context0);         SecretKeySpec secretKeySpec0 = new SecretKeySpec(Arrays.copyOfRange(arr_b, 00x20), this.alg);         IvParameterSpec ivParameterSpec0 = new IvParameterSpec(Arrays.copyOfRange(arr_b, 0x300x40));         this.cipher.init(2, secretKeySpec0, ivParameterSpec0);         byte[] arr_b1 = Base64.decode("iGWkBaxepj8l7BrKpeIntuEjRqHv3Tt41hRw7w+UwwcXTrlb/l9tELh9RflIpyDT"0);         this.cipher.doFinal(arr_b1);     }         catch(NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | InvalidAlgorithmParameterException generalSecurityException0)          {         generalSecurityException0.printStackTrace();         }
它先初始化新密码,调用静态函数(GenerateKeys.getKey(context))创建密钥,然后进行解密。我做了一些简单的代码注释:
try {    // 1. 获取加密器实例    this.cipher = Cipher.getInstance(this.alg);    // 2. 获取密钥    byte[] key = GenerateKeys.getKey(context);    // 3. 初始化加密器    this.cipher.init(2// 模式:2 通常表示解密模式 (Cipher.DECRYPT_MODE)                     new SecretKeySpec(Arrays.copyOfRange(key, 032), this.alg), // 从获取的key中取前32字节作为密钥                     new IvParameterSpec(Arrays.copyOfRange(key, 4864))); // 从获取的key中取第48到63字节作为初始化向量(IV)    // 4. 执行解密/加密操作    this.cipher.doFinal(Base64.decode("iGWkBaxepj8l7BrKpeIntuEjRqHv3Tt41hRw7w+UwwcXTrlb/l9tELh9RflIpyDT"0));catch (InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {    e.printStackTrace();}
稍微缕一缕代码逻辑,意思就是,首先进行一个条件判断(setOperation(0)) 。如果条件不满足,则显示 "bugger off!" 的提示。
如果条件满足,它会尝试使用一个从GenerateKeys.getKey()获取的密钥和初始化向量(IV)来解密一段硬编码的Base64字符串。所以接下来的思路就是,用Frida hook两个函数:setOperation和cipher.doFinal

让Frida使得setOperation(0)总是返回true,这样!setOperation(0)就会永远为false,因此,代码才能往下走,否则就会一直打印“bugger off!”

第二个hook,查看javax.crypto.Cipher类中的doFinal方法处理的数据,特别是尝试将处理的字节数据转换成字符串打印出来,希望能从中找到“Flag”。

0x03 Frida hook

Java.perform(function() {    var buggeroff = Java.use("com.w.buggeroff.MainActivity");    var cipher = Java.use("javax.crypto.Cipher");    // 定位到 buggeroff (MainActivity类) 中的 setOperation 方法。    // .overload("int") 指定我们要Hook的是接受一个整型(int)参数的那个 setOperation 方法版本。    buggeroff.setOperation.overload("int").implementation = function(i) { // 参数 i 对应Java方法中的 int 类型参数        // 当被Hook的 setOperation 方法被调用时,在Frida控制台打印一条日志信息。console.log("setOperation 永远为 true");        // 强制该方法总是返回布尔值 true,无论其原始逻辑或输入参数 i 是什么。return true;};    // 定位到 cipher (javax.crypto.Cipher类) 中的 doFinal 方法。    // .overload('[B') 指定我们要Hook的是接受一个字节数组(byte[])作为参数的那个 doFinal 方法版本。cipher.doFinal.overload('[B').implementation = function(b) { // 参数 b 对应Java方法中的 byte[] 类型输入数据        // 当被Hook的 doFinal 方法被调用时,在Frida控制台打印一条日志信息。console.log("doFinal方法被调用了");        // 调用 this.doFinal(b) 来执行原始的、未被修改的 Cipher.doFinal(byte[] input) 方法。        // 并将其返回值(一个byte[],通常是加密或解密的结果)存储在 retVal 变量中。var retVal = this.doFinal(b);        // 将 Java 的 byte[] (即 retVal) 包装成JavaScript 数组 buffer。var buffer = Java.array('byte', retVal);        // 初始化一个空字符串,用于累积从字节转换过来的字符。var result = "";        // 循环遍历 buffer (即 doFinal 方法返回的字节数组) 中的每一个字节。for(var i = 0; i < buffer.length; ++i){            // String.fromCharCode(buffer[i]) 将当前字节的数值当作字符编码值(如ASCII)转换为对应的字符。            // 然后将转换后的字符追加到 result 字符串。result+= (String.fromCharCode(buffer[i]));}        // 在Frida控制台打印 "Flag: " 后跟着上面转换得到的字符串 result。console.log("Flag是: " + result);        // 将原始 doFinal 方法的返回值 retVal 返回给调用者,以确保应用程序的正常流程。return retVal;};}, 0); 

有对Frida脚本格式和框架不熟的可以看看Eureka公众号主页动态栏中的安卓逆向内容,也就是公众号的第一篇文章,里面有介绍,这里就不再赘述,每一行我都写了备注,非常清晰。

frida-ps -Ua
国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag
先启动一下Frida服务端:
国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag
frida -U -f com.w.buggeroff -l zangcc_bugger.js --no-pause
国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

完美拿到Flag.

0x03 Frida hook

 

原文始发于微信公众号(Eureka安全):国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flag

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月4日09:02:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   国外Matrix CTF「Oh, Bugger」思路解析:Frida hook 轻松拿Flaghttps://cn-sec.com/archives/4129495.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息