吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9511|回复: 20
收起左侧

[Android CTF] 教你使用frida来快速解出安卓CTF题目

  [复制链接]
顶风能尿三丈远 发表于 2020-12-14 14:14
本帖最后由 顶风能尿三丈远 于 2020-12-14 17:42 编辑

在现在的CTF比赛赛制中,前三名解出题目的队伍都会有额外加分,如何快速的解出问题,对于参赛选手来说至关重要。因为往往就是一分之差,淘汰多支队伍。公司第五届安全技术大赛半决赛出了一道名为hw02的apk题目,我们拿到了二血,这里我来分享一下,如何快速的capture apk’s flag
首先jeb来加载hw02.apk,工具jeb的下载链接可以参考吾爱爱盘下载链接 这里可以根据Manifest来分析出apk的主入口activity,这里是MainActivity 11.png
Input 变量为用户的输入,从上图代码所示,判断input输入的字符串格式 “flag{”开头 , “}” 结尾。字符串长度不能低于10。否则会报错 tryagain~ 或者 flag format error ~重点逻辑在  this.checkFlag 这个native函数,它的处理逻辑在so层,输入的参数就是 flag{xxx}中间的那坨xxx。将apk解压缩,发现有两个架构的so文件,我们的测试机是64位的,那就从arm64-v8a里获取so吧 22.png 使用IDA工具来分析libcheckflag.so文件看到init_array 有初始化的过程 33.png
44.png
这里会修改.bss段变量的值,这个变量后面也没有用到,我们暂时不管。跟进JNI_OnLoad函数
55.png

JNI_OnLoad 函数对 checkFlag函数进行动态注册了
66.png

sub_DD78才是真正的checkFlag函数,我们进入sub_DD78
77.png
看第一个箭头,v13代表字符串的长度,这里v13 长度需要超过15,低于15长度就直接退出了。第二个箭头处Sub_DFC8是干嘛的?跟进去
88.png
GetStringUTFChars是将java层传入的jstring转化为char*, 这里我们简单的理解就是获取用户输入的字符串的。我们知道GetStringUTFChars有三个参数,这里ida对函数优化之后,没有显示任何参数。右键选择Force call type,就可以看到三个参数了。 99.png
接下来,我们只需要关注下面的三个重要的函数,经过这三个函数的运算之后,会产生一个新的值,固定值"bb4ME6An/z82AwX5r0FXgwJwzp3JaFgW7JtmKc4T9Q=="进行对比。相同就可以返回true了sub_E018 我们来看一下函数内部逻辑
111.png

sub_E1D8
222.png
sub_E56C
333.png
这三个函数内部逻辑都很复杂,如果直接去逆推,需要花很长时间,这里我们采用frida工具来帮助我们快速的解题。Hook函数实现代码
[JavaScript] 纯文本查看 复制代码
var libhm  = Process.findModuleByName("libcheckflag.so");
                    if(libhm != undefined)
                    {
                            var modulebase = libhm.base; 
                            console.log("base:"+modulebase); 
                            var sub_E018 = modulebase.add(0xE018);
                            var sub_E56C = modulebase.add(0xE56C); 
                            var sub_E7F8 = modulebase.add(0xE7F8);
                            
                         Interceptor.attach(sub_E018,{ 
                                    onEnter: function(args){
                                            //console.log(Memory.readCString(args[0]));
                                    },
                                onLeave: function(retval){ 
                                        //console.log("retval:"+retval);
                                        //Memory.readUtf8String(retval);
                                        //retval.replace(1)
                                        } 
                                });
                                
                                Interceptor.attach(sub_E56C,{ 
                                    onEnter: function(args){
                                            //console.log(Memory.readCString(args[0]));
                                    },
                                
                                onLeave: function(retval){ 
                                        //console.log("retval:"+retval);
                                        //Memory.readUtf8String(retval);
                                        //retval.replace(1)
                                        }
                                });
                                Interceptor.attach(sub_E7F8,{ 
                                    onEnter: function(args){
                                            //console.log(Memory.readCString(args[0]));
                                    },
                                onLeave: function(retval){ 
                                        console.log("retval:"+retval);
                                        var data = Memory.readUtf8String(retval);
                                        var result = “bb4ME6An/z82AwX5r0FXgwJwzp3JaFgW7JtmKc4T9Q==”;

                                                var index= (round-1) *4;
                                                var result1 = result.substring(index,index+4);
                                        if(data.substring(index,index+4) == result1)
                                        {
                                        console.log("[+]Found:"+Memory.readUtf8String(retval));
                                        }
                                        //retval.replace(1)
                                        }
                                });
}

Frida hook了这些关键的函数之后,我们就可以看到函数的输入参数,和输出结果。我们尝试输入不同的字符来看输出情况最终得出结论:Input输入的字符长度,除去flag{} 之外有31位时,计算出的结果才和bb4M E6An /z82 AwX5 r0FX gwJw zp3J aFgW7Jtm Kc4 T9Q== 一样长,这个长度是线性增加的,可以采用爆破的方法。而且每输入3个字符,对应输出结果的4个字符。 所以我们先找第一个三字符   xyz  对应  bb4M第二组 三字符 xyz 对应E6An ,那这里我们以第二组为例,第一组我们爆破出来为qeo注意上面hook函数中的 var index = (round-1)*4; 这里的round对应的是第几组。
爆破函数实现代码
[JavaScript] 纯文本查看 复制代码
var MainActivity$1 = Java.use("com.ssj.hw02.MainActivity$1");
            var MainActivity = Java.use("com.ssj.hw02.MainActivity");
            var ma = MainActivity.$new()
        MainActivity$1.onClick.implementation =function(){
                        for(var j =0; j <pool.length; j++)
                                {
                                for(var i =0; i <pool.length; i++)
                                        {
                                                for(var k =0; k <pool.length; k++)
                                                {
                                                var data = "qeo"+pool[j]+pool[i]+pool[k]+"1111111111111111111111111";
                                                console.log(data);
                                                ma.checkFlag(data);
                                                }
                                        }
                                }
        }

444.png
这样就可以知道第二轮的3字符为irk我们再重新设置爆破函数中的变量  var data = "qeoirk"+pool[j]+pool+pool[k]+"1111111111111111111111";hook函数中的round=3以此类推,将所有的字符全部猜解出。 qeoirklnxcvxfgiefhdweruoulksdnm最终提交的flag为 flag{ qeoirklnxcvxfgiefhdweruoulksdnm} 这样就可以快速的爆破出所有的字符了,省去了大量的中间逆向和逻辑细节了,能够在ctf比赛中脱颖而出

免费评分

参与人数 6威望 +1 吾爱币 +23 热心值 +5 收起 理由
不会逆向 + 1 谢谢@Thanks!
红烧排骨 + 1 热心回复!
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
无敌小车 + 1 + 1 学习到了
yaoyao7 + 1 + 1 用心讨论,共获提升!
foolboy + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 顶风能尿三丈远 发表于 2020-12-25 14:33
奇奇小霸王龙 发表于 2020-12-24 15:56
V9不等于0XB9B1CB10就结束第一层循环,即v13小于15的情况;没事 我看错了!!

这里稍微有点绕,不过静下心是可以理顺的,这里应该是题目开发者有意设置的一个坑。
iammike 发表于 2021-3-12 16:04
在另一个题目使用此方法,报错了。请问有 大神遇到过吗?
var MainActivity = Java.use("com.ssj.hw02.MainActivity");
var ma = MainActivity.$new(); //跑到这里报错
burnda 发表于 2020-12-14 21:33
hui00000 发表于 2020-12-14 21:59
谢谢分享
yaoyao7 发表于 2020-12-15 09:15
感谢分享,希望可以继续发一些安卓CTF的东西
YenKoc 发表于 2020-12-15 09:20
大佬,来个样本学习一波?
linyii 发表于 2020-12-15 09:35
感谢楼主分享
吾爱蛋蛋 发表于 2020-12-15 10:41
可以破解钉钉考试吗
 楼主| 顶风能尿三丈远 发表于 2020-12-15 10:55
YenKoc 发表于 2020-12-15 09:20
大佬,来个样本学习一波?

我努力了一把,但是最终还是不让我公开题目样本,对不住兄弟了
 楼主| 顶风能尿三丈远 发表于 2020-12-15 10:55
吾爱蛋蛋 发表于 2020-12-15 10:41
可以破解钉钉考试吗

钉钉考试是什么?单独的一款APP?
吾爱蛋蛋 发表于 2020-12-15 11:36
顶风能尿三丈远 发表于 2020-12-15 10:55
钉钉考试是什么?单独的一款APP?

钉钉里面的考试,可以用FD吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 14:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表