用JEB查看MainActivity的onCreate函数。首先创建了一个CheckClass类的实例c,调用c.a()函数处理输入,最后判断c.check()的返回值。
this.button.setOnClickListener(new View$OnClickListener() { public void onClick(View arg4) { MainActivity.this.c = new CheckClass(); MainActivity.this.c.a(MainActivity.this.text.getText().toString()); if(MainActivity.this.c.check()) { MainActivity.this.textView1.setText("flag is XMAN{" + MainActivity.this.text.getText().toString() + "}"); } else { MainActivity.this.textView1.setText("WORING!"); } }双击c.a()函数查看一下代码,就是将输入 一个字节一个字节的放入A数组中,没有其他的操作。
public void a(String arg5) { int v1 = 30; this.A = new byte[v1]; this.B = arg5.getBytes(); int v0; for(v0 = 0; v0 < arg5.length(); ++v0) { this.A[v0] = this.B[v0]; } this.B = new byte[v1]; }接下来看一下check()函数,这个函数有点长,定义了一个v0,有一个for循环,将v0传入b函数中,然后根据返回的值进行选择操作。
public boolean check() { boolean v9 = false; int[] v0 = new int[]{40, 42, 65, 67, 68, 2, 0x40, 70, 0x60, 98, 0xB5, 7, 10, 0x40, 23, 17, 37, 20, 45, 91, 74, 72, 0x87, 33, 57, 43, 87, 99, 0x93, 53}; byte[] v5 = new byte[]{52, 0x6F, 102, 0x71, 52, 52, 98}; int v2 = 0; int v4 = 0; int v7 = 0; int v1; for(v1 = 0; v1 < v0.length; ++v1) { int v8 = this.b(v0[v1]); new String(); Log.d("now array:", String.valueOf(v8)); switch(v8) { case 0: { this.A[v7] = ((byte)(this.A[v7] ^ v7)); break; } case 1: { if(this.A[v4] != 0) { ++v4; } else { } break; } case 2: { v5[v4] = ((byte)(v5[v4] ^ v4)); ++v4; break; } case 3: { if(v5[v7] == this.A[v7]) { ++v7; } else { } break; } case 4: { if(v7 == v4) { v9 = true; } return v9; } case 5: { if(v4 != v5.length) { v1 = v0.length - 3; } else { v4 = 0; } break; } default: { ++v2; break; } } } return v9; }switch语句中总共有6个分支,我们这个分析一下功能。
case 0:将A数组元素与数组下标进行异或,A数组就是输入
case 1:计数器的功能。
case 2:将:v5数组元素与数组下标进行异或, v5数组已经给出了,是一个长度为7的数组
case 3:比较v5与A的元素是否相等。
case 4:比较v4与v7是否相等,相等的话将v9置为True,v9是返回值,成功的标志。
case 5:对v4进行判断,如果等于v5的长度,那么置0,否则执行v1 = v0.length - 3;
其中v1、v4、v7可以看成i、j、k之类的,方便理解,在JEB中可以通过快捷键n来实现重命名。最终的目的是让返回值v9为True,也就是执行case4,使v4和v7相等。v7的值的改变只和case3有关,v4的值通过case1、case2和case5都会发生改变。
我们看一下b函数,b函数的作用是将数字10110101与数组中的数字进行运算,对应位置位1的时候取出数字,相加后得到的数字即为下标,范围是0~5。
public int b(int arg4) { int v0 = 0xB5 & arg4; return (v0 & 1) + ((v0 & 4) >> 2) + ((v0 & 16) >> 4) + ((v0 & 0x20) >> 5) + ((v0 & 0x80) >> 7); }写个脚本跑一下,看看程序是怎么运行的。
def fuc_b(arg4): v0 = 0xB5 & arg4 return (v0 & 1) + ((v0 & 4) >> 2) + ((v0 & 16) >> 4) + ((v0 & 0x20) >> 5) + ((v0 & 0x80) >> 7) v0 = [40, 42, 65, 67, 68, 2, 0x40, 70, 0x60, 98, 0xB5, 7, 10, 0x40, 23, 17, 37, 20, 45, 91, 74, 72, 0x87, 33, 57, 43, 87, 99, 0x93, 53] v1 = list(map(fuc_b, v0)) print(v1) # 结果为[1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 5, 2, 0, 0, 3, 2, 3, 2, 3, 2, 0, 0, 3, 2, 3, 2, 3, 2, 3, 4]首先case0是异或操作,连续两个case0相当于执行了A[v7] ^ v7 ^ v7,没有改动,因为是连续的两个case0,所以v7没有变化,可以忽略掉。
然后注意到前面有8个1(忽略0),也就是执行8个case1相当于对你的输入进行计数,如果你的输入长度为7的话,那么v4=7,进入到case5的时候就会重置为0。
然后忽略连续的两个0,你会发现是2,3的组合,也就是说执行一次case2就会执行一次case3,也就是v4和v7是同步增加的,实际上就是判断你的输入是否等于v5[v4] ^ v4。
最后解题脚本如下
flag = '' v5 = [52, 0x6F, 102, 0x71, 52, 52, 98] for i, v in enumerate(v5): flag += chr(v^i) print(flag)