CTF Reverse Engineering Write-Up: Challenge
基本
文件类型: ELF 64-bit LSB executable, x86-64, stripped
目标: 逆向分析二进制验证逻辑,获取正确 flag
Flag 格式: geesec{...}
静态分析
信息收集
首先通过 strings 提取可打印字符串,获得关键线索:
geesec{ ← flag 前缀
Unmask the hidden secret. Input your flag:
flag length error ← 长度错误提示
flag format is incorrect ← 格式错误提示
Incorrect flag, please try again.
Congratulations! The flag is correct.
86f;6a30:?ln>?o<'&v#%q#u(}x,,~-( ← 可疑加密字符串(32字节)
主函数逻辑 (0x401470)
通过反汇编分析主函数流程:
输出提示信息 "Unmask the hidden secret..."
scanf 读取用户输入到栈缓冲区
调用 strlen 检查输入长度是否为 0x28(40 字节)
调用 0x4012d0 验证 flag 格式并提取内容
调用 0x4013b0 对内容进行 XOR 加密变换
memcpy 从 0x4020d0 拷贝 33 字节加密数据到局部缓冲区
strncmp 比较 XOR 结果与加密数据(32 字节)
匹配则输出 "Congratulations!",否则输出 "Incorrect flag"
格式验证函数 (0x4012d0)
strncmp(input, "geesec{", 7) → 验证前缀
input[len-1] == '}' → 验证后缀
strncpy(result, input+7, len-8) → 提取花括号内内容
返回内容指针
XOR 加密函数 (0x4013b0)
核心加密循环:
for (int i = 0; i < length; i++) {
result[i] = input[i] ^ (i & 0xff);
}
即每个字节与自身索引进行 XOR。
加密数据
从 .rodata 段 0x4020d0 提取 32 字节加密数据:
38 36 66 3b 36 61 33 30
3a 3f 6c 6e 3e 3f 6f 3c
27 26 76 23 25 71 23 75
28 7d 78 2c 2c 7e 2d 28
对应字符串:86f;6a30:?ln>?o<'&v#%q#u(}x,,~-(
逆向算法
XOR 是可逆运算,解密公式:
content[i] = encrypted[i] ^ i
解密脚本:
encoded = bytes([
0x38, 0x36, 0x66, 0x3b, 0x36, 0x61, 0x33, 0x30,
0x3a, 0x3f, 0x6c, 0x6e, 0x3e, 0x3f, 0x6f, 0x3c,
0x27, 0x26, 0x76, 0x23, 0x25, 0x71, 0x23, 0x75,
0x28, 0x7d, 0x78, 0x2c, 0x2c, 0x7e, 0x2d, 0x28
])
content = ''.join(chr(encoded[i] ^ i) for i in range(32))
flag = f'geesec{{{content}}}'
print(flag)
Flag
geesec{87d82d5726fe22a377d01d5b0db70c37}
验证
重新用加密算法加密解密结果,与原始加密数据完全一致,确认 flag 正确。
注意事项
二进制文件被 strip 过,所有符号被移除,但不影响逆向分析
注意 objdump -s 的 hex 输出是按内存地址顺序逐字节显示,4 字节分组仅为视觉辅助,不要当成小端序 32
位整数解析(这是初期的易错点)