rwctf体验赛-Snake详解

首先展示一下apk中的内容,一个简单的贪吃蛇游戏

静态分析

蛇撞墙会有提示,直接去看

定位到com.example.ct_sanke.SnakeView.i()

i()方法只有一处调用,随着蛇吃食物进行逻辑处理

考虑到游戏需要绘制,看到Snake类下还有一个onDraw()方法,查看该方法

发现一处逻辑判断,当efalse并且c不为1时,就会执行a()方法,看一下细节

发现这个方法又调用了一个a()方法,这个方法带两个参数,返回值给到了y,进入一下这个方法

发现其实是去请求了资源id,这个id可以在b.a.a.b类中找到

看一下Snake类中y属性的初值,发现和资源中a5的值一致

这几个资源是在资源目录下的图片

实际上就是找这些图片当做食物,不停变换

接下来回到判断点,当c等于1时,就会去执行b()方法

这时b()方法和a()方法几乎只有最后传入参数有区别,用到了f[v],且资源抬头是b,那么可以看一下都是啥,先看b资源吧

很明显,b资源给到的是文字,也就是说说flag应该要走b()方法才对,接下来看fv属性

可以看到f属性是通过b.a.a.a.a()方法解密了一串文本并解析成整数,那么f属性中保存的应该就是b资源的索引,接下来看v属性

发现在i()方法中,满足某些条件时,cv都会被处理,将c置为1时,就会触发b()方法,也就是说此时的食物就是b资源中的某一个字,然后v自增1,。显然,当第一次触发b()方法时,v的值是1,也就是说,实际上展示的内容就是f属性从第1个元素开始的索引对应的资源,接下来对f进行分析

幸运的是, 如果你使用的反编译工具是JEB,那么JEB会帮你自动处理b.a.a.a.a()这个解密方法,这时f的值就是16,9,3,3,12,8,0,1,11,8,6,0,11,0,13,8,1,15,3,14,12,12,12,从第1个元素开始,对应的资源显示也就是K33PG01NGD0N0TG1V3UPPP,答案也就是这一串

当然我们也可以利用hook的方式,去hookb.a.a.a.a()方法,打印其返回值,方法比较容易hook,直接用GDA自动生成的hook代码即可

setImmediate(function() {
Java.perform(function() {
	var targetClass='b.a.a.a';
	var methodName='a';
	var gclass = Java.use(targetClass);
	gclass[methodName].overload('java.lang.String').implementation = function(arg0) {
		console.log('\nGDA[Hook a(java.lang.String)]'+'\n\targ0 = '+arg0);
		var i=this[methodName](arg0);
		console.log('\treturn '+i);
		return i;
	}
})
})

拿到的结果也是一样的

当然我们也可以进行动态调试去验证,常规情况下,c属性的值很难被置为1

动态调试

这个apk是不允许调试的,我们可以利用apktool进行解包,修改AndroidManifest.xml,为application标记添加android:debuggable="true"使其允许调试,再重新打包

使用修改后的apk进行安装,利用JEB进行调试

附加成功后,找到onDraw()方法中的判断语句,Ctrl+B下断点

长按屏幕重新游戏后,点击开始,就能抵达断点位置

这时查看局部变量,能看到bcf的值,此时的f和之前分析的值也是一样的

重新回去查看vc赋值的条件,发现在jadx中的反编译是有问题的,不过JEBGDA没有问题

在满足b大于55c不等于2的情况下,cv的值会改变,而需要调用b()方法的条件是c等于1,那么就可以将b的值修改为56c的值修改为1,同时需要注意,在c被赋值为1后,v会自增一次,所以修改的时候,v也需要加上1v的初值是0,改为1即可

这时候取消断点,再运行

这时食物就会变成资源b的内容,吃到的食物会跟在屁股后面,并且随着吃到的食物的增多,也不会进行加速

资源b全部吃完后,又会重新回到资源a

可以看到经过动态调试之后,得到的内容和静态分析的结果也是一致的

总结

其实出结果很快,不过一开始忽略了v的自增,提交的时候多了第0位,很可惜,不过这个apk非常好玩。

最后,做apk逆向一定要多个反编译工具一起使用,以防某些逻辑解析错误!!

posted @ 2023-01-09 12:58  WXjzc  阅读(375)  评论(0编辑  收藏  举报