文章目录
- 前言
- 一、样式与功能点
- 二、反编译
- 三、Frida Get Flag
- 四、BurpSuite插件-Brida
- 总结
前言
第一次做外国CTF比赛的mobile challenge 题,题目就是一个安卓的apk安装包。顺便记录一下代码分析过程以及分享两种不同的解题思路。
提示:以下是本篇文章正文内容,下面案例可供参考
一、样式与功能点
下载apk并安装后,发现这个app打开是一个cookie曲奇饼干。只有两个功能点可以按。
1、中间大大的曲奇饼,点了之后,上面的Cookies:数量会增加。
2、最下面的GET FLAG按钮。
从字面意思上来看,关键点肯定是这个GET FLAG按钮了,直接点击,发现提示:
“You do not hava enough cookies to get the flag”,中文意思是说没有足够的cookies去获得这个flag。
二、反编译
先把这个apk安装包反编译出源代码。然后搜索关键字符串“flag”和“You do not have enough cookies to get the flag”,最后定位到两个关键方法getFlag()和getFlagButtionClick()
代码Toast.makeText(this.getApplicationContext(), “You do not have enough cookies to get the flag”, 0).show();输出的就是我们app里面点击按钮之后输出的内容。整段代码的意思就是,它这里使用Intrinsics.checkNotNullParameter(view0, “view”)来检查传入的view0参数是否为null。如果view0为null,这个方法会抛出一个异常。
然后,它检查一个名为CLICKS的成员变量是否等于十六进制数值0x5F5E0FF(十进制表示为100000000)。也就是一亿。如果等于,那么它会调用getFlag()方法获取一个字符串,并在应用的上下文中显示一个Toast消息,内容为这个字符串。
Toast消息的显示时间长度为0,这在Android中表示Toast.LENGTH_SHORT,即较短的显示时间。
如果CLICKS不等于0x5F5E0FF,那么它会在应用的上下文中显示一个Toast消息,内容为"You do not have enough cookies to get the flag"。同样,这个Toast消息的显示时间长度也为0。
所以,这个方法已经说得很明显了,就是要你点击1亿下。否则,他们会看到一个提示消息,告诉你还没有收集到足够的"cookies"……
那么能不能连续点一个通宵,暴力无脑地把点击数点到1亿呢?那这样岂不是用个按摩枪对准手机疯狂输出就行了。
所以看到了上面的方法,名为cookieViewClick。这个方法的主要功能是在用户点击按钮时增加CLICKS的值,并更新显示CLICKS值的文本视图。
首先,它将CLICKS的值加1,并将结果保存回CLICKS。它检查新的CLICKS值是否大于或等于十六进制数值0xCC07C9(十进制表示为13377345)。也就是一千三百多万。如果是,那么它会将CLICKS的值设置为0xCC07C9。这是为了限制CLICKS的最大值。所以手动点击cookie,暴力无脑拿flag显然不是获取flag的方式。
接下来,它使用findViewById(0x7F080075)方法找到一个文本视图(TextView),并将其文本设置为CLICKS的值。这个文本视图用于显示用户当前的"cookies"数量。
三、Frida Get Flag
所以思路有了,就是hook MainActivity.getFlagButtonClick()方法,打印出通过调用新创建的MainActivity实例的getFlag()方法得到的值。下面就用Frida框架写一个JavaScript脚本,用于动态地修改Android应用中的Java代码。
首先,Java.perform(function() {…})是Frida框架中的一个函数,它确保当前线程被附加到Java虚拟机(VM)上,并执行传入的函数。这里可以看frida官方的api文档,里面有说明。
https://frida.re/docs/javascript-api/
编写Frida JavaScript脚本:
Java.perform(function() {
console.log("+zangcc+");
var ma_Class = Java.use('com.example.clickme.MainActivity');
ma_Class.getFlagButtonClick.implementation = function(view){
const main = Java.use('com.example.clickme.MainActivity');
var flag = main.$new().getFlag();
console.log(flag);
};
});
com.example.clickme.MainActivity的Java类,并将其赋值给变量main_activity。
接下来,用main_activity.getFlagButtonClick.implementation = function(view){…}修改MainActivity类中的getFlagButtonClick方法的实现。新的实现会在方法被调用时执行传入的函数。
在Frida框架中,implementation是一个特殊的属性,它允许你替换一个方法的实现。当你为implementation赋值一个函数时,这个函数就会在原方法被调用时执行,而不是执行原方法的代码。
main_activity.getFlagButtonClick.implementation = function(view){…}这行代码将MainActivity类中的getFlagButtonClick方法的实现替换为了一个新的函数。
这个新的函数接受一个参数view,这个参数对应于原getFlagButtonClick方法的参数。由于getFlag()方法不是一个静态方法,所以要实例化一个类对象。用var flag = main.$new().getFlag()创建一个新的MainActivity实例,并调用其getFlag()方法,将返回值赋值给变量flag。最后,用console.log(flag)打印出变量flag的值。
通过之前的源码分析,我们知道必须点击 cookie 近1亿次。在cookieViewClick方法中,还可以看到计数器将在大约 1300 万次点击时停止增加。所以点击cookie显然不是获取flag的方式。
所以可以hook这个getFlagButtionClick方法,CLICKS当单击标志按钮时将成员设置为所需的值。
Java.perform(function(){
console.log("+zangcc——2+");
var ma = Java.use("com.example.clickme.MainActivity");
ma.getFlagButtonClick.implementation = function(view){
this.CLICKS.value = 99999999;
this.getFlagButtonClick(view);
}
});
所以可以hook这个getFlagButtionClick方法,CLICKS当单击标志按钮时将成员设置为所需的值。
当点击GET FLAG按钮,flag信息会输出到面板上。
四、BurpSuite插件-Brida
如果用习惯了Brida,问题也不大,毕竟Brida就是把Frida和BurpSuite结合在了一起的工具,本质上没太大区别。
配置完之后,Attach application:
Save JS file->Reload JS->Comple & reload JS。整套流程其实就是保存后并加载这个brida.js然后再编译。
进入Debug export项,然后输入我们刚刚编辑的方法test,然后点击Run export,出现“Brida zangcc hook”说明调用脚本成功了,然后这时点击app的GET FLAG按钮,flag就打印输出到brida的控制面板。
总结
这里只想到这两种办法解,如果你还有更好的办法或者思路,欢迎提出。欢迎关注公众号:Eureka安全团队。以后文章多数会以公众号为主。
文章原创,欢迎转载,请注明文章出处: 【逆向】NahamCon CTF -Click Me Writeup(Brida&Frida Hook 拿Flag).。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。