安装并打开CTF_100.apk之后,发现题目为爬到指定的楼层然后才能显示FLAG:
先使用JEB2反编译apk查看逻辑:
爬一层楼的点击事件:首先已爬楼层数+1并更新已爬楼层数,紧接着判断是否达到要爬楼层数,如果达到,就设置爬到了,看FLAG的点击结果为true。
最终看到FLAG按钮的点击事件,可以看到最终的返回FLAG方法在native层实现。我们可以使用IDA进行分析。
onCreate方法的实现,主要包含以下几步:看FLAG按钮的点击事件设置为flase,只有当达到要爬楼层数才设置点击事件可见;要爬楼层数设置为随机数;while循环里面是对随机数的一些操作。如果是负数或者大于5时先模32求余再乘以16384。
分析完成之后进行解题:
(1)最简单的是对java层进行修改并重新打包
首先想到的就是在onCreate方法启动时修改要看Flag的点击事件结果为true
对比smali和java,可见控制参数的寄存器为v5,修改寄存器初始值,重新编译,提示:
百度下知道了原来是:
用010editor查看对用位置的png文件发现其实文件为jpeg格式,修改图片格式后重新编译:
(2)由于前面分析时提到返回FALG的方法是在native层实现,使用IDA调试so文件:
静态分析so文件发现方法为动态注册,并且搜索不到get_flag方法(自己注册的实现方法,因此函数名称可能会发生变化)。
使用IDA进行动态调试,由于是动态注册,所以定位到JNI_OnLoad方法:
继续跟进,发现返回flag字符串的方法比较复杂,不过最后终究会返回一个字符串:
在这里进行下断点,点击 “爬到了,看FLAG” 按钮进行触发逻辑,并F8进行调式直到BLX为止(一般跳转指令都用来调用函数):
BLX调用NewStringUTF函数返回result,查看此时R1寄存器的值(R1寄存器保存了NewStringUTF函数第二个参数的值,刚好是result,第一个参数为env):
synchronize with R1看一下,发现:
返回的result值为26879…,刚好为FLAG的值。
(3)HOOK
这里使用Frida来hook,可以想到的方法有:
1)修改已爬楼层数为一个很大的值
2)修改要爬楼层数为很小的值
3)在点击事件中调用get_flag方法