XMAN2017选拔赛(Mobile)writeup

0x01 mobile1(First_Mobile)

  1. 提取dex
    1. 这里推荐使用Androidlxzs ,这个工具集成得很好,基本把Java层的逆向工具都集成了
  2. Dex2jar把dex文件转jar文件
  1. jd-gui查看源码
    image
    看程序主入口onCreate方法代码逻辑,可以清晰地看到输入内容作为参数调用encode的check方法,返回true时输出current,然后再看看encode类
    image
    此处分析check逻辑可以得到一条公式((input[i]+b[i])%61)*2-i=input[i]

  2. 那么我们使用爆破泡一下就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class XMan {
public static void main(String[] args) {
byte []b = new byte[] { 23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32 };
byte []res = new byte[16];
for (int i=0; i<b.length; i++){
for (int j=0; j<128; j++){
byte tmp = (byte) ((j+b[i])%61);
if ( (tmp*2-i)==j ){
res[i] = (byte)j;
break;
}
}
}
System.out.println(“XMAN{”+new String(res)+”}”);
}
}

得到flag=XMAN{LOHILMNMLKHILKHI}

0x02 mobile2(HelloSmali2)

这个真的需要一些smali语法功底zzz

  1. 先把所以逻辑一句一句转化成java,经过分析
    check方法的逻辑是:
    把输入字符串每一位字符转化为二进制字符(补0补满8位)append到一个StringBuilder,
    然后从这个StringBuilder每6位二进制转化为一个整数,该整数为字符串”+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789”的索引,利用索引得到一个char,添加到另一个StringBuilder,最后得到一串字符”xsZDluYYreJDyrpDpucZCo”,再加上”!?”,最后和”xsZDluYYreJDyrpDpucZCo!?”比较,相等即返回true
    怎么解?,逆过来即可
  2. 逆向过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class XMan {
public static void main(String[] args) {
String v6 = "+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String s = "xsZDluYYreJDyrpDpucZCo";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
int tmp = v6.indexOf(s.charAt(i));
String ss = Integer.toBinaryString(tmp);
if (ss.length() == 5) {
ss = "0" + ss;
} else if (ss.length() == 4) {
ss = "00" + ss;
} else if (ss.length() == 3) {
ss = "000" + ss;
} else if (ss.length() == 2) {
ss = "0000" + ss;
} else if (ss.length() == 1) {
ss = "00000" + ss;
} else if (ss.length() == 0) {
ss = "000000" + ss;
}
sb.append(ss);
}
String x = sb.toString() + "0000";
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < x.length(); i += 8) {
String tmp = x.substring(i, i + 8);
byte b = (byte) Integer.parseInt(tmp, 2);
stringBuilder.append((char) b);
}
System.out.println(stringBuilder.toString());


}
}

0x03 mobile3(rev1)

  1. 提取dex
  2. dex转jar
  3. 该题dex2jar后分析代码,
    先调用CheckClass的b方法,把所有check方法的array元素作为输入分别调用b方法,得到输出:

    1. (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 )
    2. 再看代码return结果为b3,而能改变b3的只有case 4,而case 4需要满足b2==b为true才有b3=true,
      而能改变b2的只有case 3,能改变b的只有case 2,
      而每一次case 0都会对A[b2]做一次与b2的异或取值,
      case 5是会把b重置为0,
      而看上面的输出,5后刚刚好有7个2和7个3并且每个2后都有一个3,
      case 2会对array2的第b个元素与b取异或且++ b,
      case 3会比较异或后的array2[b2]和输入的this.A[b2]比较,相同就++b2,
      好了,到这里,我们可以看出,每一个输入值(字符)this.A[b2]都会与异或后的array2[b2]相等且仅有7位,到最后一个4,b=7,b2=7,满足条件b3赋值true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public class CheckClass
{
private byte[] A;
private byte[] B;

public void a(String paramString)
{
this.A = new byte[30];
this.B = paramString.getBytes();
for (int i = 0; i < paramString.length(); i++)
this.A[i] = this.B[i];
this.B = new byte[30];
}

public int b(int paramInt)
{
int i = 0xB5 & paramInt;
return (i & 0x1) + ((i & 0x4) >> 2) + ((i & 0x10) >> 4) + ((i & 0x20) >> 5) + ((i & 0x80) >> 7);
}

public boolean check()
{
int[] arrayOfInt = { 40, 42, 65, 67, 68, 2, 64, 70, 96, 98, 181, 7, 10, 64, 23, 17, 37, 20, 45, 91, 74, 72, 135, 33, 57, 43, 87, 99, 147, 53 };
byte[] arrayOfByte = { 52, 111, 102, 113, 52, 52, 98 };
int i = 0;
int j = 0;
int k = 0;
int m = 0;
int n = arrayOfInt.length;
boolean bool = false;
if (m < n)
{
int i1 = b(arrayOfInt[m]);
new String();
Log.d("now array:", String.valueOf(i1));
switch (i1)
{
default:
i++;
case 1:
case 2:
case 3:
case 4:
case 5:
case 0:
}
}
while (true)
{
m++;
break;
if (this.A[j] != 0)
{
j++;
continue;
arrayOfByte[j] = ((byte)(j ^ arrayOfByte[j]));
j++;
continue;
if (arrayOfByte[k] == this.A[k])
{
k++;
continue;
bool = false;
if (k == j)
bool = true;
return bool;
if (j != arrayOfByte.length)
{
m = -3 + arrayOfInt.length;
}
else
{
j = 0;
continue;
this.A[k] = ((byte)(k ^ this.A[k]));
}
}
}
}
}
}
  1. 该代码得到每一个调用b方法的输出值:
1
2
3
4
5
6
7
8
9
10
public class XMan {
public static void main(String[] args) {
final int[] array = { 40, 42, 65, 67, 68, 2, 64, 70, 96, 98, 181, 7, 10, 64, 23, 17, 37, 20, 45, 91, 74, 72, 135, 33, 57, 43, 87, 99, 147, 53 };
CheckClass c = new CheckClass();
for (int i=0;i<array.length;i++){
System.out.print(c.b(array[i])+" ");
}
}

}
  1. 执行以下代码得到flag:
1
2
3
4
5
6
7
8
9
10
public class XMan {
public static void main(String[] args) {
byte[] array2 = { 52, 111, 102, 113, 52, 52, 98 };
for (int i=0;i<array2.length;i++){
array2[i] ^= i;
}
System.out.println("XMAN{"+new String(array2)+"}");
}

}

输出flag=XMAN{4ndr01d}

0x04 写在最后

虽说整个比赛三题mobile都没有涉及到native代码,但是很好的考验了Java代码和smali代码的逻辑分析能力,相信这是基本功,而能做好这个基本工才能说入门mobile,要不然连Java、smali代码都不懂,是不行的,pengyou!