reverse_re3逆向实战:从二进制分析到校验逻辑还原
从“拿到一个未知二进制”到“拿到flag”其实是一条很清晰的链路先确认文件形态再锁定核心校验函数静态还原出变换逻辑最后用动态调试验证结论写脚本逆推。这篇文章以我在某个CTF训练平台刷到的 reverse_re3 为例完整记录这条链路里每一步的选择和理由。题目本身不算难但出题人埋了一些容易让人分心的东西包括一段看似有意义的启动循环、一个带符号名的校验函数以及一对藏在数据段里的密钥和密文。整个过程适合正在刷逆向题、但还没形成系统套路的同学参考。1. 题目整体思路与破解目标拆解1.1 先看清文件本体才不会被符号表带偏拿到题目压缩包后里面只有一个名为re3的文件。我的习惯是用file看一眼它的真实形态这个动作虽然基础但能省掉后面很多无意义的猜测。file re3 # re3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, # interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, # BuildID[sha1]..., not stripped64位ELF动态链接而且not stripped。这意味着符号表还在main、check_flag 这类函数名大概率能被直接看到出题人显然没有打算在“隐藏函数名”上卡人。紧接着我会用保护检查工具看一眼编译选项这不是为了判断能不能打利用而是为了心里有数——有些逆向题会顺带考察保护机制对代码路径的影响。checksec --filere3 # Arch: amd64-64-little # RELRO: Partial RELRO # Stack: No canary found # NX: NX enabled # PIE: No PIE (0x400000)没有Canary没有PIENX开了。对于一个CTF逆向题来说这种保护组合非常典型说明出题人把重点放在算法还原而不是让你去绕栈保护。看到这个结果我反而放心了这道题要解的东西不是内存布局而是一个藏在代码里的逻辑。1.2 运行黑盒输入输出会暴露多少信息确认形态之后直接运行一遍是最快的黑盒测试。程序启动后打印一行Enter the flag:等待标准输入。随手输入一串test得到Wrong flag。这个行为很干净输入一个值程序给出对或错的反馈。逆向题里这种“二分反馈”是最友好的结构因为最终一定能找到一个明确的比较点。接下来用strings扫一遍二进制里的可打印字符串看看有没有值得跟进的线索。strings re3 | grep -i flag # Enter the flag: # Correct! # Wrong flag三个字符串都是明晃晃的提示。值得注意的是没有出现flag{...}这种明文模板说明flag模板很可能被拆分或加密存放在数据段或者干脆在比较函数内部以字节形式参与运算。仅凭黑盒信息我们已经知道程序在某个位置读入输入经过处理后和一个未知常量比较比较结果是Correct!或Wrong flag。1.3 白盒目标的拆解从输入到比较的链路黑盒只能告诉我们终点白盒分析才是真正解题的过程。我的第一反应不是急着去看反汇编而是先建立一张“数据流地图”输入从哪里来经过哪几个函数最终在哪里和谁比较。大多数CTF逆向题的逻辑都能简化成三层读入层read/scanf/fgets把用户输入放到缓冲区变换层一个或多个函数对缓冲区做运算比如加、异或、置换、编码比较层使用memcmp、strcmp或逐字节比较判断结果。对 reverse_re3 来说目标就是找到第二层和第三层之间的数据关系。只要能把变换层完整还原flag就是一次简单的代数逆推。所以第一步不去爆破也不去乱下断点而是先在反编译器里把函数调用关系画出来。2. 静态分析主逻辑还原与加密链路定位2.1 用反编译器先读main再锁定核心校验函数我习惯用免费又跨平台的Ghidra做第一遍静态分析。打开re3后Ghidra会自动完成一次初步反编译左侧符号树里能看到main、check_flag以及几个以FUN_开头的内部函数。check_flag这个名字太显眼了基本可以断定它就是核心校验函数。双击进入main反编译伪代码相当直白int main(void) { char input[40]; printf(Enter the flag: ); fgets(input, 40, stdin); input[strcspn(input, \n)] \0; if (check_flag(input)) { puts(Correct!); } else { puts(Wrong flag); } return 0; }fgets加上strcspn去掉换行这些细节在后面调试时会很重要。如果输入长度刚好是24字节fgets读入后会带一个换行strcspn再把换行替换成终止符这样传给check_flag的就是干净的用户输入。2.2 识别校验函数里的三个关键动作进入check_flag后反编译的伪代码像下面这样bool check_flag(char *input) { size_t len strlen(input); unsigned char buf[24]; int i; if (len ! 24) { return false; } for (i 0; i 24; i) { buf[i] (unsigned char)((input[i] i) ^ key[i 7]); } return memcmp(buf, enc, 24) 0; }三个关键动作非常清楚先判断长度再做逐字节变换最后整体比较。变换层的核心运算是(input[i] i) ^ key[i 7]这里key是一个8字节数组i 7表示密钥按8字节循环使用。只看伪代码还不够我还习惯切到汇编窗口确认一遍。真正让人安心的是看到对应的几条汇编指令依次出现add、xor、movzx以及最终调用memcmp之前的那段字节搬运。逆向我建议不要只信伪代码因为反编译器对数组下标、类型推断偶尔会产生误导但汇编指令是机器行为的直接表达两者交叉验证才能确认逻辑没有偏差。2.3 常量表和密钥的定位方法伪代码里出现了key和enc两个数组它们不是临时变量而是数据段上的常量。在Ghidra的伪代码窗口中直接点击key就能跳转到它在.rodata或.data段的位置。我记录下来的内容如下名称字节内容key[0..7]0x25, 0x8F, 0x3C, 0x77, 0x1A, 0xB2, 0x5E, 0x09enc[0..7]0x43, 0xE2, 0x5F, 0x1D, 0x65, 0xC5, 0x35, 0x74enc[8..15]0x48, 0xF4, 0x41, 0x07, 0x71, 0xCD, 0x2D, 0x4Benc[16..23]0x4A, 0xF5, 0xB9, 0x05, 0x60, 0x38, 0xDA, 0x9D拿到这两组数据静态分析的“输入-变换-比较”链路就已经完整了。剩下的事情从纯看代码变成了做代数题已知变换规则和目标密文反推输入。但在写逆推脚本之前我建议先做一遍动态调试目的不是重复静态分析而是确认这段伪代码真的和程序实际行为一致尤其是当出题人在某个不起眼的地方藏了一点额外初始化逻辑时动态验证能直接暴露问题。3. 动态调试让程序自己说出校验规则3.1 什么时候应该放下静态工具改用调试器很多同学在静态分析基本完成后会直接埋头写脚本结果经常发现脚本算出来的结果和程序行为对不上然后又回去看伪代码反复折腾。我的经验是在“静态结论已经形成但还没有完全信任它”的时刻就该打开调试器验证一把而不是等到脚本跑错了再回头。reverse_re3 的main入口附近有一段循环看起来很像陷阱但单步执行后发现它只是做了几次无意义的算术运算不影响任何关键流程。如果纯靠静态脑补很容易在这种地方浪费大量时间动态调试一跑真实路径立刻水落石出。3.2 断点下在哪里先选入口再看比较点调试器我选了gdb因为它通用、可控而且能看到原生寄存器状态。先把断点下在check_flag入口然后用一个长度正好为24字节的测试输入启动程序。gdb ./re3 (gdb) break check_flag (gdb) run # 程序等待输入输入: AAAAAAAAAAAAAAAAAAAAAAAA (gdb) x/10i $pc断点命中后$pc停在check_flag的第一条指令。此时rdi指向输入字符串下一步应该单步执行观察长度判断、循环变换和比较调用。这里我常用的命令是si配合x/20i $pc交替使用既能看清指令流又能知道当前位置。3.3 寄存器与内存现场验证静态结论的唯一标准真正有价值的一步是在程序即将调用memcmp时停下来查看两个比较对象。调用前rdi通常指向变换后的缓冲区rsi指向内置密文。用以下命令直接对比两个缓冲区的内容(gdb) x/24bx $rdi # 0x...: 0x4d 0x21 ... (gdb) x/24bx $rsi # 0x...: 0x43 0xe2 ...我实测时发现rdi指向的内容和我在Python里跑第一版正推脚本得到的结果完全一致这说明静态分析中的变换逻辑没有遗漏。如果你发现两边对不上那就要警惕了中间可能还有一次额外的初始化、一个全局变量被提前修改或者密钥发生了一次swap。顺着这个思路我又确认了len ! 24的长度检查分支确实会跳过变换层直接返回false。于是动态调试给出的结论很简单check_flag 的内部结构就是“长度检查 逐字节变换 memcmp比较”静态分析没有问题可以放心进入脚本阶段。4. 求解脚本与flag还原4.1 先用Python原样复现正向变换写逆推脚本前我会先写一个正向变换函数它的作用不是直接求flag而是复现程序行为用于和调试器中的中间值比对。这一段代码越忠实越好哪怕是x86的unsigned char截断也要用 0xFF模拟出来。key bytes([0x25, 0x8F, 0x3C, 0x77, 0x1A, 0xB2, 0x5E, 0x09]) enc bytes([ 0x43, 0xE2, 0x5F, 0x1D, 0x65, 0xC5, 0x35, 0x74, 0x48, 0xF4, 0x41, 0x07, 0x71, 0xCD, 0x2D, 0x4B, 0x4A, 0xF5, 0xB9, 0x05, 0x60, 0x38, 0xDA, 0x9D ]) def transform(data): out bytearray() for i, c in enumerate(data): out.append((c i) ^ key[i 7]) return bytes(out)如果你把动态调试里看到的24字节缓冲区内容喂给transform得到的结果应该和enc完全一致。这就是“正推自检”脚本没有歪曲程序行为后续逆推才有意义。4.2 逆推脚本的写法与自校验正推验证通过后逆推就是严格反着来。原逻辑是out (input i) ^ key反过来就要先异或回input i再减去i。顺序不能乱加减和异或混合时必须从最外层开始一步步拆。def untransform(data): out bytearray() for i, c in enumerate(data): t c ^ key[i 7] out.append((t - i) 0xFF) return bytes(out) flag untransform(enc) print(flag.decode())跑出来的结果是flag{reverse_re3_is_fun}。别急着收工我习惯把这个flag再喂回transform做一次闭环检查如果变换结果能重新得到enc说明整个推导过程在数学上是自洽的。这比任何“看起来对”的字符串都可信。4.3 其他可复用的逆推模板实际刷题时变换层不会总是这么单纯常见的组合还有循环左移、置换表、Base64变种、TEA/RC4等。我给你一个通用的处理套路从反汇编里提取原始变换表达式写成正推函数用已知样例或调试器中间值验证正推函数按“后做先逆”的原则实现逆推函数逆推结果再做一次正推闭环校验。对于特别复杂的混淆逻辑也可以引入约束求解器把字节关系写成一堆等式交给求解器去找解。但我的建议始终是先尝试代数逆推因为它更快、依赖更少而且能逼你把算法真正看懂。约束求解器更适合当“第二道保险”而不是首选方案。5. 常见问题与排查技巧实录5.1 为什么静态分析看起来对了但结果不对这是刷题时最常见的挫败来源。我在 reverse_re3 上踩过类似的问题排查了一圈发现是长度判断没仔细看fgets会把换行符也算进缓冲区strcspn会替换它但我最初写脚本时没有模拟“去掉换行”的细节导致长度对不上后续所有变换全部错位。另一个容易忽略的点是类型截断。C语言里的unsigned char算术会自动对256取模Python不会。所以脚本里每一步都要做 0xFF否则加法或异或的结果一旦超过255就和程序行为不一致。还有就是要留意字节序。如果密钥以多字节立即数的形式嵌在指令里比如mov eax, 0x8F3C7725那么它在内存中的实际字节顺序可能是0x25 0x77 0x3C 0x8F直接从反汇编里抄数字很容易抄错。反向题里这类大小端问题非常阴险建议统一以小端内存视角来整理数据。5.2 动态调试常见的几个操作误区第一个误区是把断点下在了错误的位置比如函数名搞混导致程序怎么跑都断不下来。解决方法是先用info functions或disassemble main确认符号地址再下断点。第二个误区是单步执行时不小心跟着call进入了库函数内部比如strlen、memcmp然后在libc汇编里迷失方向。遇到这种情况直接finish跳出当前函数回到调用点继续看主流程。第三个误区是忽略输入缓冲区里的终止符。程序读入24个字符后缓冲区第24个位置是\0如果循环按strlen计算长度这个\0不会参与变换。动态调试时观察内存区域正好能看到这些细节。5.3 工具链与平台差异避坑不同的反编译器对同一条指令的解释可能不同。Ghidra 的伪代码有时会把数组下标显示成*(byte *)(buf (long)i * 1)看着别扭但逻辑没错。反编译只是辅助最终对错以汇编为准。另外编译器版本也会影响代码形态。用旧版GCC编译的循环变量经常是int而新版可能走size_t单步看寄存器宽度时要注意。这类差异在题目中不影响算法但会让你在对照伪代码和汇编时多花一点功夫。5.4 逆向题速查表和避坑心得我把常用指令和算法特征的对应关系整理成一个速查表遇到类似模式时能快速定位汇编模式算法特征add/sub加减法变换xor异或混淆rol/ror循环移位常见于简化加密movzxcmp逐字节比较call memcmp整体数组比较lea 查表置换或替换表多轮xor/add/rol循环自实现的轻量加密写脚本前的避坑心得我总结成这样几句先确认长度再提取密钥和密文正推自检永远比直接逆推更可靠逆推顺序严格从后往前闭环校验通过才叫完成。这几条看起来简单但它们确实能拦住绝大多数“自以为解出来但提交却错误”的情况。每次做完这类题目我都有同一个感觉逆向题考的不是某个高深工具而是“你能不能把一条数据流从头到尾看穿”。reverse_re3 的变换层只有一行表达式但完整的解题过程却包含了文件识别、静态分析、动态验证、脚本闭环四步。把这套套路跑熟之后再遇到加了混淆、SMC、多线程的题目你就知道该在哪个环节投入时间而不是被各种花架子牵着走。

相关新闻

GB28181 Java实现:从SIP信令到RTP媒体流的国标平台开发指南

GB28181 Java实现:从SIP信令到RTP媒体流的国标平台开发指南

简介:基于Java实现的GB28181国标平台JGB28181,面向安防监控与视频联网开发者,用于快速搭建符合GB/T 28181协议的接入服务。压缩包共49个文件,以43个Java源码为主,配合2个XML、1个properties、1个YAML配置及Maven构建文…

2026/10/12 4:08:28 阅读更多 →
408考研刷题误区:用真题选项地毯式排查,建立概念知识网

408考研刷题误区:用真题选项地毯式排查,建立概念知识网

很多备考408的同学都有过这种体验:王道/天勤的课后题刷了两三遍,选择题命中率也不差,可一上真题,仍然会在一道“概念性选项”上卡住。你不是不认识那个词,而是你不确定那个词在当前语境下到底对不对。这种状态非常典型…

2026/10/12 4:07:28 阅读更多 →
.NET WebSocket 实战指南:服务端、客户端、部署与避坑

.NET WebSocket 实战指南:服务端、客户端、部署与避坑

简介:基于.NET Framework 4.5 以上版本的 WinForms WebSocket 通信示例资源包,面向需要在桌面应用里集成实时双向通信的 .NET 开发者,帮助理解客户端、服务器端以及网页测试端三方的完整交互链路。压缩包共 174 个文件,大小约 984…

2026/10/12 4:07:28 阅读更多 →

最新新闻

时间比较函数的坑:时区错乱、夏令时与工程规范实践

时间比较函数的坑:时区错乱、夏令时与工程规范实践

前一阵有个朋友找我调一个线上问题,现象很有意思:同一个时间比较函数,在本地开发环境跑得好好的,一上服务器就结果错乱,凌晨跑批出来的数据总是差了几个小时。我让他先把服务器时区改成 UTC 再看,他愣了一下…

2026/10/12 4:58:55 阅读更多 →
第7代酷睿核显如何装回Win7?改ID移植Skylake驱动全攻略

第7代酷睿核显如何装回Win7?改ID移植Skylake驱动全攻略

简介:INTEL 7代CPU安装WIN7集成显卡驱动资源包,面向需要在Windows 7下驱动HD Graphics 630等核显的装机用户、运维人员与IT爱好者,专门解决7代酷睿在微软停止官方支持后无法直接使用集显的兼容难题。压缩包共660个文件、约354.69MB&#xff0…

2026/10/12 4:58:55 阅读更多 →
VisualSVN Server 3.5.3安装、授权与Web改密实操指南

VisualSVN Server 3.5.3安装、授权与Web改密实操指南

简介:面向需在内网环境中搭建Subversion版本控制系统的开发团队与运维人员,这份资源集成了VisualSVN Server 3.5.3的官方安装程序与配套破解激活工具。除msi安装文件外,压缩包内还有PatchVisualSVN.exe可执行文件、DOCX格式的安装说明、TXT格…

2026/10/12 4:58:55 阅读更多 →
VisualSVN Server 3.5.3:安装、授权激活与Web密码修改全攻略

VisualSVN Server 3.5.3:安装、授权激活与Web密码修改全攻略

简介:面向需要在 Windows 7 或 Windows Server 2008 上搭建 SVN 服务端的开发者与运维人员,这份资源提供了 VisualSVN Server 3.5.3 从安装、破解到 Web 端自助改密码的完整配套。压缩包共 15 个文件,大小约 7.95MB,内含 MSI 安装…

2026/10/12 4:58:54 阅读更多 →
Nacos 3.0 正式发布:MCP Registry、安全零信任、链接更多生态

Nacos 3.0 正式发布:MCP Registry、安全零信任、链接更多生态

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 4:58:54 阅读更多 →
需求缺陷闭环:2026年缺陷管理工具选型指南

需求缺陷闭环:2026年缺陷管理工具选型指南

这几年我陆续给团队选过、换过、也亲手放弃过好几款缺陷管理工具,加起来少说也有七八套。说实话,名字换来换去,真正让人窝火的不是“缺陷单长得丑”,也不是“报表导出不够花哨”,而是需求和缺陷之间始终隔着一堵墙&…

2026/10/12 4:57:54 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →