游客发表
CTF逆向题最坑的向题地方在于:你花了三个小时把汇编指令一条条啃完,最后发现flag就藏在字符串里,向题压根没加密。向题
这种事我遇到过不止一次。向题新手总觉得逆向就是向题IDA一开,F5一按,向题伪代码自动出来,向题然后顺着逻辑走就能拿flag。向题现实是向题——F5经常给你一堆看不懂的sub_401000和unk_404060,变量名全是向题v1到v28,指针满天飞。向题你得手动重命名几十个函数,向题才能勉强理出一条能走通的向题路径。
拿到一个二进制文件,向题第一步不是向题急着扔进IDA。先跑一下。file看架构,strings扫一遍,ltrace/strace跟一下系统调用。很多题目的check逻辑做得花里胡哨,结果flag直接明文写在rodata段里,或者经过一个简单的异或就能还原。
我就吃过亏。某次比赛一道200分的逆向,我上来就静态分析,追了半天的AES加密流程。队友拿过去跑了个strings,直接看到flag格式的字符串,试了一下就交了。那一刻想砸键盘。
IDA的F5确实强,但遇到控制流平坦化(OLLVM那种)就歇菜了。伪代码会变成一大坨while(1)加switch,状态变量来回跳,根本看不出原始逻辑。这时候要么上Angr做符号执行,要么手动去混淆——把状态变量追踪出来,还原真实的跳转关系。
还有一种情况:程序在运行时才解密关键代码。你静态看过去,那段区域全是0x00或者垃圾指令。得用调试器(x64dbg、gdb)跟到解密完成之后,再把内存dump出来重新分析。这种自修改代码的题目,纯静态分析基本没戏。
调试逆向题跟弹钢琴有点像,得掌握节奏。下断点不能太密,否则程序跑两步就断,你光按F9了。也不能太疏,不然关键分支早就过去了。
我的习惯是:先找输入相关的API。scanf、fgets、read、std::cin,在这些地方下断点,确认输入缓冲区地址。然后对缓冲区下硬件读写断点,看哪些指令动了你的输入。这样能快速定位check函数,省去大段无关代码的干扰。
有个细节:很多题目会先对输入做长度检查。长度不对直接退出,根本不进核心逻辑。所以先试几个不同长度的输入,观察程序行为差异,能帮你判断有效长度范围。
逆向题里的加密算法翻来覆去就那些。看到0x67452301、0xEFCDAB89这几个常数,基本就是MD5。看到0x9E3779B9,TEA系列没跑了。AES的S盒、RC4的256字节初始化、Base64的编码表——这些特征见多了,扫一眼汇编就能认出来。
但出题人也不傻。他们会改常数、换S盒、调整轮数。这时候光靠特征匹配不够,得理解算法结构。比如TEA的核心就是那个delta和32轮Feistel结构,就算delta被改了,看循环次数和移位异或的模式也能认出来。
分析完算法,最后一步是写脚本还原flag。Python的z3约束求解器是神器,遇到那种一堆if-else判断每个字符的题目,直接把约束条件翻译成z3表达式,让它自己解。比手动推快十倍。
不过z3也不是万能的。遇到非线性运算或者浮点比较,它可能跑半天没结果。这时候老老实实按算法逆回去写解密函数,反而更靠谱。
说到底,CTF逆向考的是耐心加经验。工具会用就行,关键是你脑子里得有一张地图——知道程序大概会怎么组织校验逻辑,知道哪里容易藏flag,知道什么情况下该换方法。刷题量上去了,看到题目自然就有手感。
友情链接