资讯详情

Natas幽灵王病毒汇编级分析:从壳到入口点完整拆解

📅 2026/10/17 5:51:06 | 华诺云谱 👁 阅读
Natas幽灵王病毒汇编级分析:从壳到入口点完整拆解
我整理老样本库时碰到的这个 Natas 幽灵王病毒其实是某套汇编教程里第 105 讲的案例但你别小看它把它从壳到入口点完整拆一遍基本上能把汇编语言里跟 PE 结构、反调试、解密循环相关的知识点全串起来。这类感染型病毒不像远程控制木马那样喜欢挂一堆花指令它的代码逻辑很集中特别适合用来做汇编级分析训练。这篇文章我不想讲太虚的东西就直接以这个样本为主角从头到尾说清楚我是怎么从汇编指令层一步步确认它的执行流程、感染方式和修复思路。如果你对 PE 文件结构有基本了解又恰好想知道恶意样本分析到底从哪下手这篇文章应该能给你一条比较顺的路径。1. 样本速览与“为什么非看不可”1.1 幽灵王到底是什么样的样本从文件名和内部字符串来看这个样本在病毒库里的代号是 Natas中文社区习惯叫它“幽灵王”。它属于比较典型的老式文件感染型病毒目标优先选择同目录或指定目录下的 32 位 PE 可执行文件。整体体积不大几十 KB 左右但加了一层自定义壳主程序代码在运行前会先经过一段解密例程所以直接看静态缓冲区的汇编指令会看到一堆乱码必须先定位解密循环。它的爆发逻辑并不复杂一旦被运行它会在当前目录和几个常见路径下扫描可执行文件找到没有被它标记过的 PE 文件以后把自己附加到文件的空白区或者新增一个节里同时保存并修改原始入口点把执行流程改成先去执行病毒代码等病毒逻辑跑完后再跳回原始入口点继续运行正常程序。这么做的好处很明显——宿主程序看起来能正常打开用户根本不会意识到出了问题但病毒已经完成了自我复制。这种感染方式放到几十年前可能很有效放到现在反而是最好的教学样本。因为它的代码结构清晰、感染流程固定没有太多网络对抗和复杂的反调试逻辑非常适合拿来做汇编级源码解读。特别是对你理解“入口点覆盖”“PE 节表扩展”这类概念比看一百页文档都直观。1.2 分析它需要哪些汇编底子给你一个比较实际的结论不需要你成为汇编高手但有四个知识点必须掌握否则后面查代码会很痛苦。第一是寄存器的作用。至少要知道 EAX 通常被当作累加器、ECX 常用于循环计数、ESI 和 EDI 经常被当作源和目的地址、EBP 和 ESP 跟栈帧有关。幽灵王病毒的解密循环里大量用到 ESI 和 ECX如果你对这几个寄存器的职责不敏感看一小段就会迷路。第二是栈与调用约定。病毒代码里频繁调用系统 API它压参数的方式是 stdcall 还是 cdecl决定了你追踪参数时该看栈顶还是栈底。好在样本里的调用都是比较标准的 stdcall参数从右往左压栈被调用方负责平衡栈所以重点盯住 ESP 的变化就够了。第三是常见指令的组合逻辑。MOV、LEA、XOR、TEST、CMP、JMP、CALL、LOOP这八个指令就覆盖了它 70% 以上的操作。特别是 XOR很多壳和加密循环都用它做数据和单字节密钥的异或运算我在后面章节里会展开讲。第四是 PE 文件结构的基本认知。你不用背完整结构但至少要知道 DOS 头、NT 头、节表、AddressOfEntryPoint 这几个字段在哪。因为感染型病毒的本质就是改 PE 结构你只有先把结构顺序搞清楚才能在入口点变化时一眼看出异常。如果你这四个底子基本具备那这份分析你可以直接上手。如果还差一点建议先把这几个概念翻出来过一遍不然跟着走的时候会频繁卡壳。2. 静态分析先用汇编视角确认目标2.1 先做“壳”识别再看入口点我拿到这个样本后的第一步不是直接扔进调试器而是先做静态识别。原因很简单——动态调试工具只能告诉你程序当前在干什么却不能直接告诉你它为什么这么干。对一个有壳的样本直接下断点你只会看到一段段莫名的 push、pop 和跳转很容易被带偏。这个阶段的工具不需要多高级我习惯用查壳工具配合十六进制编辑器一起看。先用常见的查壳工具跑一遍确认这个样本有没有已知的壳特征。幽灵王样本给出的结果比较模糊既有可能是未知壳又有可能只是普通程序被混淆过。这时候就需要用十六进制编辑器手工确认。我照着 PE 头定位到节表发现了一个奇怪的现象默认的节区名称不是常见的.text、.data这类而是一串看似随机的名字最后一个节的 RawSize 明显比 VirtualSize 大很多。这说明节表里被人动过手脚通常是为了容纳解密后的代码或者附加病毒数据。看到这里基本可以判断样本外层有一层自写的封装壳必须先找到壳的入口才能看到真正的病毒主体。明确了这一点以后我再看 PE 头里的 AddressOfEntryPoint。它指向的位置不在任何一个正常节的起始范围附近而是指向了一个节区的中后段。你可以这么理解——正常程序入口一般位于.text节开头附近像一个住宅楼的大门这个样本的入口却指向电梯井里的某个夹层摆明了就是一个暗门。你初步判断这几点以后静态分析的“目标画像”就算完成了。2.2 用“三个关键窗口”快速熟悉文件结构静态分析不像动态分析你没法用断点去感知程序的运行节奏所以得靠三个“窗口”来建立整体认知。第一个窗口是反汇编窗口。用反汇编器打开样本后先把 CPU 视角切到入口点地址观察从这里开始的指令序列。如果有大量形如push ebp; mov ebp, esp; sub esp, xx的栈帧代码说明这段代码是用高级语言编译器生成的普通函数如果看到很多没有逻辑的跳转和连续push操作就得怀疑是壳在混淆。幽灵王样本从入口点开始的一段就是典型的壳代码它会先把壳所在的内存区域解密再跳转到真正的病毒主模块。第二个窗口是导入表窗口。查看样本导入的函数列表关注它导入了哪些系统 DLL 的哪些函数。这个样本的导入表非常有意思它没有直接导入文件操作相关的函数而是只导入了 LoadLibraryA 和 GetProcAddress 两个动态加载函数。这就说明它很可能是先画出最小导入集再在运行过程中用动态方式加载真正需要的 API。这种做法的目的是增加静态分析的难度让你在导入表里找不到病毒真正调用的文件函数。第三个窗口是字符串窗口。把样本里的 ASCII 和 Unicode 字符串都提取出来你会看到很多像文件路径、特定扩展名、错误提示之类的内容。幽灵王样本里能明显看到一些类似“感染标记”的字符串通常是病毒用来判断目标文件是否已经被感染的特征码。只要把这三个窗口的信息交叉比对基本上就能还原出样本的总体框架了。2.3 定位真实入口从哪里切入最省力很多人静态分析失败是因为错误地选择了切入位置。面对这种带壳样本你不能从入口点一路单步到天亮正确做法是先通过节表信息找到壳的尾部也就是壳解密完以后跳转的位置。这种跳转在汇编里通常表现为一个间接跳转比如jmp eax或者call [ebxoffset]因为它要跳到的地址是在程序运行过程中算出来的。我的做法是先在反汇编器里做一遍模拟执行看看壳代码有没有可能被脚本自动还原。如果不行就手动跟踪跳转目标寄存器。幽灵王这个样本的壳比较简单它最后一个步骤是把解密后的地址放入 EDI然后执行jmp edi。所以在静态阶段我只需要定位到这条指令就能确定真正的病毒代码区域大概是在哪个节哪一段。确定真实入口后再重新加载反汇编器强制把起始地址设置为这个位置文字注释和函数识别会立刻清晰很多病毒的主逻辑也就暴露出来了。这一步相当于绕开了壳的干扰直接拿到了内部代码的执行入口后续分析效率会成倍提高。3. 汇编级代码拆解与关键算法3.1 解码循环怎么看进入病毒主体以后最先映入眼帘的往往是一个大循环这个循环本质上是把加密后存放在数据节里的内容逐字节还原。幽灵王病毒的解码循环非常典型大致结构是这个样子loop_start: mov al, byte ptr [esi] xor al, 0x56 rol al, 3 mov byte ptr [edi], al inc esi inc edi dec ecx jnz loop_start这个循环的格式很标准ESI 指向加密数据源EDI 指向解密后的目标缓冲区ECX 是总字节数。它先取当前字节做一次异或运算再做一次循环左移完成后写入新地址。你可以把它想象成一道两道手续的密码锁每次取出一个字符转一下锁盘再擦掉重写。分析这种循环的时候千万不要急着记下密文和密钥重点要搞清楚三件事循环长度多少也就是 ECX 的初始值解密后的缓冲区指向哪里也就是 EDI 的最终地址以及解密完以后控制流去了哪里。因为你最终的目的是找到它把这个解密完的数据交给谁而不是复现它的解密过程。实际分析时我会在解密循环结束后第一条指令处设一个内存断点看数据被写到哪个区域。幽灵王样本在解密完成以后会构造一个函数指针并调用它这块解密出来的区域基本就是病毒真正干活的核心模块。你把核心模块从内存里 dump 出来再单独分析会比直接分析原始文件轻松得多。3.2 感染逻辑的调用顺序核心模块里最值得分析的是它的文件感染子程序。这段程序的汇编代码并不算长但逻辑层次分明。一般来说它会按以下顺序执行调用FindFirstFileA/FindNextFileA遍历目标目录找出后缀为.exe的候选文件。对每个候选文件读取它的 PE 头检查是不是合法 PE 格式。检查文件头部或者节表里有没有特定的感染标记如果已经有标记就跳过。如果没被感染过就打开文件把自己加载到内存映射里。修改节表和入口点把原始入口点记录下来。关闭文件继续遍历下一个文件。从汇编指令来看这个顺序会反映在一串call指令和分支跳转上。你不需要挨个函数研究最省事的方法是把导入表里动态加载的函数调用点全部标出来然后看每个调用点附近的参数。比如调用WriteFile之前它一定会先压入文件句柄和写入长度参数。你按照这个线索去逆推就能知道它是往哪个文件、哪段数据、写入了多少内容。整个过程最需要注意的地方是检查感染标记这一段。很多分析者容易忽略它但它恰恰是修复合修复的关键。看到感染标记以后要记录下它的偏移量和长度因为这意味着修复受感染文件时你可以根据这个标记判断文件是否被处理过以及原始入口点信息大概存在哪个结构里。3.3 反分析特征怎么判断这个样本虽然技术不算特别高明但在对抗分析师的细节上还是动了不少脑筋。比如它会用动态加载的方式调用CreateFileA和WriteFile而不是直接出现在导入表里。这会让只懂看导入表的新手误判它没有文件操作能力但一旦你把它的程序逻辑完整串起来就会发现它其实在频繁调用这些 API。另外还有一个非常典型的特征——它把关键字符串分段保存在不同区域用的时候临时拼接。比如“Path”和“FindFirstFileA”这些词不会完整地出现在数据段里而是被拆成几段在运行时按需组装。这种做法的目的在于绕过字符串扫描让你的静态字符串列表变脏看不到完整的关键信息。还有一段花指令出现在感染子程序的入口附近正常函数会先建立栈帧但它会在前面插入几个看似没有意义的 MOV 和 JMP让反汇编器的线性扫描算法迷失方向。应对这种手段我的习惯做法是直接看跳转关系因为真实代码最终一定会通过绝对跳转或者条件跳转连接起来。你只要把跳转箭头都打开花指令区域的“假指令”就会现出原形。反分析特征不是洪水猛兽本质上就是让人多绕几个弯你没必要焦虑按部就班地顺藤摸瓜就好。4. 动态验证与行为核实4.1 在虚拟机里调试要注意的前提静态分析做到一定阶段以后就要开始动态验证了。这步有个大前提——必须在隔离环境里做。我通常会准备一台专门的虚拟机快照设在干净状态所有网络共享和剪贴板共享都关掉模拟目标系统设置为老一点的 Windows 版本因为这类老样本对高版本系统的 API 兼容性并不好。跑动态调试之前我还会把静态阶段分析出的关键地址列表提前记好。比如解密循环结束后的跳转地址、感染标记字符串所在的内存地址、动态调用的 API 地址。等调试器跑起来以后我会在这些地址先设好断点让程序一开始就往这些位置走节省不必要的单步时间。必须提醒一句感染型病毒在虚拟机里运行它可不会只感染一个文件。它一旦跑起来就会在当前目录和系统目录里乱翻所以调试之前文件夹里只放几个无价值的测试文件避免宿主测试程序被反复感染导致环境变得一团糟。我见过有人直接在安装了完整开发环境的虚拟机里调试结果整个目录里所有 exe 全被感染最后环境只能重建。4.2 断点战术等待“新模块”接管动态调试这种带壳样本我的核心战术是“等新模块”。因为在壳解密完成以前病毒主体并没有出现在内存里你很难跟踪到有效的代码路径。与其在壳里挣扎不如让程序跑起来然后在关键转换点设断点。具体操作上我会在 LoadLibraryA 和 GetProcAddress 两个函数上设置断点。因为幽灵王病毒需要动态加载大量 API每次加载时调试器就会停下来我就能看到它正在准备调用哪个函数、参数是什么反向推断它下一步要做什么。这个方法的妙处在于你不需要去手动定位解密完的代码所有隐藏的函数调用都会自己送上门来。等运行到它第一次调用WriteFile的时候基本就能确认它已经开始感染文件了。此时我会检查当前进程打开的文件句柄和写入缓冲区对照静态分析时记录的感染标记确认我刚才的判断是否准确。如果两者吻合说明这段感染逻辑的静态分析没有跑偏。4.3 行为对照表静态推测 vs 动态实况动态分析的价值在于验证而不是替代静态分析。我建议你建一张简单的对照表把静态阶段每个推测记下来再和动态阶段的观察结果做对比。拿这个样本举例我在静态阶段推测它会遍历当前目录下的 exe 文件动态阶段就观察到它在当前目录下创建了文件快照并逐一读取静态阶段判断它会检查感染标记动态阶段就往测试文件头部特定偏移处写入了标记字符串。两边一比分析结论的正确率就能立刻确认。如果出现静态和动态不一致的情况比如静态推测它跳到了某个地址但动态阶段发现那个地址是一条无效指令那就说明有地方分析错了。常见原因有壳解密长度搞错、感染逻辑里存在多分支、或者原始入口点被做了多层跳转包装。遇到这种情况别硬撑回到反汇编器里重新过一遍跳转关系往往会更快。5. 感染识别与手动修复5.1 从 PE 视角识别被感染文件分析完病毒的感染逻辑以后你最大的收获其实是能够准确识别哪些文件被它感染过。这类感染型病毒因为要附加代码或者新增节必然会在 PE 结构上留下痕迹。第一个识别特征是入口点异常。正常可执行文件的入口点应该在可执行节区的上半段附近而被感染文件的入口点往往指向一个非常靠后的偏移甚至落在一个名称异常的节里。第二个特征是节表里存在多余节不常见名称且 RawSize 和 VirtualSize 相差悬殊因为病毒需要把实际数据填进去。第三个特征是在文件末尾能看到明显追加的一块数据这段区域通常就是病毒代码或者感染标记。你还可以直接从十六进制数据里搜索感染标记字符串一般病毒设计者都会把它做得比较独特保证不会和正常程序内容混淆。一旦在文件里搜索到该标记基本可以宣告这个文件已经被处理过。这个判定方法对企业内部的应急响应非常实用因为你可以写一个简单脚本批量扫描整个服务器目录而不是靠人工逐个检查。5.2 手动修复流程的思路与限制聊到修复我得先泼一盆冷水手动修复感染文件不是每个人都能直接上手因为需要比较扎实的 PE 结构知识而且对新手来说改错哪怕一个字节都可能导致文件直接损坏无法运行。如果你只是想恢复一台机器的正常运行唯一的办法是重新安装软件或者从干净备份恢复文件。但如果你确实想练手修复我可以简单讲一下流程。第一步用十六进制编辑器打开被感染文件找到节表中新增的那个异常节记录它的尺寸和偏移。第二步搜索感染标记在附近寻找原始入口点字段。很多感染型病毒会把原始入口点保存在一个固定偏移处找到这个值以后把它写回到 PE 头里的 AddressOfEntryPoint 字段。第三步把新增节从节表中删除并把节数量字段改回原来的值。第四步保存文件再用 PE 查看器重新检查一遍确认入口点和节表都恢复正常。这里有一个很关键的心态要摆正修复操作本质上是一种外科手术而病毒运行时对文件的改动是不可逆的稍微处理不好会造成二次伤害。所以我建议所有想练手的人先在副本上反复实验不要一上来就动原文件更不要拿重要文件当测试对象。5.3 组织层面的应急防御思路处理完单个样本以后我更关心的是怎么防止它在团队环境里扩散。这款病毒靠文件共享和可移动介质传播所以最直接的防御就是限制可执行文件在网络共享目录中被大量存放和双击运行。把共享目录里的 exe 文件权限收紧日常只允许读取不允许执行就能阻断大部分传播路径。部署杀毒软件的时候也要注意不是装完就完事。感染型病毒往往有多个变种特征码可能随时变化所以最好同时开启文件实时监控和启发式检测。同时应急预案里要加入批量扫描脚本第一时间把所有共享盘和本地盘扫一遍把所有命中感染标记的文件隔离出来。我见过很多企业在遭遇这类样本时最耽搁时间的不是查杀本身而是排查范围不全。有人清了当前磁盘结果漏掉了移动硬盘里的备份第二天又中了一遍。所以清理过后一定要做全网范围的二次扫描确保所有接进来的存储设备都被扫过才能算是真正的应急闭环。6. 实操心得与高频错误汇总6.1 初学者最常见的四个翻车点聊了这么多技术细节最后我想把实战里踩过的坑集中整理一下基本都是初学汇编病毒分析时最容易翻车的点每一条我都有切身体会。第一一上来就单步跟踪而不做静态规划。幽灵王这种样本还好如果你直接单步走它那几十步解密循环很浪费时间而且容易迷失。正确顺序永远是先静态分析确定关键地址再动态验证。第二看到壳就慌一门心思去脱壳。其实很多壳你不需要手动脱你只需要知道它解密完以后跳到哪就行。我的经验是判断“控制流去哪”比“数据怎么解”更重要尤其对于这种老式样本来说跳转目标地址才是关键路径。第三忽略文件的熵值和尾部数据。很多分析师看入口点没问题就认为文件是干净的可这类感染型病毒有时候并不会修改入口点而是通过其他方式劫持流程。所以你扫描时不仅要看入口点还要看节表有没有奇怪的多余节和明显的文件尾部追加数据。第四动态调试忘记关中断优先级。某些反调试代码很擅长利用调试器的单步异常机制来干扰你提醒你陷入断点地狱的时候先别怀疑自己回头检查一下哪些异常被设置成了无条件中断把非必要的异常全部忽略掉调试体验会好非常多。6.2 从这次分析里沉淀出的逆向习惯最后再分享一个小习惯是这次分析以后我一直保留的。面对任何未知样本我会先在一张纸上画出它的“生命周期图”样本启动 → 壳解密 → 跳转到真实模块 → 动态加载 API → 搜索目标 → 执行感染 → 返回原始入口点。这张图一旦画出来你的分析就有了坐标所有后续工作都围绕这张图去验证和补全。另一个习惯是把分析过程中每一个关键跳转地址都记录下来无论是壳的跳板地址、真实模块入口、还是调用系统 API 的 call 目标。等后面需要动态验证时这些地址就是你的断点地图能让你在调试器里始终占领先机。这类的老式感染型病毒在今天的真实网络里已经不算主流威胁但作为汇编语言和 PE 结构的学习载体它依然是很好的素材。每次重新复盘我都还能从里头找到一些之前没注意到的细节而这份细抠代码的耐心恰恰是逆向工作里最不能丢的东西。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑