简介de4dot-netcore 是经典 .NET 脱壳工具 de4dot 面向 .NET Core 环境适配的版本主要服务于安全研究人员、逆向工程师及恶意样本分析人员用于剥离 ConfuserEx、.NET Reactor、Themida 等常见保护壳还原可分析的原始程序集。压缩包共 48 个文件约 1.87MB以 dll 动态库、pdb 调试符号、json 运行时配置、txt 许可说明及 exe 可执行文件为主涵盖 de4dot 主程序、代码分析模块、dnlib 依赖与多份第三方许可证结构完整、开箱即用。已有 532 人学习关注。借助该工具可快速完成 .NET Core 程序的脱壳与反混淆为静态分析、漏洞挖掘和取证工作提供基础其开源特性也便于按需定制扩展适合作为逆向分析流程中的实用组件。1. 从一次“版本对不上”的翻车说起de4dot-netcore 到底装哪个某开发者把一份 .NET 程序丢给我说反编译工具一打开就报错界面还没出来就退了。我第一反应是工具没装对——他装的是老版 de4dot跑在 .NET Framework 上而目标程序是 .NET Core / .NET 5 编译出来的。这类“版本对不上”的翻车在逆向和代码审计场景里太常见了de4dot 本身是个老牌混淆清理工具原版长期停留在 .NET Framework 时代遇到新运行时的程序集要么加载失败要么清理完输出还是坏的。de4dot-netcore 就是在这个背景下被维护起来的移植分支把目标框架挪到 .NET Core 上让它在新的运行时环境里能正常加载和运行。这篇笔记记录的是我实际装这套环境的完整过程装什么运行时、怎么拉源码、怎么编译、配置怎么改、装坏了怎么退回去。适合两类人——第一次接触 de4dot 想跑通的新手以及装过原版、被版本问题坑过想换分支的老手。2. 环境准备de4dot-netcore 的运行时与 SDK 版本怎么选装 de4dot-netcore 之前先把“它跑在什么上面”这件事定死。这一步选错后面编译、运行全是连锁报错。我一般会先确认三件事目标程序集的目标框架、本机已装的 .NET 运行时、以及准备用来编译的 SDK 版本。三者不匹配就是最常见的“装上了但跑不起来”。2.1 先确认目标程序集的运行时版本动手装工具前先搞清楚你要处理的程序集是哪个框架编译的。这一步决定了 de4dot-netcore 需要哪个运行时来加载它。常见做法是用一个轻量的方式读程序集元数据或者直接看文件属性里的运行时信息。如果你手上已经有 ILSpy 之类的工具打开看一眼目标框架最省事。# 查看程序集的目标框架需要 dotnet 环境 # 用 monodis 或 ildasm 也可以这里用 dotnet 自带的元数据读取思路 file ./TargetApp.dll # 输出里若出现 .NETCoreApp 相关字样说明是 Core 系 strings ./TargetApp.dll | grep -i NETCoreApp\|NETFramework | head -5file只能给出 PE 文件的大致类型真正判断框架版本要靠元数据里的TargetFrameworkAttribute。strings过滤是个土办法能快速看到NETCoreApp,Versionv6.0这类字符串够用来做初判。如果目标是NETFramework,Versionv4.x那原版 de4dot 反而更稳如果是NETCoreApp或NETStandard就走 de4dot-netcore 这条路。这个判断别省我见过有人拿 Core 分支去处理 Framework 程序集清理逻辑能跑但输出偶尔异常排查半天才发现是分支选错。2.2 运行时与 SDK 的版本对照de4dot-netcore 的编译和运行对 .NET 版本有要求。原版 de4dot 依赖 .NET Framework 4.x而 netcore 分支把目标框架改成了 .NET Core 3.1 及以上实际维护中更常见的是面向 .NET 6 / .NET 8 的构建。下面这张表是我整理的环境对照按目标程序集框架反推该装什么目标程序集框架建议运行时建议 SDK说明.NET Framework 4.x.NET Framework 4.8不需要 Core SDK优先用原版 de4dot.NET Core 3.1.NET Core 3.1 Runtime.NET SDK 6.0老项目运行时可能已停止支持.NET 6.NET 6 Runtime.NET SDK 6.0长期支持版最稳的组合.NET 8.NET 8 Runtime.NET SDK 8.0新项目首选注意 SDK 别装成预览版选版本的原则很简单SDK 版本不低于目标程序集的运行时版本运行时版本与目标程序集一致或更高一个主版本。比如目标是 .NET 6装 .NET SDK 6.0 编译、.NET 6 Runtime 运行最省心。装 .NET 8 SDK 去编译面向 .NET 6 的代码通常也能过但如果你在项目文件里锁了TargetFrameworkSDK 太新反而可能触发分析器警告把警告当错误就编译失败。提示不要同时装多个预览版 SDK。dotnet --list-sdks里出现8.0.100-preview这类版本时global.json没锁版本的话构建可能选中预览版行为不稳定。2.3 安装 .NET SDK 与运行时确认版本后开始装。Linux 下我一般用官方脚本或包管理器Windows 下用安装包。这里以 .NET 6 为例给出可复现的安装命令# 以 Ubuntu 为例先装微软源再装 SDK 6.0 wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get update sudo apt-get install -y dotnet-sdk-6.0 aspnetcore-runtime-6.0第一行拉的是微软的包源配置dpkg -i把它注册进 apt之后apt-get update才能索引到 dotnet 包。dotnet-sdk-6.0带编译工具链aspnetcore-runtime-6.0是运行时如果只跑不编译装dotnet-runtime-6.0就够。装完立刻验证dotnet --list-sdks dotnet --list-runtimes两条命令分别列出 SDK 和运行时。输出里应该能看到6.0.x的 SDK 和Microsoft.NETCore.App 6.0.x的运行时。如果--list-sdks为空但--list-runtimes有内容说明只装了运行时没装 SDK编译会直接报dotnet build找不到 SDK。这一步的坑在于包名dotnet-sdk-6.0和dotnet-runtime-6.0是两个包装错一个就缺一半能力。3. 拉源码与编译de4dot-netcore 从仓库到可执行文件环境齐了接下来把 de4dot-netcore 的源码拉下来编译成可执行文件。这一步的核心是搞清楚仓库结构、还原依赖、选对构建配置。原版 de4dot 是单个大解决方案netcore 分支通常做了项目拆分编译入口和输出路径跟原版不完全一样照抄老教程容易在dotnet build那一步卡住。3.1 克隆仓库与目录结构确认先把源码拿到本地。de4dot-netcore 的仓库托管在常见的代码托管平台上克隆命令按你实际拿到的地址替换git clone de4dot-netcore 仓库地址 de4dot-netcore cd de4dot-netcore ls -la克隆后先看目录。典型的 netcore 分支会有src/或直接平铺的项目目录里面能找到*.csproj或*.sln。我一般会先找解决方案文件find . -maxdepth 3 -name *.sln -o -maxdepth 3 -name *.csproj | head -20-maxdepth 3限制搜索深度避免在大仓库里翻太久。输出里如果只有一个.sln直接用它构建如果有多个.csproj但没有.sln说明分支可能只保留了核心项目需要单独指定项目文件构建。这一步别急着dotnet build先确认项目文件里的TargetFrameworkgrep -r TargetFramework --include*.csproj . | head -10输出会告诉你这个分支面向net6.0还是net8.0。如果显示net6.0而你只装了 .NET 8 SDK构建时可能提示需要 .NET 6 的目标包反过来 SDK 版本高于目标框架一般能过。看到netcoreapp3.1就要注意这个框架已停止支持SDK 6 以上构建时可能报兼容性警告。3.2 还原依赖与构建确认项目文件后开始还原和构建。还原是把 NuGet 依赖拉下来构建是编译成 dll/exe# 还原依赖指定解决方案或项目文件 dotnet restore ./de4dot.sln # 以 Release 配置构建输出到默认 bin 目录 dotnet build ./de4dot.sln -c Release --no-restoredotnet restore会读项目文件里的PackageReference把依赖下载到本地 NuGet 缓存。--no-restore表示构建时不再重复还原前提是上一步成功。-c Release选发布配置输出经过优化体积和运行效率都比 Debug 好。构建成功后可执行文件一般在bin/Release/目标框架/下find . -path */bin/Release/* -name de4dot* -type f | head -10输出里应该能看到de4dot.dll或de4dot.exeWindows 下。Linux 下通常是de4dot.dll用dotnet de4dot.dll运行。如果find什么都没找到说明构建没产出可执行项目回去看构建日志里是不是某个项目被跳过或报错了。3.3 构建失败时的常见处理构建报错分几类处理方式不同。第一类是 NuGet 还原失败日志里出现Unable to load the service index或NU1301多半是包源不可达或缓存损坏。常见做法是清缓存再还原dotnet nuget locals all --clear dotnet restore ./de4dot.sln--clear清掉全局包缓存和临时缓存能解决大部分缓存导致的还原异常。第二类是目标框架不匹配报NETSDK1045或提示找不到Microsoft.NETCore.App的某个版本说明本机运行时/SDK 版本低于项目要求按第 2 章的对照表补装对应版本。第三类是编译错误比如某个 API 在当前框架下不存在这通常是分支代码与 SDK 版本不匹配换用项目文件里声明的目标框架对应的 SDK 再试。我踩过最隐蔽的一次是global.json锁了旧 SDK 版本本机没有那个版本dotnet build直接拒绝执行报错信息里明确写了期望版本删掉或改掉global.json里的version字段就好。4. 配置与运行de4dot-netcore 的参数怎么配、输出怎么控编译出可执行文件只是第一步真正干活靠参数配置。de4dot 的参数体系比较老派netcore 分支基本沿用了原版的命令行风格但运行方式从直接执行 exe 变成了dotnet xxx.dll参数传递和路径处理上有几处要注意。这一章把常用参数、输出控制和运行方式讲清楚照着配就能跑。4.1 基本运行方式与参数结构Linux/macOS 下用dotnet宿主运行编译产物Windows 下如果生成了 exe 可以直接执行。基本结构# Linux/macOS用 dotnet 宿主运行 dotnet ./bin/Release/net6.0/de4dot.dll 目标程序集 [选项] # Windows直接运行 exe de4dot.exe 目标程序集 [选项]第一个位置参数是目标程序集路径后面跟选项。de4dot 的选项分几类输入输出控制-o指定输出路径、混淆类型指定-p指定检测的混淆器、清理强度-f强制、--dont-rename不改名等。最常用的是指定输出文件dotnet ./bin/Release/net6.0/de4dot.dll ./TargetApp.dll -o ./TargetApp_cleaned.dll-o后面跟输出路径不指定的话默认在原文件同目录生成带-cleaned后缀的文件。这个参数别写错路径输出目录不存在时工具不会自动创建直接报错退出。我一般会先mkdir -p把输出目录建好再跑。4.2 常用参数与取舍参数不是越多越好配错反而把程序集改坏。下面这张表是我常用的参数组合和适用场景参数作用什么时候用注意-o 路径指定输出文件总是用目录需已存在-f强制清理忽略检测失败确认有混淆但自动检测没识别可能误伤正常代码--dont-rename不重命名符号需要保留原始名称做对照清理效果打折-p 类型指定混淆器类型已知混淆器自动检测不准类型名要写对--strtok等特定清理选项针对特定混淆手法按需别全开-f是最容易用错的。它的语义是“不管检测结果按默认策略强清”适合你确定程序集被混淆、但工具没自动识别出来的情况。如果程序集本身没混淆加-f可能把正常的符号表改乱输出反而不能用。我的习惯是先不加-f跑一遍看日志里检测到什么混淆器再决定要不要强制。--dont-rename在需要对比清理前后差异时很有用代价是清理不彻底适合调试阶段不适合最终产出。4.3 输出验证与日志解读跑完不是结束得看输出对不对。de4dot 运行时会打印检测到的混淆器和清理动作日志里出现Detected字样说明识别到了具体混淆器出现ERROR或WARNING要逐条看。常见做法是清理后立刻用反编译工具打开输出文件确认类型和方法能正常展开# 清理后检查输出文件是否可加载 dotnet ./bin/Release/net6.0/de4dot.dll ./TargetApp_cleaned.dll -o /tmp/check.dll这条命令拿清理后的文件再跑一遍 de4dot如果能正常加载并输出“未检测到混淆”说明输出文件结构完整、可被运行时解析。如果这一步报BadImageFormatException或加载失败说明上一次清理把程序集改坏了回去检查是不是-f用过头或参数组合冲突。这个“二次加载”验证是我每次清理后必做的动作比肉眼翻反编译结果快得多。5. 避坑与排查de4dot-netcore 装完跑不起来的五类问题装环境这件事成功路径往往只有一条失败路径能列一页。这一章把我实际遇到和收集到的五类高频问题按“现象 → 原因 → 解决”整理出来每条都是踩过的坑照着对能省不少时间。5.1 现象dotnet de4dot.dll报找不到运行时原因编译时用的目标框架版本高于本机安装的运行时。比如项目面向net8.0本机只装了 .NET 6 Runtime宿主找不到匹配的运行时就会报You must install .NET to run this application并列出期望的框架版本。解决按报错信息里提示的版本补装运行时或者用--roll-forward让宿主向上兼容dotnet --roll-forward Major ./bin/Release/net8.0/de4dot.dll ./TargetApp.dll--roll-forward Major允许用更高主版本的运行时加载适合本机运行时比目标新一个主版本的情况。反过来本机运行时太旧只能补装roll-forward 救不了。5.2 现象构建成功但运行时报Could not load file or assembly原因依赖的某个程序集没被复制到输出目录或者版本冲突。netcore 分支如果引用了特定版本的 NuGet 包运行时找不到对应 dll 就会抛这个异常报错信息里会写明缺的是哪个程序集。解决先看输出目录里有没有报错提到的 dll没有的话检查项目文件的PackageReference是否被正确还原。常见做法是重新发布一次用dotnet publish而不是dotnet buildpublish 会把所有依赖收拢到输出目录dotnet publish ./de4dot.sln -c Release -o ./publish-o ./publish指定发布目录产物里包含运行时依赖直接dotnet ./publish/de4dot.dll运行缺依赖的概率低很多。5.3 现象清理后的程序集反编译报错或方法体为空原因参数用过头比如对未混淆程序集加了-f或者清理策略与混淆器类型不匹配把正常的方法体改坏了。解决去掉-f重跑让工具自动检测如果自动检测不准用-p显式指定混淆器类型。清理前先备份原文件清理后用第 4 章的“二次加载”方法验证加载失败就换参数组合重来。我一般会保留每次清理的输出命名带参数后缀出问题能快速定位是哪组参数导致的。5.4 现象dotnet restore卡住或超时原因NuGet 包源不可达或者本地缓存损坏。日志里常见NU1301、Unable to load the service index。解决先清缓存再还原必要时换包源dotnet nuget locals all --clear dotnet restore ./de4dot.sln --source https://api.nuget.org/v3/index.json--source显式指定包源绕开配置文件里可能写错的源地址。如果公司网络有内部镜像源换成内部源地址通常更快。5.5 现象Windows 下双击 exe 闪退原因exe 是控制台程序双击运行时如果参数缺失或目标文件路径不对窗口一闪就关看不到报错。解决别双击从命令行运行或者在 cmd 里先cd到 exe 目录再执行这样报错信息会留在窗口里。也可以加pause或用cmd /k启动让窗口停住看输出。这个坑新手最容易踩以为程序坏了其实只是没看到错误信息。6. 装完怎么验证跑通三步确认法与我的固定习惯装完 de4dot-netcore别急着拿真实目标开干先用一个可控的小程序集把整条链路验证一遍。我固定走三步版本自检、最小样例清理、输出回读。三步都过才算这套环境真的能用。第一步版本自检。确认宿主、SDK、运行时三者版本对得上dotnet --version dotnet --list-runtimes | grep NETCore dotnet ./bin/Release/net6.0/de4dot.dll --help前两条确认环境第三条确认 de4dot 本身能加载并打印帮助。--help能正常输出参数列表说明程序集加载、依赖解析都没问题。如果--help就报错别往下走回第 5 章对现象排查。第二步最小样例清理。拿一个自己编译的、带简单混淆的小程序集做输入跑一遍完整清理# 用最小样例验证清理链路输出到独立目录 mkdir -p ./verify dotnet ./bin/Release/net6.0/de4dot.dll ./Sample.dll -o ./verify/Sample_cleaned.dllSample.dll建议自己用任意 .NET 项目编译一个加个简单的名称混淆即可别拿生产程序集做首次验证。跑完看日志里有没有Detected和清理统计输出文件是否生成。第三步输出回读。用第 4 章的二次加载方法确认输出文件结构完整dotnet ./bin/Release/net6.0/de4dot.dll ./verify/Sample_cleaned.dll -o ./verify/Sample_check.dll能正常加载并提示未检测到混淆说明清理产物可被运行时解析链路通了。三步都过之后再拿真实目标程序集跑心里有底。下面这张表是我验证时记录的检查项照着勾一遍检查项命令/动作通过标准宿主可用dotnet --version输出非空版本号运行时匹配dotnet --list-runtimes含目标框架对应运行时工具可加载de4dot.dll --help正常打印参数清理链路最小样例 -o输出文件生成、日志无 ERROR输出完整二次加载输出文件可加载、无格式异常这套三步法不是官方流程是我被“装上了但跑不通”坑过几次之后固定下来的习惯。最惨的一次是环境看着全绿拿真实程序集一跑输出全是坏的回头才发现是运行时版本差了一个主版本--help能过但实际清理时加载目标程序集失败。从那以后我每次装完 de4dot-netcore都强制走一遍最小样例加二次加载不跳过。希望这套流程能帮你少走一遍我踩过的弯路。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
BLE6.0技术解析:智能门锁性能优化与安全增强 1. BLE6.0与智能门锁的性能革命去年调试一款智能门锁时,我遇到个典型问题:用户在门前1米处频繁出现开锁失败,但走到0.5米内又能正常响应。这种"幽灵距离"现象正是传统蓝牙门锁的痛点——RSSI测距精度不足导致的误判。直到BLE6.0规范… · 2026/11/5 3:32:59
2025年AI科研助手评测与技术趋势分析 1. 2025年AI科研助手全景扫描当我在实验室调试第17个参数时,突然意识到:AI科研助手已经彻底改变了我们的研究方式。从文献综述到实验设计,从数据处理到论文润色,这些智能伙伴正在重塑科研工作流。2025年的AI科研助手市场呈现出三个… · 2026/11/5 2:44:46
自适应滤波器LMS与RLS:结构选型、参数取舍与收敛调试 简介:围绕自适应滤波器设计与应用整理的毕业设计论文,面向通信、电子与信号处理方向的高年级本科生、研究生及课程设计者,帮助其建立从理论推导到MATLAB仿真的完整认知。文档以南航硕士课程论文为底稿,系统梳理自适应滤波基础理论… · 2026/11/5 8:56:47
渭南市考电工证官方报名入口在哪?怕被中介坑的看这篇 渭南市考电工证官方报名入口在哪?怕被中介坑的看这篇 不知道去哪报名怕被中介坑?渭南市考电工证官方报名入口在哪里?很多人在备考电工证的时候,总担心被一些“中介”忽悠,多花冤枉钱,浪费时间和精力。今天就从真实案例出发,告诉你怎么避开陷阱,安全高… · 2026/11/7 11:29:20
双柏县电工证办理在哪考才靠谱?怕考不过白交培训费看这篇就够了 双柏县电工证办理在哪考才靠谱?怕考不过白交培训费看这篇就够了 怕考不过白交培训费?你不是一个人。现在很多人在双柏县电工证办理的路上走得小心翼翼,担心花了不少钱,最后还是没拿到证。其实,只要选对了地方,掌握了方法,通过率并不低。下面我们就来聊… · 2026/11/7 11:29:20
云南低压电工证流程值不值得考?学历不高也能拿证 云南低压电工证流程值不值得考?学历不高也能拿证 学历不高怕报不上名?别急,云南低压电工证的报考门槛其实没你想的那么高。很多过来人都说,只要你想干这行,这个证就是你职业生涯的“敲门砖”。今天咱们就来聊聊云南低压电工证的流程到底怎么走,值不值得… · 2026/11/7 11:29:20
连山电工证培训怎么走?郑州报考避坑指南帮你搞懂薪资前景 连山电工证培训怎么走?郑州报考避坑指南帮你搞懂薪资前景 实操考试心里没底怕挂科,这事儿我懂。去年我帮亲戚报名连山电工证培训,结果他一上手就懵了,连基本的接线都搞不清楚,最后差点挂科。别急,今天咱就聊聊这个证的 薪资前景 ,特别是结合… · 2026/11/7 11:29:20
电工证主播学习怎么选?电子证书过期了怎么办? 电工证主播学习怎么选?电子证书过期了怎么办? 证书过期了不知道怎么复审延期?这事儿不少电工证持有者都遇到过,尤其是从事电工相关工作的主播,证件一旦失效,直接影响直播内容的合规性和平台审核。特别是 电子证书… · 2026/11/7 11:29:20
渭南市考电工证怎么转回本地?考前押题干货来了 渭南市考电工证怎么转回本地?考前押题干货来了 之前考的证在外省能不能转过来?这个问题,很多从外地回来或者打算在渭南发展的人,都会遇到。别急,今天我就从一个在濮阳培训过的老学员角度,给你讲讲渭南市考电工证的那些事儿,包括 考前押题… · 2026/11/7 11:28:20
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 11:25:08
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23
澳洲水电工证考试:证书过期了不知道怎么复审延期?电子证书怎么弄? 澳洲水电工证考试:证书过期了不知道怎么复审延期?电子证书怎么弄? 证书过期了不知道怎么复审延期?别慌,很多人在拿到【澳洲水电工证考试】的电子证书后,一不小心就忽略了复审时间,结果证书失效,工作受阻,甚至被单位追责。今天就从【澳洲水电工证考试… · 2026/11/7 0:00:41
电工作业提示版通过率揭秘:怎么考才能一次过? 电工作业提示版通过率揭秘:怎么考才能一次过? 怕考不过白交培训费?别急,今天我就从驻马店应届工程类毕业生的视角,带你全面了解电工作业提示版的考试流程、备考要点和真实通过率,帮你少走弯路、提高一次通过率。… · 2026/11/7 0:00:41
电工证年审报名千万别踩坑 外省证转过来要搞清这几点 电工证年审报名千万别踩坑 外省证转过来要搞清这几点 之前考的证在外省能不能转过来?这个问题是很多电工从业者最关心的,特别是像你这样在商丘从事公路工程的人员,经常需要跨省流动,证书的 有效性 和 可迁移性… · 2026/11/7 0:00:41
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/7 11:25:08
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23