资讯动态

恶意代码网络行为分析实战:从抓包到IOC提取与检测规则落地

发布时间:2026/10/19 17:03:40 来源:尧图企业网站定制
最近把《恶意代码分析实战》第14章配套的 Labs 完整过了一遍。这一章的主题是恶意代码的网络特征实验做下来比前几章都要过瘾。之前我一直把精力放在静态分析上一遇到动态抓包就有点心虚总觉得流量这东西抓是抓到了但不知道该怎么“读懂”。这次借着 Labs-14我把“会联网的样本”从头到脚扒了个干净整个过程补齐了我在网络行为分析上的很多短板。如果你正在学恶意代码分析或者在安全运营、蓝队应急里负责样本分析这章实验非常值得认真做。大部分恶意代码最终都要通过网络才能完成命令与控制、数据回传和更新所以网络侧的分析能力直接决定了你能不能把一个样本的完整行为讲清楚。走完 Labs-14你掌握的不只是某一个样本的行为更是一整套分析套路先从静态线索定位网络行为再用虚拟环境动态抓包还原网络交互最后提取 IOC 并落地成检测规则。下面我把这次实验的过程、思路和踩过的坑完整写出来。1. 先把实验环境搭成一个“小黑房”1.1 虚拟机和快照策略做网络行为分析最忌把样本放到真实生产网络里跑。我的做法是在虚拟机里搭一套完全隔离的“小黑房”。实验机用的是 Windows 7 32 位虚拟机分配了 1 核 2G 内存装完系统后不打任何真实业务补丁把所有共享文件夹、拖拽、剪贴板共享全部关掉然后打一个干净快照。为什么选 Windows 7 32 位因为第 14 章的实验样本大多是 32 位 PE 文件这类样本在 32 位系统上兼容性最好执行环境越接近样本的“预期”越容易触发完整行为。当然如果你要分析 64 位样本就得准备 64 位虚拟机但原理是一样的。快照这个动作特别重要。每跑完一个样本不管结果是好是坏一定要恢复到干净快照再跑下一个。否则前一个样本留下的注册表自启动项、服务、释放文件都会污染后一个样本的运行环境最后分析出来的结果全是脏数据。我现在养成了铁律动态分析前必须从干净快照启动分析完直接回滚绝不在同一个系统状态下连续跑两个样本。1.2 把流量收口ApateDNS 和 INetSim 的配合接着是网络侧的准备。分析主控机我用 Kali Linux开着 Wireshark 抓包。Windows 虚拟机配置静态 IP比如 192.168.1.100网关指向 Kali 的 IP 192.168.1.1。这样所有流量都会经过 KaliWireshark 抓的就是两台机器之间的完整通信。但光抓包还不够。恶意样本通常会尝试连接某个域名或 IP如果域名解析到了真实公网请求就会发到互联网上这既不可控也不安全。而且公网上的 DNS 状态、服务器响应千变万化会严重干扰分析结论。所以我一般在 Windows 虚拟机里装 ApateDNS把所有 DNS 请求固定解析到 Kali 的 IP 上。Kali 里再启动 INetSim它会模拟 HTTP、HTTPS、SMTP、FTP、DNS 等常见服务让样本误以为自己真的连上了服务器从而继续往下执行。这套组合的好处是所有请求和响应都停在内网里你可以随时返回伪造的响应内容观察样本在不同服务端反馈下的行为变化。比如你用 INetSim 返回一个空页面样本可能继续等返回一个带特定字段的页面样本可能进入下载下一步模块的流程。这种可控性是真实互联网给不了的。1.3 辅助工具别凑合除了网络工具进程和注册表行为也得盯着。我常用的辅助工具包括 Process Monitor用来记录文件、注册表、网络、进程创建事件Regshot用来对比样本运行前后的注册表变化以及 PE 查看工具比如 DIE 和 CFF Explorer用来做静态定位。这一套环境搭好之后我建议先做一个自检在 Windows 里执行 nslookup把 DNS 指向 Kali 的 IP解析一个测试域名确认 ApateDNS 能正常响应再用 curl 访问 192.168.1.1 的 80 端口确认 INetSim 的 HTTP 服务有返回。这个自检最多两分钟但能省掉后面大量“为什么样本不出流量”的排查时间。2. 静态分析拿到样本先别双击看它想联网的痕迹2.1 查壳和基础信息拿到样本后我不急着双击先把它丢进 DIE 里看一遍。Dec 或 Detect It Easy 能识别编译器、加壳器、区段信息。第 14 章的样本大部分没有加壳但有几道题会故意用 UPX 壳练手。如果入口点落在一个可执行区段或者区段名是 UPX0、UPX1说明加壳了得先脱壳再继续。为什么要先脱壳因为壳会把真正的导入表和字符串藏起来你不脱壳看到的导入函数全是壳自身的对分析没有意义。脱壳可以用工具也可以手脱但咱们做分析实验重点是行为而不是脱壳技巧所以只要能把内存里还原的 PE dump 出来就够了。基础信息里还有一个容易被忽略的点编译时间戳。虽然这个字段可以被伪造但有时候能给你提供线索。比如一个编译时间写着 2003 年的样本却用了现代 API 和加密库这本身就说明作者故意改了时间戳背后可能有反分析意识。2.2 导入表不会说谎WinINet 与 WS2_32 的预兆接下来是静态分析的重头戏打开导入表优先找网络相关的函数。这里我会分两类看一类是 WinINet / WinHTTP 系列函数比如 InternetOpen、InternetConnect、HttpOpenRequest、HttpSendRequest。出现这类函数说明样本大概率走 HTTP 协议做通信常见于下载器、C2 木马、信息窃取木马。它会把一部分行为藏进 URL 和请求头里。另一类是 WinSock / WS2_32 系列函数比如 socket、connect、send、recv、select。如果样本导入表只有这些网络函数说明它不走 HTTP而是使用自定义的 TCP 或 UDP 协议这种通信比 HTTP 更隐蔽分析难度也更高。以 Lab14-1 为例我静态看到它导入了 InternetOpenA、InternetConnectA、HttpOpenRequestA、HttpSendRequestA字符串里还有 “POST” 和 “/login.php”。到这时候基本能断定它一定会发起 HTTP POST 请求并且会有内容回传。至于回传什么就要靠动态抓包来验证。再看 Lab14-2导入表完全不同主要是一堆 socket、send、recv字符串里也没有明显的 URL。说明这个样本走的是原始 TCP 或 UDP甚至可能是 DNS 隧道。这样我在动态阶段就会重点观察非 80/443 的端口以及 DNS 请求的异常形态。2.3 字符串里藏着的“明文线索”字符串提取不用太复杂用 strings 扫一遍再过滤出 http、https、ftp、.dll、.php 这些关键字就够用了。除了 URL我还会找 User-Agent、Content-Type、User-Agent 后面的版本号以及一些看起来像加密密钥的固定字符串。这里有一个重要提醒不要因为静态字符串里没看到 URL 就认为样本不联网。有的样本会把 URL 分成多段存储在数据段里运行时再拼接也有的样本把域名做了 base64 编码或异或处理静态看起来就是乱码。所以字符串分析只能作为线索不能作为结论。我习惯把静态看到的线索列成一个表可能的协议方向HTTP 还是原始 TCP可能的目标域名或 IP可能用到的 URI 路径可疑的 User-Agent是否加壳、是否有反调试有了这个表动态阶段就有了明确的观察目标。比如看到一个可疑域名我在 Wireshark 里就会专门过滤 dns.qry.name 那个域名看到一个 POST 路径就盯着 HTTP 请求里是否有同样的路径。这个习惯能大大提升效率。3. 动态分析让流量自己说真话3.1 每次运行前的固定检查动态分析看起来简单其实最容易翻车。我现在每次运行样本前都会按固定清单走一遍把 Windows 恢复到干净快照确认静态 IP 能 ping 通 Kali在 Windows 里启动 ApateDNSDNS 指向 Kali 的 IP在 Kali 里启动 INetSim在 Kali 里启动 Wireshark过滤条件设为 ip.addr 192.168.1.100在 Windows 里启动 Process Monitor过滤进程名为样本名双击样本开始计时观察。样本运行后不要急着关掉很多恶意代码会等一段时间再发起通信。我见过有的样本延迟几分钟才开始连 C2也有的样本会在特定系统时间触发行为。所以至少要观察 2 到 3 分钟如果一直没有流量再考虑是不是有反虚拟环境或延迟逻辑。3.2 HTTP 样本的表与里Lab14-1 运行后Wireshark 很快出现了三组包DNS 查询域名解析到 192.168.1.1这是 ApateDNS 伪造的响应TCP 三次握手到 192.168.1.1 的 80 端口HTTP 请求POST /login.php HTTP/1.1Host 是那个可疑域名User-Agent 是一个伪造的浏览器标识。跟着 HTTP 流看请求体能明显看到一段十六进制数据。我把这段数据复制出来用 CyberChef 的 From Hex 解了一下发现里面包含了计算机名、用户名和部分注册表信息。也就是说这个样本首先会收集主机信息然后通过 HTTP POST 外传。到这里外传行为已经确认但网络分析不能只停在“它发了什么”。我回头对照 Process Monitor看到样本创建了一个互斥体写入了注册表 Run 键还在 Temp 目录释放了一个文件。这说明网络行为只是它整个生命周期的一环持久化和释放文件也同样重要。把网络和行为链结合起来才能对一个样本给出完整判断。3.3 DNS 隧道怎么识别Lab14-2 的过程让我印象最深。静态阶段没看到 URL动态跑起来后Wireshark 里几乎看不到 80/443 流量反而是一连串 DNS 查询。用过滤器 dns.flags.response 0 只看请求能看到类似这样的域名aa2f1.example-c2-lab.com、b3d9c.example-c2-lab.com、cf7aa.example-c2-lab.com。这种域名结构非常可疑同一个根域名、二级域名各不相同、每段子域名字符集很散、长度基本一致。正常程序的 DNS 请求不会这么规律域名更不会带这种随机字符。我把这些 qname 拼接起来去掉根域名后剩下的字符用 base32 尝试解码结果解出了一段类似指令的内容。这就是典型的 DNS 隧道数据被打进 DNS 查询的子域里传输。识别 DNS 隧道不能只看“全是有 DNS 请求”。我总结的区分要点有三个请求的域名是否集中在同一个根域名下子域名长度是否固定、字符是否随机请求频率和内容是否明显超出正常程序解析域名的需要。如果三条都满足基本可以判定是隐蔽信道。3.4 加密流量要在内存里找答案Lab14-3 则展示了另一种情况静态只有 socket、send、recv动态连接的是一个不常见的高端口 1337。Follow TCP Stream 之后载荷开头几个字节像固定标志后面跟着长度字段再往后全是看不出含义的字节。遇到这种加密或编码流量我通常的做法是回到调试器在 recv 函数返回值上下断点然后查看接收缓冲区的内容。这一步很关键网络包里看到的是密文内存里经过函数处理后的缓冲区可能就是明文。对比两者的差异就能判断它到底是简单异或、base64 变种还是用了 AES 这类强加密。Lab14-3 后来被我测出来是对每个字节异或 0x2A密钥是固定写死在程序里的。这种“玩具级”加密在真实恶意代码里也不少见尤其是很多样本作者为了省事直接用了可逆编码。分析的时候不要一看到流量不像 HTTP 就往高级加密上想先试 Magic 和最简单的基础编码往往有意外收获。3.5 时间线跟到底Procmon 和 Wireshark 对表新手容易犯一个错误只抓包不抓进程。其实流量和进程行为必须放一起看才能还原出完整攻击链。Process Monitor 的时间戳和 Wireshark 的包时间戳是可以对齐的。我会把样本进程的网络事件拉出来看它连接远程端口的时间点再和 Wireshark 里对应流的时间点比对这样能确认流量是哪个进程、哪个操作触发的。更复杂的情况是样本做了进程注入网络流量并不是从样本自己的进程发出的。这时候 Process Monitor 可能显示正常的系统进程里有外联连接比如 svchost.exe 突然多了到远程端口的连接。遇到这种情况要立刻 dump 对应进程的内存结合注入痕迹分析不然你会误判流量来源。4. 把分析结果变成检测规则4.1 提取 IOC 的一手模板动态分析结束后不能只留下“啊我看到了 C2 域名”这种模糊印象。我会把所有可观测特征整理成一张 IOC 表包括网络侧和主机侧。网络侧我会记这些域名和 IP端口和协议HTTP URI、请求方法、User-AgentDNS 查询模式比如子域长度和字符集TCP 载荷的固定标志位或前几个字节主机侧我会记这些互斥体名称注册表 Run 键或服务名释放的文件路径创建的进程名称进程注入的目标进程这张表既是报告的素材也是接下来写检测规则的输入。4.2 写一条 Snort 规则网络侧的检测规则我一般用 Snort 或 Suricata 语法。比如 Lab14-1 的 HTTP 外传行为可以快速写成下面这样alert tcp $HOME_NET any - $EXTERNAL_NET $HTTP_PORTS ( msg:Potential C2 HTTP POST - login.php; content:POST /login.php; content:Host: example-c2-lab.com; content:User-Agent: Mozilla/5.0; sid:140001; rev:1; )写规则的时候我特别强调“选稳定的特征”。域名和 URI 路径如果固定可以作为主特征User-Agent 可能会变化就不要单独用来命中而是组合使用。如果样本使用 DNS 隧道Snort 规则可以对 DNS 查询做长度和字符计数但这种规则容易误报建议先用 Zeek 或脚本离线分析确定隧道频次之后再落成签名。4.3 写一条 YARA 规则主机侧的检测主要靠 YARA 识别样本文件和释放物。YARA 可以扫字符串、导入表特征、PE 结构等。一个简单的例子rule Lab14_1_HTTPC2 { meta: author yourname description Detection for Lab14-1 HTTP C2 sample strings: $s1 POST /login.php ascii $s2 example-c2-lab.com ascii $s3 InternetOpenA ascii condition: uint16(0) 0x5A4D and all of them }注意 YARA 规则的第一个条件先用 uint16(0) 0x5A4D 判断文件是 MZ 头避免把非 PE 文件也拉进来。字符串最好选那些静态分析阶段稳定存在的不要选频繁变动的 URL 参数。这样的 YARA 规则才能用于主机扫描和样本库检索。规则写完之后最重要的一步是用干净的软件和正常流量做“负反馈验证”。我见过太多规则能抓样本但也能把王者荣耀的流量误判成恶意这种规则生产环境根本不敢用。验证的时候手头没有真实环境我就用虚拟机的正常系统更新流量做测试至少保证规则不会在日常系统里乱报。5. 常见问题与排查记录5.1 样本不产生任何网络流量这个坑出现频率最高。样本不联网的原因可能有几种样本检测到虚拟化环境直接退出或进入“休眠”状态ApateDNS 没生效域名解析失败样本的网络栈没走到发起请求那一步INetSim 没有正确模拟样本期待的服务端响应样本卡在等待状态样本内建了很长的延迟需要多等一会儿。我的排查顺序是先看 Procmon 里进程是否还活着再看 ApateDNS 的日志里有没收到解析请求再看 INetSim 的日志里有没有连接记录最后才怀疑反虚拟化。最有效的自检办法是先用正常程序验证环境比如 nslookup 设置 DNS 为 Kali 的 IPcurl 测一下 HTTP 服务确认链路畅通后再跑样本。5.2 样本检测到虚拟机就休眠怎么办有些样本会检查注册表里的虚拟机标识、硬件设备名甚至进程列表里的 vmware tools 进程。遇到这种情况先别急着硬碰硬可以先做一次常规规避关闭虚拟机里的拖拽、剪贴板共享、硬件加速把虚拟机名称改成非默认名称再把 tools 的服务停掉。很多样本的反虚拟机逻辑只做表面检查这些手段能蒙过去。如果样本用更底层的方式识别虚拟机比如比较 CPU 指令集特征那就要用调试器跟进去 patch 了。但这一章实验的重点是网络行为分析不建议在反调试上花太多时间。先把样本能不能跑出正常行为这个问题解决再回来研究它的反分析手段。5.3 Wireshark 有包但看不明白是什么当 Wireshark 里有 TCP 连接但 Follow HTTP Stream 没有解析出 HTTP 内容时十有八九是自定义协议或加密流量。这时候先看原始数据流如果载荷首字节不是 GET、POST 这类 ASCII 明文就按自定义协议处理。处理自定义协议我有一套固定流程保存原始 pcap把载荷导出成二进制文件再用 CyberChef 的 Magic 模块跑一遍看能不能识别出 base64、base32、异或等编码。如果 Magic 也识别不出来就回调试器在 recv 函数下断点直接看内存缓冲区的真实数据。这一招在对付“表面加密”的样本时非常有效。5.4 DNS 请求太多怎么区分正常和异常正常程序也会有大量 DNS 请求尤其是浏览器和系统更新进程。区分隧道流量我主要看三个统计指标请求域名数量分布是否高度集中在同一个根域名子域名长度和字符熵正常域名可读性高隧道子域名通常是无意义字符请求频率隧道为了传数据频率通常会明显高于正常解析。用 Wireshark 的 Statistics - DNS 面板可以很快看到域名列表。如果某个域名的请求数量占比异常高再结合子域名特征基本就能锁定。5.5 环境越跑越脏结果全是错的最后说一个我踩过很多次的坑贪图省事不还原快照结果前一个样本留下的自启动项和注册表键把后一个样本的触发条件给满足了分析结论毫无意义。现在我每次跑样本都从干净快照启动样本跑完不管有没有抓到流量都立刻还原。这个过程看似麻烦实际节省的时间远超浪费的时间。分析工作最怕“结论不可复现”而干净快照是复现一切的基础。最后再分享一个小技巧。第 14 章的实验做完后我把每个样本的网络行为整理成了一张固定模板表包含协议、目标地址、端口、载荷特征、关联进程。以后遇到新样本直接按这个模板填能很快建立初步印象。动态分析不是看一遍流量就完事要多跑几次每次换不同的服务端响应观察样本有没有多分支逻辑。我在做 Lab14-2 时就通过改变 INetSim 的 DNS 响应内容发现样本会根据响应长度决定是否进入下一阶段。这种隐藏在“变体行为”里的细节只抓一次包是永远发现不了的。希望这份实验记录能帮你少走点弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑