浅析ByteCTF2024 Reverse
字数 1904 2025-08-23 18:31:08
ByteCTF2024 Reverse 题目解析与教学文档
1. babyapk 题目解析
1.1 初步分析
- 这是一个基于 Flutter 架构的 APK 文件
- 使用 DIE 工具扫描确认架构后,考虑使用 blutter 进行反编译
1.2 环境配置
配置 blutter 环境时常见问题:
- 网络问题:需要全局代理
- 编译环境缺失:确保安装完整的编译环境
- CMake 相关错误:检查 VS 模块是否安装完整
1.3 反编译与符号表恢复
- 使用 blutter 成功启动后,运行 addName 脚本恢复符号表
- 可能需要多次运行脚本才能完全恢复符号表
- 搜索 APK 名称字段可以找到相关函数
关键函数:
babyapk_main__MyHomePageState::test_264c0c:包含主要逻辑- 修复函数结构技巧:"先U再C再P"原则(Undefine, Code, Procedure)
1.4 Frida Hook 分析
- 使用真机而非模拟器(模拟器可能缺少 ARM 底层支持)
- 修改 blutter 提供的 hook 脚本地址进行注入
- 关键 Hook 点:
- 0x198d18:flag 头检测
- 0x198df8:flag 头验证
- 0x264d88:flag 尾部验证
发现:Flutter 层仅进行 flag 格式验证,实际加密在 Rust 部分
1.5 Rust 部分分析
- 在
librust_lib_babyapk.so中找到关键字符串 "m3N4B5V6" - 定位到加密函数
sub_3AEE0 - 发现 flag 格式验证和连接符验证
1.6 Z3 求解
加密部分是一系列方程式,使用 Z3 求解器:
from z3 import *
data = [0x1EE59, 0x22A, 0x1415, 0x40714, 0x13E0, 0x8B8, 0xFFFDCEA0, 0x313B,
0x3D798, 0xFFFFFE6B, 0xC4E, 0x23884, 0x8D, 0x1DB4, 0xFFFC1328, 0x1EAC,
0x43C64, 0x142B, 0xFFFFF622, 0x23941, 0xFFFFEF6D, 0x120C, 0xFFFBD30F,
0x1EBE, 0x45158, 0xFFFFEF66, 0x1D3F, 0x4C46B, 0xFFFFF97A, 0x1BFD,
0xFFFBA235, 0x1ED2]
for i in range(4):
s = Solver()
v46, v47, v45, v44, v48, v49, v50, v51 = BitVecs("v46 v47 v45 v44 v48 v49 v50 v51", 8)
# 添加约束条件...
if s.check() == sat:
print(s.model()[v46], end=",")
# 输出其他变量...
求解后得到字节数组:
byte = [51, 50, 101, 55, 53, 48, 99, 56, 102, 98, 50, 49, 52, 53, 54, 50,
97, 102, 50, 50, 57, 55, 51, 102, 98, 53, 49, 55, 54, 98, 57, 99]
1.7 Flag 格式确定
- 32字节数据 + 4个连接符 + "ByteCTF{}" = 45字符
- 猜测为 GUID 格式:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
- 使用爆破脚本确定连接符位置:
from itertools import combinations
original_string = "32e750c8fb214562af22973fb5176b9c"
byte_18E46 = [...] # 验证数组
def validate_hyphen_positions(input_str):
# 验证逻辑...
return True
# 生成所有可能的连接符位置组合
positions = list(combinations(range(len(original_string) + 1), 4))
for pos in positions:
temp_str = original_string
# 插入连接符...
if validate_hyphen_positions(temp_str):
print(f"Valid combination: {temp_str}")
最终得到 flag 格式:
32e750c8-fb21-4562-af22-973fb5176b9c
2. ByteBuffer 题目解析
2.1 文件分析
- 文件包含点和边的信息,推测需要绘制图形
- 结构体特征:
- Edge 部分:前部是大数字,中间是两个四字节整数(端点编号)
- Dot 部分:包含 x,y 坐标信息
2.2 数据提取脚本
import struct
import matplotlib.pyplot as plt
def u32(a):
return struct.unpack('<I', a)[0]
with open("ByteBuffer.bin", 'rb') as fp:
buffer = fp.read()
# 提取 Edge 数据
edges = []
addr = 0x3AC
while addr <= 0x1203:
# 读取结构体...
edges.append(bts)
# 提取 Dot 数据
dots = []
while addr <= 0x1f85:
# 读取结构体...
dots.append(bts)
# 提取坐标点
points = []
for i in dots:
x_d = u32(i[4:8])
y_d = u32(i[8:12])
points.append((x_d, y_d))
# 绘制图形
for i in edges:
p1 = u32(i[8:12])
p2 = u32(i[12:16])
p2p = [120 - p1, 120 - p2] # 索引反转
x_coords = [points[i][0] for i in p2p]
y_coords = [points[i][1] for i in p2p]
plt.plot(x_coords, y_coords, '-o')
plt.gca().invert_yaxis()
plt.show()
3. ByteKit 题目解析
3.1 文件分析
- 包含启动 QEMU 镜像的脚本和 qcow2 镜像
- 镜像中有一个 flag 验证程序,验证路径:
/sys/firmware/efi/efivars/ByteCTFOut-93e91ed6-1a7a-46a1-b880-c5c281700ea2
3.2 提取 EFI 文件
方法:
- 使用 7zip 直接解压
- 使用 uefi_retool 工具:
python uefi_retool.py get-images bin路径
3.3 加密分析
- 发现 "ByteCTFIn"、"KEY:" 等字符串
- 使用 IDA 分析 ModuleEntryPoint 函数
- 发现 11 位循环异或加密:
- 密钥:
2CE83EE0BC1A0956B9D994 - 加密数据大小:0x6c4
- 密钥:
3.4 解密脚本
from idaapi import *
startaddr = 0x3A37
xoraddr = 0x3A2C
size = 0x6c4
for i in range(size):
patch_byte(startaddr + i, get_byte(startaddr + i) ^ get_byte(xoraddr + i % 11))
# 导出解密文件
fp = open("output", "wb+")
fp.write(get_bytes(startaddr, size))
fp.close()
3.5 二次解密
解密后的文件包含 "KEY:" 验证和异或加密:
enc = [0x4B, 0x27, 0x42, 0x55, 0x48, 0x6E, 0x41, 0x29, 0x1F, 0x5E, 0x04, 0x04,
0x6B, 0x3E, 0x57, 0x5F, 0x08, 0x07, 0x5F, 0x3A, 0x31, 0x17, 0x40, 0x30,
0x5F, 0x7A, 0x75, 0x67, 0x36, 0x36, 0x36, 0x36]
key = [...] # 密钥数组
for i in range(len(key) // 3):
v14 = key[i * 3 + 1]
v15 = v14 + key[i * 3 + 2]
while (v15 > v14):
enc[v14] ^= key[i * 3]
v14 += 1
flag = ''.join([chr(i) for i in enc])
print(flag) # KEY:By71d@nnc6_Wan77_y@0_zug6666
4. 极限逃脱题目解析
4.1 初步分析
- 直接分析 IPA 文件中的 ByteCTFDemo 部分
- 符号表较完整,主要查看 ViewController
4.2 第一按钮验证
firsButtonClicked 方法:
- 生成随机数:
arc4random_uniform(0x1F4) - 验证输入是否匹配随机数
- 通过后显示第二个按钮
4.3 第二按钮验证
secondButtonClicked 方法:
- 验证 flag 格式(UUID 格式)
- 初始化数据(注意:第一部分数据实际使用 fifth 的数据)
- 拼接 flag 格式字符串并计算 SHA256
- 分段进行字符替换:
- a → b
- b → c
- c → d
- d → e
- e → f
4.4 Flag 生成脚本
enc = 'a67be199da4b-b092-bd3e-e777-a67be199da4b'
hash = '6c9838a3c6810bdb2633ed5910b8547c09a7a4c08bf69ae3a95c5c37f9e8f57e'
p1 = ''
for i in range(1, 9):
p1 += hash[i]
p1 = p1.replace('a', 'b')
p2 = ''
for i in range(9, 13):
p2 += hash[i]
p2 = p2.replace('b', 'c')
p3 = ''
for i in range(5, 9):
p3 += hash[i]
p3 = p3.replace('c', 'd')
p4 = ''
for i in range(5, 9):
p4 += hash[i]
p4 = p4.replace('d', 'e')
p5 = ''
for i in range(5, 17):
p5 += hash[i]
p5 = p5.replace('e', 'f')
flag = 'ByteCTF{' + p1 + '-' + p2 + '-' + p3 + '-' + p4 + '-' + p5 + '}'
print(flag) # ByteCTF{c9838b3c-6810-8a3d-8a3c-8a3c6810bdb2}
总结
本教学文档详细分析了 ByteCTF2024 中的四个逆向题目,涵盖了:
- Flutter 应用逆向
- 二进制文件结构分析
- EFI 固件逆向
- iOS 应用逆向
关键技巧包括:
- 使用 blutter 反编译 Flutter 应用
- Frida 动态分析
- Z3 求解器使用
- 二进制结构体解析
- 多阶段加密分析
- iOS 运行时分析