1. 题目背景与核心挑战解析
"魔鬼凯撒的RC4茶室"是2021年长城杯网络安全竞赛政企组的逆向工程题目,这道题融合了多种经典加密算法和逆向技巧。从题目名称就能看出几个关键信息点:"魔鬼凯撒"暗示存在凯撒加密变种,"RC4茶室"指向RC4流加密算法,而"茶室"可能暗指TEA系列加密。实际分析发现题目还使用了UPX加壳技术,形成了多层防御体系。
这道题的核心难点在于:
- 程序使用UPX 3.96版本加壳,需要先脱壳才能进行静态分析
- 加密逻辑嵌套了凯撒密码、RC4和TEA三种算法
- 各加密环节之间存在数据转换和依赖关系
- 关键字符串和密钥都做了混淆处理
2. UPX脱壳与初步分析
2.1 识别UPX加壳
使用Detect It Easy工具可以快速确认程序使用了UPX 3.96版本加壳。UPX是最常见的可执行文件压缩壳,虽然官方版本脱壳简单,但比赛中经常会遇到修改过的版本。
code复制$ diec devil_tea
UPX(3.96)[NRV,brute]
2.2 动态脱壳技巧
对于标准UPX壳,可以使用以下方法脱壳:
- 使用upx -d直接脱壳(仅对未修改版本有效)
- 使用x64dbg调试器,在OEP处dump内存
实际操作中发现题目使用的UPX壳有轻微修改,直接upx -d会失败。这时需要手动脱壳:
- 在x64dbg中运行程序,停在UPX入口点
- 单步执行直到看到大跳转(jmp指令)
- 跳转目标就是原始入口点(OEP)
- 使用Scylla插件dump内存并修复IAT
提示:遇到反调试时可以尝试在调试器启动前修改PE头标志位,或者使用硬件断点替代软件断点。
2.3 初步静态分析
脱壳后使用IDA Pro加载程序,可以看到主要逻辑集中在main函数。关键函数包括:
- tea_encrypt:TEA加密实现
- rc4_crypt:RC4加密/解密
- caesar_shift:凯撒移位密码
程序基本流程:
- 读取用户输入
- 进行凯撒移位
- RC4加密处理
- TEA加密最终校验
3. 凯撒密码变种分析
3.1 传统凯撒密码回顾
传统凯撒密码是将字母表中的每个字母移动固定的位数。例如移动3位:
A → D, B → E, ..., Z → C
3.2 题目中的变种实现
本题中的凯撒加密有以下特殊之处:
- 不仅处理字母,还包括数字和部分特殊字符
- 移位量不是固定的,而是根据字符位置动态计算
- 加密方向交替变化(先右移后左移)
加密函数伪代码:
c复制for (int i = 0; i < len; i++) {
if (i % 2 == 0) {
buf[i] = (buf[i] + i) % 128;
} else {
buf[i] = (buf[i] - i) % 128;
}
}
3.3 逆向解密算法
根据加密逻辑,解密算法需要反向操作:
python复制def caesar_decrypt(data):
result = []
for i in range(len(data)):
if i % 2 == 0:
result.append((data[i] - i) % 128)
else:
result.append((data[i] + i) % 128)
return bytes(result)
4. RC4算法实现分析
4.1 RC4算法基本原理
RC4是一种流加密算法,包含两个主要阶段:
- 密钥调度算法(KSA):初始化S盒
- 伪随机生成算法(PRGA):生成密钥流
4.2 题目中的RC4实现特点
- 使用固定密钥"Welcome_to_RC4_Tea_House"
- 对标准RC4做了轻微修改,在PRGA阶段增加了额外的XOR操作
- 加密前会对输入数据做一次Base64解码
关键代码片段:
c复制void rc4_init(unsigned char *key, int key_len) {
for (int i = 0; i < 256; i++) {
S[i] = i;
}
int j = 0;
for (int i = 0; i < 256; i++) {
j = (j + S[i] + key[i % key_len]) % 256;
swap(&S[i], &S[j]);
}
}
void rc4_crypt(unsigned char *data, int len) {
int i = 0, j = 0;
for (int k = 0; k < len; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap(&S[i], &S[j]);
data[k] ^= S[(S[i] + S[j]) % 256] ^ 0xAA; // 额外XOR
}
}
4.3 RC4解密实现
由于RC4是对称加密,解密使用相同流程:
python复制def rc4_decrypt(data, key):
# 初始化S盒
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
# 生成密钥流
i = j = 0
result = []
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
result.append(byte ^ k ^ 0xAA)
return bytes(result)
5. TEA加密算法解析
5.1 TEA算法简介
TEA(Tiny Encryption Algorithm)是一种分组加密算法,特点:
- 64位分组大小
- 128位密钥
- 简单高效的轮函数
5.2 题目中的TEA实现
程序使用的是XTEA变种,主要特点:
- 使用16轮加密
- 密钥硬编码在代码中
- 加密前会对数据进行填充
加密函数伪代码:
c复制void xtea_encrypt(uint32_t v[2], uint32_t key[4]) {
uint32_t v0 = v[0], v1 = v[1], sum = 0;
for (int i = 0; i < 16; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += 0x9E3779B9;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
}
v[0] = v0; v[1] = v1;
}
5.3 TEA解密实现
TEA解密需要逆向轮函数:
python复制def xtea_decrypt(v, key):
v0, v1 = v[0], v[1]
delta = 0x9E3779B9
sum = (delta * 16) & 0xFFFFFFFF
for i in range(16):
v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + key[(sum >> 11) & 3])
sum -= delta
v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + key[sum & 3])
return [v0, v1]
6. 完整解题流程与脚本
6.1 解题步骤总结
- 脱UPX壳获取可分析的程序
- 逆向分析程序逻辑,识别三种加密算法
- 提取硬编码的RC4密钥和TEA密钥
- 按照逆向顺序解密:
- 先TEA解密
- 然后RC4解密
- 最后凯撒解密
6.2 Python解密脚本
python复制import base64
# TEA解密
def xtea_decrypt(v, key):
v0, v1 = v[0], v[1]
delta = 0x9E3779B9
sum = (delta * 16) & 0xFFFFFFFF
for i in range(16):
v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + key[(sum >> 11) & 3])
sum -= delta
v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + key[sum & 3])
return [v0, v1]
# RC4解密
def rc4_decrypt(data, key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
result = []
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
result.append(byte ^ k ^ 0xAA)
return bytes(result)
# 凯撒解密
def caesar_decrypt(data):
result = []
for i in range(len(data)):
if i % 2 == 0:
result.append((data[i] - i) % 128)
else:
result.append((data[i] + i) % 128)
return bytes(result)
# 硬编码的密钥
rc4_key = b"Welcome_to_RC4_Tea_House"
tea_key = [0x12345678, 0x9ABCDEF0, 0x0FEDCBA9, 0x87654321]
# 密文数据(示例)
encrypted_data = bytes.fromhex("A1B2C3D4E5F6...")
# 解密流程
# 1. TEA解密
tea_blocks = [int.from_bytes(encrypted_data[i:i+4], 'little')
for i in range(0, len(encrypted_data), 8)]
decrypted_tea = []
for i in range(0, len(tea_blocks), 2):
block = tea_blocks[i:i+2]
decrypted = xtea_decrypt(block, tea_key)
decrypted_tea.extend(decrypted)
# 2. RC4解密
rc4_decrypted = rc4_decrypt(bytes(b for num in decrypted_tea
for b in num.to_bytes(4, 'little')), rc4_key)
# 3. 凯撒解密
final_flag = caesar_decrypt(rc4_decrypted).decode()
print("Flag:", final_flag)
7. 解题过程中的关键技巧
-
动态调试技巧:
- 在RC4初始化后下断点,可以直接从内存中提取S盒
- 使用x64dbg的Trace功能记录加密过程的数据流变化
-
算法识别技巧:
- TEA算法的特征常量0x9E3779B9
- RC4的256字节S盒初始化
- 凯撒移位的简单算术运算
-
数据转换技巧:
- 注意程序中的字节序处理(小端/大端)
- 加密数据可能经过Base64或十六进制编码
-
反调试对抗:
- 修改PEB.BeingDebugged标志
- 使用硬件断点替代软件断点
- 在关键检查点前修改标志寄存器
8. 类似题目的扩展思考
这道题目展示了CTF逆向工程的典型套路:多种加密算法组合+代码混淆。在实际比赛中,还可能遇到以下变种:
-
算法变种:
- 使用XXTEA代替XTEA
- RC4与其它算法嵌套使用
- 凯撒密码与Vigenère密码结合
-
保护加强:
- 使用自定义的加壳方式
- 关键代码动态生成
- 反调试和反虚拟机技术
-
解题思路扩展:
- 使用符号执行分析加密逻辑
- 通过侧信道分析获取密钥
- 使用约束求解器自动推导输入
逆向分析这类题目时,最重要的是保持耐心,逐步拆解每一层保护,同时注意积累常见算法的特征和识别方法。
