ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CTF-PWN入门全攻略:从栈溢出到ROP的漏洞利用实战

2026/9/15 4:32:56 拓冰建站 浏览量
CTF-PWN入门全攻略:从栈溢出到ROP的漏洞利用实战 这两年CTF越来越火但很多新手一进来就卡在同一个地方看到PWN两个字母就直接劝退。问就是“得先学汇编”“要看操作系统”“要有逆向基础”搞得好像不啃完几本大部头根本碰不得。等你真去搜教程知乎一堆劝退文B站成体系的全集又少好不容易找到一个收藏吃灰打开第1集就睡着。所以当我看到这个“【全35集】B站最细CTF-PWN教程全集从入门到精通”的标题时第一反应是终于有人愿意把PWN往“小白友好”的方向做了。这篇博文不聊虚的就顺着这套教程对应的学习方向把CTF-PWN到底是什么、怎么入门、工具怎么装、题目怎么做、坑在哪里一次讲透。不管你是刚听完课还是纯零基础只要你打算认真入坑PWN这篇文章值得先存下来边学边对照。1. CTF-PWN到底是什么为什么值得花大量时间去啃1.1 从“夺旗赛”说起PWN在CTF里的位置CTFCapture The Flag夺旗赛说白了就是一场安全技术竞赛选手通过分析题目、寻找漏洞、突破程序最后拿到一串叫flag的指定格式字符串提交得分。比赛题目通常分成Web、PWN、Reverse、Crypto、Misc几大类每类考察的能力方向完全不同。而PWN这个方向核心就是漏洞利用也就是通过分析目标程序发现它哪里写得不安全然后构造特定输入让程序执行你希望它执行的逻辑最终拿到flag。为什么说PWN是CTF的硬骨头因为它是所有方向里最接近计算机底层的一类。它不像Web那样改改参数、绕绕认证就能出题也不像Misc那样主要靠脑洞和工具扫描。PWN要求你理解内存布局、函数调用过程、汇编指令、程序装载甚至操作系统对进程的管理机制。入门门槛确实高但反过来讲一旦你跨过这个门槛你对程序如何运行这件事的理解会上升一个台阶这种“底层感”是其他方向很难给的。1.2 学PWN对普通人有什么用很多人问我不做安全相关工作学PWN是不是纯浪费时间我自己的看法是看你对“有用”的定义是什么。如果你只是想拿奖、找工作那PWN确实是安全领域里含金量很高的方向很多做二进制安全、漏洞挖掘、攻防对抗的岗位都认这个方向的经验如果你纯粹是好奇计算机怎么工作那PWN就是最好的“解剖学教材”它强迫你用肉眼去看一个C语言程序在内存里到底经历了什么。对比一下就能感受到差距普通程序员写代码只知道函数调用了就执行返回了就继续往下走。但你学了PWN之后会发现函数调用时返回地址被压在栈上输入一不小心就把这个地址覆盖了程序就跑到你希望它去的地方。这种“原来还能这样”的顿悟是学PWN最上头的时刻。就算你以后不做安全这种对内存和程序的直觉在排查疑难bug、理解底层框架时也会帮到你。1.3 学PWN前需要的基础其实没传说中那么夸张说句实话PWN入门前需要的基础没有网上传的那么吓人。按我的经验只需要三样一点C语言语法知道scanf、gets、strcpy这些函数是干嘛的一点Linux命令行操作会cd、ls、cat、chmod就不算抓瞎剩下的就是一个“接受新概念”的心态因为栈、寄存器、libc这些内容刚开始肯定是陌生的但只要一个个拆开理解并没有哪个是过不去的坎。你不需要先系统学完《汇编语言》《操作系统》再去碰PWN。正确顺序是反过来先做出一道ret2text知道“哦原来返回地址可以被覆盖”你才有动力去把汇编补扎实把内存布局搞明白。好奇心驱动的学习比嚼书本快得多这也是这类面向小白的视频教程最大的价值先拉你下水再教你游泳。2. 动手之前先把环境、工具、资料一次备齐2.1 为什么必须用Linux以及环境怎么选PWN题目基本都在Linux环境下文件是ELF格式所以要打PWN果断切换到Linux环境。那么问题来了用什么发行版装虚拟机还是装双系统我的建议是第一优先级是虚拟机不要碰双系统更不要用Windows直接硬打。推荐套路是这样的VMware或者VirtualBox装一个Ubuntu 20.04或22.04的虚拟机给4GB以上内存、40GB磁盘就够用了。虚拟机的最大好处是随便折腾装错了重来也不伤主力机。如果你之后走上比赛这条路会发现很多在线靶场和比赛平台都要求你在Linux下操作提前把Linux用顺很值。另一个可选方案是Docker用现成的pwn环境镜像拉下来就用省去配置折腾但对新手来说反而少了一次“手动装环境从而理解工具链”的机会。这里补充一个我踩过的坑刚开始用Ubuntu时不要装太重型的桌面环境也别一上来就配花里胡哨的终端美化把这些精力省下来。PWN真正高频用到的是终端、文本编辑器、调试器和IDA图形界面需求很低能跑就行。越干净的环境越不容易出幺蛾子。2.2 工具清单拿到题目后我都在用什么工具是PWN的上手门槛之一但也就那几样别被吓到。我给出一份最小可用清单按使用频率排序IDA Pro或者Ghidra反编译利器。IDA Pro 7.x搭配Hex-Rays反编译器能直接把汇编还原成伪C代码效率极高。Ghidra免费功能也强但界面丑一点新手更推荐从Ghidra开始省钱熟练后能找到适合自己的版本。pwntoolsPython的PWN开发库写exploit漏洞利用脚本的核心工具。发数据、算地址、连远程都能做没有它寸步难行。gdb加插件调试程序的利器。原生gdb不好用配合pwndbg或者peda插件能看到栈布局、寄存器状态、堆结构调试效率直接翻倍。checksec查看程序保护机制的小脚本用来判断题目开了哪些防护比如NX、Canary、PIE、RELRO。ROPgadget搜索ROP链需要的汇编片段gadget构造ROP链时必备。one_gadget在特定libc版本中查找“一条指令拿shell”的地址提速神器。patchelf本地调试时修改ELF文件的动态链接器路径和库路径让本地环境和题目环境尽量一致。一些基础小工具file看文件类型、strings抽字符串、hexdump看十六进制配合grep用很多时候能快速发现线索。工具本身不复杂大部分人卡在“装完不知道干什么”。所以别急着把所有工具都装好先装pwntools、gdb插件、IDA这几样跟着教程做一道题在解题过程中自然就明白每个工具是干嘛的。工具是越用越会不是越会越用。2.3 题库和资料去哪找BUUCTF、攻防世界和NSSCTF怎么选环境备好了下一步就是找题目练手。国内用得比较多的平台有这么几个BUUCTF是老牌CTF刷题平台题目量大很多经典PWN题都能找到而且有在线环境可以直接连接对新手最友好攻防世界分级别适合按难度梯度推进NSSCTF相对新一些题目和比赛环境都维护得不错。如果英文阅读没压力国外的pwn.college是专门做二进制安全教育的知名平台课程设计非常有体系。我的建议是新手不要贪多就选一个平台先刷。BUUCTF是目前我见过对新手最友善的选择因为大多数题目已经有人写过writeup解题报告卡住了能搜到完整过程学习效率比硬啃E题高得多。看到不会的题先搜writeup跟着复现一遍然后关掉题解自己独立再写一遍这一步非常重要。不要有“搜题解作弊”的洁癖CTF入门阶段大量模仿是正常路径关键是复现后要能独立做出来。3. 从“看不懂汇编”到“能自己写exp”一套完整学习路线拆解3.1 整体节奏35集入门课对应的能力成长路径套教程敢叫“从入门到精通”那它的节奏大概会覆盖一条比较完整的路径。从我的经验看一套好的PWN入门课大致会把学习过程分成五个递进阶段扫盲期、工具期、原理期、套路期、实战期。扫盲期是让你知道CTF和PWN是什么有哪些题型比赛是怎么回事。工具期是带你把虚拟机、IDA、pwntools、gdb跑顺。原理期开始讲汇编、ELF文件结构和函数调用栈这是从“看热闹”到“看门道”的关键转折。套路期进入大量经典漏洞利用手法的学习比如栈溢出、格式化字符串、堆利用、整数溢出等每个类型都有固定套路。实战期就是刷题、打比赛、写writeup把学到的套路组合起来解决没见过的题目。这个结构非常合理。它最大的优点是不要求你一下就吃透所有底层知识而是用“做题需求”来牵引“知识学习”。比如你要理解ret2libc就必须知道PLT和GOT是什么、libc版本怎么确定于是这些知识被自然带出来。比你先啃一个月操作系统再做题要高效得多。3.2 扫盲与工具期先把“怎么操作”变成肌肉记忆第一个阶段的目标很简单看到题目能自己跑起来这就赢了。具体到操作上你要能完成这些事下载题目后用file看一下文件类型用checksec查看保护机制用IDA打开程序找到main函数在终端里执行python3你的脚本调用pwntools把本地程序跑起来。这个阶段最忌讳的就是“贪多”一会儿看格式化字符串一会儿研究堆利用结果哪个都没搞明白。正确做法是跟着教程一步步操作哪怕不懂原理也要把每个命令敲一遍把每个工具的画面看熟。就拿pwntools来说你不一定要理解它内部怎么实现的但你得会用这几个最核心的APIprocess()启动本地程序、remote()连接远程、sendline()发送一行数据、recv()接收返回、interactive()进入交互模式。会用这些你就能跑通最简单的题目了。我自己带新人的时候特别喜欢强调一个办法把每一道做过的题的exp脚本和writeup保存好按漏洞类型分类。比如ret2text一个文件夹、ret2libc一个文件夹、格式化字符串一个文件夹。这样当你需要回顾时直接翻自己的笔记就行。所谓“肌肉记忆”就是重复到一定次数后你拿到题目自然知道该按什么顺序操作。3.3 原理期函数调用栈是绕不开的“分水岭”如果你学了几个礼拜还在“用工具但不懂原理”那是正常的但你不能一直停在这。真正让PWN入门者拉开差距的就是对函数调用栈的理解。我见过很多学生工具用得溜IDA反编译也看得懂伪代码但一到算偏移、构造ROP链就卡壳根子就是对栈上数据怎么排布的缺乏直觉。函数调用栈大概是怎么回事呢当一个函数被调用时系统会把返回地址压到栈上然后跳转进函数函数再把自己的局部变量也安排到栈上。如果你用的函数不安全比如gets它从键盘读数据往一个固定大小的缓冲区里写又不检查长度那数据就会一层层往上覆盖最终把返回地址盖掉。CPU执行完函数要返回时按照栈上被改过的地址跳转程序就被你“劫持”到任意位置了。理解了这个你就理解了PWN的半壁江山。推荐在这个阶段配合gdb的调试功能给程序下断点单步跟踪用info registers看寄存器用stack查看栈内存。看十遍书不如自己亲眼看到“哦这个位置确实是返回地址”。这种直观感受是纯理论学不来的。3.4 套路期与实战期经典题型逐个击破才是提升最快的路径到了套路期你会发现PWN其实很像做数学题。栈溢出这类基础漏洞有固定模板找漏洞点算偏移定位可用函数或gadget写exp拿flag。格式化字符串是另一个模板利用printf的参数个数与栈上数据的关系实现任意读写。堆题则更复杂但入门阶段无非是UAF释放后使用、double free重复释放、堆溢出这些经典套路。从刷题感受来看BUUCTF上有好几个梯度的题目设计得特别好。一开始是那种一眼能看到system函数的送分题帮你建立信心然后是没有system要用libc的进阶题再往后是开启了PIE、Canary保护的综合题最后是堆题和难点组合。建议你每一类题型都至少独立做三到五道形成“看到同类题能立刻反应出套路”的条件反射。实战期就是参加比赛。新手别被门坎吓着很多比赛有新手赛道或者允许你观察前排队伍的动态你对齐自己会做的题就行。赛后看官方writeup和前排名选手的writeup是学习速度最快的环节。一个实用的习惯是每次比赛结束都给自己总结一份“赛中卡点记录”把哪些题卡了多久、卡在哪个知识点上写下来这就是你下一阶段的复习清单。4. 35集背后的核心知识点栈溢出、ROP与格式化字符串4.1 栈溢出一切PWN的基础先把这个吃透栈溢出是PWN里最经典、也最基础的漏洞类型。它的本质就是前面讲的程序向栈上的缓冲区写入超过容量的数据覆盖了栈上的其他内容包括返回地址。利用栈溢出最基础的题型叫ret2text意思是“返回到代码段中已有的某些关键函数”。很多入门题直接在程序里放了一个后门函数比如一个名为win或get_shell的函数里面调用system(/bin/sh)你只需要把返回地址覆盖成这个函数的地址程序就会帮你开一个交互shellflag自然就到手了。但是PWN没有这么简单。为了提升难度出题人会给程序加上各种保护机制。用checksec可以看到这些保护NX开启时栈不可执行你没法在栈上放shellcode直接跳过去执行Canary存在时栈里有个随机值覆盖返回地址之前如果动到它程序会直接崩溃PIE开启时程序每次运行的地址都会变你没法用一个固定函数地址RELRO影响的是GOT表能否被改写。所以后面所有高级利用手法本质上都是在想办法绕过这些保护。对于刚入门的读者我给一个非常实操的建议第一周只做“无保护或低保护”的栈溢出题把偏移计算练到闭眼能算。偏移是什么就是缓冲区起始地址到返回地址的距离。32位程序一般就是缓冲区大小加464位程序加8。你用一个pwntools里的cyclic生成一串有规律的字符串代替输入程序崩溃后gdb报出的地址在cyclic字符串中的位置就是偏移。这比死记硬背公式靠谱得多。4.2 从ret2text到ret2libc真正的入门分界线当你知道栈溢出能用后下一道坎就是没有后门函数怎么办。这类题里程序没有system代码里也没有/bin/sh但程序在运行时会加载系统的C库libc而libc里面就包含了system函数的实现和/bin/sh字符串。问题变成两步第一步想办法泄露程序加载的libc基址第二步用基址加偏移计算出system和/bin/sh的真实地址然后构造ROP调用它。这就是ret2libc这个经典套路的完整思路。实现时有两个关键点一是泄露地址。常见办法是利用程序中已经存在的puts或printf函数把某个GOT表里的真实地址打印出来然后用LibcSearcher这类工具或者直接搜索libc数据库匹配出远程环境用的libc版本。二是利用PLT和GOT。函数第一次调用时走PLT去查GOTGOT里存的是真实地址。你只要能把GOT项的内容“吐”出来就能反推出libc基址。理解了这条链接你才算真正从“背套路”走向“理解原理”。实际写exp时还有很多细节要注意最典型的坑是64位程序的栈对齐问题。因为system函数内部某些指令要求栈指针按16字节对齐如果你直接返回到一个普通函数地址可能因为对齐不对直接段错误崩溃。解决办法是在返回链里额外多放一个ret指令的gadget来“补对齐”。这类细节只有自己写exp多次踩坑才能熟练看书很难记住。4.3 格式化字符串printf用的不对也能出大问题第二个必学的基础漏洞是格式化字符串漏洞。它出现的条件很微妙程序直接用了printf(buf)而不是printf(%s, buf)也就是把用户可控的字符串直接当作格式化字符串使用。这时候输入里的%s、%p、%n这些格式化符就会被printf解析造成信息泄露甚至任意内存写入。其中最常用的两个技巧用%p或%s来读取栈上的地址这叫做任意读。比如不断在输入里填充%p.%p.%p……程序就会把栈上的内容按指针格式打印出来你就能观察栈里有哪些libc地址、栈地址、程序基址等。而%n是写入方向的利用它能把已经输出的字符数量写入指定地址结合栈上的地址布局可以实现修改GOT表项、改写返回地址等操作也就是任意写。这个漏洞往往出现在程序开启了PIE保护时你找不到函数地址的场景里。思路通常是先利用%s把程序基址liak出来再计算出system函数的真实地址然后用%n把返回地址或者某个GOT项改掉实现控制流劫持。格式化字符串的难点在于理解“参数位置”与“目标地址”之间的对应关系有时候要试很多次才能把写入位置对准。这块没有捷径只能多做题建议刷完栈溢出后集中做一个星期的格式化字符串专项。4.4 保护机制与壳题目为什么“看起来不一样”有不少新手会卡在一个很基础但很本质的问题上为什么有些题我一拿到就能看到函数有些题在IDA里显示的函数全是乱的这里面的关键点有两个一是PIE二是“去除符号表”或者说“脱壳”。PIE开启后程序每次运行地址都随机化IDA静态分析时看到的地址不是真实运行地址只是相对偏移。所以你在看代码时看到函数地址是0x1234这种小地址而在gdb里运行时却是0x55...这样的完整地址。写exp时需要用泄露出来的地址减去对应偏移得到程序基址再算出目标函数真实地址。去除符号表的意思是程序在编译时加了-strip把函数名、变量名这些调试信息都删掉了。传统解法是用gdb动态调试确定关键函数位置或者用一些自动识别函数边界的插件比如IDA的FLIRT签名有时能恢复一部分库函数。新手碰到这种题不用慌套路是固定的先判断保护再动态调试找漏洞入口拿到关键函数或gadget偏移后照常构造payload。PWN的乐趣恰恰在这里同一个漏洞在不同保护条件下有不同解法解题过程像组合积木一样。5. 实操复盘从一道入门题到拿到flag的完整过程5.1 先选一道“看得懂”的题ret2text经典示例用文字讲再多原理不如完整走一遍一道题。我拿一个最经典的ret2text入门题当例子这类题在BUUCTF等平台上非常多比如名字叫“level0”或者“ciscn_2019_n_1”这种难度的反向题目大家网上一搜就能找到。这里我把题目逻辑抽象成标准形态方便你对照学习。假设题目文件叫pwn1它的核心逻辑是一个函数里面定义了一个长度为64字节的缓冲区然后调用gets(buf)从标准输入读数据。同时程序里有一个“不怀好意”的函数叫win里面执行了system(/bin/sh)。程序开启了NX但没开启Canary和PIE。目标很明确用gets覆盖缓冲区和返回地址让vuln函数返回时跳到win函数获得交互shell然后执行cat flag。这类题目之所以适合入门是因为它只有栈溢出和返回地址劫持两个点不涉及libc也不涉及地址随机化你可以在一个相对干净的环境里完整体验“分析-写exp-拿flag”的流程。5.2 五步走file、checksec、IDA、算偏移、写exp第一步拿到题目先在终端执行file pwn1。输出会告诉你这是一个64位的ELF可执行文件是否去除了符号等元信息。第二步执行checksec pwn1。你会看到类似NX enabled、PIE disabled、Canary disabled的输出说明这个程序除了NX没什么保护。第三步用IDA打开程序。快捷键ShiftF12可以看字符串窗口你会看到“/bin/sh”或者“cat flag”之类的关键字符串还能顺藤摸瓜找到引用了它的win函数。点进win函数记录它的地址比如0x4006b2。再点进漏洞函数能看到gets(buf)这样的伪代码推断出buf是64字节。第四步算偏移。64位程序里函数栈布局大概是局部变量区buf的64字节加保存的rbp8字节然后才是返回地址。所以偏移就是64872也就是0x48。如果你不想纯手工算可以用pwntools的cyclic生成100个有规律的字符组成测试负载输入后程序崩溃gdb报错信息里会出现一个特征字符串用cyclic_find查它在pattern中的下标同样能得到偏移。第五步写exp。这个脚本非常简洁核心逻辑就是把“72字节填充win函数地址”的payload发给程序from pwn import * # 本地调试 p process(./pwn1) # 远程靶机时改成p remote(node.example.com, 10001) win_addr 0x4006b2 payload ba * 0x48 p64(win_addr) p.sendline(payload) p.interactive()运行这个脚本后你会直接掉进shell可以执行命令。如果目标是CTF题交互shell里通常直接能看到flag文件输入cat flag就能拿到flag提交得分。整个过程不超过两分钟但你已经亲手完成了一次完整的漏洞利用链路读文件、看保护、逆向分析、算偏移、写exp、拿flag。这就是PWN最初的成就感。5.3 如何从“能跑通本地”升级到“能打通远程”你在本地能拿到flag只是第一步真正的CTF比赛往往要求你连接远程靶机打。远程连接用pwntools的remote函数传入地址和端口。但这里会出现一个很经典的坑本地通了远程不通。原因是远程环境的libc版本、程序加载方式、甚至栈对齐情况可能跟本地有细微差异。解决办法是这样的优先保证题目给的远程环境信息是准确的。如果远程环境提示了运行系统的版本尽量用相同版本的Ubuntu或相同libc去调试。在初始化脚本里可以加上context.log_level debug把收发数据都打印出来。如果远程打不通但本地能通先用nc直接手动连接远程看看程序输出是不是和本地一样。很多时候只需要微调payload里的额外填充字节数或者换一个可用的gadget做对齐。另外要注意交互时的超时问题。连接远程后可以让脚本等待特定字符串出现再发下一段数据比如p.recvuntil(bplease input:)。盲发数据经常导致题目程序还没准备好你的输入就丢了特别是在网络延迟较大或题目有交互多轮的情况下。养成“先收后发”的习惯远程打题会顺利很多。6. 新手学PWN一定会遇到的坑以及我个人的排查建议6.1 偏移算错和地址写错最常见的两个“低级错误”我在带新人的过程中发现很多人的exp卡住根本问题不是不会思路而是低级错误反复犯。第一个高发问题是偏移算错。常见原因包括没看清楚是32位还是64位程序64位程序返回地址在高8个字节的位置你按32位的去填自然错或者缓冲区定义和实际栈布局不同比如定义了char buf[10]但编译器为了对齐实际给分配了16字节甚至更多直接拿代码里的10去算就不对。解决办法是不要猜用cyclic实测一次就一清二楚。第二个高发问题是地址写错。比如你在IDA里看到的后门函数地址是0x4006b2但程序开启了PIE这个地址是相对偏移不是实际加载地址。解决方法是运行程序后用gdb的info proc mappings确认程序基址然后拿基址加偏移得到真实地址。另外一个细节是在x86架构下有地址的最后几个字节如果是字符串里的换行符或空格比如0x0a、0x0d、0x00会被输入函数截断payload就断了。这时要考虑找地址相近的其他指令或者调整利用思路比如改成先覆盖低位或者改用scanf这种不一定受换行影响的方式。6.2 libc版本不匹配远程打不通的头号原因初学ret2libc时最让人崩溃的就是本地明明能拿shell一发远程就段错误或者直接没有反应。这种现象九成是libc版本不匹配导致的。你本地Ubuntu的libc跟远程题目用的libc版本不一样计算出来的system、bin/sh的偏移自然不一样地址全错程序自然崩溃。排查思路是这样的先确保你能从题目环境里泄露地址比如打印一个puts的真实地址。然后用这个地址去匹配libc版本。国内用得比较多的是LibcSearcher这个Python库输入泄露出的函数名和地址它能帮你模糊匹配出候选libc列表。更精准的用法是收集多个函数的地址一起匹配比如puts和printf的地址都泄露出来交叉验证准确率会高很多。匹配出版本后用patchelf把本地程序的解释器和libc改成对应版本在本地复现远程环境再调试这是标准做法。一个非常实用的排查习惯写exp时先用recvuntil接收程序返回的所有输出再发送下一段payload。很多人exp不稳定就是因为内置了sleep乱猜时序。用recvuntil等待明确的提示字符串或者标志性输出等于你在“手动握手”能极大提高成功率。如果远程没输出可等再用sleep兜底。6.3 只调试不总结学了十道题等于学了零道最后想说一个心态层面的坑。PWN是一门“技术密度”非常高的学科只做不总结进步会很慢。很多初学者刷题时有一个习惯做不出来看writeup复制exp跑通了开心一下然后刷下一题。这样过一两个星期你会发现自己遇到新题时还是不会原因就是没有把每一道题转化为自己的知识。我的建议是每道题必须写writeup但不用写给别人看给自己看就行。内容包含四块这题的漏洞点是什么为什么这里能利用exp每一行在干什么如果去掉某一行会怎样。尤其要记录自己卡住的地方是没找到漏洞是算错了偏移还是泄露地址拼接不对把卡点写下来它就是你最薄弱的地方下次复习时重点看这里。另一个建议是“变式训练”。同一道入门题你可以自己改条件练习。比如原题没开PIE你尝试在编译时加上PIE保护思考怎么利用格式化字符串泄露地址原题有system你再想想如果没有system怎么用onegadget。这种思维体操效果非常好它能帮你从“背套路”转向“理解套路”而这正是从入门到进阶的那条跳板。从我个人的经验来看PWN入门最需要的不是智商而是耐心和复盘习惯。第一次看不懂汇编没关系第一次exp跑不通也没关系困在某个知识点一个礼拜都没问题这些都是过程。关键是每走一步都留下记录把错误变成下一次判断的依据。等你有幸回头翻自己第一周的writeup时你会惊讶自己已经走了多远。如果这篇学习路径能帮你少踩几个坑那我写它的目的就达到了。