首页
社区
课程
招聘
1
[原创]Android赛区题解
发表于: 2015-10-19 12:07 6828

[原创]Android赛区题解

2015-10-19 12:07
6828
1> Cobb的记忆
下载apk后解包反编译,反编译出的check.smali代码有4万多行,有3个函数:
access$_T11306:解析字符串,会在check函数里调用。
access$_T15566:也是解析字符串,会在check里被反射调用。
check:这个就是验证函数了,会调用上面两个access函数处理加密过的字符串,这些字符串应该是反射调用的函数名。
看了一圈,没有找到计算结果的代码片段,感觉4万多行代码没办法逆算法,于是尝试插入log代码打包,把关键信息打印出来。
搜索return,可以发现check函数里面只有一个return点,在12348行(修改过的代码,位置可能跟原来的代码位置有出入,下同)左右的
1
2
3
4
5
6
7
8
9
10
11
12
move-result-object v4
 
check-cast v4, Ljava/lang/Boolean;
 
invoke-virtual {v4}, Ljava/lang/Boolean;->booleanValue()Z
:try_end_68
.catch Ljava/lang/reflect/InvocationTargetException; {:try_start_68 .. :try_end_68} :catch_c
 
move-result v4
 
:goto_0
return v4

可以看到v4是一个boolean型,那么这个值应该就是比较的结果了。再搜索一下goto_0,在36184行左右看到代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const-wide/32 v4, 0xf4240
 
rem-long v4, v8, v4
 
const-wide/32 v6, 0x1e74e
 
add-long/2addr v4, v6
 
cmp-long v4, v4, v10 # 比较v4和v10
 
if-nez v4, :cond_3 # 不相等跳到 cond_3: const/4 v4, 0x0    # v4 = false
 
                            #                                  goto/16 :goto_0
 
const/4 v4, 0x1   # v4 = true
 
goto/16 :goto_0

那么这儿就是与正确key比较的地方了,在这里打上log(感谢蒸米@wooyun的代码:http://drops.wooyun.org/papers/6045)。如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const-wide/32 v6, 0x1e74e
 
add-long/2addr v4, v6
 
invoke-static {v4, v5}, Ljava/math/BigInteger;->valueOf(J)Ljava/math/BigInteger;
move-result-object v7
 
invoke-static {v7}, Lk2015/mzheng/MZLog;->Log(Ljava/lang/Object;)V
 
cmp-long v4, v4, v10
 
invoke-static {v10, v11}, Ljava/math/BigInteger;->valueOf(J)Ljava/math/BigInteger;
move-result-object v10
 
invoke-static {v10}, Lk2015/mzheng/MZLog;->Log(Ljava/lang/Object;)V
 
if-nez v4, :cond_3
 
const/4 v4, 0x1
 
goto/16 :goto_0

这儿需要注意,java内置的long型是不能作为Object型传给log函数的,因此需要先转换为BigInteger型。另外,smali指令中一个long型是用两个寄存器存储的,在传参的时候要指定两个寄存器,如上面的v4,v5、v10,v11,否则运行时会报错。打印出的寄存器值如下图:

对于不同的输入,v4总是固定的520676,那么这个就是正确的key了。
得到了正确的key,还是不知道算法,于是往上面搜索v10,在29043行左右找到计算v10的算法,同样插入log,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
add-int/lit8 v7, v17, 0x4
 
move-object/from16 v16, v5
 
move-object v9, v14
 
move-wide/from16 v10, v20
 
invoke-static {v10, v11}, Ljava/math/BigInteger;->valueOf(J)Ljava/math/BigInteger;
move-result-object v10    # v10转换成BigInteger型
 
invoke-static {v10}, Lk2015/mzheng/MZLog;->Log(Ljava/lang/Object;)V    # 打印log
 
invoke-virtual {v10}, Ljava/math/BigInteger;->longValue()J
move-result-wide v10    # 把v10还原为long型
 
move/from16 v17, v7
 
move-object v7, v15
 
goto/16 :goto_1

这样就可以打印出每轮计算后的值,如下:

通过每一轮计算的结果,可以发现一个规律:
输入1111,第一轮计算结果是1112。1112-1111 = 1;
第二轮是1117,1117-1112 = 5;
第三轮是1126,1126-1117 = 9;
第4轮是1139,1139-1126  13;
...
每一轮与上一轮的差值是一个等差数列,因此很容易有算法解出答案:
1
2
3
4
5
6
i = 997
n = 520676
while i >= 1:
    n = n - i
    i = i - 4
print n

解出结果为395926。
2> Satio的要求
这个题最后是解掉了,但是没来得及提交答案比赛就结束了,比较可惜。
java层的逻辑比较简单,程序启动后会输出一个logcat,是"wojiushidaan"的莫斯码,这个并没有什么用。程序注册的onClick函数调用一个java层的Ch.a函数,它首先检查包的MD5值,如果不对就直接return false。这个步骤是用来防止重打包的,修改smali代码中的比较值就可以绕过去了。然后程序会调用libwbox.so中的ch函数,key的算法实际是存放在这里的。
取出这个so,拖进ida,简单看一下就能找到反调试的地方。sub_1284这个函数会读取/proc/pid/status中的TracerPid,如果发现不为0说明被调试,就发送信号杀死自己。so的.init_array中有个函数会创建一个线程循环调用这个函数。另外,在sub_1DE0中,算法开始之前也会调用一次这个函数。还有就是在算法自解密(详见下文)的过程中,也会查询这个值,如果不为0就会乱写一段代码,造成执行失败。
由上述分析,其实所有的反调试手段都依赖于/proc/pid/status中的TracerPid,只要保证它为0,就不会触发任何的反调试。因此可以通过修改内核的方式,使得这个值始终为0。修改kernel代码目录中的fs/proc/array.c,task_state是处理/proc/pid/status文件的函数,将191行的tpid修改为0,那么无论有没有被调试,/proc/pid/status中的TracerPid都会始终为0,这样就可以绕过反调试了。
绕过反调试之后,就尝试解密算法。程序本身的代码有一部分是加密的,在执行的过程中会一点点解密,然后返回的时候再次加密回去。在合适的地方下断点,dump内存,就可以获取解密后的代码了。过程中的主要函数如下:
相对偏移0x1DE0:这个函数会初始化一个16字节的内存,内容为0x00, 0x01, 0x02, ..., 0x0f,然后将用户的输入复制到这个地方。输入的有效位数是16字节,超出16字节的部分不参与运算。如果不足16字节,那么会被初始化的内容填充到16字节。随后这个函数就解密0x24C8处的代码,然后调用解密后的函数。调用0x24C8的指令地址为0x2198,在这个位置下断点,就可以获取解密后的0x24C8函数。
0x24C8这个函数首先处理input,伪代码:
1
2
for (i = 0; i < 16; i++)
    input[i] = input[i] + i;

随后像0x1DE0一样,解密下一个函数0x14A4。在0x2984处下断点,可以dump出解密后的0x14A4。
0x14A4这个函数同样首先处理input,这里用到了一个固定值的数组,地址为0x1DE0,内容如下:
1
2
3
4
(gdb) x/16xb $r0
x/16xb $r0
0x63e1fde0:     0x1f    0xbc    0xda    0xff    0xe6    0x4c    0xbc    0x44
0x63e1fde8:     0xf5    0xb8    0x13    0xc8    0xec    0xa8    0xcd    0xbd

伪代码:
1
2
for (i = 0; i < 16; i++)
    input[i] = input[i] + array[i];

然后,函数mmap一块内存,赋予执行权限,将算法代码复制进去解密并调用。算法的输入是上面处理过的input。然后与加密后的key值比较,将比较结果层层返回。加密后的key值是写死在代码里的,如下:
1
2
x/20xw 0x63E23D10
0x63e23d10:     0x2f77da5c      0x393ec6a3      0xedf3f0b6      0x86995a51

真正的算法实际是在这个mmap的内存中,在0x1944处下断点,可以dump出解密后的算法代码。
这个算法才是真正的开始,前面的反打包、反调试、代码的自解密跟算法一比根本不值一提。
IDA中F5后的代码如下:
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
int __fastcall sub_64da8000(char *a1, char *a2) {
  out = a2;
  in = (int *)a1;
  v2 = 0x6BCDC67A;
  v3 = &v79;
  v4 = 0;
  v5 = (unsigned int)&v79 | 4;
  v80 = 0x6BCDC67A;
  *(_DWORD *)(v5 + 4) = 0x6B2B7C9D;
  *(_DWORD *)(v5 + 8) = 0x8DA459B1;
  v6 = 0xAB9D0680;
  v83 = 0xAB9D0680;
  while ( 1 )
  {
    if ( v4 & 3 )
    {
      v7 = (int)&v3[v4];
      v6 ^= v2;
    }
    else
    {
      v8 = v3;
      v9 = *(_WORD *)(int_64DA8758() + (((unsigned int)v6 >> 15) & 0x1FE));
      v10 = (*(_WORD *)(int_64DA8758() + (((unsigned int)v6 >> 7) & 0x1FE)) << 16) & 0xFF0000 | (v9 << 24);
      v11 = v10 | (*(_WORD *)(int_64DA8758() + 2 * (unsigned __int8)v6) << 8) & 0xFF00;
      v12 = (v11 | *(_BYTE *)(int_64DA8758() + (((unsigned int)v6 >> 23) & 0x1FE))) ^ v2;
      v13 = sub_64DA8958();
      v3 = v8;
      v6 = v12 ^ *(_DWORD *)(v13 + ((v4 + ((unsigned int)(v4 >> 31) >> 30)) & 0xFFFFFFFC));
      v7 = (int)&v8[v4];
    }
    *(_DWORD *)(v7 + 20) = v6;
    if ( v4 == 39 )
      break;
    v2 = v3[v4++ + 2];
  }
  v79 = 10;
  xor_4 = _byteswap_ulong(in[3]) ^ v83;         // 0x80741682
  xor_3 = _byteswap_ulong(in[2]) ^ v82;         // 0xbb5517b4
  xor_2 = _byteswap_ulong(in[1]) ^ v81;         // 0x74ac851e
  v16 = v3 + 8;                                 //
                                                //
  xor_1 = _byteswap_ulong(*in) ^ v80;           // 0x3b22c94c
  v18 = 0;
  do
  {
    ina = v16;                                  // 0x64d88e58
    v19 = xor_1;
    out_4 = xor_3;
    out_8 = xor_2;
    out_12 = v18;
    v23 = (xor_1 >> 23) & 0x1FE;
    v24 = int_64DA8758();
    v25 = xor_2;
    v26 = ((*(_WORD *)(v24 + v23) & 0xFF) << 8) | (*(_WORD *)(v24 + v23) << 16) | *(_WORD *)(v24 + v23) & 0xFF ^ ((unsigned int)*(_WORD *)(v24 + v23) >> 8);
    v27 = int_64DA8758() + ((xor_2 >> 15) & 0x1FE);
    v28 = (*(_WORD *)v27 & 0xFF | (*(_WORD *)v27 << 8) | ((*(_WORD *)v27 ^ ((unsigned int)*(_WORD *)v27 >> 8)) << 24)) ^ v26;
    v29 = *(_WORD *)(int_64DA8758() + ((xor_3 >> 7) & 0x1FE));
    v30 = *(_WORD *)(int_64DA8758() + 2 * (unsigned __int8)xor_4);
    at = v28 ^ *(ina - 3) ^ (v29 | (((unsigned __int8)v29 ^ (v29 >> 8) | (v29 << 8)) << 16)) ^ (((((unsigned __int8)v30 << 8) | (v30 << 16) | (unsigned __int8)v30 ^ (v30 >> 8)) << 8) | (v30 >> 8));
    v31 = int_64DA8758();
    v32 = ((*(_WORD *)(v31 + ((v25 >> 23) & 0x1FE)) & 0xFF) << 8) | (*(_WORD *)(v31 + ((v25 >> 23) & 0x1FE)) << 16) | *(_WORD *)(v31 + ((v25 >> 23) & 0x1FE)) & 0xFF ^ ((unsigned int)*(_WORD *)(v31 + ((v25 >> 23) & 0x1FE)) >> 8);
    v33 = *(_WORD *)(int_64DA8758() + ((xor_3 >> 15) & 0x1FE));
    v34 = ((unsigned __int8)v33 | (v33 << 8) | ((v33 ^ (v33 >> 8)) << 24)) ^ v32;
    v35 = *(_WORD *)(int_64DA8758() + (((unsigned int)xor_4 >> 7) & 0x1FE));
    v36 = *(_WORD *)(int_64DA8758() + 2 * (unsigned __int8)v19);
    bt = v34 ^ *(ina - 2) ^ (v35 | (((unsigned __int8)v35 ^ (v35 >> 8) | (v35 << 8)) << 16)) ^ (((((unsigned __int8)v36 << 8) | (v36 << 16) | (unsigned __int8)v36 ^ (v36 >> 8)) << 8) | (v36 >> 8));
    v37 = *(_WORD *)(int_64DA8758() + ((xor_3 >> 23) & 0x1FE));
    v38 = ((unsigned __int8)v37 << 8) | (v37 << 16) | (unsigned __int8)v37 ^ (v37 >> 8);
    v39 = *(_WORD *)(int_64DA8758() + (((unsigned int)xor_4 >> 15) & 0x1FE));
    v40 = ((unsigned __int8)v39 | (v39 << 8) | ((v39 ^ (v39 >> 8)) << 24)) ^ v38;
    v41 = *(_WORD *)(int_64DA8758() + ((v19 >> 7) & 0x1FE));
    v42 = *(_WORD *)(int_64DA8758() + 2 * (unsigned __int8)out_8);
    ct = v40 ^ *(ina - 1) ^ (v41 | (((unsigned __int8)v41 ^ (v41 >> 8) | (v41 << 8)) << 16)) ^ (((((unsigned __int8)v42 << 8) | (v42 << 16) | (unsigned __int8)v42 ^ (v42 >> 8)) << 8) | (v42 >> 8));
    v44 = *(_WORD *)(int_64DA8758() + (((unsigned int)xor_4 >> 23) & 0x1FE));
    v45 = ((unsigned __int8)v44 << 8) | (v44 << 16) | (unsigned __int8)v44 ^ (v44 >> 8);
    v46 = int_64DA8758();
    v47 = (*(_WORD *)(v46 + ((v19 >> 15) & 0x1FE)) & 0xFF | (*(_WORD *)(v46 + ((v19 >> 15) & 0x1FE)) << 8) | ((*(_WORD *)(v46 + ((v19 >> 15) & 0x1FE)) ^ ((unsigned int)*(_WORD *)(v46 + ((v19 >> 15) & 0x1FE)) >> 8)) << 24)) ^ v45;
    v48 = *(_WORD *)(int_64DA8758() + ((out_8 >> 7) & 0x1FE));
    v49 = int_64DA8758();
    v16 = ina + 4;
    v50 = v48 | (((unsigned __int8)v48 ^ (v48 >> 8) | (v48 << 8)) << 16);
    xor_3 = ct;
    v51 = *(_WORD *)(v49 + 2 * out_4);
    xor_4 = v47 ^ *ina ^ v50 ^ (((((unsigned __int8)v51 << 8) | (v51 << 16) | (unsigned __int8)v51 ^ (v51 >> 8)) << 8) | (v51 >> 8));
    xor_2 = bt;
    v18 = out_12 + 1;
    xor_1 = at;
  }
  while ( out_12 + 1 < v79 - 1 );
  v52 = ina[1];
  v53 = *(_WORD *)(int_64DA8758() + (((unsigned int)at >> 23) & 0x1FE));
  v54 = (*(_WORD *)(int_64DA8758() + (((unsigned int)bt >> 15) & 0x1FE)) << 16) & 0xFF0000 | (v53 << 24);
  v55 = v54 | (*(_WORD *)(int_64DA8758() + (((unsigned int)ct >> 7) & 0x1FE)) << 8) & 0xFF00;
  v56 = (v55 | *(_BYTE *)(int_64DA8758() + 2 * (unsigned __int8)xor_4)) ^ v52;
  *out = BYTE3(v56);
  out[1] = (unsigned int)v56 >> 16;
  out[2] = BYTE1(v56);
  out[3] = v56;
  v57 = ina[2];
  v58 = *(_WORD *)(int_64DA8758() + (((unsigned int)bt >> 23) & 0x1FE));
  v59 = (*(_WORD *)(int_64DA8758() + (((unsigned int)ct >> 15) & 0x1FE)) << 16) & 0xFF0000 | (v58 << 24);
  v60 = v59 | (*(_WORD *)(int_64DA8758() + (((unsigned int)xor_4 >> 7) & 0x1FE)) << 8) & 0xFF00;
  v61 = (v60 | *(_BYTE *)(int_64DA8758() + 2 * (unsigned __int8)at)) ^ v57;
  out[4] = BYTE3(v61);
  out[5] = (unsigned int)v61 >> 16;
  out[6] = BYTE1(v61);
  out[7] = v61;
  v62 = ina[3];
  v63 = *(_WORD *)(int_64DA8758() + (((unsigned int)ct >> 23) & 0x1FE));
  v64 = (*(_WORD *)(int_64DA8758() + (((unsigned int)xor_4 >> 15) & 0x1FE)) << 16) & 0xFF0000 | (v63 << 24);
  v65 = v64 | (*(_WORD *)(int_64DA8758() + (((unsigned int)at >> 7) & 0x1FE)) << 8) & 0xFF00;
  v66 = (v65 | *(_BYTE *)(int_64DA8758() + 2 * (unsigned __int8)bt)) ^ v62;
  out[8] = BYTE3(v66);
  out[9] = (unsigned int)v66 >> 16;
  out[10] = BYTE1(v66);
  out[11] = v66;
  v67 = *v16;
  v68 = *(_WORD *)(int_64DA8758() + (((unsigned int)xor_4 >> 23) & 0x1FE));
  v69 = (*(_WORD *)(int_64DA8758() + (((unsigned int)at >> 15) & 0x1FE)) << 16) & 0xFF0000 | (v68 << 24);
  v70 = v69 | (*(_WORD *)(int_64DA8758() + (((unsigned int)bt >> 7) & 0x1FE)) << 8) & 0xFF00;
  v71 = (v70 | *(_BYTE *)(int_64DA8758() + 2 * (unsigned __int8)ct)) ^ v67;
  out[12] = BYTE3(v71);
  out[13] = (unsigned int)v71 >> 16;
  out[14] = BYTE1(v71);
  out[15] = v71;
  return 0;
}

代码大致可以分为两个循环,第一个循环用来初始化一个int型数组,数组为定值。在第二个循环中这个数组会参与运算。随后将输入的16字节按大字端产生4个int值,暂且称之为a,b,c,d。
这4个值会首先与4个定值进行异或,然后进入第二个循环,共9轮。
整个算法如下(略去产生数组的第一层循环,可以认为是一个常量):
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
约定b1(a)为取a数学意义上的最高两位,如b1(0x12345678) = 0x12。b2,b3,b4依次类推。
约定":"为数字的连接,如0x12:0x34:0x56:0x78 = 0x12345678。
约定h(a)为取一个short型数字的高8位,如h(0x1234) = 0x12;l(a)为取一个short型数字的低8位,如l(0x1234) = 0x34。
其中每轮有4种算法,称之为m1,m2,m3,m4。其中:
m1(t) = h(t) : l(t) : l(t) : (h(t)^l(t))
m2(t) = (h(t)^l(t)) : h(t) : l(t) : l(t)
m3(t) = l(t) : (h(t)^l(t)) : h(t) : l(t)
m4(t) = l(t) : l(t) : (h(t)^l(t)) : h(t)
算法存在一个定值数组,为256个short型,共512字节,记为M。
同时存在第一个循环初始化过的定值数组,为40个int型,记为X。
 
/* 大字端扩展 */
a = in[0] : in[1] : in[2] : in[3];
b = in[4] : in[5] : in[6] : in[7];
c = in[8] : in[9] : in[10] : in[11];
d = in[12] : in[13] : in[14] : in[15];
 
a = a ^ 0x6bcdc67a;
b = b ^ 0x6b2b7c9d;
c = c ^ 0x8da459b1;
d = d ^ 0xab9d0680;
 
i = 0;
do {
    at = m1(M[b1(a)]) ^ m2(M[b2(b)]) ^ m3(M[b3(c)]) ^ m4(M[b4(d)]) ^ X[i];
    bt = m1(M[b1(b)]) ^ m2(M[b2(c)]) ^ m3(M[b3(d)]) ^ m4(M[b4(a)]) ^ X[i+1];
    ct = m1(M[b1(c)]) ^ m2(M[b2(d)]) ^ m3(M[b3(a)]) ^ m4(M[b4(b)]) ^ X[i+2];
    dt = m1(M[b1(d)]) ^ m2(M[b2(a)]) ^ m3(M[b3(b)]) ^ m4(M[b4(c)]) ^ X[i+3];
    a = at;
    b = bt;
    c = ct;
    d = dt;
    i++;
} while (i < 9);
 
/* 最后的处理 */
af = l(M[b1(a)]) : l(M[b2(b)]) : l(M[b3(c)]) : l(M[b4(d)]);
af = af ^ X[36];
bf = l(M[b1(b)]) : l(M[b2(c)]) : l(M[b3(d)]) : l(M[b4(a)]);
bf = bf ^ X[37];
cf = l(M[b1(c)]) : l(M[b2(d)]) : l(M[b3(a)]) : l(M[b4(b)]);
cf = cf ^ X[38];
df = l(M[b1(d)]) : l(M[b2(a)]) : l(M[b3(b)]) : l(M[b4(d)]);
df = df ^ X[39];
 
/* 保存到out,同样是大字端 */
out[0] = b1(af);
out[1] = b2(af);
out[2] = b3(af);
out[3] = b4(af);
 
out[4] = b1(bf);
out[5] = b2(bf);
out[6] = b3(bf);
out[7] = b4(bf);
 
out[8] = b1(cf);
out[9] = b2(cf);
out[10] = b3(cf);
out[11] = b4(cf);
 
out[12] = b1(df);
out[13] = b2(df);
out[14] = b3(df);
out[15] = b4(df);

逆出算法之后,觉得眼一黑:这个算法(我觉得)是无法逆运算的!只能采用暴力破解的方式。
仔细看“最后的处理”部分的代码,从af,bf,cf,df逆运算得到最后一轮的a,b,c,d比较简单,因为af的每个字节只与上轮的a,b,c,d中的一个值有关,有
b1(af ^ X[36]) = l(M[b1(a)])。这样只需要一层循环,就可以获得最后一轮a中的某一位。
1
2
3
for i in range(len(M)):
    if l(M[i]) = b1(af ^ x[36]):
        #此时的i就是上轮a的第一个字节,b1(a)

依次类推,我们可以获取最后一轮的a、b、c、d。
对于9轮循环,问题就比较麻烦,因为a中一个字节与上轮循环中的a、b、c、d都有关系,虽然说有了正向的算法后可以通过4层循环来跑,但是4层循环太慢了。当时我测试了一下,在我机器上跑一个字节就要好几分钟,一轮跑4个字节,9轮,速度太慢了,感觉不应该这么粗暴的解。
仔细观察每轮循环中的算法,可以发现一个规律,这里以a为例说明。
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
at = m1(M[b1(a)]) ^ m2(M[b2(b)]) ^ m3(M[b3(c)]) ^ m4(M[b4(d)]) ^ X[i];
首先跟定值X[i]异或,结果以ax代替,即
ax = m1(M[b1(a)]) ^ m2(M[b2(b)]) ^ m3(M[b3(c)]) ^ m4(M[b4(d)]);
然后展开其中的m,对于h(M[b1(a)]),用ha代替,有
ax = (ha:la:la:ha^la) ^ (hb^lb:hb:lb:lb) ^ (lc:hc^lc:hc:lc) ^ (lc:lc:hc^lc:hc)
对于ax的每一个字节,记为a1, a2, a3, a4。于是,
a1 = b1(ax) = ha ^ (hb ^ lb) ^ lc ^ ld
a2 = b2(ax) = la ^ hb ^ (hc ^ lc) ^ ld
a3 = b3(ax) = la ^ lb ^ hc ^ (hd ^ ld)
a4 = b4(ax) = (ha ^ la) ^ lb ^ lc ^ hd
对于异或运算,它满足交换律和结合律,即
x ^ y = y ^ x
(x ^ y) ^ z = x ^ (y ^ z)
因此对于x1 ^ x2 ^ x3 ^ ... ^ xn,其顺序可以任意改变而不会应该其结果。
另外,异或还有这样的性质:
x ^ x = 0
x ^ 0 = x
因此,有下面的等式,
t1
= a1 ^ a2 ^ a4
= (ha ^ (hb ^ lb) ^ lc ^ ld) ^ (la ^ hb ^ (hc ^ lc) ^ ld) ^ ((ha ^ la) ^ lb ^ lc ^ hd)
= (ha ^ la ^ ha ^ la) ^ (hb ^ lb ^ hb ^ lb) ^ (lc ^ hc ^ lc ^ lc) ^ (ld ^ ld ^ hd)
= hc ^ lc ^ hd
同理,有
t2 = a1 ^ a3 ^ a4 = hb ^ lb ^ hc
t3 = a2 ^ a3 ^ a4 = ha ^ la ^ hb
t4 = a1 ^ a2 ^ a3 = ha ^ hd ^ ld
这样,就有了4个约束条件。
于是代码就可以这样写:
for i in range(len(M)):
    for j in range(len(M)):
        if h(M[i]) ^ l(M[i]) ^ h(M[j]) == t3:
            for k in range(len(M)):
                if h(M[j]) ^ l(M[j]) ^ h(M[k]) == t2:
                    for q in range(len(M)):
                        if h(M[k]) ^ l(M[k]) ^ h(M[q]) == t1:
                            if h(M[i]) ^ h(M[q]) ^ l(M[q]) == t4:
                                # 上轮中a、b、c、d中的某一位
                                at1 = i
                                bt2 = j
                                ct3 = k
                                dt4 = q
这样在第二、三层循环中就加入了约束条件,大大减少循环次数。在我机器上,9轮循环,一轮4个字节,4.5秒左右就可以跑完。
依次类推到本轮的b、c、d,就可以获得其他字节,组合就得到了上轮的a、b、c、d。

循环问题解决后,其他的算法就是加加减减和异或,不再赘述。
最后放上我的解密代码,求得结果为kboloy0
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
import time
 
matrix = [
0xC663 ,
0xF87C ,
0xEE77 ,
0xF67B ,
0xFFF2 ,
0xD66B ,
0xDE6F ,
0x91C5 ,
0x6030 ,
0x201  ,
0xCE67 ,
0x562B ,
0xE7FE ,
0xB5D7 ,
0x4DAB ,
0xEC76 ,
0x8FCA ,
0x1F82 ,
0x89C9 ,
0xFA7D ,
0xEFFA ,
0xB259 ,
0x8E47 ,
0xFBF0 ,
0x41AD ,
0xB3D4 ,
0x5FA2 ,
0x45AF ,
0x239C ,
0x53A4 ,
0xE472 ,
0x9BC0 ,
0x75B7 ,
0xE1FD ,
0x3D93 ,
0x4C26 ,
0x6C36 ,
0x7E3F ,
0xF5F7 ,
0x83CC ,
0x6834 ,
0x51A5 ,
0xD1E5 ,
0xF9F1 ,
0xE271 ,
0xABD8 ,
0x6231 ,
0x2A15 ,
0x804  ,
0x95C7 ,
0x4623 ,
0x9DC3 ,
0x3018 ,
0x3796 ,
0xA05  ,
0x2F9A ,
0xE07  ,
0x2412 ,
0x1B80 ,
0xDFE2 ,
0xCDEB ,
0x4E27 ,
0x7FB2 ,
0xEA75 ,
0x1209 ,
0x1D83 ,
0x582C ,
0x341A ,
0x361B ,
0xDC6E ,
0xB45A ,
0x5BA0 ,
0xA452 ,
0x763B ,
0xB7D6 ,
0x7DB3 ,
0x5229 ,
0xDDE3 ,
0x5E2F ,
0x1384 ,
0xA653 ,
0xB9D1 ,
0      ,
0xC1ED ,
0x4020 ,
0xE3FC ,
0x79B1 ,
0xB65B ,
0xD46A ,
0x8DCB ,
0x67BE ,
0x7239 ,
0x944A ,
0x984C ,
0xB058 ,
0x85CF ,
0xBBD0 ,
0xC5EF ,
0x4FAA ,
0xEDFB ,
0x8643 ,
0x9A4D ,
0x6633 ,
0x1185 ,
0x8A45 ,
0xE9F9 ,
0x402  ,
0xFE7F ,
0xA050 ,
0x783C ,
0x259F ,
0x4BA8 ,
0xA251 ,
0x5DA3 ,
0x8040 ,
0x58F  ,
0x3F92 ,
0x219D ,
0x7038 ,
0xF1F5 ,
0x63BC ,
0x77B6 ,
0xAFDA ,
0x4221 ,
0x2010 ,
0xE5FF ,
0xFDF3 ,
0xBFD2 ,
0x81CD ,
0x180C ,
0x2613 ,
0xC3EC ,
0xBE5F ,
0x3597 ,
0x8844 ,
0x2E17 ,
0x93C4 ,
0x55A7 ,
0xFC7E ,
0x7A3D ,
0xC864 ,
0xBA5D ,
0x3219 ,
0xE673 ,
0xC060 ,
0x1981 ,
0x9E4F ,
0xA3DC ,
0x4422 ,
0x542A ,
0x3B90 ,
0xB88  ,
0x8C46 ,
0xC7EE ,
0x6BB8 ,
0x2814 ,
0xA7DE ,
0xBC5E ,
0x160B ,
0xADDB ,
0xDBE0 ,
0x6432 ,
0x743A ,
0x140A ,
0x9249 ,
0xC06  ,
0x4824 ,
0xB85C ,
0x9FC2 ,
0xBDD3 ,
0x43AC ,
0xC462 ,
0x3991 ,
0x3195 ,
0xD3E4 ,
0xF279 ,
0xD5E7 ,
0x8BC8 ,
0x6E37 ,
0xDA6D ,
0x18D  ,
0xB1D5 ,
0x9C4E ,
0x49A9 ,
0xD86C ,
0xAC56 ,
0xF3F4 ,
0xCFEA ,
0xCA65 ,
0xF47A ,
0x47AE ,
0x1008 ,
0x6FBA ,
0xF078 ,
0x4A25 ,
0x5C2E ,
0x381C ,
0x57A6 ,
0x73B4 ,
0x97C6 ,
0xCBE8 ,
0xA1DD ,
0xE874 ,
0x3E1F ,
0x964B ,
0x61BD ,
0xD8B  ,
0xF8A  ,
0xE070 ,
0x7C3E ,
0x71B5 ,
0xCC66 ,
0x9048 ,
0x603  ,
0xF7F6 ,
0x1C0E ,
0xC261 ,
0x6A35 ,
0xAE57 ,
0x69B9 ,
0x1786 ,
0x99C1 ,
0x3A1D ,
0x279E ,
0xD9E1 ,
0xEBF8 ,
0x2B98 ,
0x2211 ,
0xD269 ,
0xA9D9 ,
0x78E  ,
0x3394 ,
0x2D9B ,
0x3C1E ,
0x1587 ,
0xC9E9 ,
0x87CE ,
0xAA55 ,
0x5028 ,
0xA5DF ,
0x38C  ,
0x59A1 ,
0x989  ,
0x1A0D ,
0x65BF ,
0xD7E6 ,
0x8442 ,
0xD068 ,
0x8241 ,
0x2999 ,
0x5A2D ,
0x1E0F ,
0x7BB0 ,
0xA854 ,
0x6DBB ,
0x2C16 ,
]
 
xor_m = [
0x34a20b18, 0x5f897785, 0xd22d2e34, 0x79b028b4 ,
0xd19686ae, 0x8e1ff12b, 0x5c32df1f, 0x2582f7ab ,
0xc6fee491, 0x48e115ba, 0x14d3caa5, 0x31513d0e ,
0x1fd94f56, 0x57385aec, 0x43eb9049, 0x72baad47 ,
0xfb4cef16, 0xac74b5fa, 0xef9f25b3, 0x9d2588f4 ,
0xe4885048, 0x48fce5b2, 0xa763c001, 0x3a4648f5 ,
0xfedab6c8, 0xb626537a, 0x1145937b, 0x2b03db8e ,
0x0563af39, 0xb345fc43, 0xa2006f38, 0x8903b4b6 ,
0x65eee19e, 0xd6ab1ddd, 0x74ab72e5, 0xfda8c653 ,
0x915a0cca, 0x47f11117, 0x335a63f2, 0xcef2a5a1 ,
]
 
def b1(n):
    return (n >> 24) & 0xff;
 
def b2(n):
    return (n >> 16) & 0xff;
 
def b3(n):
    return (n >> 8) & 0xff;
 
def b4(n):
    return n & 0xff;
 
def m1(t):
    th = (t >> 8) & 0xff
    tl = t & 0xff
    return th << 24 | tl << 16 | tl << 8 | (th ^ tl)
 
def m2(t):
    th = (t >> 8) & 0xff
    tl = t & 0xff
    return (th ^ tl) << 24 | th << 16 | tl << 8 | tl
 
def m3(t):
    th = (t >> 8) & 0xff
    tl = t & 0xff
    return tl << 24 | (th ^ tl) << 16 | th << 8 | tl
 
def m4(t):
    th = (t >> 8) & 0xff
    tl = t & 0xff
    return tl << 24 | tl << 16 | (tl ^ th) << 8 | th
 
def geth(t):
    return (t >> 8) & 0xff
 
def getl(t):
    return t & 0xff
 
def find_l(l):
    for i in range(len(matrix)):
        if matrix[i] & 0xff == l:
            print hex(i)
            return i
 
def find_h(h):
    for i in range(len(matrix)):
        if (matrix[i] & 0xff00) >> 8 == h:
            print hex(i)
            return i
 
def merge_int(a1,a2,a3,a4):
    return a1 << 24 | a2 << 16 | a3 << 8 | a4
 
# 加密后的正确key
af = 0x2f77da5c
bf = 0x393ec6a3
cf = 0xedf3f0b6
df = 0x86995a51
 
'''
# 输入1234567890123456的计算结果
af = 0x128b387f
bf = 0x489b84af
cf = 0x4940ab58
df = 0x858b3ae5
'''
 
af = b4(af) << 24 | b3(af) << 16 | b2(af) << 8 | b1(af)
bf = b4(bf) << 24 | b3(bf) << 16 | b2(bf) << 8 | b1(bf)
cf = b4(cf) << 24 | b3(cf) << 16 | b2(cf) << 8 | b1(cf)
df = b4(df) << 24 | b3(df) << 16 | b2(df) << 8 | b1(df)
print hex(af),hex(bf),hex(cf),hex(df)
 
af = af ^ xor_m[36]
bf = bf ^ xor_m[37]
cf = cf ^ xor_m[38]
df = df ^ xor_m[39]
 
 
at1 = find_l(b1(af))
bt1 = find_l(b1(bf))
ct1 = find_l(b1(cf))
dt1 = find_l(b1(df))
 
bt2 = find_l(b2(af))
ct2 = find_l(b2(bf))
dt2 = find_l(b2(cf))
at2 = find_l(b2(df))
 
ct3 = find_l(b3(af))
dt3 = find_l(b3(bf))
at3 = find_l(b3(cf))
bt3 = find_l(b3(df))
 
dt4 = find_l(b4(af))
at4 = find_l(b4(bf))
bt4 = find_l(b4(cf))
ct4 = find_l(b4(df))
 
i = 8
 
start = time.time()
while i >= -1:
    print "====================================="
    am = merge_int(at1, at2, at3, at4)
    bm = merge_int(bt1, bt2, bt3, bt4)
    cm = merge_int(ct1, ct2, ct3, ct4)
    dm = merge_int(dt1, dt2, dt3, dt4)
    print hex(am),hex(bm),hex(cm),hex(dm)
    if (i == -1):
        print "done."
        break
     
 
    am = am ^ xor_m[i*4]
    bm = bm ^ xor_m[i*4 +1]
    cm = cm ^ xor_m[i*4 + 2]
    dm = dm ^ xor_m[i*4 + 3]
    print hex(am),hex(bm),hex(cm),hex(dm)
 
    # hd ^ hc ^ lc
    t1 = b1(am) ^ b2(am) ^ b4(am)
    # hb ^ lb ^ hc
    t2 = b1(am) ^ b3(am) ^ b4(am)
    # ha ^ la ^ hb
    t3 = b2(am) ^ b3(am) ^ b4(am)
    # ha ^ hd ^ ld
    t4 = b1(am) ^ b2(am) ^ b3(am)
 
    for j in range(256):
        for k in range(256):
            if geth(matrix[j]) ^ getl(matrix[j]) ^ geth(matrix[k]) == t3:
                for l in range(256):
                    if geth(matrix[k]) ^ getl(matrix[k]) ^ geth(matrix[l]) == t2:
                        for m in range(256):
                            if geth(matrix[m]) ^ geth(matrix[l]) ^ getl(matrix[l]) == t1:
                                if geth(matrix[j]) ^ geth(matrix[m]) ^ getl(matrix[m]) == t4:
                                    at1 = j
                                    bt2 = k
                                    ct3 = l
                                    dt4 = m
                                    break
 
 
    # a d d
    t1 = b1(bm) ^ b2(bm) ^ b4(bm)
    # c c d
    t2 = b1(bm) ^ b3(bm) ^ b4(bm)
    # b b c
    t3 = b2(bm) ^ b3(bm) ^ b4(bm)
    # b a a
    t4 = b1(bm) ^ b2(bm) ^ b3(bm)
 
    for j in range(256):
        for k in range(256):
            if geth(matrix[j]) ^ getl(matrix[j]) ^ geth(matrix[k]) == t3:
                for l in range(256):
                    if geth(matrix[k]) ^ getl(matrix[k]) ^ geth(matrix[l]) == t2:
                        for m in range(256):
                            if geth(matrix[m]) ^ geth(matrix[l]) ^ getl(matrix[l]) == t1:
                                if geth(matrix[j]) ^ geth(matrix[m]) ^ getl(matrix[m]) == t4:
                                    bt1 = j
                                    ct2 = k
                                    dt3 = l
                                    at4 = m
                                    break
 
 
    # b a a
    t1 = b1(cm) ^ b2(cm) ^ b4(cm)
    # d d a
    t2 = b1(cm) ^ b3(cm) ^ b4(cm)
    # c c d
    t3 = b2(cm) ^ b3(cm) ^ b4(cm)
    # c b b
    t4 = b1(cm) ^ b2(cm) ^ b3(cm)
 
    for j in range(256):
        for k in range(256):
            if geth(matrix[j]) ^ getl(matrix[j]) ^ geth(matrix[k]) == t3:
                for l in range(256):
                    if geth(matrix[k]) ^ getl(matrix[k]) ^ geth(matrix[l]) == t2:
                        for m in range(256):
                            if geth(matrix[m]) ^ geth(matrix[l]) ^ getl(matrix[l]) == t1:
                                if geth(matrix[j]) ^ geth(matrix[m]) ^ getl(matrix[m]) == t4:
                                    ct1 = j
                                    dt2 = k
                                    at3 = l
                                    bt4 = m
                                    break
 
 
    # c b b
    t1 = b1(dm) ^ b2(dm) ^ b4(dm)
    # a a b
    t2 = b1(dm) ^ b3(dm) ^ b4(dm)
    # d d a
    t3 = b2(dm) ^ b3(dm) ^ b4(dm)
    # d c c
    t4 = b1(dm) ^ b2(dm) ^ b3(dm)
 
    for j in range(256):
        for k in range(256):
            if geth(matrix[j]) ^ getl(matrix[j]) ^ geth(matrix[k]) == t3:
                for l in range(256):
                    if geth(matrix[k]) ^ getl(matrix[k]) ^ geth(matrix[l]) == t2:
                        for m in range(256):
                            if geth(matrix[m]) ^ geth(matrix[l]) ^ getl(matrix[l]) == t1:
                                if geth(matrix[j]) ^ geth(matrix[m]) ^ getl(matrix[m]) == t4:
                                    dt1 = j
                                    at2 = k
                                    bt3 = l
                                    ct4 = m
                                    break
    i = i - 1
 
print "time: " + str(time.time() - start)
 
am = am ^ 0x6bcdc67a
bm = bm ^ 0x6b2b7c9d
cm = cm ^ 0x8da459b1
dm = dm ^ 0xab9d0680
 
print hex(am),hex(bm),hex(cm),hex(dm)
 
sub_a1 = b1(am)
sub_a2 = b2(am)
sub_a3 = b3(am)
sub_a4 = b4(am)
 
sub_b1 = b1(bm)
sub_b2 = b2(bm)
sub_b3 = b3(bm)
sub_b4 = b4(bm)
 
sub_c1 = b1(cm)
sub_c2 = b2(cm)
sub_c3 = b3(cm)
sub_c4 = b4(cm)
 
sub_d1 = b1(dm)
sub_d2 = b2(dm)
sub_d3 = b3(dm)
sub_d4 = b4(dm)
 
subee = [0x1f,0xbc,0xda,0xff,0xe6,0x4c,0xbc,0x44,0xf5,0xb8,0x13,0xc8,0xec,0xa8,0xcd,0xbd]
sub_list = [sub_a1, sub_a2, sub_a3, sub_a4, sub_b1, sub_b2, sub_b3, sub_b4, sub_c1, sub_c2, sub_c3, sub_c4, sub_d1, sub_d2, sub_d3, sub_d4]
 
sub_re = []
 
for i in range(len(sub_list)):
    print hex(sub_list[i]),
    sub_re.append((sub_list[i] + 0x100 - subee[i]) & 0xff)
 
print ""
passwd = []
for i in range(len(sub_re)):
    passwd.append(chr(sub_re[i] - i))
 
print "passwd: " + str(passwd)

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 1
支持
分享
赞赏记录
参与人
雪币
留言
时间
教教我吧~
为你点赞~
2023-6-29 14:39
最新回复 (2)
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
牛逼牛逼
2016-2-18 10:16
0
雪    币: 174
活跃值: (334)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
厉害厉害
2018-11-20 11:23
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册