2026/10/29 7:33:39

古董级远控样本虚拟机复现与清除:注册表服务端口痕迹排查

古董级远控样本虚拟机复现与清除:注册表服务端口痕迹排查 1. 为什么一款“古董级”远控样本还值得在虚拟机里跑一遍很多人第一次看到这类上世纪九十年代末、两千年初风格的远程控制样本时第一反应是“这玩意早就该进博物馆了现在跑它有什么意义”。我最初也是这个想法直到有一次做终端侧异常行为排查的复盘发现自己在“一个陌生进程突然多出一条监听、注册表里多出一个自启动项”这种最朴素的判断上反应速度反而不如刚入行的同事。原因很简单现在的样本太“安静”了它们藏在合法进程里、走加密信道、行为碎片化你很难在一个下午里把“植入—驻留—通信—受控”这条完整链路看清楚。而那些早期的远控样本恰恰相反它把整套机制摊开摆在你面前端口明晃晃地开着注册表键值大大方方地写着服务名甚至不带伪装。用它做一次完整的复现与清除演练等于把“远程控制到底是怎么发生的”这件事从抽象概念变成可以亲手触摸的流程。这里必须先说清楚一件事这类实验只能在完全隔离、无外网、你自己拥有完全处置权的虚拟机里做。原因不是怕“技术外流”而是这类样本的设计年代太早它没有现代样本的自我保护意识一旦落到真实网络里它那套明文通信和固定端口的行为会立刻被周边设备标记同时你自己也可能在不知情的情况下让一台“被控端”长期挂在网络上。实验的目的不是“学会控制别人”而是“学会在自己负责的机器上把不该存在的东西找出来、清干净、并留下可复用的检测规则”。这个定位定下来后面所有步骤才有意义。我自己给这类实验定的规矩有三条写在这里供参考第一宿主机的共享目录、剪贴板同步、拖拽传文件全部关掉样本只能在虚拟机内部流转第二虚拟机网络只保留“仅主机”或“内部网络”模式绝不桥接绝不 NAT 到外网第三实验开始前打一个干净快照实验结束后直接回滚回滚之后再手动核对一遍关键位置。这三条看起来啰嗦但它是把“研究”和“事故”隔开的那道墙。我见过有人图省事用桥接模式做实验结果虚拟机里的被控端在局域网里被另一台机器扫到并连上虽然没造成实际损失但那次之后他把所有实验环境的网卡模式都改成了仅主机。从学习路径上看这款样本的价值集中在四个点上C/S 架构的最小实现、基于注册表与服务双通道的自启动、明文或弱混淆的命令通道、清除时容易遗漏的“第二落点”。前三点帮你理解远控的骨架第四点才是真正值钱的部分——绝大多数人清除失败不是因为不知道主文件在哪而是因为不知道样本在运行过程中还额外落地了哪些东西。这套“第二落点”的排查思路放到今天任何一个终端异常处置场景里都不过时。2. 隔离实验环境的三层防线网络、快照、宿主隔离环境这一块我不想写成“打开软件点下一步”的流水账而是说清楚每一层防线到底防的是什么你才知道哪一步可以省、哪一步绝对不能省。2.1 网络层为什么“仅主机”比“NAT”更合适虚拟机网络模式常见的有桥接、NAT、仅主机、内部网络几种。做这类实验仅主机模式是最稳妥的选择虚拟机会得到一个由虚拟网卡分配的私有地址能和宿主机通信但出不了物理网卡也进不了你所在的真实网段。NAT 模式看起来也“安全”因为外部主动连不进来但它保留了出站能力样本一旦带有外联逻辑就可能真的把数据发出去这在实验场景里是不必要的风险。内部网络模式则更彻底虚拟机之间能通、和宿主机都不通适合做“控制端与被控端分离”的双机实验。我的做法通常是这样的组合准备两台虚拟机一台作为“控制侧”一台作为“被控侧”两者都挂在同一个内部网络上宿主机只通过虚拟网卡的管理界面观察不参与通信。这样你在被控侧抓包时看到的流量就是干净的两点通信没有宿主机各种后台请求的干扰分析起来非常舒服。如果你只有一台机器那就用仅主机模式把控制侧跑在宿主机的一个隔离目录里但要注意宿主机的防火墙规则要单独确认一遍别让实验流量和你日常办公流量混在一起。这里有个容易忽略的点虚拟网卡的地址段不要和你办公网段重叠。我吃过一次亏实验用的私有段和公司访客网络撞了结果宿主机路由表里出现两条冲突条目抓包工具看到一堆不属于实验的流量排查了半天才反应过来是网段冲突。后来我固定用一段很少见的私有地址并且写进实验记录模板里省了很多事。2.2 快照层不是“打一个就行”而是“打三个”快照的正确用法不是实验前打一个、实验后回滚而是打三个干净基线快照、样本落地后快照、清除完成后快照。这三个快照对应三个不同的对照状态价值完全不一样。干净基线快照是“什么都没装”的状态它的作用是给你一份可对比的清单进程列表、服务列表、注册表自启动项、监听端口、系统目录文件列表。这份清单最好在打快照之前就导出成文本存到宿主机上因为回滚之后虚拟机里的文件也回到原点了你得有一份外部留存的“参照物”。样本落地后快照是“植入完成、尚未清除”的状态。这个快照的作用是让你可以反复回到“案发现场”做验证——比如你写了一版检测脚本想知道它能不能在这个状态下命中直接回滚到这个快照跑一遍就行不用每次重新走一遍植入流程。这个技巧在做检测规则调试时特别省时间。清除完成后快照是“你认为已经清干净了”的状态。它存在的意义是过一两天你再回头看如果发现还有残留比如某个计划任务在重启后才暴露可以从这个快照出发继续排查而不是从头再来。我一般会在这个快照上多留一天确认系统重启两次、关键目录无新增、端口无监听之后才把它合并掉。2.3 宿主隔离层共享目录、剪贴板、拖拽这三项是很多人实验时的“便利陷阱”。共享目录让你传样本很方便但它同时也是一条双向通道剪贴板同步让你复制命令很方便但它可能把你宿主机上的敏感内容带进虚拟机也可能反过来拖拽就更直接了。做这类实验时我建议把这三项全关样本通过虚拟光驱挂载 ISO 的方式传进去或者干脆在虚拟机内部用命令行生成测试用的假样本文件——很多行为观察根本不需要真实样本一个同名的空壳文件就足以让你看清自启动机制是怎么工作的。顺便说一句做这类实验的虚拟机我从来不装任何和宿主机账号相关的同步工具也不登录任何个人账号。这台机器就是一个一次性的实验台用完回滚它的存在价值只有“观察”这一件事。3. 样本落地后的痕迹地图文件、注册表、服务、端口这一节是全文最核心的部分。清除能不能做干净取决于你对“痕迹分布”有没有一张完整的图。我把这类早期远控样本的落点分成四层从上到下分别是文件层、注册表层、服务层、网络层每一层都有它自己的排查方法和容易漏掉的角落。3.1 文件层主文件之外的三个高发位置主程序文件通常在系统目录或者某个看起来“很系统”的目录下文件名往往模仿系统组件。这个大家都会找。真正容易漏的是下面三个位置第一个是临时目录下的解压/释放残留。样本在首次运行时往往会把自己复制到目标位置复制过程中可能在临时目录留下原始副本或者中间文件。这类文件在重启后不一定被清理尤其是当样本进程异常退出时。第二个是用于存放配置或日志的附属文件。远控类样本通常需要一个地方记录控制端地址、端口、连接状态。有的写在注册表里有的落一个配置文件扩展名可能伪装成 .ini、.dat、.log。这类文件体积很小用文件大小排序反而容易漏建议用“按修改时间排序 关注系统目录外的新增”这个思路去找。第三个是样本为了持久化而额外投放的“守护”组件。早期的实现方式比较朴素比如一个批处理脚本、一个用来定时检查主进程是否存活的辅助程序。这类组件名字往往很随意甚至就是随机字符它们的特征是“没有数字签名、位于用户目录或系统临时目录、创建时间和主文件接近”。排查方法我习惯用两条线交叉一条是“按时间”把系统盘的修改时间排序筛出实验时间窗口内的新增文件另一条是“按位置”重点扫系统目录、用户目录下的隐藏文件夹、临时目录、启动目录。两条线的交集基本就是重点怀疑对象。Windows 自带的命令行工具就能做这件事不必上重型工具下面这段是我常用的思路示意PowerShell仅用于展示筛选逻辑# 按修改时间筛出实验窗口内的文件示意时间范围按实际情况调整 Get-ChildItem -Path C:\ -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-3) } | Select-Object FullName, Length, LastWriteTime | Sort-Object LastWriteTime -Descending | Export-Csv -Path C:\temp\recent_files.csv -NoTypeInformation这段脚本跑起来会比较慢实际用的时候建议限定目录范围比如只扫系统目录和用户目录。另外注意导出结果要存到虚拟机外部或者一个你确认干净的路径别把结果文件本身也混进待排查清单里。3.2 注册表层自启动的四个常见键位注册表自启动是这类样本最经典的驻留方式。大家熟知的是 Run 键但只查 Run 是不够的。我把常见键位整理成一张表排查时逐个过一遍键位路径作用排查要点HKLM\Software\Microsoft\Windows\CurrentVersion\Run全局自启动关注指向系统目录外、无签名、带参数的可疑项HKCU\Software\Microsoft\Windows\CurrentVersion\Run当前用户自启动隐蔽性更高容易被忽略HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce一次性自启动执行后自动删除事后排查看不到需在实验时实时记录HKLM\System\CurrentControlSet\Services服务注册见下一节重点看 ImagePath 与启动类型RunOnce 这个位置特别值得说一句它的设计意图是“执行一次就删掉”所以事后回看注册表往往是干净的你会在清除阶段误以为没有这一项。要抓到它必须在样本首次运行之前就开着注册表监控或者用进程监控工具记录注册表写入事件。这也是我建议“先开监控再跑样本”的原因顺序反了很多瞬时行为就看不到了。除了自启动键位还有两个位置经常被用来做“辅助驻留”一个是文件关联相关的键样本可能把自己挂到某个常见扩展名的打开方式上另一个是浏览器辅助对象或者外壳扩展相关的键。这两个位置在老样本里不算高频但一旦命中清除时非常容易漏因为它不在你习惯的自启动清单里。3.3 服务层为什么“服务”比“Run 键”更难清服务方式的驻留比 Run 键更难处理原因有三第一服务可以在系统启动早期就运行不依赖用户登录第二服务有独立的注册表子树包含显示名、描述、可执行路径、依赖关系、失败恢复动作等多个字段改一个字段就可能让服务“看起来正常但实际不工作”第三服务被删除后如果对应的可执行文件还在某些情况下会被重新注册。排查服务我一般看四个字段ImagePath指向的路径是否合理、Start的值是什么自动、手动、禁用、DisplayName和Description是不是伪装成系统组件的名字、ObjectName用的是不是 LocalSystem 这种高权限账户。用sc query和sc qc可以快速看一个服务的配置用注册表编辑器可以直接定位到HKLM\SYSTEM\CurrentControlSet\Services\服务名看全貌。# 列出所有服务及其可执行路径便于人工筛查异常路径 sc query type service state all sc qc 服务名需要提醒的是清除服务不要只删注册表键正确顺序是先用sc delete删除服务注册再删可执行文件最后重启验证。反过来做的话文件被占用删不掉你会以为清除失败其实是顺序问题。3.4 网络层监听端口的“合理性”判断远控样本必然要有通信通道最朴素的做法就是监听一个固定端口等控制端连进来。排查监听端口netstat -ano是最快的入口关键是学会判断“这个监听合理不合理”。判断标准我总结成三条端口号是否符合该进程的身份、监听地址是 0.0.0.0 还是 127.0.0.1、进程路径是否在系统目录之外。比如一个位于用户临时目录、名字随机、监听 0.0.0.0 上某个高位端口的进程基本可以直接列为重点怀疑对象。反过来一个位于系统目录、有签名的服务监听本机回环地址就属于正常范畴。netstat -ano | findstr LISTENING tasklist /fi pid eq PID这两条命令配合起来能把“端口—进程—路径”这条链打通。如果你的环境里有抓包工具建议在样本运行期间开着把通信过程录下来后面分析协议时用得上。4. 抓包与进程视角看清 C/S 通信的真实样子4.1 抓包能看到什么看不到什么在隔离网络里抓包你能看到的是连接建立的三次握手、双方的地址和端口、数据包的长度分布、发送的时间间隔、载荷是否可读。对于这类早期样本载荷往往是明文或者极弱的混淆你能直接在包里看到命令字符串、目录列表、甚至文件内容片段。这种“看得见”的体验对建立直觉非常有帮助——你会真切地理解“远程控制”本质上就是一条长连接加上一套约定的命令格式。但抓包也有看不到的东西你看不到控制端的界面长什么样看不到命令是怎么被解析执行的看不到文件是怎么被写到磁盘上的。这些要靠进程监控和文件系统监控来补。我的习惯是“三件套同时开”抓包看通道、进程监控看行为、文件监控看落地。三者时间轴对齐一条完整的行为链就出来了。4.2 进程视角父进程、子进程与命令行参数观察进程重点不是“有没有可疑进程”而是“这个进程是谁拉起来的、带了什么参数、又拉起了谁”。远控样本被植入后通常由服务或者自启动项拉起所以它的父进程往往是services.exe或者explorer.exe而不是你手动点击的那个 shell。这个特征本身就是一条很好的检测规则。命令行参数也值得看。有的样本会带一个参数用来指定配置文件路径或者控制端地址这个参数在进程列表里是可见的。如果你在进程命令行里看到一串看起来像 IP 加端口的东西基本可以确认通信目标。命令行的查看方式任务管理器的“命令行”列就够用想看更细的可以用系统自带的工具查询Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, Name, CommandLine | Sort-Object ParentProcessId按父进程 ID 排序之后一棵进程树就出来了哪个进程是“孤儿”、哪个进程的父进程对不上号一眼就能看出来。4.3 把行为和流量对上号这一步是整个实验里最有价值的部分。你需要在时间轴上做三件事的对照某个时刻抓到了什么包、同一时刻哪个进程在活动、同一时刻磁盘上多了什么文件。对齐之后你会发现很多有意思的细节比如连接建立的那一刻进程会去读一次配置文件收到某个命令后进程会创建一个临时文件断开重连的间隔是固定的几十秒。这些细节就是检测规则的原料。比如“某进程在启动后 5 秒内必然发起一次外连”这种行为模式比单纯的“文件名黑名单”稳健得多。我做完这类实验之后通常会写下三到五条这样的行为特征存到自己的笔记里下次遇到类似场景直接拿来用。5. 完整清除链路从排查到验证的六步闭环清除这件事最怕的是“看着清干净了其实还留了个尾巴”。我把流程拆成六步每一步都有明确的输入和输出照着走基本不会漏。5.1 第一步冻结现场先取证再动手发现异常之后第一反应不要是“赶紧删”。先做三件事导出当前进程列表、导出当前服务列表、导出当前监听端口列表。这三份清单是后续验证的基准删完之后要拿它们对照。如果有条件把可疑文件复制一份到隔离目录留作样本别直接删——万一后面发现还有第二落点你手里得有原件做比对。取证的时候注意一点不要用会修改文件访问时间的工具去读文件。某些场景下文件时间戳本身就是线索你读一遍反而把线索破坏了。如果确实需要读内容先复制再读副本。5.2 第二步切断通道先断网再清进程清除顺序上我建议先切断通信通道再处理进程。原因很实际如果先杀进程样本的守护组件可能会把它重新拉起来你会陷入“杀了又起”的循环。切断通道的方式有两种一种是把虚拟网卡禁用另一种是在防火墙上临时加一条阻断规则。虚拟机环境里直接禁用网卡最简单。通道断了之后再结束进程。结束进程要用能拿到完整进程树的方式把子进程一起处理掉避免出现“主进程死了、子进程还在监听”的情况。5.3 第三步清自启动四个键位加服务一起过这一步要把前面表格里的四个注册表键位全部过一遍同时把服务清掉。顺序上先删服务注册再删文件前面说过原因。删注册表键之前把键值内容完整记录下来包括键名、值名、值数据这些是后面写检测规则的素材。有一个细节值得注意有些样本会在多个位置同时注册自启动形成“互为备份”。你删了 Run 键服务还在删了服务RunOnce 里可能还有一个待执行的项。所以这一步不能只查一个位置就收工必须四个键位加服务全部确认一遍。5.4 第四步清文件重点扫“第二落点”文件清除不要只删主程序。按前面说的三个高发位置逐个扫临时目录、配置文件可能的落地目录、守护组件可能的所在目录。扫的时候用“修改时间窗口 目录白名单”的方式别用全盘搜索太慢且噪音大。删完之后把第一步导出的文件清单拿出来对照确认所有新增项都已处理。这一步我一般会做成一个小脚本把“实验前基线清单”和“当前清单”做差集差集里剩下的就是漏网的。这个思路比人工一个个看靠谱得多。5.5 第五步重启验证看它会不会“复活”重启是清除流程里最容易被跳过、但最重要的一步。很多驻留机制只有在重启后才会暴露比如某个一次性自启动项、某个延迟加载的服务、某个计划任务。重启之后重新导出进程、服务、端口三份清单和第一步的基线清单对比。判断标准是新增项为零且原基线项全部存在。如果出现新增项说明还有没清干净的东西回到第三步重新过一遍。如果基线项少了说明你误删了系统组件需要从快照恢复或者用系统修复工具补回来。5.6 第六步二次重启加观察期一次重启不够我一般会做两次重启中间间隔一段时间。原因是有些驻留机制带有延迟触发逻辑第一次重启时条件不满足第二次才触发。两次重启之后再观察一段时间看有没有异常的网络连接尝试、有没有新的文件落地。整个流程走完如果你想让这次实验的价值最大化建议把每一步的操作记录整理成一份“清除检查单”下次遇到类似情况直接照着走。检查单的价值不在于步骤本身而在于它帮你避免了“凭记忆操作”带来的遗漏。6. 把这套经验翻译成防御规则实验做完如果只停留在“我清掉了”这个层面价值就浪费了一半。真正有用的是把观察到的行为翻译成可复用的检测规则。我通常从三个维度来写。6.1 基于路径与签名的静态规则最基础的一层是路径规则系统目录之外的可执行文件、用户临时目录下的可执行文件、启动目录下的非预期文件这几类可以直接列为关注对象。加上签名维度会更准无签名 位于用户目录 有自启动项这三个条件同时满足时告警优先级可以提高。静态规则的局限也很明显容易误伤也容易被绕过。所以它只能作为第一层过滤不能作为唯一依据。6.2 基于行为链的动态规则这一层价值更高。典型的行为链是某进程创建后短时间内注册服务或写入自启动键 → 随后发起对外连接 → 连接目标为内网地址或固定端口。把这条链拆成三个可观测点任何一个点命中都记录两个点同时命中就告警。这种规则比单点规则稳得多因为它描述的是“行为模式”而不是“文件特征”。我在实际环境里用过类似的思路效果比纯黑名单好很多。代价是需要有进程创建、注册表写入、网络连接这三类日志的采集能力对日志基础设施有一定要求。6.3 基于资产基线的差异规则这一层的思路是“和已知的干净状态比”。每台机器维护一份基线正常的自启动项、正常的服务列表、正常的监听端口。定期做差集差异项进入人工复核队列。这个方法的优点是覆盖面广任何新增的驻留方式都会被捕获缺点是需要维护基线且系统更新会带来大量正常差异需要做好白名单。三層规则配合起来基本能覆盖大部分场景。我的建议是先从静态规则起步跑一段时间积累误报样本再逐步过渡到行为规则最后用基线差异做兜底。一步到位往往不现实也很容易因为误报太多而被弃用。7. 几个实操里反复踩到的坑第一个坑是监控开启顺序。很多人是先跑样本、再开监控结果最关键的“首次运行行为”全丢了。正确的顺序是监控全开 → 打快照 → 跑样本 → 记录 → 停止。顺序错了你看到的只是“稳态”看不到“落地过程”而清除时最需要的信息恰恰在落地过程里。第二个坑是只清主文件不清配置。配置里存着控制端地址和端口主文件删了、配置还在某些实现会在下次启动时根据配置重新拉取组件。所以配置文件的排查要和主文件同等重视别因为它小就忽略。第三个坑是服务删除顺序反了。前面提过先删文件后删服务文件被占用删不掉你会误判为清除失败。正确顺序是先停服务、再删服务注册、最后删文件。第四个坑是快照回滚后忘了核对。回滚不等于干净回滚只保证“回到某个时间点”如果那个时间点本身就已经被污染比如你在打快照之前不小心跑了一次样本回滚之后依然是脏的。所以每次回滚后要重新核对三份清单确认和基线一致再继续。第五个坑是在真实设备上做“验证”。有些人为了确认样本能不能被检测到会把它放到一台真实的办公机上试一下。这个做法风险极高完全没有必要。检测规则的验证完全可以在隔离环境里完成把规则逻辑跑通、误报率测出来就够了不需要真实环境。最后一个体会这类实验真正的产出不是“我复现成功了”而是“我形成了一套可复用的排查顺序和检查单”。样本会过时工具会换代但“先取证、再断链、后清除、必验证”这个顺序以及“文件、注册表、服务、端口四层痕迹”这个观察框架放到今天依然是终端异常处置的基本盘。我自己后来处理过几次完全不同类型的终端异常靠的都是这套框架而不是某个具体工具的命令参数。