PE文件手动新增节实战:从结构解析到参数计算与避坑指南
1. 手动新增节的核心思路与整体设计1.1 为什么选择“手动新增节”作为实战切入点搞二进制方向的朋友大概都有这种体会看了一堆PE结构解析的文章什么DOS头、NT头、节表、数据目录每个字段都能背下来了但真让你动手改一个PE文件往往无从下手。原因很简单——看懂结构和能改结构之间隔着一整套手工操作的工程经验。“手动新增节”这个操作恰好是打通这层隔阂的最佳练手项目。它不像加壳那样涉及复杂的加密和重定位也不像修复导入表那样需要逆向分析它就是一个纯粹的“结构扩展”操作在现有节表后面追加一个新的节表项在文件末尾追加对应的节数据然后修正几个关键字段。整个过程逻辑清晰、可验证性强做完之后你对PE文件的理解会从“平面图”升级成“立体模型”。这个实战适合谁如果你已经能用工具查看PE结构知道IMAGE_NT_HEADERS里大概有什么但没亲手改过字节那这个项目就是为你准备的。如果你完全零基础建议先花半小时补一下PE基本结构至少搞清楚DOS头、NT头、节表三者的位置关系否则后面算偏移量会非常痛苦。1.2 新增节能解决什么实际问题有人会问现在工具这么多为什么还要手动做我自己的体会是手动做一遍你才能理解工具背后到底干了什么。具体来说新增节这个操作在实际场景中有几个真实用途给程序打补丁原程序没有足够的代码空间新增一个节专门放补丁代码然后修改入口点跳过去。添加自定义数据比如给某个程序附加配置信息、资源数据放在独立节里方便定位。学习PE加载机制通过观察新增节后程序能否正常运行理解内存对齐和文件对齐的区别。为后续加壳/混淆打基础很多保护方案的第一步就是新增节把原始代码搬进去再加密。注意手动修改PE文件属于底层操作建议只在你自己拥有合法权限的程序上练习不要对商业软件或系统文件做任何修改。1.3 整体方案设计三步走策略我把整个操作拆成三个核心步骤每一步都有明确的输入和输出第一步分析目标文件确定新增节的参数。包括节名、虚拟大小、虚拟地址、原始大小、原始地址、节区属性。这些参数不是随便填的需要根据文件当前状态计算。第二步扩展节表写入新节表项。在原有节表末尾追加一个40字节的IMAGE_SECTION_HEADER结构同时更新文件头中的NumberOfSections字段。第三步追加节数据修正关键字段。在文件末尾按文件对齐粒度追加节数据更新SizeOfImage字段确保新节的虚拟地址不与其他节冲突。这个方案的优势在于不破坏原有结构。我们只是在末尾追加内容原有节的偏移和大小都不变所以即使新节有问题原程序的核心逻辑也不会被破坏。这比“在中间插入”要安全得多。1.4 关键参数的计算逻辑新增节最容易出错的地方就是参数计算。我见过不少人填完参数后程序直接崩溃排查半天发现是虚拟地址算错了。这里把几个核心参数的计算逻辑说清楚虚拟地址VirtualAddress新节的虚拟地址必须紧接在最后一个现有节的虚拟地址之后并且按节对齐SectionAlignment向上取整。公式是新节VA 对齐(最后一个节的VA 最后一个节的VirtualSize, SectionAlignment)原始地址PointerToRawData新节的文件偏移必须紧接在最后一个现有节的文件数据之后并且按文件对齐FileAlignment向上取整。公式是新节Raw 对齐(最后一个节的Raw 最后一个节的SizeOfRawData, FileAlignment)虚拟大小VirtualSize这是节在内存中的实际大小可以小于文件中的原始大小。一般填你实际数据的长度即可。原始大小SizeOfRawData这是节在文件中的大小必须是FileAlignment的整数倍。如果你实际数据只有100字节但FileAlignment是512那这里要填512。SizeOfImage这是整个映像在内存中的总大小更新后应该等于最后一个节的VA加上对齐后的VirtualSize再按SectionAlignment对齐。这些公式看起来简单但实际操作时最后一个节的VirtualSize和SizeOfRawData往往不相等取哪个值参与计算需要根据具体情况判断。我的经验是计算下一个可用VA时用VirtualSize计算下一个可用Raw时用SizeOfRawData这样最稳妥。2. 核心细节解析与实操要点2.1 PE文件结构的快速定位方法在动手改之前你得先能准确找到节表的位置。很多人卡在这一步因为PE结构里有好几层指针绕来绕去容易晕。我用一个最直白的路径来描述从文件开头看偏移0x3C处是一个4字节的值叫e_lfanew它指向IMAGE_NT_HEADERS的起始位置。到了NT头先是一个4字节的签名PE\0\0然后是20字节的IMAGE_FILE_HEADER接着是IMAGE_OPTIONAL_HEADER。节表就紧跟在IMAGE_OPTIONAL_HEADER之后。IMAGE_FILE_HEADER里有两个关键字段NumberOfSections2字节偏移2和SizeOfOptionalHeader2字节偏移16。节表的起始位置可以用这个公式算节表起始 e_lfanew 4 20 SizeOfOptionalHeader每个节表项固定40字节所以第N个节表项的位置就是第N个节表项 节表起始 (N-1) * 40我习惯用十六进制编辑器配合计算器操作先把这些偏移量算好记在纸上改的时候直接跳转效率比来回翻结构定义高得多。2.2 节表项结构的逐字段解读IMAGE_SECTION_HEADER结构占40字节字段分布如下偏移长度字段名说明0x008Name节名ASCII不足8字节补00x084VirtualSize内存中的实际大小0x0C4VirtualAddress内存中的虚拟地址RVA0x104SizeOfRawData文件中占用的空间大小0x144PointerToRawData文件中的偏移0x184PointerToRelocations重定位表偏移一般填00x1C4PointerToLinenumbers行号表偏移一般填00x202NumberOfRelocations重定位数量一般填00x222NumberOfLinenumbers行号数量一般填00x244Characteristics节属性标志节名可以随便取但建议用有意义的英文比如.newsec、.patch。注意不要超过8字节超了会被截断。Characteristics字段决定了节的内存权限常用的值有0x60000020代码节可执行可读0xC0000040已初始化数据可读可写0xE0000020代码可执行可读可写0x40000040只读数据如果你新增的节要放可执行代码至少要有0x20000000可执行和0x80000000可读标志。我一般直接给0xE0000020省事读写执行全开调试阶段方便。2.3 文件对齐与内存对齐的区别这是新手最容易混淆的概念我单独拎出来说。PE文件有两个对齐粒度FileAlignment文件中对齐粒度通常是0x200512字节或0x10004096字节。它决定了每个节在文件中的起始偏移必须是它的整数倍。SectionAlignment内存中对齐粒度通常是0x10004096字节。它决定了每个节在内存中的起始地址必须是它的整数倍。为什么要有两个对齐因为磁盘按扇区读写内存按页管理两者的最小单位不同。文件对齐通常小于或等于内存对齐这样可以节省磁盘空间。实际操作中你新增节时文件偏移按FileAlignment对齐虚拟地址按SectionAlignment对齐SizeOfRawData必须是FileAlignment的整数倍VirtualSize不需要对齐但SizeOfImage计算时要按SectionAlignment对齐提示如果FileAlignment和SectionAlignment相等比如都是0x1000计算会简单很多但文件体积会变大。大多数正常编译的程序FileAlignment是0x200。2.4 修改前的备份与验证策略动手之前必须备份原文件。这不是客套话我见过太多人改到一半发现算错了想回退却发现原文件已经被覆盖。备份命名建议加上时间戳比如target_backup_20250101.exe。备份之后先做一次“空验证”用工具打开原文件记录下以下关键值NumberOfSections最后一个节的VirtualAddress和VirtualSize最后一个节的PointerToRawData和SizeOfRawDataSizeOfImageFileAlignment和SectionAlignment把这些值写在一张纸上或者记事本里改的时候对照着看。改完之后再用工具打开逐项核对是否与预期一致。这个习惯能帮你省下大量排查时间。另外建议在虚拟机或沙箱环境中测试修改后的文件避免意外情况影响你的工作环境。3. 实操过程与核心环节实现3.1 分析目标文件并提取关键参数假设我们有一个模拟的PE文件demo.exe用十六进制编辑器打开先定位到0x3C处读取e_lfanew。假设读到的值是0x000000F0那么NT头从0xF0开始。跳到0xF0前4字节是50 45 00 00PE签名接着0xF4处是IMAGE_FILE_HEADER。在0xF4 2 0xF6处读取NumberOfSections假设是0x0004说明有4个节。在0xF4 16 0x104处读取SizeOfOptionalHeader假设是0x00E0。那么节表起始位置节表起始 0xF0 4 20 0xE0 0x1F8第4个节表项最后一个的位置第4个节表项 0x1F8 3 * 40 0x1F8 0x78 0x270跳到0x270读取这个节表项的各个字段。假设读到Name:.dataVirtualSize:0x00001234VirtualAddress:0x00003000SizeOfRawData:0x00001400PointerToRawData:0x00002600Characteristics:0xC0000040再读取Optional Header中的SizeOfImage偏移在Optional Header起始56处和FileAlignment36处、SectionAlignment32处。假设SizeOfImage:0x00005000FileAlignment:0x00000200SectionAlignment:0x000010003.2 计算新节的各项参数有了上面的数据开始计算新节参数。新节虚拟地址最后一个节VA VirtualSize 0x3000 0x1234 0x4234 按SectionAlignment(0x1000)对齐0x4234 → 0x5000 新节VA 0x5000新节文件偏移最后一个节Raw SizeOfRawData 0x2600 0x1400 0x3A00 按FileAlignment(0x200)对齐0x3A00 → 0x3A00已经是0x200的整数倍 新节Raw 0x3A00新节虚拟大小假设我们要放入的数据是200字节VirtualSize填0x000000C8。新节原始大小200字节按FileAlignment(0x200)对齐0xC8 → 0x200 SizeOfRawData 0x00000200新节属性填0xE0000020可执行可读可写。更新SizeOfImage新节VA 对齐(VirtualSize, SectionAlignment) 0x5000 0x1000 0x6000 SizeOfImage 0x00006000更新NumberOfSections从4改为5。3.3 写入新节表项在节表末尾第4个节表项之后即0x270 40 0x298处写入新的40字节节表项。按字段顺序逐字节写入偏移0x298: 2E 6E 65 77 73 65 63 00 // .newsec\0 偏移0x2A0: C8 00 00 00 // VirtualSize 0xC8 偏移0x2A4: 00 50 00 00 // VirtualAddress 0x5000 偏移0x2A8: 00 02 00 00 // SizeOfRawData 0x200 偏移0x2AC: 00 3A 00 00 // PointerToRawData 0x3A00 偏移0x2B0: 00 00 00 00 // PointerToRelocations 0 偏移0x2B4: 00 00 00 00 // PointerToLinenumbers 0 偏移0x2B8: 00 00 // NumberOfRelocations 0 偏移0x2BA: 00 00 // NumberOfLinenumbers 0 偏移0x2BC: 20 00 00 E0 // Characteristics 0xE0000020注意多字节值按小端序写入。写完后回到0xF6处把NumberOfSections从04 00改为05 00。3.4 追加节数据并修正SizeOfImage跳到文件偏移0x3A00处这是新节数据的起始位置。写入你的200字节数据剩余部分用0填充到0x200字节。如果原文件在0x3A00之后还有数据比如覆盖层需要先把这些数据后移或者确认新节数据不会覆盖它们。然后找到Optional Header中SizeOfImage的位置。Optional Header起始于0xF80xF0 4 20 0x108等一下重新算NT头起始0xF0签名4字节FileHeader 20字节所以Optional Header起始于0xF0 4 20 0x108。SizeOfImage在Optional Header偏移56处即0x108 56 0x140。把这里的值从0x00005000改为0x00006000。3.5 验证修改结果改完后用PE查看工具打开新文件检查以下几点NumberOfSections是否为5第5个节表项的Name、VirtualAddress、PointerToRawData是否与预期一致SizeOfImage是否为0x6000新节的数据是否在文件偏移0x3A00处正确写入如果工具显示正常可以尝试运行程序。如果程序能正常启动说明修改没有破坏原有结构。如果崩溃检查新节的VirtualAddress是否与其他节重叠或者SizeOfImage是否算错。实操心得我第一次做的时候忘了更新SizeOfImage程序直接报“不是有效的Win32应用程序”。后来发现是加载器根据SizeOfImage分配内存值不对就直接拒绝加载。这个字段一定要改。4. 常见问题与排查技巧实录4.1 程序无法启动的排查思路修改后程序无法运行是最常见的问题原因通常集中在几个地方。我整理了一个排查顺序按这个顺序走基本能定位到问题第一检查NumberOfSections是否更新。如果节表项写了但数量没改加载器根本不会读取新节但也不会报错只是新节被忽略。这种情况程序可能正常运行但你的新节不生效。第二检查SizeOfImage是否正确。这个值决定了加载器分配多少内存。如果太小新节可能超出分配范围如果太大浪费内存但一般不影响运行。值不对时加载器可能直接拒绝加载。第三检查VirtualAddress是否冲突。新节的VA必须大于等于最后一个节的VAVirtualSize并且按SectionAlignment对齐。如果VA落在已有节的范围内加载器会认为节重叠拒绝加载。第四检查PointerToRawData是否越界。新节的文件偏移加上SizeOfRawData不能超过文件实际大小。如果超出加载器读取时会失败。第五检查Characteristics是否合理。如果新节要执行代码但没有可执行标志调用时会触发访问违规。4.2 节表空间不足的处理方法节表位于Optional Header之后、第一个节的数据之前。如果Optional Header和第一个节数据之间的空隙不够放下新的40字节节表项就会覆盖第一个节的数据。判断方法第一个节的PointerToRawData减去节表起始位置就是可用空间。如果小于(NumberOfSections1)*40就需要另想办法。常见的处理方式有两种扩大Optional Header修改SizeOfOptionalHeader字段但这会影响所有后续偏移操作复杂。移动节表把整个节表搬到文件末尾然后修改e_lfanew指向新的NT头位置。这个操作更复杂但更灵活。我一般建议初学者选择目标文件时先确认节表后面有足够空隙。大多数正常编译的程序节表后面会有一些0填充足够放一两个新节表项。4.3 常见问题速查表问题现象可能原因解决方法程序无法启动报无效Win32程序SizeOfImage未更新或值错误重新计算并修正SizeOfImage程序启动但新节不生效NumberOfSections未更新修改FileHeader中的节数量加载时报节重叠VirtualAddress计算错误重新按SectionAlignment对齐计算VA读取新节数据时崩溃PointerToRawData越界检查文件偏移是否超出文件大小执行新节代码时访问违规Characteristics缺少可执行标志添加0x20000000标志修改后文件体积异常增大SizeOfRawData对齐值过大检查FileAlignment按实际对齐粒度填写4.4 独家避坑经验分享做了多次新增节操作后我总结了几个文档里不会写的经验经验一先用0x200对齐试不行再换0x1000。有些程序的FileAlignment是0x1000如果你按0x200算文件偏移会不对齐加载器可能仍然能加载但某些校验严格的程序会拒绝。最稳妥的方法是直接读取Optional Header中的FileAlignment值按实际值计算。经验二新节数据先填0xCC。如果你新增的是代码节调试阶段先把数据填成0xCCint3断点指令这样如果程序意外跳到这里会立即断下来方便定位问题。确认没问题后再换成真实数据。经验三用脚本辅助计算。手动算偏移量容易出错我写了一个简单的Python脚本输入最后一个节的VA、VirtualSize、Raw、SizeOfRawData和对齐值自动输出新节的各项参数。这个脚本帮我省了不少时间也减少了计算错误。def align(value, alignment): return (value alignment - 1) ~(alignment - 1) last_va 0x3000 last_vsize 0x1234 last_raw 0x2600 last_rsize 0x1400 section_align 0x1000 file_align 0x200 new_va align(last_va last_vsize, section_align) new_raw align(last_raw last_rsize, file_align) new_vsize 0xC8 new_rsize align(new_vsize, file_align) new_size_of_image align(new_va new_vsize, section_align) print(f新节VA: 0x{new_va:X}) print(f新节Raw: 0x{new_raw:X}) print(f新节VirtualSize: 0x{new_vsize:X}) print(f新节SizeOfRawData: 0x{new_rsize:X}) print(f新SizeOfImage: 0x{new_size_of_image:X})经验四改完后用多个工具交叉验证。不同PE工具对某些字段的解析可能有差异用一个工具看没问题换一个工具可能报异常。我一般用两到三个工具交叉检查确认所有字段都符合预期。经验五记录每次修改的偏移和原值。养成写修改日志的习惯记录你改了哪个偏移、原值是什么、新值是什么。如果改错了可以快速回退。这个习惯在复杂修改中尤其重要。

相关新闻

figma导入psd实战笔记:用TaoToken统一Key打通设计稿到PSD的自动化链路

figma导入psd实战笔记:用TaoToken统一Key打通设计稿到PSD的自动化链路

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

2026/10/18 3:31:17 阅读更多 →
深入理解PyTorch Autograd与计算图:从调包到精通的实战指南

深入理解PyTorch Autograd与计算图:从调包到精通的实战指南

1. 为什么每个PyTorch使用者都该吃透Autograd刚接触PyTorch那会儿,我以为loss.backward()就是个黑盒——调一下,梯度就出来了,然后optimizer.step()更新参数,完事。直到有一次我尝试自己实现一个自定义损失函数,反向传…

2026/10/18 3:31:17 阅读更多 →
PyTorch Autograd与计算图深度解析:从反向传播原理到梯度调试实战

PyTorch Autograd与计算图深度解析:从反向传播原理到梯度调试实战

1. 为什么每个PyTorch使用者都该吃透Autograd刚接触PyTorch那会儿,我以为loss.backward()就是一句魔法咒语——写上去,梯度就出来了,参数就能更新了。直到有一次自定义了一个带条件分支的损失函数,训练死活不收敛,梯度…

2026/10/18 3:31:17 阅读更多 →

最新新闻

OpenClaw语音控制实战:多用户语音识别与声纹认证的权限隔离方案

OpenClaw语音控制实战:多用户语音识别与声纹认证的权限隔离方案

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

2026/10/18 4:19:29 阅读更多 →
昇腾NPU强化学习迁移指南:从DQN到PPO的避坑与提速实践

昇腾NPU强化学习迁移指南:从DQN到PPO的避坑与提速实践

1月29号晚上那场《昇腾NPU强化学习案例》直播,我全程看完了。作为在GPU上跑了两三年强化学习、最近因为成本和资源原因开始评估昇腾NPU的人,直播里提到的报错、性能瓶颈和迁移细节,几乎把我踩过的坑全过了一遍。这篇不是录播的文字稿&#xf…

2026/10/18 4:19:29 阅读更多 →
ai大模型(一)

ai大模型(一)

0.认识大模型1.大模型计量单位2.大模型分类3.大模型训练环节4.大模型如何落地5.工程化几个模块-如何访问大模型6.提示词工程几个要素

2026/10/18 4:19:29 阅读更多 →
RAG效果差?从分块、检索、重排到Prompt的全链路优化指南

RAG效果差?从分块、检索、重排到Prompt的全链路优化指南

1. 先搞清楚:你的RAG为什么效果差?——全链路优化的起点做RAG(检索增强生成)这个方向的人,多半都经历过这种尴尬:辛辛苦苦把文档灌进知识库,上线一问,答得前言不搭后语,引…

2026/10/18 4:19:29 阅读更多 →
Umi-OCR 免费离线 OCR 工具:3 分钟上手,截图抠文字、扫描件能搜索

Umi-OCR 免费离线 OCR 工具:3 分钟上手,截图抠文字、扫描件能搜索

Umi-OCR 免费离线 OCR 工具:3 分钟上手,截图抠文字、扫描件能搜索 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生…

2026/10/18 4:19:29 阅读更多 →
用anime.js实现无缝滚动走马灯:原理、踩坑与完整方案

用anime.js实现无缝滚动走马灯:原理、踩坑与完整方案

我在给运营后台做公告滚动条的时候,被“走马灯”这个看似不起眼的小组件卡了整整一个下午。需求列出来其实没几条:公告项一行或两行横向滚动,鼠标悬停时暂停、移开继续,窗口从桌面缩到平板时不能出现空白断层,内容列表…

2026/10/18 4:18:29 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →