0%

SycLang出题思路

SycLang 出题思路

本题目提供了中间代码和编译器前端,要求将中间代码逆向回C,自行编译后解出 flag(当然也可以直接通过中间代码分析 flag)

首先,本程序有3个陷阱:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!tempa := {#8}*{var16<+64>}
var12<+32> := var22(@exp.key[0])<+8><+488><+tempa>
temp84 := #1
temp85 := var15<+56> + temp84
var18<+80> := temp85
#!tempa := {#8}*{var18<+80>}
var13<+40> := var22(@exp.key[0])<+8><+488><+tempa>
temp86 := #0
var13<+40> := temp86
temp87 := var12<+32> ^ var13<+40>
var14<+48> := temp87
#!tempa := {#8}*{var16<+64>}
var22(@exp.key[0])<+8><+488><+tempa> := var14<+48>
  • var13<+40> 在异或前会赋值“0”,因此对 e1.key(var22(@exp.key[0])<+8><+488><+tempa>) 的异或加密失效
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
LABEL label59 :
temp89 := #0
var24(@exp.L[0])<+200><+1256> := temp89
temp91 := #12
var24(@exp.R[0])<+264><+1256> := temp91
temp93 := #0

......

var24(@exp.key[23])<+192><+1256> := temp195
temp196 := #23
var15<+56> := temp196
LABEL label118 :
temp198 := #0
IF var15<+56> > temp198 GOTO label117
GOTO label116
LABEL label117 :
var18<+80> := var15<+56>
#!tempa := {#8}*{var18<+80>}
var19<+88> := var24(@exp.key[0])<+8><+1256><+tempa>
temp199 := #1
temp200 := var15<+56> - temp199
var16<+64> := temp200
#!tempa := {#8}*{var16<+64>}
var17<+72> := var24(@exp.key[0])<+8><+1256><+tempa>
temp201 := var19<+88> - var17<+72>
var21<+104> := temp201
#!tempa := {#8}*{var15<+56>}
var24(@exp.key[0])<+8><+1256><+tempa> := var21<+104>
temp197 := #1
var15<+56> := var15<+56> - temp197
GOTO label118
LABEL label116 :
temp202 := #0
var15<+56> := temp202
LABEL label126 :
temp204 := #8
IF var15<+56> < temp204 GOTO label125
GOTO label124
LABEL label125 :
#!tempa := {#8}*{var15<+56>}
var16<+64> := var24(@exp.L[0])<+200><+1256><+tempa>
#!tempa := {#8}*{var15<+56>}
var18<+80> := var24(@exp.R[0])<+264><+1256><+tempa>
#!tempa := {#8}*{var15<+56>}
var20<+96> := var24(@exp.X[0])<+328><+1256><+tempa>
#!tempa := {#8}*{var16<+64>}
var17<+72> := var24(@exp.key[0])<+8><+1256><+tempa>
#!tempa := {#8}*{var18<+80>}
var19<+88> := var24(@exp.key[0])<+8><+1256><+tempa>
var17<+72> := var17<+72> + var20<+96>
var19<+88> := var19<+88> - var20<+96>
#!tempa := {#8}*{var16<+64>}
var24(@exp.key[0])<+8><+1256><+tempa> := var17<+72>
#!tempa := {#8}*{var18<+80>}
var24(@exp.key[0])<+8><+1256><+tempa> := var19<+88>
temp203 := #1
var15<+56> := var15<+56> + temp203
GOTO label126
LABEL label124 :
temp207 := #1
var15<+56> := temp207
LABEL label137 :
temp209 := #24
IF var15<+56> < temp209 GOTO label136
GOTO label135
LABEL label136 :
#!tempa := {#8}*{var15<+56>}
var17<+72> := var24(@exp.key[0])<+8><+1256><+tempa>
temp210 := #1
temp211 := var15<+56> - temp210
var16<+64> := temp211
#!tempa := {#8}*{var16<+64>}
var20<+96> := var24(@exp.key[0])<+8><+1256><+tempa>
var17<+72> := var17<+72> + var20<+96>
#!tempa := {#8}*{var15<+56>}
var24(@exp.key[0])<+8><+1256><+tempa> := var17<+72>
temp208 := #1
var15<+56> := var15<+56> + temp208
GOTO label137
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
LABEL label168 :
temp263 := #24
IF var15<+56> < temp263 GOTO label167
GOTO label166
LABEL label167 :
var16<+64> := var15<+56>
#!tempa := {#8}*{var16<+64>}
var17<+72> := var23(@exp.key[0])<+8><+872><+tempa>
var18<+80> := var15<+56>
#!tempa := {#8}*{var18<+80>}
var19<+88> := var24(@exp.key[0])<+8><+1256><+tempa>
temp264 := var17<+72> ^ var19<+88>
var21<+104> := temp264
#!tempa := {#8}*{var15<+56>}
var23(@exp.key[0])<+8><+872><+tempa> := var21<+104>
temp262 := #1
var15<+56> := var15<+56> + temp262
GOTO label168
  • e3.key(var24(@exp.key[0])<+8><+1256><+tempa>) 的前缀和差分加密会导致 e3.key 全为 “0”,进而对 e2.key(var23(@exp.key[0])<+8><+872><+tempa>) 的异或加密失效
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
LABEL label271 :
#!tempa := {#8}*{var15<+56>}
var16<+64> := var25(@exp.L[0])<+200><+1640><+tempa>
#!tempa := {#8}*{var15<+56>}
var18<+80> := var25(@exp.R[0])<+264><+1640><+tempa>
#!tempa := {#8}*{var15<+56>}
var20<+96> := var25(@exp.X[0])<+328><+1640><+tempa>
#!tempa := {#8}*{var16<+64>}
var17<+72> := var25(@exp.key[0])<+8><+1640><+tempa>
#!tempa := {#8}*{var18<+80>}
var19<+88> := var25(@exp.key[0])<+8><+1640><+tempa>
var17<+72> := var17<+72> - var20<+96>
var19<+88> := var19<+88> + var20<+96>
#!tempa := {#8}*{var16<+64>}
var25(@exp.key[0])<+8><+1640><+tempa> := var17<+72>
#!tempa := {#8}*{var18<+80>}
var25(@exp.key[0])<+8><+1640><+tempa> := var19<+88>
temp369 := #1
var15<+56> := var15<+56> + temp369
GOTO label272
LABEL label270 :
temp373 := #1
var15<+56> := temp373
LABEL label283 :
temp375 := #24
IF var15<+56> < temp375 GOTO label282
GOTO label281
LABEL label282 :
#!tempa := {#8}*{var15<+56>}
var17<+72> := var25(@exp.key[0])<+8><+1640><+tempa>
temp376 := #1
temp377 := var15<+56> - temp376
var16<+64> := temp377
#!tempa := {#8}*{var16<+64>}
var20<+96> := var25(@exp.key[0])<+8><+1640><+tempa>
var17<+72> := var17<+72> + var20<+96>
#!tempa := {#8}*{var15<+56>}
var25(@exp.key[0])<+8><+1640><+tempa> := var17<+72>
temp374 := #1
var15<+56> := var15<+56> + temp374
GOTO label283
  • e4.key(var25(@exp.key[0])<+8><+1640><+tempa>) 的前缀和差分加密最后会得到一个 fake flag

程序有效部分的核心逻辑如下:

  • 程序读取 flag 存入 e1.key 进行第一次前缀和差分,区间修改的操作数在 e1.L,e1.R,e1.X 中(已知)
  • 将第一轮计算的结果间隔取8个存入 e2.X,当做第二次前缀和差分的操作数
  • 第二次使用 e1.L,e1.R,e2.Xe2.key(已知)进行前缀和差分
  • 最后对比 e1.keye2.key 完全相同则 success

前缀和差分相当于对 [L,R) 的所有数字 +X:

  • 由于第一次前缀和的操作数已知,得到结果 e1.key[i]INPUT[i] + C[i]
  • 由于第二次前缀和差分需要用到第一次前缀和差分的结果,此时的 X[i] 已经变成 INPUT[i*3] + C[i*3],结果 e2.key[i] 表达为 INPUT[j1] + INPUT[j2] ...... INPUT[jn] + C[j]
  • 由于 e2.key 的初始值已知,常数 C[j] 可通过 e1.L,e1.R,e1.X 算出,加密后的 e1.key[i] 可以由含有 INPUT[j] 的式子来表示,加密后的 e2.key[i] 也可以用含有 INPUT[j] 的式子来表示,两者结合可以得到 24 组一次方程

通过中间代码提取出来的C代码样例如下:

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
for(i=0;i<24;i++){
key1 = 0;
x = i;
key1 = flag[x];
y = 23 - i;
e1.key[y] = key1;
}

for(i=23;i>0;i--){
y = i;
ky = e1.key[y];
x = i - 1;
kx = e1.key[x];
kz = ky - kx;
e1.key[i] = kz;
}

e1.L[0] = 0;
e1.R[0] = 8;
e1.X[0] = 11;
e1.L[1] = 15;
e1.R[1] = 23;
e1.X[1] = 0-13;
e1.L[2] = 2;
e1.R[2] = 11;
e1.X[2] = 17;
e1.L[3] = 10;
e1.R[3] = 20;
e1.X[3] = 0-19;
e1.L[4] = 6;
e1.R[4] = 13;
e1.X[4] = 23;
e1.L[5] = 9;
e1.R[5] = 21;
e1.X[5] = 0-29;
e1.L[6] = 1;
e1.R[6] = 19;
e1.X[6] = 31;
e1.L[7] = 4;
e1.R[7] = 17;
e1.X[7] = 0-37;

for(i=0;i<8;i++){
x = e1.L[i];
y = e1.R[i];
z = e1.X[i];
kx = e1.key[x];
ky = e1.key[y];
kx += z;
ky -= z;
e1.key[x] = kx;
e1.key[y] = ky;
}

for(i=1;i<24;i++){
kx = e1.key[i];
x = i-1;
z = e1.key[x];
kx += z;
e1.key[i] = kx;
}

e2.key[0]=252;
e2.key[1]=352;
e2.key[2]=484;
e2.key[3]=470;
e2.key[4]=496;
e2.key[5]=487;
e2.key[6]=539;
e2.key[7]=585;
e2.key[8]=447;
e2.key[9]=474;
e2.key[10]=577;
e2.key[11]=454;
e2.key[12]=466;
e2.key[13]=345;
e2.key[14]=344;
e2.key[15]=486;
e2.key[16]=501;
e2.key[17]=423;
e2.key[18]=490;
e2.key[19]=375;
e2.key[20]=257;
e2.key[21]=203;
e2.key[22]=265;
e2.key[23]=125;

for(i=0;i<8;i++){
x = i + i + i;
kx = e1.key[x];
e2.X[i] = kx;
}

for(i=23;i>0;i--){
y = i;
ky = e2.key[y];
x = i;
x -= 1;
kx = e2.key[x];
kz = ky - kx;
e2.key[i] = kz;
}

for(i=0;i<8;i++){
x = e1.L[i];
y = e1.R[i];
z = e2.X[i];
kx = e2.key[x];
ky = e2.key[y];
kx -= z;
ky += z;
e2.key[x] = kx;
e2.key[y] = ky;
}

for(i=1;i<24;i++){
kx = e2.key[i];
x = i-1;
z = e2.key[x];
kx += z;
e2.key[i] = kx;
}

下面是公式推导的过程:

通过 z3 即可求解 flag:

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
# -*- coding:utf-8 -*-
from z3 import *

s = []
for i in range(24):
s.append(Int('S'+str(i)))
x = Solver()

# 0
x.add(s[0]+s[0]+22 == 252)
# 1
x.add(s[0]+s[18]+s[1]+23 == 352)
# 2
x.add(s[0]+s[18]+s[6]+s[2]+85 == 484)
# 3
x.add(s[0]+s[18]+s[6]+s[3]+85 == 470)
# 4
x.add(s[0]+s[18]+s[6]+s[21]+s[4]+35 == 496)
# 5
x.add(s[0]+s[18]+s[6]+s[21]+s[5]+35 == 487)
# 6
x.add(s[0]+s[18]+s[6]+s[21]+s[12]+s[6]+27 == 539)
# 7
x.add(s[0]+s[18]+s[6]+s[21]+s[12]+s[7]+27 == 585)
# 8
x.add(s[18]+s[6]+s[21]+s[12]+s[8]+5 == 447)
# 9
x.add(s[18]+s[6]+s[21]+s[12]+s[15]+s[9]-91 == 474)
# 10
x.add(s[18]+s[6]+s[21]+s[12]+s[15]+s[9]+s[10]-105 == 577)
# 11
x.add(s[18]+s[21]+s[12]+s[15]+s[9]+s[11]-167 == 454)
# 12
x.add(s[18]+s[21]+s[12]+s[15]+s[9]+s[12]-167 == 466)
# 13
x.add(s[18]+s[21]+s[15]+s[9]+s[13]-159 == 345)
# 14
x.add(s[18]+s[21]+s[15]+s[9]+s[14]-159 == 344)
# 15
x.add(s[18]+s[21]+s[15]+s[9]+s[3]+s[15]-113 == 486)
# 16
x.add(s[18]+s[21]+s[15]+s[9]+s[3]+s[16]-113 == 501)
# 17
x.add(s[18]+s[15]+s[9]+s[3]+s[17]-63 == 423)
# 18
x.add(s[18]+s[15]+s[9]+s[3]+s[18]-63 == 490)
# 19
x.add(s[15]+s[9]+s[3]+s[19]-64 == 375)
# 20
x.add(s[15]+s[3]+s[20]-50 == 257)
# 21
x.add(s[3]+s[21]+46 == 203)
# 22
x.add(s[3]+s[22]+46 == 265)
# 23
x.add(s[23] == 125)

if(x.check()==sat):
model = x.model()
print(model)

model = x.model()

flag = [0]*24

for i in str(model).split(','):
pos, val = i.split('=')[:2]
pos = int(''.join([i for i in pos if i.isdigit()]))
val = int(''.join([i for i in val if i.isdigit()]))
flag[pos] = chr(val)

flag = ''.join(flag)

print(flag)