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.X 对 e2.key(已知)进行前缀和差分 
最后对比 e1.key 和 e2.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 from  z3 import  *s = [] for  i in  range (24 ):    s.append(Int('S' +str (i))) x = Solver() x.add(s[0 ]+s[0 ]+22  == 252 ) x.add(s[0 ]+s[18 ]+s[1 ]+23  == 352 ) x.add(s[0 ]+s[18 ]+s[6 ]+s[2 ]+85  == 484 ) x.add(s[0 ]+s[18 ]+s[6 ]+s[3 ]+85  == 470 ) x.add(s[0 ]+s[18 ]+s[6 ]+s[21 ]+s[4 ]+35  == 496 ) x.add(s[0 ]+s[18 ]+s[6 ]+s[21 ]+s[5 ]+35  == 487 ) x.add(s[0 ]+s[18 ]+s[6 ]+s[21 ]+s[12 ]+s[6 ]+27  == 539 ) x.add(s[0 ]+s[18 ]+s[6 ]+s[21 ]+s[12 ]+s[7 ]+27  == 585 ) x.add(s[18 ]+s[6 ]+s[21 ]+s[12 ]+s[8 ]+5  == 447 ) x.add(s[18 ]+s[6 ]+s[21 ]+s[12 ]+s[15 ]+s[9 ]-91  == 474 ) x.add(s[18 ]+s[6 ]+s[21 ]+s[12 ]+s[15 ]+s[9 ]+s[10 ]-105  == 577 ) x.add(s[18 ]+s[21 ]+s[12 ]+s[15 ]+s[9 ]+s[11 ]-167  == 454 ) x.add(s[18 ]+s[21 ]+s[12 ]+s[15 ]+s[9 ]+s[12 ]-167  == 466 ) x.add(s[18 ]+s[21 ]+s[15 ]+s[9 ]+s[13 ]-159  == 345 ) x.add(s[18 ]+s[21 ]+s[15 ]+s[9 ]+s[14 ]-159  == 344 ) x.add(s[18 ]+s[21 ]+s[15 ]+s[9 ]+s[3 ]+s[15 ]-113  == 486 ) x.add(s[18 ]+s[21 ]+s[15 ]+s[9 ]+s[3 ]+s[16 ]-113  == 501 ) x.add(s[18 ]+s[15 ]+s[9 ]+s[3 ]+s[17 ]-63  == 423 ) x.add(s[18 ]+s[15 ]+s[9 ]+s[3 ]+s[18 ]-63  == 490 ) x.add(s[15 ]+s[9 ]+s[3 ]+s[19 ]-64  == 375 ) x.add(s[15 ]+s[3 ]+s[20 ]-50  == 257 ) x.add(s[3 ]+s[21 ]+46  == 203 ) x.add(s[3 ]+s[22 ]+46  == 265 ) 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)