简介面向软件安全与逆向工程学习者这份资源收纳了经典的反汇编工具IDA 5.0主程序及配套组件适用于漏洞分析、恶意代码剖析和二进制算法还原等场景特别适合初次接触静态分析的入门用户。压缩包共114个文件整体约55.71MB其中exe为程序主体与辅助工具pat和idc文件用于扩展反汇编模式sig签名库与idt类型描述可提升自动识别效率bat脚本负责环境启动txt、readme等文档则给出基础使用说明。目前已有318人学习下载内容覆盖IDA核心功能所需的常见文件类型。包内特意保留idag.CHS中文语言包配合crc16.cpp示例与多个批处理入口可帮助读者快速熟悉界面布局、函数识别及常用菜单操作这套经典版本体积紧凑适合作为日常逆向分析的工具备用。1. 反汇编工具IDA 5.0这份“老古董”还有没有上手价值很多人第一次听说反汇编工具是从某本十多年前的逆向入门书开始的书里配的截图灰蒙蒙一片标题栏写着IDA 5.0。这些年IDA换代到7.x、8.x功能越来越自动化F5反编译在破解、漏洞分析里已经接近标配但你会发现老样本分析、旧版插件兼容、CTF的misc题、甚至某些工业软件遗产代码维护始终绕不开IDA 5.0这个版本。它没有新版的“智能气泡”却把交叉引用、命名、函数识别这套最原始的反汇编工作流做得极其扎实。如果你手里正好有一台低配虚拟机、一份旧样本或者只是想把汇编基础打牢而不是依赖反编译伪代码来“猜”IDA 5.0反而比新版更像一个趁手的器械。本文从选型边界、加载配置、IDC脚本、常见翻车点到进阶技巧完整讲一遍在这份老版本上落地的路径。适合准备入门逆向、维护旧工程的人阅读。2. IDA 5.0能干什么这个版本的特性边界与选型理由2.1 为什么选 5.0 而不是最新版三个真实场景选老版本通常不是因为怀旧而是因为它恰好卡在几个真实场景里。场景一是旧教材与旧课程的配套需求。大量早期逆向教材、高校实验课、企业内部老培训资料的截图和命令都基于IDA 5.0菜单路径、快捷键、IDC函数接口都是那一代的如果你在复现课时实验新版本里很多入口已经改得面目全非对照截图反而寸步难行。场景二是低配分析环境。有些单位的审计机、隔离虚拟机硬件配置很低新版IDA动辄几百MB甚至上GB带着分析引擎和反编译模块在那类机器上启动都要一分钟IDA 5.0主体体积小在几十MB的范围内启动速度和响应手感在老机器上明显更友好。场景三是老样本与旧文件格式。一些十多年前的恶意样本、老驱动程序、嵌入式中断表、遗留固件本来就是按照那个时代的编译器产物写的用新版本打开时新版默认的自动分析策略反而会过度“优化”把一些非标准结构标得乱七八糟IDA 5.0的分析算法更朴素所见即所得。我一般会提醒同事如果目标文件是最近三五年编译的首选新版或开源工具如果目标文件本身就是老古董5.0并不会输。2.2 5.0 的看家本领交叉引用、命名与函数识别IDA 5.0被许多人视为“经典交互式反汇编工具”的定型版本它的核心能力围绕三个点展开。第一是交叉引用。在反汇编视图里任何一个地址、变量、函数名都可以按X键拉出完整的引用列表哪些地方写入、哪些地方调用、哪些地方取地址一目了然。这个能力在5.0里已经非常成熟向后兼容做得也好。第二是命名与注释的联动。手动把某个地址重命名后所有引用位置的显示立刻同步刷新配合冒号注释和重复注释一份原本满是地址的清单可以快速变成“函数级流程图”。第三是函数识别。加载PE或ELF文件后5.0会通过入口点、调用约定、栈帧设置等线索自动切出函数边界生成函数列表窗口。这三个能力在新版本里更强大但5.0的优势在于每一项操作都有最直接的快捷键和菜单入口没有中间层干扰非常适合用来建立“反汇编视图就是工作台”的思维习惯。2.3 5.0 的边界哪些活它确实干不了我对这个版本的定位是“能打但偏科”有些活它会让你翻车。64位程序的支持在5.0里属于可用但粗糙的水平。x64的很多反汇编细节、新式异常处理、大量使用寄存器的传参模型都会让自动分析手足无措处理现代x64大型软件效率和正确率都不如后面的版本。F5反编译在5.0时代并不是内置功能它依赖Hex-Rays Decompiler这个独立授权插件而且早期插件对5.0的适配版本不多大部分5.0使用者其实就是在一片汇编里硬看这既是缺点也成为了练内功的好机会。此外面对高版本编译器产物的类型信息比如MSVC 2015以上的RTTI、Clang的模板实例化、Swift/Go的混合符号5.0基本无法还原出像样的结构体与类层次。所以不该选5.0的场景也很清楚现代大型软件、移动端二进制、需要快速伪代码输出的漏洞分析任务。它擅长的是老平台、老编译器、规模适中的二进制以及教学与CTF的底层训练。维度IDA 5.0的表现建议x86 32位程序成熟函数识别稳定首选场景x64 程序基本可用细节粗糙尽量用新版反编译依赖外部Hex-Rays插件没有就手写分析旧编译器产物匹配度高适合老样本现代编译器产物类型信息还原弱不要硬扛3. 在IDA 5.0里跑通一次反汇编分析最小流程与6个必用操作3.1 加载二进制文件时这几个选项必须看把样本拖进IDA 5.0第一个弹出的就是加载对话框。很多人习惯一路点确定结果后面分析乱成一锅粥问题往往出在加载选项上。对话框里最需要留意的是“加载为”类型。5.0会根据文件头自动判断PE、ELF、Mach-O或COFF但如果文件头被污染、扩展名被改它可能识别不出格式。这时候我会手动指定格式比如“Microsoft Portable Executable”而不是选择Binary File。选择Binary File会把文件当裸数据加载所有导入表、资源段、重定位信息全部丢失后续分析量会成倍增加除非确实在分析纯固件或Shellcode否则不要选它。其次是自动分析相关选项。默认勾选的自动分析(Autoanalysis)会在加载后扫描整个可执行段尝试识别函数与指令边界。对小文件没问题但如果文件很大或者包含大量数据混排段自动分析可能长时间卡住。我在处理体积较大的文件时会先把自动分析关掉加载完成后用方向键逐块细看需要时再执行一次完整分析(Options - Analysis - Reanalyze program)避免一开始就被卡死。加载完成后建议先在Names窗口按导出名梳理一遍导出表清晰的文件可以从DllMain、start等入口快速定位。看不清时就打开Segments窗口确认各节区加载地址和可执行属性这一步能避免后面把数据和代码搞混。3.2 从入口点到主流程六个必用快捷键IDA 5.0的操作密度比现代版本低但快捷键设计非常经典把下面六个用熟分析速度立刻上一个台阶。G键跳转。按G输入地址或函数名直接从当前视图跳过去在长文件中定位入口点效率最高。N键重命名。光标停在一个地址上按N输入有意义的名称比如把sub_401000改成decrypt_buffer所有引用处会同步更新。这一步是让反汇编清单可读的关键。冒号键添加注释。在目标行按冒号弹出注释编辑框IDA的注释分普通注释和可重复注释可重复注释在每次函数被调用到的地方都会显示非常适合标记函数用途。X键查看交叉引用。光标停在某个操作数或函数上按X列出所有引用位置能迅速搞清“谁调用了它”“它调用了谁”。U键取消定义。遇到IDA把数据误认成代码或反之按U把当前项恢复为未定义再重新处理。C键转成代码、D键转成数据、A键转成字符串这三个命令配合使用能手工修正大部分识别偏差。比如说在入口点start处按X能看到它被启动代码引用的位置跳过去后按G找到主函数入口用N命名后按冒号写下“主逻辑入口”。这几个动作轮流做一两轮之后整个控制流骨架就出来了。需要提醒的是快捷键对焦点位置敏感。按N前务必把光标放在目标行上按X前光标要停在具体的操作数上而不是行首地址处。光标停错位置弹出来的引用列表可能完全不相干。3.3 函数边界修整自动识别的鸡蛋里挑骨头自动识别函数在5.0里不是每次都对。常见情况是某个函数开头被识别成数据或者一个函数被拆成两段。这时候我会手动修正函数边界。先将光标放在疑似函数起始地址按U取消定义再按C把第一个字节转成代码。IDA会把后续可以解码的指令切出来但往往只形成指令碎片还没有形成函数。这时再按P告诉IDA“从这里开始是一个函数”。P键会弹出一个对话框让你确认函数属性如果起点正确IDA会自动向后扫描把函数的结束地址和栈帧分析出来。更麻烦的情况是函数中间夹着跳跃表或花指令导致IDA在某个中间位置把函数截断。处理方法是先看反汇编代码里有没有jmp [tableeax*4]这类间接跳转找到跳转表所在的数据段用D键把它正确定义为数据再回到函数体内把中断处用C键重新连起来。修复后在Function窗口里确认函数列表没有碎片必要时删掉错误函数重建覆盖范围。这类修整工作的本质在于反汇编工具给出的从来不是绝对正确的结果而是一份需要验核的草稿。5.0的价值恰恰在于它把这份草稿的“修改接口”暴露得很直接不像新版那样给你一个看似完整的、其实更难临时调整的中间表示。4. 用IDC脚本接管重复劳动5.0的自动化从这里开始4.1 为什么在 5.0 里先学 IDC 而不是 IDAPythonIDA早期版本的自动化主要靠IDC脚本实现。IDC是一种C语言风格的脚本语言语法很轻不需要编译环境直接在IDA里通过File - IDC Command或脚本文件执行。IDAPython在5.0时代已经出现但多以第三方插件形式存在不是自带能力装插件本身又是一层环境依赖。所以如果目标是“在5.0里快速自动化”先学IDC是更可靠的路。它运行在IDA内置的脚本解释器上同一段脚本在5.0和后续版本里多数能直接跑兼容性很好。另一个好处在于IDC的语法简单到几乎没有学习成本返回值、参数、循环和C语言几乎一样只是不关心指针和类型。写几个脚本后就会发现与其在反汇编视图里手工标注几千行不如让脚本批量完成。4.2 给当前函数打标记第一段能跑起来的 IDC第一次写IDC建议从一段“作用于当前函数”的脚本开始不要一上来就遍历整个程序。下面这段脚本会把光标所在函数的函数名和起始地址输出到Output窗口并在函数开头写入一条可重复注释。// IDC从光标所在位置找到所属函数并在函数开头加入注释 auto ea, fstart, fend, fname, cmt; ea ScreenEA(); // 取光标当前位置 fstart GetFunctionAttr(ea, FUNCATTR_START); // 函数起始地址 if (fstart BADADDR) { Message(当前地址 0x%x 不在任何函数内\n, ea); } else { fname GetFunctionName(fstart); cmt [ fname ] 待补充分析; MakeRptCmt(fstart, cmt); // 写入可重复注释 Message(函数起点 0x%x名称 %s注释写入成功\n, fstart, fname); }逻辑很直接先用ScreenEA()拿到光标地址再用GetFunctionAttr(ea, FUNCATTR_START)寻找它所属函数的起点。如果返回值是BADADDR说明当前地址不在已识别的函数里这在代码碎片区域很常见不应直接写注释只有起点有效时才用GetFunctionName取出函数名并通过MakeRptCmt落一条注释。这里选择可重复注释MakeRptCmt而不是普通注释MakeComment是因为重复注释会在所有调用该函数的位置同步显示后续追踪调用链时非常醒目。执行方式在IDA里按AltF7File - IDC File…选择脚本文件或按AltF9打开IDC Command窗口粘贴脚本再回车。执行完去反汇编视图看函数开头应该多了一行以“待补充分析”开头的注释。4.3 遍历全函数清单把黑匣子变成表格单一函数操作练熟后就可以写批量脚本。下面这段遍历当前程序所有函数把地址、函数名、长度三个字段输出到Output窗口信息量足够手动生成一份“函数地图”。// IDC遍历全程序函数输出 地址/名称/长度 auto seg, ea, end, fstart, fname, flen; for (seg FirstSeg(); seg ! BADADDR; seg NextSeg(seg)) { for (ea SegStart(seg); ea SegEnd(seg); ea NextHead(ea, SegEnd(seg))) { fstart GetFunctionAttr(ea, FUNCATTR_START); if (fstart BADADDR) continue; // 当前头项不属于函数 if (ea ! fstart) continue; // 只打印函数起始点 fname GetFunctionName(fstart); flen GetFunctionAttr(fstart, FUNCATTR_END) - fstart; Message(0x%x\t%s\t%d\n, fstart, fname, flen); } }这段代码的关键点在两层循环外层的FirstSeg/NextSeg遍历所有段内层用SegStart/SegEnd限定段范围再通过NextHead逐个向后跳转头项而不是逐字节扫描。头项是IDA数据库里的最小可寻址单元可能是指令、数据或未定义字节用它遍历比逐字节快得多。判断ea fstart是为了避免在函数中间的指令上重复打印。脚本本身不修改任何内容只读数据所以可以放心跑。如果输出里有大量长度为0或地址异常的函数可以先开Section窗口确认是不是把数据段当成代码段处理了函数列表中混进数据碎片时优先回第3章用U和C手工修边界而不是急于继续写更复杂的脚本。这一段脚本的另一层意义是它告诉我们5.0的自动化思路先定位、再判断、最后修改。定位用段扫描判断用属性接口修改用注释或改名函数。掌握这三类接口就能组合出很多批量操作。5. 避坑IDA 5.0实践中的常见问题与排查5.1 函数识别大面积失效反汇编窗口一片乱码现象加载后反汇编视图里大量地址显示为数据或者指令中间夹杂着“db 90h”之类的未定义字节函数列表里只有零散几个入口。原因最普遍的是自动分析没有跑完就被人为中断或者加载时关闭了自动分析后忘了重新分析其次是目标文件存在花指令比如在有效指令之间插入jmp 1、垃圾字节、异常序IDA 5.0的递归下降算法遇到无法解码的位置会直接放弃后续路径。解决先执行一次完整重分析在Options - Analysis里打开自动分析并重扫程序看能否自动补齐函数边界。如果重分析无效就回到被截断的位置手工处理按U取消错误定义按C强制把隐藏的有效指令转成代码必要时按P把跟随的连续指令块声明为函数。花指令密集的样本通常只能靠手工逐条修这一段没有捷径建议先把可执行段单独拉出来对照着十六进制窗口逐字节排查。5.2 栈变量和参数识别错乱函数看起来完全不像函数现象函数虽然被正确识别但反汇编里的参数和局部变量全出现在离谱的偏移位置比如[ebp-4]明明是局部变量却被当成参数或者栈帧图里出现大量负偏移。原因函数起始点选错IDA把函数头建立在了错误指令上导致它按错误的调用约定和栈帧大小推倒参数结构。另外函数使用ebp基址指针的方式不标准时比如纯esp寻址、没有标准prologue5.0也容易算错。解决先把该函数删掉方法是光标停在函数内按U撤销定义再回到正确的函数头按P重建。重建时在函数属性对话框里手动指定调用约定cdecl、stdcall还是fastcall必要时取消自动栈帧搜索。如果函数本身不保存ebp可以在函数属性中关掉“Frame pointer”假设减少对栈帧图的依赖多靠参数使用位置反推语义。碰到可疑的调用约定回溯到该函数的引用处看调用前谁压栈、谁清栈这种“由调用点反推签名”的办法比硬信自动分析可靠得多。5.3 字符串列表空荡荡明文字符串全变成乱序字节现象程序里明明有大量明文提示语但Strings窗口只有零星内容反汇编视图里指向字符串的地址显示为纯数据按A也识别不完整。原因5.0的字符串识别策略比较保守它主要识别被代码显式引用的C风格字符串对宽字符、UTF-16、非标准编码和资源段里的字符串很容易漏掉。加载时没有正确选择字符集也会让中文字符串显示成乱码。解决先在Strings窗口里打开字符串设置调整字符集和最短长度如果目标使用宽字符可以手工在可疑地址按A然后在字符串类型里选择“Unicode”让IDA把一个字一个字的宽字符串并起来。对于批量漏检的情况可以用IDC配合GetString接口在数据段里按字节扫描可打印字符区间再把发现的地址用MakeStr批量转换为字符串。类似脚本常在老游戏汉化、驱动固件分析里用到一次能恢复几百条隐藏字符串。5.4 打开新编译器产物时结构体一片空白字段全是偏移现象程序是MSVC 2015之后或Clang编译的反汇编里访问结构体成员都是[eax0x28]这种裸偏移没有字段名Local Types窗口也空空如也。原因IDA 5.0的调试信息和类型库主要覆盖那个时代的编译器。新编译器大量使用RTTI、模板、匿名命名空间PDB调试信息里的类型描述格式已经和5.0能解析的对不上。解决别指望自动恢复完整结构老老实实做两件事。第一把已知的常量偏移手动枚举出来在反汇编里看到多个0x28这种偏移时打开Structures窗口新建结构体添加成员并命名为有意义的名字第二用“Set Type”把某个地址强制指向该结构体之后IDA会在访问该结构体的位置自动显示成员名。这个过程很机械但效果扎实一次能把几十个裸偏移变成可读的字段访问是维护老版本工具链最常见的工作量来源。5.5 自动分析卡死在加载阶段脚本一跑就“假死”现象打开一个几MB到几十MB的文件时IDA像死机一样停在“Analyzing…”进度条上等多久都不结束或者写好的IDC脚本一运行就中断再也点不动界面。原因大文件里可能包含大量跳转表、递归指令或异常控制流5.0的分析算法在这些区域会陷入穷举式扫描像掉进黑匣子一样出不来。脚本里触发了对超大范围地址的读写也会让GUI线程长时间失去响应。解决加载大文件时在加载对话框里去掉Autoanalysis勾选先以纯数据形式打开之后按段逐个分析分析某个函数前先用G定位并确认边界再对局部范围进行“Analyze”避免全库重建。脚本执行前先估算循环次数尽量限制在数百个函数以内并在脚本里加一个“计数器上限”比如超过2000次就退出以防死循环。真卡死了不要反复点界面直接通过IDA的批处理模式在命令行下跑脚本导出结果趁早切断无效等待。6. 让IDA 5.0更好用的进阶三招签名、结构体与批量导出6.1 用FLIRT签名识别静态库函数IDA 5.0自带FLIRT引擎可以用sigmake工具从静态库生成签名文件。做法是准备一个.lib或.a文件以及对应的头文件运行sigmake生成.pat文件如果生成过程中出现重复模式冲突编辑.pat删除有冲突的行再经过patsort排序就能得到可加载的.sig文件。在IDA里通过File - Load File - FLIRT Signature File加载后静态库函数的调用点会直接显示出库函数名。这个技巧对分析捆绑了老版zlib、openssl的样本特别有效一次为几十个库函数集体命名。6.2 自定义结构体成员把裸偏移翻译成可读字段新建结构体不再依赖调试信息时可以把精力集中在核心结构上。打开Structures窗口按Ins新建结构逐个添加成员并指定类型和名字然后在反汇编视图中选中访问该结构体的寄存器基址按AltQ或右键选择Set Type把寄存器类型设成结构体指针*。之后同一基址的所有偏移访问都会显示字段名阅读效率能提升一截。这个做法在老版本上是标准操作核心原则是“只建真正用到的成员”不要贪多。6.3 批量导出.lst反汇编清单做最朴素的双人校验分析到一半想退出、又怕丢进展可以先用File - Produce Output File生成.lst文件把所有注释、名字、函数边界以文本形式保存下来。接下来用文本对比工具和另一台机器上用新版IDA产出的结果做差异检查能迅速发现5.0漏识别的函数和错误边界。我自己的习惯是对重要样本从不在界面里“边看边赌”一定会在节骨眼上导出一份.lst作为分析和笔录之间的过渡载体。这些年我养成的经验是版本新不代表思路新IDA 5.0能留下的原因不是它多完美而是它把“看见指令、判定边界、追问引用”这三件事教得足够费力也足够清楚。每当我在新工具里被一个“智能结果”带偏时还是会开一台装5.0的虚拟机回到原始视图中重新对齐一次目光。希望这套实践思路帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Delphi 12.3 下 ReportMachine 7.0 安装配置与报表开发实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 2:08:07
Matlab间断有限元求解声波方程:高阶格式实现与稳定计算 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 2:08:07
AXI wstrb验证实战:Synopsys VIP配置误区与排查技巧 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 2:08:07
MySQL后台注入靶场实战:从环境搭建到提权完整链路 简介:这份资源是一套存在SQL注入漏洞的网站源码,面向正在学习Web安全、需要动手复现注入攻击的初学者与进阶者,可用于本地或空间搭建靶场环境,练习后台注入的探测与利用思路。压缩包共844个文件,约4.95MB,以… · 2026/9/25 2:37:40
源师兄BH1750光照扩展完整入门:从接线到第一个积木,5分钟测出环境光照 源师兄BH1750光照扩展完整入门:从接线到第一个积木,5分钟测出环境光照 【免费下载链接】CupCode_BH1750光线模块 该模块用于测量环境光线强度 项目地址: https://gitcode.com/yuanshixiong/test
想给自己的开发板加一块能"看光"的传感器… · 2026/9/25 2:37:22
Aliens Eye递归扩展完全指南:用--recurse-depth从简介里自动挖出关联账号 Aliens Eye递归扩展完全指南:用--recurse-depth从简介里自动挖出关联账号 【免费下载链接】Aliens_eye Hunt down 840 social media accounts using AI 项目地址: https://gitcode.com/gh_mirrors/al/Aliens_eye
Aliens Eye 是一款 AI 驱动的用户名扫描工具&… · 2026/9/25 2:37:15
【Dify】腾讯云智能字幕解析应用 音视频内容的自动转写和结构化处理已成为内容管理的重要一环。腾讯云SubtitleInfo智能字幕解析工作流,面向各类音视频数据,提供了自动提取、整理字幕信息的高效方案。
本文介绍腾讯云SubtitleInfo智能字幕解析的整体流程设计、节点拆解与应用案例,重点分析如何利用自动化工… · 2026/9/25 2:37:15
【Dify】数据统计分析可视化应用 数据统计分析是理解与利用数据的基础能力,无论是商业、科研还是日常运营,数据洞察已成为必备技能。通过自动化节点协作和可视化技术,数据分析工作流不仅大大简化了操作流程,还提升了分析效率。
本文介绍一种基于自动化节点的统计分析方法,涵盖数据导入、清洗、特征工程、… · 2026/9/25 2:37:15
【Dify】诗句封面生成与语音播报应用 以AI为核心的自动化创作工具已经进入内容生产的各个领域。古诗自动生成、配套视觉封面设计、诗句语音合成等多模态创新,正成为数字内容表达的新方式。
本文介绍一种利用大模型与多种AI工具自动生成古诗、诗句封面与语音播报的完整流程,覆盖主要技术节点及实际操作方法,适合… · 2026/9/25 2:37:15
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37