题目一:click_me.apk

题目分析

拿到题目先去看看功能,同时反编译:
本次使用的是雷电模拟器9,安装后打开效果如下,这个效果很熟悉,连点嘛。

image-20240820034920558

jadx反编译看逻辑:

image-20240820035234644

先看一下Main类:

image-20240820035911868

这里就是主要的部分了,这里其实就是逻辑点:

public final native String getFlag();

这里很明显,getFlag()在native层中,这里很明显可以想到,直接通过frida的脚本(js、python)直接进行截取就行,看看触发条件,这时其实已经猜的差不多了,应该时点击达到一定的数目,可以触发点击getflag按钮:

image-20240820040344148

看看这里的两个方法,很搞笑,明显的对于CLICKS进行计数,可是还晃一下,文本框最多显示13371337下,实际需要达到99999999下,搞什么,当点击的数达到999999999下后,可以触发getFlag()函数。思路清晰,启动frida,显示在这个类中赋值给CLICKDS,然后点击按钮触发方法,截取flag:

脚本(这里就直接用js脚本,其实python脚本的格式要多多一点,但是操作简单)

Java.perform(function () {
var MainActivity = Java.use('com.example.clickme.MainActivity');
MainActivity.getFlagButtonClick.implementation = function (view) {
console.log("方法调用成功");
this.CLICKS.value = 99999999;
console.log("CLICKS value set to: " + this.CLICKS.value);
this.getFlagButtonClick(view);
};
//触发条件:点击按钮
MainActivity.getFlag.implementation = function () {
console.log("方法调用成功");
var result = this.getFlag();
console.log('getFlag() result: ' + result);
return result;
};
console.log("success!");
});

利用过程(我这里写的略微详细一下,以防忘记操作)

  1. 打开adb服务,然后进如模拟器,打开frida服务,这里是需要自己去上传对应的版本服务的:

image-20240820042204683

到这里就说明已经开启了frida服务:

  1. 下面就可以使用脚本了:

    使用的命令:frida -U -f com.example.clickme -l xxxx.js(脚本名称)

    image-20240820043118483

这里就顺利的得到flag:flag{849d9e5421c59358ee4d568adebc5a70}

image-20240820043319830

这里就是那个表面搞笑的显示。

题目二:Run

分析

同样是先去看看关键词:

image-20240820044151951

画风简洁,这就是啥,一个标题,一个按钮,一句欢迎您!!!

还是看看反编译的结果:

image-20240820044318208

好家伙,这还加上混淆了,不过混淆的还凑合,能看的,不像之前的神秘符号(输入法都输不出来的)。开整:

这里不管它怎样命名,反正就一个按钮,这个按钮肯定是关键,直接跟:

来到了wjan6g1aXIJQJJbfuT这个类:

image-20240820044620388

一眼没看见啥,就看见一个Running…,跑啥呢,我跟:

image-20240820044857745

一跟不要紧,这是干嘛呀,直接看最后:

image-20240820045108808

哎呦一看这是有戏,其实没啥,就是一个文件读写的过程:

image-20240820045230620

本来想着走走捷径,创建文件了是不,直接找文件,我就直接运行,找找文件,

image-20240820045454470

我这是直接一顿找,哥们,哥们,答案就在眼前:

image-20240820045540203

image-20240820045609776

image-20240820045625992

image-20240820045712112

这是个啥,发现这写入的内容与时间有关,之后回去,看看写入的方法:

image-20240820045922691

随机点开一个这里有时间戳,还有写入的字符,这想要看完整的写入内容,就需要用frida将所有的写入的动作的字符存在一个变量中。说干就干,直接截取这个apk的写入内容就行。写了脚本,进行调试:这个脚本就是直接调用写的方法就行,主要是在写的过程中要注意,写入文件的格式。将每个字符变为字符串,然后发现,它没写入一个字符,就要换行,不利于我们缓存,想想,直接忽略换行符。(注意这里还有空格)

脚本:

Java.perform(function () {
var RandomAccessFile = Java.use("java.io.RandomAccessFile");
var readData = "";
var writeData = "";
var timer = null;

// 挂钩write()方法
RandomAccessFile.write.overload('[B', 'int', 'int').implementation = function (buffer, off, len) {
// 调用原始write方法
var result = this.write(buffer, off, len);

// 打印写入的内容
var data = "";
for (var i = off; i < off + len; i++) {
data += String.fromCharCode(buffer[i]);
}
data = data.replace(/\n/g, ""); // 将换行符替换为空字符串
writeData += data;
console.log("Write data: " + data);

// 重置计时器
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(function () {
console.log("Complete data: " + writeData);
}, 3000);

return result;
}
});

最后不能让它运行不停,设个时钟,到点重传,不对,是到点,下班。脚本效果:

image-20240820051254577

image-20240820052759299

一长句话:Sdaj ukq snepa w lnkcnwi bkn Wjznkez, ukq qoa pda Knwyha Fwrw pkkho bkn aranupdejc, wjz wp pda ranu ajz, ukq lqod w xqppkj wjz owu, ‘Ykjranp pdeo pk Wjznkez bkniwp.’ BHWC{Yd4hh4jc3-5QyY33Z3z-y0jp1jQa!} Ajfku pda peju qjatlhwejwxha oaykjz. Ukq ywj hawnj sdwparan ukq swjp!

一看就是又进行了某种位移加密,直接怒嗦:

image-20240820053956285

发现在凯撒的位移22下出现了flag:

mode1 #22: When you write a program for Android, you use the Oracle Java tools for everything, and at the very end, you push a button and say, ‘Convert this to Android format.’ FLAG{Ch4ll4ng3-5UcC33D3d-c0nt1nUe!} Enjoy the tiny unexplainable second. You can learn whatever you want!

总结

这两题都是相较基础的题目,主要看对于hook的初步使用,不用不知道到,用了才知道有多舒服,其实在这之前已经做过相关的题目了,所以在处理这两题来说才会想到直接用frida来搞。后来其实如果是脚本能力好的,可以根据时间戳和字符,直接获取,之后按照时间戳的大小来对字符进行排序,所以看到这个方法,感觉解题的方法还是很多的,主要看哪个操作自己更熟练一些了。但是无论哪种,还是要写脚本的。第二题,本来想着走捷径,结果上了一课。在frida等工具上还要加强使用,如果可以动手拆开apk文件,重新在打个标签,就好玩了,虽然之前游戏逆向,都会这么做一下,但是在android开发上还没有尝试,等有时间,一定要好好玩玩!!!

最后文末,欢迎大家来小站一起交流学习,多多评论。同同行对话其乐无穷,同大佬交流受益匪浅。虽然没人关注小站。但是橘子还是想去多多结识不同的人。