☰
恶意代码分析实战:课后练习实验文件从静态到动态的完整分析流程
2026/10/13 11:28:57 网站建设 项目流程

简介:这份资源是《恶意代码分析实战》一书的课后练习配套实验文件,面向正在学习逆向工程与恶意代码分析的安全从业者、CTF选手及高校学生,帮助读者在阅读理论章节后动手完成书中各章实验,解决缺少真实样本、无法复现分析流程的问题。压缩包共74个文件,约973KB,以52个exe可执行样本和11个dll动态链接库为主,另含2个sys驱动、2个py脚本、2个bin二进制文件,以及pdf、dat、csv、txt、ini等辅助说明与哈希校验文件,覆盖从基础静态分析到高级动态调试的多种样本类型。内容按章节组织,涵盖多个实验模块,并附有哈希清单便于核对样本完整性。目前已有812人学习下载,适合希望系统练习PE结构解析、加壳识别、行为监控与反混淆技术的读者,可作为课程实验或自学演练的完整素材。

1. 恶意代码分析实战:课后练习实验文件到底能帮你练什么

很多人学恶意代码分析卡在一个尴尬的地方:书看了,工具装了,真扔给你一个样本,手是抖的。PE 头从哪看、导入表哪个函数可疑、字符串里哪些是噪音、动态跑起来该盯注册表还是文件系统,脑子里没有一条固定的流水线。这套课后练习实验文件解决的就是这个问题——它把「看什么、按什么顺序看、看到什么算异常」拆成了可以反复练的靶子,而不是让你对着一个真实样本从零硬啃。

它适合三类人:刚学完逆向基础想找练手样本的;做安全运营想补二进制分析能力的;准备相关认证或课程考核需要刷实验的。不适合指望拿它直接去打真实 APT 的人——练习样本和真实恶意代码之间有差距,这个后面会讲。核心价值在于,它把静态分析、动态行为、网络特征这几条线串成了一个可复现的流程,你练的是方法,不是背结论。

2. 实验文件的结构与静态分析切入点

拿到一批实验文件,第一件事不是急着双击,而是先搞清楚它们是什么形态。常见的练习样本会包含 PE 可执行文件、DLL、可能还有脚本类样本和配套的流量包或日志。不同形态的分析入口完全不同,选错工具等于白干。

2.1 先分类再动手:文件类型与对应工具链

我一般会先做一轮快速分类,把样本按「可执行 / 动态库 / 脚本 / 文档」分开,再决定用哪套工具。这一步用file命令加 PE 工具就能完成,不需要任何高级技巧,但能省掉后面大量返工。

# 先看文件真实类型,别信扩展名 file ./lab_samples/* # 对 PE 文件看基本头和节区 python3 -c " import pefile pe = pefile.PE('./lab_samples/sample01.exe') print('入口点:', hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)) print('镜像基址:', hex(pe.OPTIONAL_HEADER.ImageBase)) for s in pe.sections: print(s.Name.decode().strip('\x00'), hex(s.VirtualAddress), s.SizeOfRawData) "

这段代码的逻辑是先确认文件真实格式,再用 pefile 读出入口点、镜像基址和节区布局。参数上重点看AddressOfEntryPoint是否落在正常代码节里,如果入口点指向最后一个节或者节区名字异常(比如叫.upx、.aspack),基本可以判断加了壳。节区大小和虚拟地址的比值也能暴露问题——正常编译的节区两者差距不会太离谱,手工构造的样本经常对不上。

提示:练习文件里如果有加壳样本,先别急着脱壳,把壳的特征记下来本身就是分析成果的一部分。

2.2 导入表与字符串:从「它想干什么」倒推

静态分析里性价比最高的两个动作,一个是看导入表,一个是看字符串。导入表告诉你这个程序调用了哪些系统能力,字符串经常直接泄露作者意图或者调试残留。

import pefile pe = pefile.PE('./lab_samples/sample01.exe') # 遍历导入表,按 DLL 分组看函数 for entry in pe.DIRECTORY_ENTRY_IMPORT: dll_name = entry.dll.decode() print(f'\n[DLL] {dll_name}') for imp in entry.imports: if imp.name: print(f' {imp.name.decode()}')

逻辑说明:这段代码把导入表按 DLL 分组打印,方便你快速定位可疑能力。参数上重点关注几类函数——VirtualAlloc/VirtualProtect组合通常意味着运行时代码注入或解密;CreateRemoteThread/WriteProcessMemory指向进程注入;InternetOpen/HttpSendRequest说明有网络通信;RegSetValue/CreateService涉及持久化。如果这些函数集中出现在一个练习样本里,那它的行为链基本就清晰了。

字符串提取用strings配合编码识别,注意宽字符和 Base64 编码的内容:

# 提取 ASCII 和 Unicode 字符串 strings -a -n 6 ./lab_samples/sample01.exe > ascii_str.txt strings -a -el -n 6 ./lab_samples/sample01.exe > unicode_str.txt # 找可疑的 URL、IP、注册表路径 grep -Ei 'http|\.exe|\.dll|CurrentVersion|Run|SOFTWARE' ascii_str.txt unicode_str.txt

参数-n 6是控制最短字符串长度,太短噪音多,太长会漏。-el指定小端 Unicode,Windows 样本里宽字符很常见。grep 的关键词列表可以根据样本类型调整,练习文件里经常故意留下明显的 URL 或注册表路径作为线索。

2.3 静态分析的边界:什么时候必须转动态

静态分析有个硬边界——遇到加密字符串、运行时解密的配置、或者加壳样本,光看静态文件就是看个黑匣子。这时候不要死磕,直接转动态。判断标准很简单:导入表里出现大量内存操作函数、字符串区几乎为空、节区熵值接近 8,这三条中两条满足就该上动态了。

熵值计算可以用简单脚本快速判断:

import math from collections import Counter def entropy(data): if not data: return 0 counter = Counter(data) length = len(data) return -sum((count/length) * math.log2(count/length) for count in counter.values()) with open('./lab_samples/sample01.exe', 'rb') as f: raw = f.read() print(f'整体熵值: {entropy(raw):.2f}')

熵值超过 7.2 基本可以判定有加密或压缩数据。这个指标在练习文件里特别有用,因为很多教学样本会刻意做一层简单加密让你练脱壳或解密。

3. 动态行为监控:把样本跑起来看它到底干了什么

静态分析给你假设,动态分析给你证据。练习文件的价值在这一步体现得最明显——你可以放心地跑,不用担心真实感染。但放心跑不等于随便跑,环境隔离和监控点设置决定了你能拿到多少有效信息。

3.1 隔离环境与快照策略

我一般会用一个干净的虚拟机快照作为基线,跑样本前先拍快照,跑完直接回滚。这样每次实验都是干净环境,不会因为上一次的残留影响判断。工具层面,Procmon 抓文件、注册表、进程行为,Wireshark 抓网络,Regshot 做注册表前后对比,这三件套覆盖了大部分练习场景。

# 用 Regshot 做注册表快照对比的典型流程 # 1. 跑样本前拍第一个快照 regshot --save baseline.hive # 2. 运行样本,等待行为稳定 # 3. 拍第二个快照并生成对比报告 regshot --compare baseline.hive after.hive --output diff.txt

逻辑说明:Regshot 的核心价值是给你一个「变化清单」,而不是让你在几万条注册表项里肉眼找。参数上注意快照要包含 HKLM 和 HKCU 两个根键,很多持久化行为写在 HKCU 的 Run 键下。对比报告里重点看新增的键值和修改的系统配置项。

注意:练习样本虽然相对安全,但养成隔离习惯比什么都重要。我见过太多人在宿主机上跑练习文件,结果样本带了个简单的下载器行为,直接拉了个真东西下来。

3.2 Procmon 过滤:从几万条事件里捞出有效行为

Procmon 默认输出是灾难级的,几万条事件里 99% 是系统噪音。必须用过滤器把范围缩小到样本进程及其子进程。

操作步骤:

  1. 打开 Procmon,先按Ctrl+E停止捕获,清空现有事件
  2. 过滤器设置Process Name is sample01.exe,再添加Operation is CreateFile、RegSetValue、TCP Connect这几类
  3. 启动捕获,然后运行样本
  4. 观察结果,重点看文件落地路径、注册表写入位置、外连 IP 和端口
过滤规则示例(Procmon Filter 面板): Process Name is sample01.exe Include Operation is CreateFile Include Operation is RegSetValue Include Operation is TCP Connect Include Path contains Temp Include

这套过滤规则能把事件量压到几十条以内,每条都值得看。文件落地到%TEMP%或%APPDATA%是常见行为,注册表写入Run键说明有自启动意图,TCP 外连要看目标 IP 是不是练习环境里预设的模拟地址。

3.3 网络行为分析:从流量包反推通信协议

练习文件里如果有配套的流量包,那是最好的学习材料——你可以同时看到样本的发送行为和实际流量,两边对照着看协议结构。

# 用 tshark 快速提取 HTTP 请求和 DNS 查询 tshark -r ./lab_samples/traffic.pcap -Y "http.request or dns" \ -T fields -e frame.time -e ip.src -e ip.dst -e http.host -e http.request.uri -e dns.qry.name

参数说明:-Y是显示过滤器,http.request or dns只保留这两类流量。-T fields指定输出字段,这样出来的结果是结构化的,方便直接看。重点观察 DNS 查询的域名是否有规律(比如 DGA 生成的随机域名)、HTTP 请求的 User-Agent 是否异常、POST 数据是否有编码特征。

如果流量是加密的,练习文件通常会提供密钥或者用已知协议,这时候可以结合样本里的字符串和导入表来推断通信逻辑。真实场景下遇到 TLS 加密流量,没有密钥就只能看证书和 SNI 信息,这是动态分析的另一个边界。

4. 避坑与排查:练习文件分析中最容易翻车的五个点

4.1 样本跑不起来,双击没反应

现象:在虚拟机里双击样本,进程一闪而过或者完全没动静。

原因:练习样本经常需要特定运行条件——缺少某个 DLL、需要命令行参数、或者检测到分析环境主动退出。有些样本还会检查父进程,从 explorer 启动和从 cmd 启动行为不一样。

解决:先用tasklist确认进程是否真的没起来,再用 Procmon 看进程创建后立刻退出的原因。如果是缺 DLL,看导入表里哪个 DLL 没找到;如果是环境检测,试试用cmd /c sample01.exe启动,或者用调试器挂上去看退出前的最后几条指令。

4.2 静态分析看到一堆乱码字符串

现象:strings输出里大量无意义字符,找不到 URL、IP 或注册表路径。

原因:字符串被加密或编码了,常见的是 XOR 单字节加密、Base64 编码、或者运行时才解密的配置。练习文件里这种设计很常见,目的是让你练解密。

解决:先看熵值,如果某个节区熵值特别高,说明加密数据集中在那里。然后找解密函数——通常在入口点附近或者main函数开头。用调试器在解密函数返回处下断点,直接看解密后的内存。XOR 加密可以用脚本暴力试 255 个密钥,看哪个输出像正常字符串。

# 暴力试 XOR 单字节密钥 data = open('./lab_samples/encrypted.bin', 'rb').read() for key in range(256): decoded = bytes(b ^ key for b in data) if b'http' in decoded or b'.exe' in decoded: print(f'密钥: {hex(key)}') print(decoded[:200]) break

4.3 动态跑完注册表对比没变化

现象:Regshot 前后对比报告是空的,但样本明明运行了。

原因:样本可能把配置写到了文件而不是注册表,或者写到了 Regshot 没覆盖的注册表位置。还有一种可能是样本检测到 Regshot 进程,故意不执行恶意行为。

解决:先确认样本是否真的执行了核心逻辑——用 Procmon 看文件操作和进程操作。如果文件系统有变化,重点分析落地文件。如果怀疑是环境检测,把 Regshot 改名或者用其他工具替代,再跑一次。

4.4 网络流量抓不到

现象:Wireshark 里看不到样本的任何外连流量。

原因:样本可能用了非标准端口、或者通信被加密后走 443 端口看起来像正常 HTTPS。也可能是样本根本没触发网络行为——很多练习样本的网络模块需要特定条件才激活。

解决:先在 Procmon 里确认有没有TCP Connect操作。如果有连接但 Wireshark 没抓到,检查抓包网卡选对没有。如果连接目标是 443,看 TLS 握手里的 SNI 字段,那里面通常有域名信息。实在抓不到就上 API 监控,看ws2_32.dll里的connect和send调用参数。

4.5 分析报告写成了流水账

现象:把 Procmon 事件、字符串、导入表全贴进报告,但读的人不知道结论是什么。

原因:缺少行为链的串联。单个行为(比如写注册表)没有意义,只有把「释放文件 → 写注册表自启动 → 外连 C2」串成一条链,才能说明样本的完整意图。

解决:分析前先定一个假设,比如「这个样本是下载器」,然后用静态和动态证据去验证或推翻。报告按「假设 → 证据 → 结论」组织,每个行为都要回答「这一步在攻击链里起什么作用」。练习文件的好处是行为通常比较清晰,正好用来练这种串联能力。

5. 从练习到实战:把分析流程固化成可复用的检查清单

练完这批实验文件,最重要的不是记住了某个样本的行为,而是把分析流程变成肌肉记忆。我自己的习惯是每次分析前先过一遍检查清单,避免漏掉关键步骤。这个清单在练习阶段就养成,到了真实样本面前才不会手忙脚乱。

阶段检查项工具/命令输出物
预处理文件类型、哈希、熵值file / sha256sum / 熵值脚本样本指纹
静态PE 头、节区、导入表pefile / PEStudio能力假设
静态字符串提取与解码strings / XOR 脚本线索列表
动态进程、文件、注册表Procmon / Regshot行为清单
动态网络通信Wireshark / tshark流量特征
关联行为链串联手工整理分析结论

这个表不是让你机械填,而是提醒自己每个阶段都有产出物,下一阶段基于上一阶段的产出推进。练习文件的好处是你可以反复跑同一个样本,每次换一个角度切入,直到整个流程不需要看笔记就能走完。

还有一个进阶技巧:把常见样本类型的分析模板整理成脚本,比如 PE 文件自动提取导入表可疑函数、自动计算节区熵值、自动跑 strings 并过滤关键词。这样拿到新样本先跑一遍脚本,几分钟内就能有个初步判断,再决定往哪个方向深挖。

# 快速 triage 脚本框架 import pefile, math from collections import Counter SUSPICIOUS_IMPORTS = ['VirtualAlloc', 'VirtualProtect', 'CreateRemoteThread', 'WriteProcessMemory', 'InternetOpen', 'HttpSendRequest', 'RegSetValue', 'CreateService', 'ShellExecute'] def triage(path): pe = pefile.PE(path) print(f'=== {path} ===') print(f'入口点: {hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)}') # 检查可疑导入 hits = [] for entry in pe.DIRECTORY_ENTRY_IMPORT: for imp in entry.imports: if imp.name and imp.name.decode() in SUSPICIOUS_IMPORTS: hits.append(imp.name.decode()) print(f'可疑导入: {hits}') # 检查节区熵值 for s in pe.sections: ent = entropy(s.get_data()) if ent > 7.2: print(f'高熵节区: {s.Name.decode().strip(chr(0))} ({ent:.2f})') triage('./lab_samples/sample01.exe')

这个脚本把前面几节的检查点串成了一个自动化流程,跑一遍就能拿到样本的基本画像。参数上SUSPICIOUS_IMPORTS列表可以根据你的分析经验持续补充,熵值阈值 7.2 是经验值,实际用的时候可以按样本类型微调。

从那以后我每次拿到新样本,不管多简单,都强制先跑一遍 triage 脚本再动手。这个习惯帮我省了很多「看了一半才发现方向错了」的时间。练习文件的价值就在这——它让你在低风险环境里把流程跑熟,把工具用顺,把判断标准刻进直觉。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询