先学会看汇编,再谈逆向:一份从零开始的逆向工程学习地图"

admin 2026-10-16 08:39:47 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

先学会看汇编,再谈逆向:一份从零开始的逆向工程学习地图

原创

Sink
Sink

船山信安

2026年9月24日 18:40
湖南

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

底层手艺 · BINARY

先学会看汇编,再谈逆向:一份从零开始的逆向工程学习地图

逆向入门 · 写给想碰二进制、又怕看不懂汇编的人

打开 IDA,拖进一个 exe,然后呢?大多数人卡在第二步——屏幕上一排排 mov、call、jmp,像天书。这很正常。逆向最难的地方不是看不懂,是根本不知道该从哪一行开始看。这篇不哄你\"七天入门\",只把那条从零到能干活的小路标清楚。

01逆向不是\"破解\",是把黑盒翻译成白盒

逆向这两个字,被误解得太久了。很多人脑子里第一反应是\"破解软件、搞注册机、把收费的弄成免费的\"。那是逆向里极小、而且越来越不划算的一块。把目标一上来就定成\"能破\",你走偏了。

我更愿意把它定义成一句话:你拿到一个没有源码、或者你本不该看源码的程序,通过它最终落地的那堆二进制,把\"它到底在干什么\"这件事还原出来。

这件事的正当用途多得很。安全研究员拿到一段恶意样本,要弄清楚它连了哪个 C2、动了哪几个文件;做固件的,要在一台路由器的镜像里找厂商偷偷留的后门;审计自己团队依赖的某个开源库,确认它没在后台偷偷上传数据;漏洞复现,要把补丁前后那几行 diff 对应到二进制里到底改了哪片内存。还有 CTF 里的 RE 题——它和破解不一样,题目本来就是给你练手用的。

所以先正个名:逆向是手艺,不是\"搞破坏\"的近义词。把这门手艺练出来,你看待任何程序的方式都会变——别人看到的是界面,你看到的是它把数据放在哪、什么时候越过边界。

一个真实的逆向会话长这样:你打开工具,函数名清一色变成 sub_401230、sub_4012A0,里面六个 case,其中有一个你追进去发现永远走不到——编译器把它当成死分支优化掉了,或者作者当年留了个没接上的判断。第一次遇到这种事会觉得乱,但看多了你会冒出一个念头:原来就这么点东西。

02先补三块地基:C 语言、汇编、操作系统

很多人一上来就装 IDA,然后对着一片反汇编发呆。发呆的根源只有一个:他不知道这段二进制是怎么来的。一个程序从你写的 .c 到能跑起来,中间要走过编译、链接、装载、再变成进程内存里的布局。这四步你心里没图,反汇编里每一行都是孤立的。

举个具体的:你写 int a[4]; 然后越界写了第 8 个元素,编译器不会拦你。但内存里,隔壁那个变量的命运已经被你改写了。逆向时要反过来——你得从那片被改写的字节,倒推回去\"谁动了它\"。这种倒推的直觉,只能在学 C 的时候亲手把内存搞乱几次才养得出来。

再就是文件格式。Windows 上是 PE,Linux 上是 ELF,它们都只是\"把代码、数据、导入表、重定位信息按约定排好\"的集装箱。你不用背结构,但得知道入口点在哪、导入表长什么样、.text 段和 .data 段分别装什么。否则你连\"该从哪开始看\"都答不上来。

模块 学什么 为什么必须
C 语言的内存视角 指针就是地址、结构体怎么排、栈/堆/BSS/数据/代码段各装什么 不懂内存,反汇编里每个变量你都定位不到
汇编(十来条就够) mov / push / pop / call / ret / lea / cmp / jmp / add 这是二进制和你能读懂的东西之间唯一的桥
操作系统基础 虚拟地址、装载过程、动态链接、系统调用 不知道程序怎么被装进内存,你就找不到起点

把这四步拆开看:编译把每个 .c 变成 .o,链接把一堆 .o 和标准库拼成最终那个可执行文件,装载时操作系统读着 PE/ELF 头部的描述,把它一段段映射到进程的虚拟地址空间里。你平时双击运行的那个 exe,在磁盘上和在被加载进内存后,地址常常是不一样的——这正是重定位存在的理由。反汇编工具帮你把\"磁盘上的字节\"和\"内存里的地址\"对上,而你能不能利用它,取决于你知不知道这个映射关系。

有个反直觉的建议:练 C 的阶段别急着上 IDE。用文本编辑器写,用 gcc 在命令行编译,把告警一个个看懂,再用 objdump -d 看它变成了什么。IDE 把\"编译、链接、加载\"这些细节藏得太好了,而恰恰是这些细节,后面每次逆向都要用到。

练到能看反汇编之后,下一步是学会\"读头\"。用 readelf -h 看 ELF 的头部,你能直接看到入口点地址、节区数量、数据是按小端还是大端排的;PE 也有对应的 IMAGE\_NT\_HEADERS。这些信息在工具里点一下就有,但我建议你手动敲一遍——因为真正难的二进制往往头被改过、节被合并过,那时你只能靠对这些字段的肌肉记忆去判断\"哪里不对劲\"。

03工具链怎么选

工具不用一次配齐。先把\"静态看\"和\"动态跑\"各选一个顺手的,够用半年。下面这张表把常见的列全了,你按自己的平台和阶段挑。

工具 平台 免费? 适合阶段 入门建议
IDA Free 跨平台 免费(非商业) 入门看界面 仅 x86/x64,反编译走云端,先认 IDA 长相
Ghidra 跨平台 免费开源 主力静态 NSA 2019 开源,自带反编译器,架构覆盖广
Binary Ninja 跨平台 付费($149+) 进阶/自动化 API 友好,个人版便宜,CTF 圈常用
radare2 / Rizin 跨平台 免费开源 命令行/脚本 命令多,配 Cutter 图形界面上手
x64dbg Windows 免费开源 动态调试 改跳转、看内存,Windows 下首选
GDB + pwndbg Linux 免费 动态/漏洞 配合 checksec 看保护,看寄存器顺手
WinDbg Windows 免费 内核/驱动 微软官方,文档全,但界面冷硬
strings / binwalk 跨平台 免费 辅助 先看字符串、提取固件,几分钟定方向
Process Monitor Windows 免费 行为监控 看文件/注册表/网络,先静态后动态
Frida 跨平台 免费(部分) 动态插桩 不改文件,直接改运行时
Wireshark 跨平台 免费 网络 抓协议流量,配 Frida 看明文

几个容易踩的点说一下。IDA Free 不是 IDA 的阉割试用版那么简单——它把反编译锁死在 x86/x64,而且要走云端,还不能商用(来自 Hex-Rays 官方的 IDA Free 说明页)。你若想认 IDA 的界面、建立直觉,它够用;真要干活,Ghidra 反而更宽。Ghidra 是 NSA 2019 年公开的,到 11.x 这一代反编译器已经能打了,架构支持也广,唯一被念叨的是界面略繁琐。Binary Ninja 个人版一百多美元起,API 设计得很讨脚本党喜欢,是很多人 CTF 的主力。radare2 免费、脚本强,但命令多到劝退,建议配 Cutter 这个图形壳先摸门道。

顺带提一句反编译器的水有多深。同一段二进制,Ghidra 和 IDA 的 Hex-Rays 反出来的伪代码常有出入,一个认得出结构体,另一个可能把它当成一团未命名字节。所以别迷信任何单一工具的输出——它给的是\"猜测的 C\",不是真相。养成习惯:反编译器说这里是个 int,你要去内存窗口里亲自核对长度和对齐。工具越智能,越要保留这一份怀疑。

04第一个月该干什么

第一个月别追求\"看懂大程序\"。你的目标应该是:亲手把\"写代码 → 看反汇编 → 改行为 → 还原逻辑\"这条链走通一遍。下面这个阶梯,每一步都能在本地复现。

第一步,自己写、自己拆。写个几十行的小 C 程序,编译,再用 objdump 对照看。你会对上\"我那行 if 变成了哪条 jmp\"。这一步没有捷径,它是后面所有感觉的来源。

比如这段故意写得极简的\"注册码\"程序:

// serial.c ── 极简的\"注册码\"程序

include

int main() {

int x;

printf(\"input: \");

scanf(\"%d\", &x);

if (x \* x == 1522756)      // 1234 的平方

printf(\"ok\
\");

else

printf(\"no\
\");

return 0;

}

编译:   gcc -O0 -o serial serial.c

反汇编: objdump -d -M intel serial | grep -A30 '

:'

第二步,找个 crackme 练手。crackmes.one、crackmy.app 上从\"入门\"标签开始,几百道题随便挑。先挑那种\"输入对了就打印 correct\"的,逻辑一目了然。

第三步,改一个跳转。用 x64dbg 或 IDA 把那处 jne 改成 je,程序就从\"拒绝\"变\"通过\"。这是你第一次亲手改掉一个程序的命运,那种掌控感会支撑你走下去。

第四步,脱最简单的壳。UPX 是最友好的入门壳,upx -d 一行就能脱。但你要理解为什么能脱——脱壳本质是让程序自己解压完,再把内存里的干净镜像 dump 出来。

第五步,还原一个算法,写出注册机。从反汇编里把那串判断逻辑抄回 C 或 Python,跑出能让程序说\"ok\"的输入。做到这一步,你才真正算\"会了一点\"。

每一步做完,强迫自己写两行\"我刚才干了什么、卡在哪\"。很多人第一个月的热情来得快去得也快,根子在从不动笔——三个月后你一定会忘记那个跳转地址当初是怎么算出来的。写下来的过程,是把\"我好像懂了\"变成\"我真的懂了\"的唯一办法。这一步偷懒,后面每道新题都像从头开始。

这五步的价值不在结果,在于让你建立一个信念:反汇编不是天书,是另一套你能学会的语言。很多人卡在第二步,就是因为跳过了第一步的\"自己写自己拆\"。

05读汇编的四个抓手

看反汇编最怕没有章法,一行一行往下捋只会晕。我教自己用的是四个抓手:函数边界、调用约定、栈帧、数据流。下面这段是编译器对一个小函数的真实产出(x86-64,Intel 语法),我们逐行过一遍。

check:

push rbp                 ; 1.函数边界:把调用者的栈帧基址存起来

mov  rbp, rsp            ;    建立当前函数的栈帧

mov  eax, DWORD [rbp-4]  ; 2.调用约定:参数在栈上被取出来

cmp  eax, 0x1337         ; 3.数据流:和那个\"暗号\"比一下

jne  .fail               ;    不相等就跳去 .fail

mov  eax, 1              ;    相等,返回值 1 放进 eax

jmp  .done

.fail:

mov  eax, 0              ;    不相等,返回值 0

.done:

pop  rbp                 ; 4.栈帧:恢复调用者的 rbp

ret                      ;    返回,eax 里就是答案

函数边界看两头:push rbp 配 pop rbp,再加一句 ret,这就是一个函数从出生到结束的框。你只要认得这个框,反汇编里成千上万行就被切成了\"一块一块\"的函数。

调用约定回答\"参数从哪来\"。x86-64 的 System V 约定里,前几个参数走寄存器(rdi、rsi、rdx…),函数常常把它们先搬进栈上的\"家\"([rbp-4] 这种)。所以你看到 [rbp-4],基本就是在读第一个参数。

栈帧是函数自己的临时工作台。rbp 是台面基准,rsp 是台面边缘。局部变量、返回地址都摆在台面上。理解了\"台面\"长什么样,你才知道溢出时到底淹了谁。

数据流是最关键的抓手:值在哪些寄存器之间搬、在哪个比较处分叉、最终落在哪返回。上面这十来行,数据流就是\"eax 取出参数 → 和 0x1337 比 → 分支决定 eax 是 1 还是 0 → 带着它返回\"。顺着值走,而不是顺着指令走,反汇编一下子就顺了。

很多人学汇编卡很久,是因为一上来就背指令集。别背。把这四个抓手挂在脑子里,遇到不懂的指令现查,查着查着你就会了。指令就那几十个,反复出现。

06常见劝退点与应对

走到这一步,劝退点开始密集。提前认得它们,摔的时候不至于以为自己不行。

现象 怎么破
编译器优化让代码变形 初学一律 -O0,再拿 -O2 对照着看,体会循环展开、内联
符号被剥离 函数变 sub\_xxx,靠字符串和交叉引用倒着找入口
C++ 虚表和 STL 膨胀 先吃透 C 程序,C++ 的 RE 是另一门课(OST2 有专门课)
混淆与加壳 先脱 UPX,再碰简单混淆;运行时用 Frida 绕
大二进制找不到入口 从字符串、导入表、TLS 回调这些\"边角\"切入

至于\"大二进制找不到入口\",本质往往不是技术难,是心态先崩——你以为必须从 main 开始,但很多样本把真正的逻辑藏在 TLS 回调、异常处理、甚至资源段里,main 只是一个幌子。先用 strings 扫一遍能打印出来的字,顺着\"错误提示\"\"配置名\"这种人类字符串往回追,比盲目从入口硬啃省力十倍。

单独说一下 C++。很多人 C 程序读得挺顺,一碰 C++ 就崩,崩在虚函数表(vtable)和 STL 那一坨模板膨胀上——一个 std::string 的反汇编能铺满好几屏。这不是你的问题,是 C++ 本身在二进制层面就是贵。OpenSecurityTraining2(OST2)有门\"Reversing C++ Binaries\"的课专门对付它,等 C 底子扎实了再去碰,别提前被劝退。

把这些劝退点摊开看,你会发现它们其实是一件事的多个面:编译器、链接器、加壳工具、C++ 标准库,全都在你和被分析的程序之间砌墙。逆向要做的事,就是一块一块把这些墙拆掉,直到你能直接看见程序原本的意图。所以别指望某天\"突然全懂了\"——是每拆掉一面墙,视野就清一点,如此而已。每清掉一处障碍,你就离\"能独立干活\"近了一步,这条路上没有白拆的墙。

07三个\"别\"

别一上来就开 IDA 啃大项目。几十 MB 的闭源软件,函数成千上万,新人进去除了绝望什么都得不到。从几十行的 crackme、从你昨天自己写的那个 C 程序开始。

别只刷题不碰真实程序。CTF 的 RE 题是出题人精心修剪过的,干净、有答案、卡点明确。真实样本脏得多——代码混着数据、逻辑被压过、还夹着反分析。去抓个真实样本(恶意样本务必在隔离机里),你会发现差距比想象的大。

别迷信鼠标流。点来点去很爽,但重复劳动会拖死你。早一点学 IDAPython、Ghidra 脚本、r2 的一行命令,把\"标函数名、找交叉引用、批量改字节\"这类事交给脚本。效率差出来的不是一倍两倍。

说到底,逆向教给你的不是某一个工具或技巧,而是一种\"不信任表面、去查证底层\"的思维方式。同一个功能,作者想让你看到的是按钮和提示,你想看到的是它在内存里如何布局、在哪些条件下会越过边界。这种视角一旦建立,你写代码、看漏洞、甚至用任何一个软件时,都会下意识多问一句\"它背后到底在干什么\"。这比任何一道题的答案都值钱。


ONE LINE
       逆向没有捷径,只有把第一行汇编看顺眼。


参考来源

· Hex-Rays 官方 IDA Free 说明页:仅支持 x86/x64、云端反编译、非商业用途、无 IDAPython/SDK(2024 在役版本)

· NSA Ghidra 发布记录:2019 年公开,11.x 系列(11.0 于 2023 年 12 月、11.3 于 2024 年 5 月)持续迭代反编译器与多架构支持

· Vector 35 Binary Ninja 官网与公开定价页:个人版 $149 起,Free 版有架构限制(2024)

· radare2 / Rizin 与 Cutter 项目主页(rizin.re、cutter.re):免费开源,r2ghidra 提供反编译

· OpenSecurityTraining2(OST2,ost2.fyi):Arch1001 x86-64 汇编、Dbg1102 入门 Ghidra、Dbg1012 入门 GDB、Vulns1001 C 语言实现漏洞、Reversing C++ Binaries 等免费课程(2021–2024)

· Dennis Yurichev《Reverse Engineering for Beginners》(beginners.re):免费开源教材,覆盖 x86/x64、ARM、PE/ELF、C++ STL

· crackmes.one / crackmy.app:公开 crackme 练习社区;Mandiant Flare-On 逆向挑战赛(年度);Mandiant FLARE VM 逆向环境

· CTF Wiki(ctf-wiki.org):逆向工程与二进制分析中文公开知识库


AI时代,以攻促防:金盾检测首战“工赋砺网”获评优秀红方单位!" 网络安全文章

AI时代,以攻促防:金盾检测首战“工赋砺网”获评优秀红方单位!"

金盾检测首次参加工赋砺网专项行动即获评优秀红方单位,该行动聚焦工业互联网与数据安全场景,通过红蓝对抗实战演练检验企业安全防护水平。公司作为红方队伍运用前沿安全测试技术挖掘潜在隐患,实现以攻促防目标。未来将持续打磨攻防能力,深度参与工业安全实战项目,护航产业数字化高质量发展。
捷普中秋节放假保障通知请查收!" 网络安全文章

捷普中秋节放假保障通知请查收!"

捷普公司发布中秋节放假保障通知,同时介绍其作为网络信息安全产品和服务提供商,提供基础设施安全、数据安全、信创安全、工业互联网安全、云安全、物联网安全、国密安全等七大系列产品,并在风险评估、渗透测试等安全服务上占据优势,协助用户提升IT基础设施安全性与合规性。
评论:0   参与:  0