一次有关算法的安卓CTF

Bonnie ·
更新时间:2024-09-21
· 884 次阅读

某年的CTF大赛题目
总结:遇到算法别头大,耐心、细心,让自己静下来。

点开之后长这样子,随便输入几个字符,提示错误。
在这里插入图片描述
查壳发现没有壳。
直接使用Jeb进行反编译。

在这里插入图片描述

看出来了,突破口是this.b.check()这个函数。

package ctf.bobbydylan; import android.content.Context; import android.content.Intent; import android.os.Bundle; public class M extends T { public M() { super(); } public void check(String arg10) { String v0_1; int v7 = 15; int v6 = 7; int v1 = 0; int v5 = 5; if(arg10.length() != 16) { throw new RuntimeException(); } try { v0_1 = this.getKey(); } catch(Exception v0) { v0_1 = this.getKey(); System.arraycopy(v0_1, 0, arg10, v5, v5); } int[] v2 = new int[16]; v2[0] = 0; v2[12] = 14; v2[10] = v6; v2[14] = v7; v2[v7] = 42; int v4 = 3; try { v2[1] = v4; v2[5] = 5; System.out.println(); } catch(Exception v3) { v2[v5] = 37; v2[1] = 85; } v2[6] = v7; v2[2] = 13; v2[3] = 19; v2[11] = 68; v2[4] = 85; v2[13] = v5; v2[9] = v6; v2[v6] = 78; v2[8] = 22; while(v1 < arg10.length()) { if((v2[v1] & 0xFF) != ((arg10.charAt(v1) ^ v0_1.charAt(v1 % v0_1.length())) & 0xFF)) { throw new RuntimeException(); } ++v1; } } public String getKey() { return "bobbydylan"; } public void onCreate(Bundle arg4) { super.onCreate(arg4); this.setContentView(0x7F030000); this.startService(new Intent(((Context)this), P.class)); this.findViewById(0x7F060001).setOnClickListener(new a(this, this.findViewById(0x7F060000))); } protected void onPause() { this.stopService(new Intent(((Context)this), P.class)); super.onPause(); } }

看到这个check,很长说实话。

里面嵌套了好几层的try catch语句,我不确定这个程序大体流程执行下去会是怎样的,也许在try看起来怎么都不会有异常抛出的地方就有异常了呢,我不想继续审代码了,还是动态调试更舒服。

Jeb动态调试

在这里插入图片描述
找到对应进程,不解释。
Jeb没有调试伪代码的功能,所以就对着smali代码和伪代码一起看吧。

这里的逻辑经过调通,只要输入的字符串长度等于16,代码逻辑就不会跳进catch里。
在这里插入图片描述
经过阅读,其实只要字符串长度满足16,和下面的算法即可。

在这里插入图片描述
其实也就是

v2[v1] = arg10.charAt(v1) ^ v0_1.charAt(v1 % v0_1.length())

这个等式成立就行。
其中v2是死的,v0_1是getKey()接口返回的"bobbydylan"也是死的。

这里我们可以通过Jeb动态调试的时候看到v2和v0_1的值。
求出来的args10就是我们要的flag。
如果v2和v0_1类型不对,显示的值不太好观察时,直接修改它们的类型就可以。
在这里插入图片描述
直接修改类型。
在这里插入图片描述
在这里插入图片描述

我们知道对一个数异或两次,其实就等于没有做任何运算。
所以这个算法可以这样去做。

v2[v1] ^ v0_1.charAt(v1 % 8) = args.charAt(v1)

贴上C语言代码

#include #include int main(){ int v2[16] = {0,3,13,19,85,5,15,78,0,7,7,68,14,5,15,42}; char v0_1[] = "bobdylan"; for(int i = 0; i < 16; i++){ int nIndex = i % 8; int nTmp = v0_1[nIndex]; printf("%c", v2[i] ^ nTmp); } }

我使用go,结果给我的是这个玩意,而且还费了我不少时间。
在这里插入图片描述
在这里插入图片描述
很明显不对。

有可能是自己太久没写代码或者当时使用go很少做异或或者ascii之类的计算吧,果然底层运算还是选C靠谱。
在这里插入图片描述

在这里插入图片描述

结束。


作者:nini_boom



算法 ctf

需要 登录 后方可回复, 如果你还没有账号请 注册新账号