简介:这份资源是华中科技大学网络空间安全学院逆向工程分析技术实验的完整存档,面向正在修读该课程或自学逆向分析的高校学生与安全爱好者,可用于课程实验复现、报告撰写参考与动手练习。压缩包共57个文件,约6.11MB,以35张png实验截图、6个xml配置、2份md说明文档为主,另含exe与i64可执行样本、apk与dex安卓逆向样本、so动态库、rsa与py脚本等,覆盖PE与Android两条逆向分析主线。资源内含源码和说明书,可自行修改,方便对照实验步骤理解反汇编、静态分析与动态调试流程。目前已有165人学习下载,适合需要完整实验方案、样本文件与操作记录来查漏补缺的读者参考使用。
1. 逆向工程实验环境搭建:从一份课程包说起
拿到“华中科技大学网络空间安全学院-逆向工程分析技术实验-内含源码和说明书”这个包的时候,很多人第一反应是解压、找 README、跑 main。我带过几轮类似的实验课,也帮同事排查过他们从各种渠道拿到的逆向练习包,发现一个规律:能跑通的人,赢在环境,不是赢在技术。这个包的核心价值在于它把“逆向工程分析技术”拆成了可操作的实验单元,附带源码和说明书,意味着你可以改、可以调、可以故意改坏再修。适合谁?适合刚学完汇编和 C 语言、想动手拆二进制但不知道从哪下手的同学,也适合工作里需要快速分析闭源模块、排查崩溃堆栈的工程师。热搜里“逆向工程”“源码”“说明书”三个词同时出现,说明大家最关心的不是概念,而是拿到手怎么用、怎么改、怎么验证。这一章先把环境立住,后面再逐层拆实验。
2. 实验包结构拆解与工具链选型:为什么不用 IDA 也能起步
2.1 先看清包里有什么,再决定装什么
课程实验包通常不会只有一个 exe。常见结构是:src/放源码,bin/或release/放编译好的可执行文件,docs/或根目录放说明书,可能还有test/或samples/放测试输入。不要急着双击 exe,先用命令行把目录树打出来:
# Linux/macOS 下查看目录结构,Windows 用 tree /F find . -maxdepth 3 -type f | sort # 或者只看关键文件 ls -laR | head -100逻辑说明:find的-maxdepth 3防止目录太深刷屏,-type f只看文件。参数说明:如果你在 Windows 的 PowerShell 里,用Get-ChildItem -Recurse -Depth 2代替。这一步的目的是确认源码和二进制是否对应。很多实验包会故意给一个和源码不完全一致的二进制,让你通过逆向找出差异——这是常见教学手法。
2.2 工具链选型:从免费到够用
逆向工程分析技术实验不一定非要上 IDA Pro。我一般会按这个顺序配:
| 工具 | 用途 | 起步建议 |
|---|---|---|
| Ghidra | 反汇编/反编译 | 免费,NSA 出品,支持多架构 |
| objdump + readelf | 快速看节区、符号 | Linux 自带,适合脚本化 |
| gdb / lldb | 动态调试 | 配合 pwndbg 或 gef 插件 |
| Python + capstone | 写自动化分析脚本 | 热搜里“python cc攻击源码”虽不相关,但 Python 做逆向辅助是主流 |
| strings / xxd | 快速提取可打印字符 | 找硬编码密钥、URL 的第一手段 |
选型理由:Ghidra 的反编译质量在免费工具里最稳,而且支持协作项目文件。如果你只是做课程实验,Ghidra + gdb + Python 足够覆盖 90% 的场景。不要一上来就折腾 IDA 的 license,时间花在分析上更值。
2.3 把源码编译一遍,建立“可控基线”
说明书里如果给了编译命令,照做;没给就自己写。以常见的 C 实验为例:
# 假设源码在 src/ 下,有 Makefile cd src make clean && make # 如果没有 Makefile,手动编译 gcc -g -O0 -o ../bin/lab1 lab1.c -lm逻辑说明:-g保留调试符号,-O0关闭优化。参数说明:做逆向实验时千万不要用 -O2,优化会打乱汇编和源码的对应关系,让你怀疑人生。编译完把生成的二进制和包里自带的二进制做对比:
# 比较两个文件的哈希和大小 sha256sum bin/lab1 release/lab1 ls -l bin/lab1 release/lab1如果哈希不一致,说明包里的二进制可能是故意改过的版本,或者编译选项不同。这时候以说明书为准,说明书说用哪个就用哪个。这一步是后面所有分析的基础,基线不稳,后面全是玄学。
3. 静态分析实战:用 Ghidra 和 objdump 定位关键逻辑
3.1 用 objdump 快速摸清节区和符号
在打开 Ghidra 之前,先用 objdump 做一轮“体检”:
# 查看节区信息 objdump -h bin/lab1 # 查看符号表(如果有) objdump -t bin/lab1 | head -50 # 反汇编 .text 节区 objdump -d -M intel bin/lab1 > lab1.asm逻辑说明:-h看节区大小和偏移,-t看符号,-d反汇编。-M intel指定 Intel 语法,比 AT&T 好读。参数说明:如果二进制被 strip 过,-t可能没输出,这时候直接看-d的结果。把lab1.asm用编辑器打开,搜索main、scanf、strcmp、printf这些关键词,能快速定位到输入校验或输出逻辑。
3.2 Ghidra 项目创建与自动分析
Ghidra 的用法:新建项目 → Import File → 选二进制 → 默认选项 → Analyze。分析完后在 Symbol Tree 里找main或entry。如果没符号,从entry开始跟。Ghidra 的反编译窗口(Decompile)会给出 C -like 代码,但不要直接信,尤其是涉及指针运算和类型转换的地方。
我一般会做两件事:
- 在反编译窗口里重命名变量和函数,比如
local_18改成input_buf。 - 用 Ghidra 的 Script Manager 跑一个简单的 Python 脚本,提取所有字符串引用:
# Ghidra Python (Jython) 脚本示例:列出所有定义的字符串及其引用 from ghidra.program.model.data import StringDataType listing = currentProgram.getListing() data_iter = listing.getDefinedData(True) for data in data_iter: if isinstance(data.getDataType(), StringDataType): print(data.getAddress(), data.getValue())逻辑说明:这段脚本遍历所有已定义数据,过滤出字符串类型并打印地址和值。参数说明:在 Ghidra 的 Script Manager 里新建 Python 脚本,粘贴后运行。输出结果可以帮你快速找到“密码错误”“成功”这类提示字符串,然后右键看引用,直接跳到校验函数。
3.3 对照源码验证反汇编理解
实验包给了源码,这是最大的优势。你可以把 Ghidra 反编译的伪代码和源码并排看,找出编译器做了什么“手脚”。比如源码里是if (a == 0x1234),汇编里可能是cmp+jne,但优化后可能变成sub+test。常见做法是:在源码里改一个常量,重新编译,再看汇编变化。这样反复几次,你对“源码到汇编”的映射就有肌肉记忆了。
提示:Ghidra 默认的反编译选项可能把
char数组识别成int,手动调整数据类型能大幅提高可读性。
4. 动态调试与补丁:用 gdb 改掉一个跳转需要几步
4.1 gdb 基础:断点、寄存器、内存
动态调试是验证静态分析结论的唯一标准。以 Linux 下的 ELF 为例:
gdb -q bin/lab1 # 在 gdb 里 (gdb) set disassembly-flavor intel (gdb) break main (gdb) run (gdb) info registers (gdb) x/20i $pc逻辑说明:set disassembly-flavor intel切语法,break main下断点,run跑起来,info registers看寄存器,x/20i $pc看当前指令附近的反汇编。参数说明:x/20i表示从$pc开始显示 20 条指令。如果你装了 pwndbg,直接context就能看到寄存器、栈、反汇编。
4.2 找到关键跳转并修改
假设静态分析发现0x400abc处有一个jne控制是否跳转到“成功”分支。在 gdb 里:
(gdb) break *0x400abc (gdb) run # 程序断下后,查看标志位 (gdb) info registers eflags # 强制修改零标志位,让跳转发生/不发生 (gdb) set $eflags |= (1 << 6) # 设置 ZF (gdb) set $eflags &= ~(1 << 6) # 清除 ZF (gdb) continue逻辑说明:jne依赖 ZF(零标志位)。set $eflags可以直接改标志位,绕过校验。参数说明:1 << 6是 ZF 的位偏移,不同架构可能不同,x86 是第 6 位。这招在实验里用来“骗过”密码检查非常有效,但只用于自己的实验环境。
4.3 生成补丁文件并验证
如果你想把修改固化下来,可以用objcopy或者直接改二进制:
# 把 jne (0x75) 改成 je (0x74) 或 nop (0x90) # 先用 xxd 找到偏移 xxd -s 0xabc -l 2 bin/lab1 # 输出类似:00000abc: 750e u. # 用 printf 写入修改 printf '\x74' | dd of=bin/lab1 bs=1 seek=$((0xabc)) conv=notrunc逻辑说明:xxd查看指定偏移的字节,dd写入新字节。参数说明:seek是文件偏移,conv=notrunc防止截断文件。改完再跑一遍,确认行为变化。这一步是逆向工程里“补丁”的雏形,热搜里“源码+笔记”那种学习方式,最终都要落到能改、能验证。
5. 避坑与排查:实验包里那些说明书没写的事
5.1 现象:编译报错“undefined reference toxxx”
原因:源码依赖了外部库,但 Makefile 或编译命令没链接。解决:看说明书里的依赖列表,或者用ldd看二进制依赖哪些 so。常见的是-lm(数学库)、-lpthread(线程库)。补上就行。
5.2 现象:Ghidra 反编译出来全是乱码或“undefined”
原因:二进制被 strip 且架构选错了。解决:Import 时手动选对处理器架构(x86:LE:32:default 或 x86:LE:64:default),不要用 Auto。如果还是不行,先用file命令确认架构。
5.3 现象:gdb 断点打不上,提示“Cannot access memory at address”
原因:地址是文件偏移,不是虚拟地址。解决:用info files看节区映射,或者直接在函数名上下断点(如果有符号)。PIE 二进制还要考虑基址随机化,set disable-randomization on可以关掉 ASLR。
5.4 现象:修改源码后重新编译,行为却和原来二进制不一样
原因:编译器版本或优化选项不同。解决:用gcc --version对比说明书里写的版本,尽量一致。如果说明书没写,就用-O0 -g作为基准,不要开-O2。
5.5 现象:实验包里的二进制运行报“Permission denied”或“No such file”
原因:缺少执行权限或动态链接器路径不对。解决:chmod +x加权限;如果是跨平台(比如在 macOS 跑 Linux ELF),需要对应的运行环境或虚拟机。不要硬扛,换环境最快。
6. 从实验到实战:用 Python 脚本批量提取特征与自动化验证
实验做完不是终点。真实场景里,你面对的是几十上百个样本,不可能一个个手动开 Ghidra。我一般会写一个 Python 脚本,用capstone做反汇编,用pefile或pyelftools解析结构,自动提取关键特征。比如下面这个脚本,用来批量检查二进制里是否包含可疑的strcmp调用和硬编码字符串:
import capstone from elftools.elf.elffile import ELFFile def analyze_elf(path): with open(path, 'rb') as f: elf = ELFFile(f) # 找 .text 节区 text = elf.get_section_by_name('.text') if not text: return code = text.data() # 用 capstone 反汇编 x86-64 md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64) for insn in md.disasm(code, text['sh_addr']): # 找 call 指令,且目标可能是 strcmp if insn.mnemonic == 'call': print(f"0x{insn.address:x}: call {insn.op_str}") # 找 mov 立即数,可能是硬编码 if insn.mnemonic == 'mov' and '0x' in insn.op_str: print(f"0x{insn.address:x}: {insn.mnemonic} {insn.op_str}") # 批量处理 import glob for f in glob.glob('samples/*'): print(f"--- {f} ---") analyze_elf(f)逻辑说明:ELFFile解析 ELF,capstone反汇编.text,遍历指令找call和mov立即数。参数说明:CS_MODE_64对应 64 位,32 位改成CS_MODE_32。这个脚本可以扩展成:匹配特定字符串、统计指令频率、提取控制流图。热搜里“源码剖析与架构实战”那种需求,本质上就是要把手动分析变成可复用的脚本。
验证方法:拿实验包里的二进制跑一遍,看输出的call地址是否和 Ghidra 里看到的一致。如果一致,说明脚本可信;不一致,检查基址和节区偏移。我自己的习惯是,每做完一个实验,就把分析过程写成脚本,下次遇到同类样本直接改参数。这样积累下来,比单纯记笔记有用得多。希望帮到你。
本文还有配套的精品资源,点击获取