1. 项目背景解析:CTF赛事中的经典题目复现
"漂流记的马里奥"这道题目源自2019年西南石油大学(SWPU)校赛的CTF竞赛题库,后被收录进NSSCTF(全国大学生信息安全竞赛)的练习题库中。作为一道经典的逆向工程类题目,它模拟了游戏角色马里奥在特殊场景下的数据交互过程,考察选手对程序逆向分析、内存调试和算法还原的综合能力。
这道题目的独特之处在于将游戏元素与二进制漏洞利用相结合。题目提供了一个经过修改的马里奥游戏程序,玩家需要通过分析游戏内存数据、逆向通信协议来获取隐藏的flag。这种将娱乐元素融入技术挑战的设计手法,使得题目既有竞技性又不失趣味性,成为近年来CTF教学中的典型案例。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 题目环境搭建与工具准备
2.1 基础环境配置
要复现这道题目,首先需要准备以下环境:
- Windows/Linux操作系统(题目原始环境为Windows)
- IDA Pro 7.0及以上版本(或Ghidra等替代工具)
- x64dbg或OllyDbg调试器
- Python 3环境(用于编写解题脚本)
- 题目提供的游戏程序包(通常为.exe文件)
注意:不同年份的NSSCTF平台可能对题目文件做过适配调整,建议从官方渠道获取原始题目文件以确保一致性。
2.2 辅助工具链配置
为提高分析效率,建议配置以下辅助工具:
- Cheat Engine:用于实时监控游戏内存数据变化
- Process Monitor:跟踪程序的文件/注册表操作
- WireShark:如需分析网络通信协议
- PEiD或Exeinfo PE:快速识别程序加壳情况
3. 题目逆向分析实战
3.1 初步文件分析
首先对游戏程序进行基础静态分析:
bash复制file mario_game.exe
strings mario_game.exe | grep -i "flag"
通过初步检查可以发现:
- 程序为32位Windows可执行文件
- 未使用强加密壳(如有UPX壳需先脱壳)
- 字符串表中存在"Congratulations"等提示语但无明文flag
3.2 核心逻辑逆向
使用IDA Pro加载程序后,重点关注以下函数:
- 游戏主循环函数(通常包含MessageLoop等特征)
- 碰撞检测相关函数(可能隐藏flag触发条件)
- 分数/生命值更新函数(可能关联关键算法)
通过交叉引用分析,发现一个名为check_flag的关键函数,其伪代码如下:
c复制int __cdecl check_flag(int a1) {
char v2[32];
// 从游戏内存0x4030C0处读取32字节数据
memcpy(v2, (const void *)0x4030C0, 0x20u);
// 与硬编码的xor密钥逐字节运算
for ( int i = 0; i < 32; ++i )
v2[i] ^= byte_402150[i];
// 比较运算结果与特定字符串
return strncmp(v2, "NSSCTF{", 7u) == 0;
}
3.3 动态调试技巧
在x64dbg中附加游戏进程后,关键断点设置位置:
- 内存地址0x4030C0的写入操作(硬件断点)
check_flag函数的调用栈回溯- 所有文件读取操作(可能隐藏资源文件)
调试中发现当马里奥角色吃到特定金币时,会在内存0x4030C0处写入加密数据。通过Cheat Engine的内存扫描功能,可以定位到该地址与游戏内金币计数的关联关系。
4. 解题思路与脚本编写
4.1 加密算法还原
分析byte_402150处的xor密钥:
python复制key = [
0x12, 0x45, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x23,
0x56, 0x89, 0xAB, 0xCD, 0xEF, 0x10, 0x32, 0x54,
0x76, 0x98, 0xBA, 0xDC, 0xFE, 0x21, 0x43, 0x65,
0x87, 0xA9, 0xCB, 0xED, 0x0F, 0x31, 0x53, 0x75
]
4.2 自动化提取脚本
编写Python脚本实现内存读取与解密:
python复制import pymem
process = pymem.Pymem("mario_game.exe")
encrypted = process.read_bytes(0x4030C0, 32)
flag = bytes([encrypted[i] ^ key[i] for i in range(32)])
print(flag.decode(errors="ignore"))
4.3 非预期解法探索
部分选手通过以下方式解题:
- 修改游戏分数直接触发flag条件
- 拦截网络包发现隐藏API接口
- 分析游戏资源文件中的提示信息
5. 技术要点总结与延伸
5.1 题目设计精髓
这道题目巧妙融合了:
- 游戏内存机制的理解
- 基础加密算法分析
- 动态调试技巧应用
- 自动化脚本编写能力
5.2 同类题目训练建议
推荐练习以下相似题型:
- [HackTheBox] Game Over
- [CTFtime] Super Hexagon Challenge
- [PicoCTF] game-keys
5.3 防御性编程启示
从出题角度可以学到:
- 敏感数据应使用更复杂的加密方式
- 关键校验逻辑需要混淆处理
- 可以考虑使用反调试技术增加难度
6. 常见问题排查指南
6.1 调试器无法附加
可能原因:
- 程序检测到调试器存在
解决方案:
- 使用ScyllaHide等插件隐藏调试器特征
- 修改注册表禁用NtGlobalFlag
6.2 内存地址不匹配
可能原因:
- 题目版本差异导致基址变化
解决方案:
- 重新分析导入表定位关键函数
- 使用特征码搜索替代固定地址
6.3 解密结果异常
可能原因:
- 未正确获取加密数据
解决方案:
- 验证内存读取时机是否正确
- 检查xor密钥是否完整匹配
7. 参赛经验分享
在实际CTF比赛中处理此类题目时:
- 先快速确认题目类型(逆向/漏洞利用等)
- 建立标准的分析流程(静态→动态→脚本)
- 合理分配时间,避免在单一题目耗时过长
- 注意保存中间结果以便团队协作
对于这道特定题目,最有效的突破口往往是:
- 快速定位到金币计数与内存地址的关联
- 发现xor算法的存在形式
- 编写自动化工具提高效率
在多次实战中发现,使用Cheat Engine的指针扫描功能可以大幅缩短内存分析时间。同时,对游戏程序的常见结构(如Unity/Unreal引擎特征)有所了解也能提升分析效率。
