某年的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靠谱。
结束。