GXYCTF2019 运气小伙子逆向解法与逻辑重构
环境评估与保护机制检测
针对该二进制样本,首要步骤是确认其是否存在加壳保护。通过加载专业的可执行文件检查工具进行分析,界面反馈如下:
分析结果表明,目标程序并未经过任何常见的压缩或混淆处理,处于原始状态。这意味着我们可以直接进行静态反汇编操作,而无需先进行脱壳处理。
函数定位与代码逻辑梳理
利用反编译利器 IDA Pro 载入样本,待自动分析流程结束后,借助全局字符串搜索功能(快捷键 Shift+F12)定位关键特征文本:
搜索结果迅速锁定了核心输出语句。双击跳转至引用处,并通过交叉引用查找调用者(Shift+X),最终聚焦于名为 get_flag 的函数入口:
开启伪代码生成模式(F5),核心逻辑展示为一层循环结构,内部嵌套了基于随机数的分支跳转:
void* process_random_logic(void) {
unsigned int time_seed;
int loop_counter;
int inner_index;
char temp_buffer[0x28];
// 初始化种子并设置随机数发生器
time_seed = GetCurrentTime();
SeedGenerator(time_seed);
for (loop_counter = 0; loop_counter < 5; loop_counter++) {
// 根据随机值决定执行路径
switch (RandomNext() % 200) {
// 分支 A:初始化部分密钥数据
case 4:
memcpy(temp_buffer, "\x7Ffo`guci", 8);
break;
// 分支 B:对数据进行位变换加密
case 5:
for (inner_index = 0; inner_index <= 7; inner_index++) {
if (inner_index % 2 != 0) {
temp_buffer[inner_index] -= 2;
} else {
temp_buffer[inner_index]--;
}
}
break;
// 分支 C:拼接前缀并打印完整凭证
case 1:
Print("OK, it's flag:");
ConcatString(flag_area, "GXY{do_not_", temp_buffer);
PrintResult(flag_area);
break;
// 其他情况为干扰项或提示错误
default:
LogFailure("Unable to retrieve credential");
break;
}
}
}
观察控制流可知,程序的正常运行依赖于特定的分支执行顺序。虽然外层是一个 5 次循环,但为了获取有效载荷,必须确保程序依次命中"初始化"、"加密变换"以及"输出结果"这三个关键状态。其中,小端序存储的数据在内存中的排列与实际读取顺序可能存在差异,需在还原过程中予以修正。
算法还原与脚本编写
基于上述分析,我们需要模拟特定分支的执行路径来还原被加密的字符串。考虑到内存布局的字节序影响,需先将获取到的密文段进行逆序处理,再根据索引奇偶性应用对应的偏移量解密。
以下为重构后的验证脚本:
def recover_secret_data(raw_input_str):
"""
解密由 C 语言二进制文件中提取的乱码数据
:param raw_input_str: 十六进制转义字符表示的密文
:return: 解密后的明文片段
"""
decrypted_chars = []
# 处理小端序问题,反转字符串以匹配实际内存访问顺序
processed_sequence = raw_input_str[::-1]
# 遍历每个字节进行处理
for idx, char_code in enumerate(processed_sequence):
if idx >= 8:
break
current_value = ord(char_code)
# 根据位置奇偶性应用不同减数
shift_offset = 2 if (idx % 2 == 1) else 1
restored_char = chr(current_value - shift_offset)
decrypted_chars.append(restored_char)
return "".join(decrypted_chars)
# 原始密文数据
payload = '\x7Ffo`guci'
# 执行恢复过程
hidden_part = recover_secret_data(payload)
print(f"Recovered segment: {hidden_part}")
运行脚本后,控制台将输出解密后的字符串片段:
Recovered segment: hate_me
目标凭证生成
结合固定的前缀信息,将解密得到的有效负载填入模板,即可构造出完整的通关凭证:
GXY{do_not_hate_me}