# 前言
第一次做外国CTF比赛的mobile challenge 题,题目就是一个安卓的apk安装包。顺便记录一下代码分析过程以及分享两种不同的解题思路。
# 一、样式与功能点
需要这个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信息会输出到面板上。
# 总结
其实除了Frida之外,还可以用BurpSuite的Brida来hook,由于文章篇幅太长,所以分开来写。欢迎大家一起交流学习。
作者Github:https://github.com/zangcc
暂无评论内容