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. 完整逆向逻辑

  1. 输入处理

    • 将24字节输入反向存储到key数组
    • 对key数组进行差分处理(key[i] = key[i] - key[i-1])
  2. 加密处理

    • 根据L、R、X数组对特定位置的key值进行加减操作
    • 恢复差分形式(key[i] += key[i-1])
  3. 密文处理

    • 初始化已知密文
    • 对密文进行差分处理
    • 使用key数组对密文进行变换
    • 恢复差分形式
  4. 验证

    • 比较处理后的输入和密文是否一致

5. 解题思路

  1. 逆向加密过程

    • 从已知密文出发,逆向执行加密步骤
    • 需要先处理密文的差分变换,然后逆向加减操作
  2. 关键点

    • 理解差分处理的双向性(正向和逆向)
    • 注意L、R数组指定的位置操作
    • 考虑X数组的值对加密的影响
  3. 编写解密脚本

    • 按照逆向顺序实现解密算法
    • 特别注意操作顺序与加密时相反

6. 总结

通过对Syclang中间指令的分析,我们能够:

  1. 理解自定义反编译器的中间表示形式
  2. 掌握从中间指令还原高级语言逻辑的方法
  3. 学习复杂加密算法的逆向分析技巧
  4. 了解差分加密在CTF题目中的应用

这种分析能力对于二进制安全研究和逆向工程至关重要,特别是面对自定义编译器和非标准中间表示时。

Syclang中间指令分析与逆向工程教学文档 1. 题目概述 2023 SYCTF中的Syclang题目展示了一个自定义的反编译器,它将源代码转换为中间指令(IR)、汇编等多种格式。本题主要关注对中间指令的分析,通过逆向工程理解程序逻辑。 2. 中间指令结构分析 2.1 数据结构定义 结构体总大小:320 + 8* 8 = 384字节 每个字段都是64位整数(long long int) 2.2 函数定义 2.3 main函数结构 3. 关键指令解析 3.1 输入处理循环 等效C代码: 3.2 差分变换循环 等效C代码: 3.3 初始化数据 完整初始化数据: 3.4 加密处理 3.5 密文处理 3.6 最终比较 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题目中的应用 这种分析能力对于二进制安全研究和逆向工程至关重要,特别是面对自定义编译器和非标准中间表示时。