用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)