2023SCTF-Syclang-关于中间指令的分析
字数 813 2025-08-23 18:31:17
Syclang中间指令分析与逆向工程教学文档
1. 题目概述
2023 SYCTF中的Syclang题目展示了一个自定义的反编译器,它将源代码转换为中间指令(IR)、汇编等多种格式。本题主要关注对中间指令的分析,通过逆向工程理解程序逻辑。
2. 中间指令结构分析
2.1 数据结构定义
STRUCT exp :
ARRAY .key(int)[24]<+0> // int类型,占8字节,8*24=192
ARRAY .L(int)[8]<+192> // 偏移192字节
ARRAY .R(int)[8]<+256> // 偏移256字节
ARRAY .X(int)[8]<+320> // 偏移320字节
- 结构体总大小:320 + 8*8 = 384字节
- 每个字段都是64位整数(long long int)
2.2 函数定义
FUNCTION read - 8 : // 参数大小8字节
PARAM var2<+8>
LABEL Flabelread :
FUNCTION writes - 0 : // 无参数
LABEL Flabelwrites :
FUNCTION writef - 0 :
LABEL Flabelwritef :
FUNCTION exit - 0 :
LABEL Flabelexit :
2.3 main函数结构
FUNCTION main - 1640 : // 栈帧大小1640字节
ARRAY var11(char)[24]<+0> // 24字节字符数组
STRUCT var22(exp)<+488> // 4个exp结构体实例
STRUCT var23(exp)<+872>
STRUCT var24(exp)<+1256>
STRUCT var25(exp)<+1640>
3. 关键指令解析
3.1 输入处理循环
// 第一个循环,将输入反向存储到key数组中
LABEL label4 :
temp4 := #24
IF var15<+56> < temp4 GOTO label3
GOTO label2
LABEL label3 :
temp5 := #0
var12<+32> := temp5
var16<+64> := var15<+56>
#!tempa := {#1}*{var16<+64>} // tempa = var16 + 1
var12<+32> ::= var11<+1><+tempa> // var12 = input[i]
temp6 := #23
temp7 := temp6 - var15<+56>
var18<+80> := temp7
#!tempa := {#8}*{var18<+80>}
var22(@exp.key[0])<+8><+488><+tempa> := var12<+32> // key[23-i] = input[i]
temp3 := #1
var15<+56> := var15<+56> + temp3
GOTO label4
等效C代码:
for (int i = 0; i < 24; i++) {
var22.key[23 - i] = input[i];
}
3.2 差分变换循环
// 第二个循环,对key数组进行差分处理
LABEL label11 :
temp10 := #0
IF var15<+56> > temp10 GOTO label10
GOTO label9
LABEL label10 :
var18<+80> := var15<+56>
#!tempa := {#8}*{var18<+80>}
var19<+88> := var22(@exp.key[0])<+8><+488><+tempa> // key[i]
temp11 := #1
temp12 := var15<+56> - temp11 // i-1
var16<+64> := temp12
#!tempa := {#8}*{var16<+64>}
var17<+72> := var22(@exp.key[0])<+8><+488><+tempa> // key[i-1]
temp13 := var19<+88> - var17<+72> // key[i] - key[i-1]
var21<+104> := temp13
#!tempa := {#8}*{var15<+56>}
var22(@exp.key[0])<+8><+488><+tempa> := var21<+104> // key[i] = 差值
temp9 := #1
var15<+56> := var15<+56> - temp9
GOTO label11
等效C代码:
for (int i = 23; i > 0; i--) {
var22.key[i] = var22.key[i] - var22.key[i - 1];
}
3.3 初始化数据
LABEL label9 :
temp15 := #0
var22(@exp.L[0])<+200><+488> := temp15
temp17 := #8
var22(@exp.R[0])<+264><+488> := temp17
temp19 := #11
var22(@exp.X[0])<+328><+488> := temp19
// ... 其他初始化代码
完整初始化数据:
var22.L[0] = 0; var22.R[0] = 8; var22.X[0] = 11;
var22.L[1] = 15; var22.R[1] = 23; var22.X[1] = -13;
var22.L[2] = 2; var22.R[2] = 11; var22.X[2] = 17;
var22.L[3] = 10; var22.R[3] = 20; var22.X[3] = -19;
var22.L[4] = 6; var22.R[4] = 13; var22.X[4] = 23;
var22.L[5] = 9; var22.R[5] = 21; var22.X[5] = -29;
var22.L[6] = 1; var22.R[6] = 19; var22.X[6] = 31;
var22.L[7] = 4; var22.R[7] = 17; var22.X[7] = -37;
3.4 加密处理
// 对flag进行加密处理
for (int i = 0; i < 8; i++) {
var22.key[var22.L[i]] += var22.X[i];
var22.key[var22.R[i]] -= var22.X[i];
}
// 恢复差分
for (int i = 1; i < 24; i++) {
var22.key[i] += var22.key[i - 1];
}
3.5 密文处理
// 初始化密文
var23.key[0] = 252; var23.key[1] = 352; var23.key[2] = 484;
var23.key[3] = 470; var23.key[4] = 496; var23.key[5] = 487;
var23.key[6] = 539; var23.key[7] = 585; var23.key[8] = 447;
var23.key[9] = 474; var23.key[10] = 577; var23.key[11] = 454;
var23.key[12] = 466; var23.key[13] = 345; var23.key[14] = 344;
var23.key[15] = 486; var23.key[16] = 501; var23.key[17] = 423;
var23.key[18] = 490; var23.key[19] = 375; var23.key[20] = 257;
var23.key[21] = 203; var23.key[22] = 265; var23.key[23] = 125;
// 对密文进行差分处理
for (int i = 23; i > 0; i--) {
var23.key[i] -= var23.key[i - 1];
}
// 使用key进行变换
for (int i = 0; i < 8; i++) {
var23.key[var22.L[i]] -= var22.key[i * 3];
var23.key[var22.R[i]] += var22.key[i * 3];
}
// 恢复差分
for (int i = 1; i < 24; i++) {
var23.key[i] += var23.key[i - 1];
}
3.6 最终比较
// 比较处理后的flag和密文
for (int i = 0; i < 24; i++) {
if (var22.key[i] != var23.key[i]) {
exit; // 不相等则退出
}
}
4. 完整逆向逻辑
-
输入处理:
- 将24字节输入反向存储到key数组
- 对key数组进行差分处理(key[i] = key[i] - key[i-1])
-
加密处理:
- 根据L、R、X数组对特定位置的key值进行加减操作
- 恢复差分形式(key[i] += key[i-1])
-
密文处理:
- 初始化已知密文
- 对密文进行差分处理
- 使用key数组对密文进行变换
- 恢复差分形式
-
验证:
- 比较处理后的输入和密文是否一致
5. 解题思路
-
逆向加密过程:
- 从已知密文出发,逆向执行加密步骤
- 需要先处理密文的差分变换,然后逆向加减操作
-
关键点:
- 理解差分处理的双向性(正向和逆向)
- 注意L、R数组指定的位置操作
- 考虑X数组的值对加密的影响
-
编写解密脚本:
- 按照逆向顺序实现解密算法
- 特别注意操作顺序与加密时相反
6. 总结
通过对Syclang中间指令的分析,我们能够:
- 理解自定义反编译器的中间表示形式
- 掌握从中间指令还原高级语言逻辑的方法
- 学习复杂加密算法的逆向分析技巧
- 了解差分加密在CTF题目中的应用
这种分析能力对于二进制安全研究和逆向工程至关重要,特别是面对自定义编译器和非标准中间表示时。