20242428 2026-2027-1 《网络与系统攻防技术》实验四实验报告
1.基础知识
1.1 PE 文件、加壳与脱壳
PE(Portable Executable)是 Windows 下可执行文件、动态链接库和目标文件的标准格式。一个 PE 文件由 DOS 头、PE 文件头、可选头、节表以及若干节区(如 .text、.rdata、.data、.rsrc、.reloc)组成,可选头中记录了程序入口点(AddressOfEntryPoint)、映像基址(ImageBase)以及导入表、导出表、重定位表等数据目录的位置。分析一个样本时,通常先看文件类型、节区数量与名称、入口点所在节区以及导入表,这些信息往往能直接暴露“这个程序是什么、用了什么技术”。
加壳(Packing)是指用专门算法对 PE 文件进行压缩或加密,再由一段附加的解压/解密代码在运行时把原始程序还原到内存中执行。加壳后,原始代码的字节序列被压缩或加密,文件的节区数量、名称、熵值和入口点都会改变,因此既能减小体积,也能隐藏特征、阻止逆向分析。UPX(Ultimate Packer for eXecutables)是最常见的开源压缩壳之一:它把原程序压缩后放进 UPX1 节,并让入口点指向 UPX1 中的解压存根(stub),由存根在内存中解压出原映像,再跳转到原始入口点(OEP)执行。标准 UPX 的存根有非常固定的形态——开头通常是 pusha、取压缩数据源与解压目标两个地址、把 ebp 置为 -1,随后进入典型的位流解压循环,用 add/adc/jb 等指令逐位还原数据——这些特征正是查壳工具和杀毒软件识别壳的依据。
脱壳的目标是恢复出未加壳的原始程序,基本步骤是:定位并跟踪到原始入口点(OEP),把内存中的原映像转储(dump)成文件,再修复导入表(IAT)和被破坏的 PE 头。对于 UPX 这类标准壳,脱壳工具可以根据壳的特征自动完成;但如果样本使用了被修改过的“魔改壳”,入口、存根或区段结构就不再完全符合标准,自动化脱壳往往会在“入口模拟跟踪”阶段失败,此时需要结合手工分析、换用其他脱壳方式或直接在内存中转储。
1.2 恶意代码分析的基本方法
恶意代码分析一般分为静态分析和动态分析两类。静态分析不运行样本,而是借助 file、md5sum、strings 等命令和 PEiD、IDA Pro 等工具查看文件结构、字符串、反汇编代码和控制流,从中提取作者信息、命令行参数、功能提示、硬编码的密钥或比较逻辑。动态分析则在隔离环境中运行样本,观察其进程、文件、注册表和网络行为。实际分析中两者需要交叉验证:静态分析给出“可能做什么”的假设,动态分析和流量证据给出“实际做了什么”的结论。
本次实验中的样本具有较强的反分析特性。RaDa 由 Visual Basic 6 编写,VB6 程序依赖 MSVBVM60.DLL 运行时,大量字符串以 Unicode(UTF-16LE)形式存储,因此在默认只显示 ASCII 字符串的工具中会“隐身”;同时 VB6 程序的导入表大多是指向 VB 运行库的转发函数,直接搜索 WS2_32.dll 之类的网络 API 往往一无所获,容易让人误判程序“没有网络功能”。此外,样本还会通过读取注册表键探测 VMware Tools 的安装路径,判断自己是否运行在虚拟机中,属于典型的反虚拟机(anti-VM)技术。
1.3 IRC 协议与僵尸网络
IRC(Internet Relay Chat)是一种即时通讯协议,客户端通过 TCP 连接到 IRC 服务器(常用端口 6667),注册时依次发送 NICK(昵称)和 USER(用户名)命令,之后用 JOIN 加入某个频道,服务器返回 353(NAMES 列表)等数字响应,并通过 PING/PONG 维持在线状态。
僵尸网络(Botnet)是攻击者通过命令与控制(C&C)服务器集中控制大量被感染主机(俗称“肉鸡”)所形成的网络。被植入 Bot 程序的主机启动后会主动连接 C&C 服务器,注册昵称、加入指定频道,然后等待指令,可被用于发起 DDoS 攻击、发送垃圾邮件、窃取信息或作为跳板。由于 IRC 协议简单、服务器资源容易获取,早期僵尸网络大量使用 IRC 作为控制通道,这也使其行为具有明显的网络特征:内网主机主动向外部 6667 端口发起连接、交互中出现 NICK/USER/JOIN 指令、频道成员名单异常庞大等。在取证时,这些特征正是定位 C&C 服务器和估算僵尸网络规模的关键。
1.4 流量取证与 BPF 过滤
网络取证通常以 pcap 抓包文件为起点。tcpdump 可以按 BPF(Berkeley Packet Filter)表达式筛选报文,例如按主机、端口、TCP 标志位过滤,并结合 awk、sort、uniq 等命令做统计;tcpflow 则按 TCP 会话把流量重组成一条条独立的流文件,便于查看完整的应用层会话;Wireshark 提供图形化的协议解析与“跟随 TCP 流”功能,可以直接观察 IRC 的命令与响应。把抓包过滤、会话重组、协议解析和统计分析结合起来,就可以从海量报文中还原出攻击链:谁扫描了谁、利用了哪种漏洞、植入了什么程序、程序回连了哪些服务器、控制的规模有多大。
2.实验内容
2.1 实验目的
1.掌握 PE 文件的基本结构与常见加壳技术,能够使用 PEiD 识别壳、使用脱壳工具/方法还原样本,并用 strings 提取脱壳后的关键字符串。
2.掌握使用 IDA Pro 对控制台程序进行静态分析的基本方法,能够通过字符串、反汇编和流程图还原程序的校验逻辑。
3.掌握恶意代码的静态与动态分析方法,能够识别 VB6 程序、Unicode 字符串、反虚拟机等技术,并对样本做出合理定性。
4.掌握基于 pcap 的僵尸网络取证流程,能够使用 tcpdump 过滤统计、tcpflow 重组会话、Wireshark 跟踪 IRC 交互,并估算僵尸网络规模与攻击源数量。
2.2 实验环境与工具
实验在 Kali Linux 虚拟机(主机名 huyue)与 Windows 11 宿主机上配合完成:Kali 用于样本识别、字符串提取和流量取证,Windows 侧用于查壳、脱壳、IDA 静态分析和运行 crackme 程序。使用的主要工具如表1所示。
表1 实验环境与工具
| 工具/环境 | 运行平台 | 主要用途 |
|---|---|---|
| Kali Linux 虚拟机(huyue) | VMware | file/md5sum/strings 样本识别、tcpdump/tcpflow 流量取证 |
| Windows 11 宿主机 | 物理机 | PEiD 查壳、超级巡警脱壳、IDA Pro 静态分析、运行 crackme |
| PEiD | Windows | 识别样本使用的壳与编译器特征 |
| 超级巡警脱壳机 | Windows | 尝试自动脱壳,验证样本是否为标准壳 |
| IDA Pro | Windows | 反汇编、字符串窗口分析、控制流图恢复 |
| Wireshark | Windows | pcap 图形化分析、IRC 会话跟踪与载荷查看 |
| tcpdump / tcpflow | Kali | BPF 过滤统计、TCP 会话重组 |
2.3 实验任务
任务一:对 RaDa.exe 进行文件识别与查壳,完成脱壳,并从脱壳文件中提取作者等关键字符串。
任务二:对 crackme1.exe、crackme2.exe 进行运行验证与逆向分析,找出并验证正确的口令与运行条件。
任务三:对 RaDa 样本进行静态分析,识别其反分析技术,判断程序类型与功能,完成样本定性。
任务四:对 botnet pcap 进行取证分析,提取 IRC 服务器地址、统计僵尸网络规模与独立攻击源数量,还原攻击链。
3.实验过程
3.1 任务一:RaDa 样本的识别、脱壳与字符串提取
3.1.1 样本基本信息识别
先在 Kali 中对样本做基础识别,查看文件类型和 MD5 值:
$ file RaDa.exe
RaDa.exe: PE32 executable for MS Windows 4.00 (GUI), Intel i386, 3 sections
$ md5sum RaDa.exe
caaa6985a43225a0b3add54f44a0d4c7 RaDa.exe
从结果(图1)可以看到:RaDa.exe 是 32 位 Windows GUI 程序(PE32,i386),节区数量为 3。正常程序的节区数量与名称都有一定规律,而节区数量偏少、内容高度压缩的形态通常与加壳有关;结合后文 PEiD 识别为 UPX 壳的结果,可以初步判断样本经过了加壳处理。这里同时记下 MD5 值,便于后续在样本库或威胁情报中核对样本来源。
3.1.2 查壳与脱壳
在 Windows 11 上用 PEiD 打开 RaDa.exe,识别结果为 UPX 0.89.6 - 1.02 / 1.05 - 1.22,说明样本使用了 UPX 压缩壳。为了获得未加壳的原始程序,使用超级巡警脱壳机进行自动脱壳,但工具在入口模拟跟踪阶段报错“入口模拟跟踪脱壳失败”。结合 PEiD 的识别结果和 IDA 中看到的解压存根可以判断:样本使用的仍是 UPX 压缩算法,解压存根也保持标准形态,但壳的头部、区段或入口跳转等特征存在改动(通常称为“魔改壳”),使依赖入口模拟跟踪的自动脱壳流程无法完成;这一现象也可能与脱壳工具对变种的兼容性有关。
为了确认壳的类型,在 IDA 中打开 RaDa.exe 并定位到入口点,可以看到典型的 UPX 解压存根代码(图2):入口先保存寄存器现场(pusha),取压缩数据源 dword_40C000 和解压目标地址,把 ebp 置为 -1,随后进入位流解压循环,通过 add ebx, ebx / jnz / mov ebx, [esi] / sub esi, 0FFFFFFFCh / adc ebx, ebx / jb 等指令一位一位地还原数据。这段存根与标准 UPX 0.89~1.2x 的解压存根形态一致,说明压缩算法没有被替换,问题主要出在壳的其它特征或入口路径上。
; IDA 中的入口解压存根(节选)
start:pushamov esi, offset dword_40C000lea edi, [esi-0B000h]push edior ebp, 0FFFFFFFFhjmp short loc_40FD42
loc_40FD38:mov al, [esi]inc esimov [edi], alinc ediadd ebx, ebxjnz short loc_40FD49mov ebx, [esi]sub esi, 0FFFFFFFChadc ebx, ebxjb short loc_40FD38mov eax, 1
自动脱壳失败后,我改用其他脱壳方式:结合对 UPX 存根的分析,在 IDA 中跟踪存根的解压流程,确认原始程序已被解压到内存后定位原始入口点并转储内存映像,最终得到脱壳文件 RaDa_unpacked.exe。脱壳是否成功,最直接的验证方式是比较前后字符串的可见性:未脱壳时 strings 很难看到原始程序中的可读字符串,脱壳后作者字符串得以恢复,说明脱壳基本成功。
3.1.3 从脱壳文件中提取作者信息
用 strings 在脱壳文件中搜索作者相关关键字:
$ strings RaDa_unpacked.exe | grep -i -E "Raul|Siles|Perez|copyright"
(c) Raul Siles && David Perez
搜索结果(图3)直接给出了样本的版权字符串 “(c) Raul Siles && David Perez”,作者字符串已成功恢复,说明脱壳基本成功。这条信息也表明 RaDa 并不是一个在野外传播的恶意程序,而是由安全研究者编写的、带有署名和作者参数(后文会看到 --authors)的演示样本,这类样本通常来自安全教学或逆向挑战项目。
3.2 任务二:Crackme 逆向分析
3.2.1 crackme1.exe 的运行观察
crackme1.exe 是控制台程序,直接双击会一闪而过,因此需要在 cmd 命令行中带参数运行,观察不同输入下的输出:
C:\Users\Huyue\Desktop>crackme1.exe
I think you are missing something.C:\Users\Huyue\Desktop>crackme1.exe 1 2
I think you are missing something.C:\Users\Huyue\Desktop>crackme1.exe 1
Pardon? What did you say?C:\Users\Huyue\Desktop>crackme1.exe "I know the secret"
You know how to speak to programs, Mr. Reverse-Engineer
四次运行的输出(图4)可以反推出程序的判断逻辑:不带参数(argc=1)和带两个参数(argc=3)时都提示 “I think you are missing something.”,说明程序要求参数个数恰好为 2;只带一个普通参数时提示 “Pardon? What did you say?”,说明参数个数正确时程序会拿该参数与某个固定字符串比较;只有输入 “I know the secret” 时才输出成功信息。需要注意命令中的英文双引号:参数中含有空格,必须用双引号括起来,否则会被拆成多个参数,仍然触发“参数个数不对”的分支。
3.2.2 crackme1.exe 的静态分析
在 IDA 中打开 crackme1.exe,在反汇编/数据视图中可以看到与运行输出完全对应的三个字符串(图5):
.rdata:00403000 Format db 'I think you are missing something.',0Ah,0
.rdata:00403024 Str2 db 'I know the secret',0
.rdata:00403036 aPardonWhatDidY db 'Pardon? What did you say?',0Ah,0
三个字符串都位于 .rdata 段,并且都标注了 DATA XREF:Format 被 _main+33 处引用,Str2 被 _main+5B 处引用,aPardonWhatDidY 被 _main+71 处引用,说明它们分别是主函数使用的打印内容和比较对象。其中 Str2 就是硬编码的口令 “I know the secret”。结合运行结果可以确定:程序先检查 argc 是否为 2,不正确就打印 Format;正确则用 _strcmp 比较 argv[1] 与 Str2,相等走成功分支,否则打印 aPardonWhatDidY。打开反汇编还可以看到 main 的栈帧带有 and esp, 0FFFFFFF0h 和 __alloca 调用等典型的 MSVC 运行库痕迹,因此这是一个用 MSVC 编译的 C 控制台程序,逻辑非常直接,分析重点在于定位字符串比较。
3.2.3 crackme2.exe 的文件名自校验
任务中要求把 crackme2.exe 重命名为 crackmeplease.exe 后再运行。为了搞清楚“为什么必须改名”,在 IDA 中查看 crackme2.exe 的主函数并恢复控制流图,结果如图6所示。程序同样先判断参数个数(cmp [ebp+argc], 2 / jz),参数个数正确后并没有直接比较口令,而是先做了一次字符串比较:把 argv[0](程序自身路径/文件名)与字符串 “crackmeplease.exe” 用 _strcmp 比较,只有比较结果相等时才进入口令校验;否则会输出 “I have an identity problem.”。口令校验失败打印 “Pardon? What did you say?”,两个校验都通过后,程序把一段按字节异或 0x42 编码的数据解码,并用 putchar 逐字符输出成功提示。
控制流图中还有一个值得注意的细节:成功分支里有一段循环,用 xor eax, 42h 把 .rdata 中 unk_403080 处的字节与 0x42 异或解码,再交给 putchar 输出(图6中可以看到 cmp [ebp+var_4], 21h / ja 的循环边界)。也就是说,成功提示并不是以明文形式存放在文件里的,因此用 Strings 窗口直接搜索是搜不到的,必须通过反汇编理解解码逻辑。这也解释了为什么 crackme 的字符串窗口中只能看到失败提示和口令,而看不到完整的成功信息。
验证时,先把 crackme2.exe 复制并重命名为 crackmeplease.exe,再在 cmd 中以同样的口令运行;程序通过了文件名检查与口令校验,并输出了成功提示,验证了上面的分析结论:crackme2 相比 crackme1 多了一个对自身文件名的校验,两个条件缺一不可。
3.2.4 两个 crackme 样本的分析结果
把两个样本的校验条件整理如表2所示。
表2 crackme 样本的校验条件与验证结果
| 样本 | 关键校验条件 | 验证方式 | 结果 |
|---|---|---|---|
| crackme1.exe | argc==2,且 argv[1] 等于 “I know the secret” | crackme1.exe “I know the secret” | 输出成功信息 |
| crackme2.exe | argc==2,argv[0] 文件名为 crackmeplease.exe,且 argv[1] 等于 “I know the secret” | 重命名为 crackmeplease.exe 后运行 | 输出成功信息 |
3.3 任务三:RaDa 恶意代码分析
3.3.1 程序类型与关键字符串
脱壳后对 RaDa_unpacked.exe 做静态分析。先看导入表:在 IDA 的导入/函数窗口中搜索不到 WS2_32.dll 及其网络函数(socket、connect、send、recv 等),也没有明显的 WinINet/WinHTTP 导入;结合左侧函数列表中的 __vba* 系列函数可以判断,这是一个由 Visual Basic 6 编写的程序,大量功能经由 MSVBVM60.DLL 运行时转接实现。不能仅凭“没有网络 API”就断定它没有网络功能,但至少说明它没有使用常规的 Socket 接口。
接着在 IDA 中查看字符串。RaDa 是 VB6 程序,字符串默认以 Unicode(UTF-16LE)存储,在反汇编/数据视图中表现为 text “UTF-16LE”, '…' 的数据定义(图7、图8);如果按 ASCII 去搜索,--authors、VMware 检测路径等关键字都会被漏掉,需要在 Strings 窗口右键选择 Setup、把默认类型改为 Unicode 后才能命中。
把两张截图中出现的关键字符串及其推断含义整理如表3。
表3 RaDa 样本中的关键字符串及分析含义
| 关键字符串 | 出现位置 | 分析含义 |
|---|---|---|
| RaDa.exe | 字符串区(UTF-16LE) | 程序自身名称 |
| HKLM\Software\VMware, Inc.\VMware Tools\InstallPath | 字符串区(UTF-16LE),被多个函数引用 | 读取注册表判断是否安装 VMware Tools,用于反虚拟机检测 |
| Starting DDoS Smurf remote attack... | 字符串区(UTF-16LE) | DDoS/Smurf 攻击的功能提示 |
| You can learn a lot playing funny security challenges | .rdata(ASCII) | 作者留言,说明样本用途为安全挑战/教学 |
| VB、Command_conf、Command_uninstall | 字符串区(UTF-16LE) | VB6 程序标识、配置命令与卸载命令 |
| --authors、--uninstall、Unknown argument: | 字符串区(UTF-16LE) | 命令行参数解析:打印作者、卸载、未知参数提示 |
| COMSPEC、/C | 字符串区(UTF-16LE) | 通过 cmd.exe /c 执行命令、构造命令参数 |
| 多个连字符 + 0123456789012 | 字符串区(UTF-16LE) | multipart 表单的分隔边界(boundary) |
| RaDa Current Configuration | 字符串区(UTF-16LE) | 配置页面/HTML 标题 |
| AppendChunk、GetChunk、Submit | 字符串区(UTF-16LE) | VB6 流对象的追加/读取与表单提交 |
| dword_402604、dword_402634 等 dword 数据块 | .rdata | 被加密/编码的数据,运行时由代码解码使用 |
除表中列出的内容外,字符串里还存在 Content-Disposition: form-data; name=" 这样的 multipart 表单字段和 RaDa Current Configuration 这样的 HTML 标题标签。这些字符串说明 RaDa 具备以下特征:可解析多条命令行参数(--authors 打印作者信息、--uninstall 执行卸载、未知参数给出错误提示);能够生成 HTML 配置页面并构造 multipart 表单进行数据上传;内部含有命令执行(COMSPEC + /C)和 DDoS Smurf 攻击的功能提示;同时会检测 VMware 虚拟机环境。程序里还保留了 “You can learn a lot playing funny security challenges” 这样的作者留言,进一步说明它是一个演示/挑战样本。
3.3.2 反分析技术分析
综合静态分析结果,RaDa 使用了多种反分析手段,可归纳为以下几类。
(1)魔改 UPX 壳。样本虽然使用 UPX 压缩,且解压存根保持标准形态,但壳的头部/入口路径等特征被改动,使超级巡警在“入口模拟跟踪”阶段报错、常规自动脱壳失效;只有结合 IDA 确认存根并改用手动方式,才能拿到原始代码。这一层挡住了大部分只想“一键脱壳”的分析者。
(2)VB6 的 Unicode 字符串。VB6 程序中的字符串以 UTF-16LE 存储,IDA 默认按 ASCII 搜索,--authors、VMware 检测路径、HTTP 上传字段等关键字都会被漏掉,很容易让分析者得出“样本很简单、没什么功能”的错误结论。分析时必须主动把字符串类型切换为 Unicode。
(3)反虚拟机检测。样本读取 HKLM\Software\VMware, Inc.\VMware Tools\InstallPath,判断自己是否运行在 VMware 虚拟机中(图7)。在真实分析环境中,样本可能根据检测结果选择静默退出或改变行为,从而逃避沙箱/虚拟机的动态分析。
(4)字符串与数据加密。除 Unicode 之外,样本还把部分提示信息和数据以 dword 数组形式存放在 .rdata 中(如图7中的 dword_402604、dword_402634 等),并在运行时解码使用;类似地,crackme2 的成功提示用与 0x42 异或的方式编码后才输出。这意味着 strings 只能看到“作者想让你看到”的那一部分字符串。
(5)功能提示与实现分离。样本保留了 “Starting DDoS Smurf remote attack...” 等敏感提示,但没有导入常规的网络 API,说明这些功能可能是加密/未激活的,或者仅作为演示存在。分析时不能只凭字符串定性,还要结合导入表、函数调用关系和运行行为综合判断。
3.3.3 样本定性与相似工具对比
结合上述分析,RaDa 是一个由 VB6 编写、带有反虚拟机与反脱壳手段、具有命令行参数、配置页面、数据上传和 DDoS 功能提示的恶意代码演示样本。它没有在野外传播的迹象,作者在程序中留下了署名和“安全挑战”留言,因此更接近教学/挑战样本(可归为 PUA,也可能被杀软标记为 HackTool/Riskware),而不是具有完整攻击能力的真实后门。但需要强调:演示样本同样具有潜在危害,其使用的加壳、反虚拟机、字符串加密等技术在真实恶意软件中非常常见,必须在隔离的虚拟机环境中分析,绝不能在生产机上运行。
与常见的同类工具对比:Netcat 是“网络瑞士军刀”,既可以做端口监听/连接和文件传输,也常被用作简易后门;Back Orifice 是经典的远程控制后门,具有隐蔽通信和远程命令执行能力。RaDa 在功能定位上(命令行参数、配置、上传/命令执行提示)与它们有相似之处;由于本次未进行动态运行验证,静态分析未能确认完整的网络通信链路,因此更应把它看作后门/僵尸网络程序的“演示版”或“教学版”。
3.4 任务四:僵尸网络流量取证分析
3.4.1 数据来源与总体观察
取证对象是实验提供的 botnet_pcap_file.dat。用 Wireshark 打开后,可以在状态栏看到该文件共捕获 54536 个报文;在显示过滤器输入 irc 后,剩余 9594 个 IRC 报文(占 17.6%),说明抓包中绝大部分交互都是 IRC 协议,这本身就是僵尸网络流量的强特征。参与通信的内网主机是 172.16.134.191(蜜罐),它在多个外部 IRC 服务器的 6667 端口上有持续的请求/响应(5 个服务器见 3.4.2 与图9);从图11的以太网头可以看到蜜罐的源 MAC 为 00:05:69:00:01:e2(VMware 虚拟网卡的 OUI),即蜜罐本身运行在 VMware 虚拟机中。
3.4.2 提取 IRC 服务器地址
为了找出蜜罐连接了哪些 IRC 服务器,用 tcpdump 过滤“源地址为蜜罐、目的端口为 6667、且带 SYN 标志”的报文,取目的地址去重:
$ tcpdump -n -nn -r botnet_pcap_file.dat 'src host 172.16.134.191 and tcp dst port 6667 and tcp[tcpflags] & tcp-syn != 0' | awk '{print $5}' | cut -d. -f1-4 | sort -u
209.126.161.29
209.196.44.172
217.199.175.10
63.241.174.144
66.33.65.58
过滤结果得到 5 个不同的 IP,说明蜜罐至少与 5 个 IRC 服务器建立过连接。图9中第一段执行时 tcpdump 也曾报 “No such file or directory”,确认 pcap 文件的实际位置后重新执行,才得到上面的结果(路径问题的处理见问题5)。命令中各部分的作用是:BPF 表达式限定“蜜罐发出的、目的端口 6667 的 SYN 报文”,awk 取 tcpdump 输出中的目的地址列,cut -d. -f1-4 去掉端口号只保留 IP,最后 sort -u 去重。
3.4.3 会话重组与僵尸网络规模统计
以其中一个 IRC 服务器 209.196.44.172 为例,用 tcpflow 把该服务器与蜜罐之间的 TCP 会话重组为独立的流文件:
$ sudo tcpflow -r /home/huyue/botnet_pcap_file.dat "host 209.196.44.172 and port 6667"
reportfilename: ./report.xml
$ ls
172.016.134.191.01152-209.196.044.172.06667 report.xml
209.196.044.172.06667-172.016.134.191.01152
$ cat 209.196.044.172.06667-172.016.134.191.01152 | grep -a " 353 " | sed 's/^.* #x[^x]*x //g' | tr ' ' '\n' | tr -d "\15" | grep -v '^$' | sort -u | wc -l
grep: (standard input): binary file matches
3461
tcpflow 按“源IP.源端口-目的IP.目的端口”的规则生成两个方向的流文件:一个是蜜罐发往服务器的请求流,另一个是服务器返回给蜜罐的响应流。僵尸网络的控制信息(谁在线、频道里有哪些成员)保存在服务器返回的响应流中,因此统计脚本读取的是 209.196.44.172 发往 172.16.134.191 的那条流。管道各步骤的含义是:grep -a " 353 " 只保留 IRC 的数字 353 响应(RPL_NAMREPLY,即频道成员名单,-a 表示把输入按文本处理),sed 删除每行行首到频道名(本数据中频道名被混淆为 #x…x 形式)之前的内容、只保留其后的昵称列表,tr ' ' '\n' 把一行中的昵称拆成多行,tr -d "\15" 删除回车符,grep -v '^$' 去掉空行,sort -u 去重,最后 wc -l 计数。终端还输出了一条 grep 对二进制输入的提示(binary file matches),不影响统计结果。统计结果如图10所示,最终计数为 3461,即该频道名单中约有 3461 个不同昵称,可估算该僵尸网络约有 3461 台被控主机。
3.4.4 Wireshark 跟踪 IRC 会话
为了看清“肉鸡是怎样加入僵尸网络的”,在 Wireshark 中应用 irc 显示过滤器,查看蜜罐发出的 IRC 注册报文(图11)。图11的报文列表中当前高亮的是 35815 号响应报文,而下方的详情和十六进制窗格对应的是第 35753 号报文:源地址 172.16.134.191、源端口 1133,目的地址 63.241.174.144、目的端口 6667。载荷中可以直接看到 IRC 命令,还原后的明文如下:
NICK eohisou
USER eohisou localhost localhost :eohisou
从十六进制内容看,载荷的前 4 个字节为 4e 49 43 4b(即 “NICK”),随后是昵称 eohisou;下一条命令 “USER” 则携带用户名、主机名和真实姓名等信息。把载荷还原成明文后可以清楚地看到:蜜罐上的 Bot 程序启动后,主动向 IRC 服务器发送 NICK 注册昵称,随后发送 USER 完成用户注册,之后还会发送 JOIN 加入频道,并周期性响应服务器的 PING。报文列表中同时可以看到服务器返回的 353(频道成员名单)等响应,以及大量 MODE、JOIN、WHO 请求,说明这个 Bot 正在执行标准的 IRC 僵尸网络上线流程。至此,从“主机被感染”到“Bot 回连 C&C、注册昵称、加入僵尸网络”的完整链路被流量证据还原出来。
3.4.5 独立攻击源 IP 统计
最后统计攻击蜜罐的独立 IP 数量。本来的思路是过滤所有“目的地址为蜜罐”的报文,提取源地址并去重:
$ tcpdump -n -nn -r ../botnet_pcap_file.dat 'dst host 172.16.134.191' | awk -F' ' '{print $3}' | cut -d. -f1-4 | sort -u > ../attack_src_ips.txt
$ wc -l ../attack_src_ips.txt
0 ../attack_src_ips.txt
这次执行时使用了相对路径 ../botnet_pcap_file.dat,而当前目录下没有该文件,tcpdump 报错后没有任何输出,统计结果自然为 0(图12)。改用 find 命令找到 pcap 文件的绝对路径后重新执行:
$ find / -name botnet_pcap_file.dat 2>/dev/null
/home/huyue/botnet_pcap_file.dat
$ tcpdump -n -nn -r /home/huyue/botnet_pcap_file.dat 'dst host 172.16.134.191' | awk -F' ' '{print $3}' | cut -d. -f1-4 | sort -u > attack_src_ips.txt
$ wc -l attack_src_ips.txt
165 attack_src_ips.txt
最终统计出 165 个不同的源 IP,即在整个捕获期间共有 165 个独立的攻击源向蜜罐发送过数据。这个数字结合前面的 IRC 会话可以把整个事件串起来:攻击者先对蜜罐进行扫描和漏洞利用(抓包中可见 SMB/RPC 等常见漏洞利用相关的流量),攻破后植入 Bot 程序;Bot 启动后主动连接 IRC 服务器,注册昵称、加入频道,使蜜罐成为僵尸网络中的一员;随后攻击者就可以通过 C&C 频道向包括蜜罐在内的所有肉鸡下发指令。
3.4.6 取证结果汇总
把任务四的关键统计结果汇总如表4所示。
表4 僵尸网络取证关键数据
| 统计项 | 结果 | 说明 |
|---|---|---|
| 抓包报文总数 | 54536 | Wireshark 状态栏统计 |
| IRC 报文数量 | 9594(17.6%) | 应用 irc 过滤器后的显示数量 |
| 蜜罐地址 | 172.16.134.191 | MAC 为 VMware 虚拟网卡 00:05:69:00:01:e2 |
| IRC 服务器数量 | 5 个 | 209.126.161.29、209.196.44.172、217.199.175.10、63.241.174.144、66.33.65.58 |
| 僵尸网络规模 | 约 3461 台 | 353 频道成员名单去重后的昵称数量 |
| 独立攻击源 IP | 165 个 | 以蜜罐为目的地址的报文源地址去重 |
| Bot 上线行为 | NICK/USER/JOIN | 图11载荷还原,源端口 1133 到目的端口 6667 |
3.5 实验过程小结
本次实验的四个任务层层递进:任务一通过“查壳—脱壳—字符串验证”完成了恶意样本静态分析的第一步;任务二用两个 crackme 练习了从运行结果反推判断逻辑、再用 IDA 验证的完整过程;任务三在脱壳基础上分析了 RaDa 的 VB6 特性、反虚拟机与字符串加密等反分析技术,并完成了样本定性;任务四则从 pcap 出发,用 tcpdump、tcpflow 和 Wireshark 三种工具互相配合,统计出 5 个 IRC 服务器、约 3461 台肉鸡和 165 个独立攻击源,还原了“漏洞利用—植入 Bot—回连 IRC—加入僵尸网络”的完整攻击链。四个任务分别对应样本层、代码层、行为层和网络层,构成了对恶意代码从“文件”到“网络”的完整分析视角。
4.问题及解决方案
- 问题1:使用超级巡警脱壳机对 RaDa.exe 脱壳时,工具报错“入口模拟跟踪脱壳失败”,无法直接得到脱壳文件。
- 问题1解决方案:判断样本使用了被修改过的 UPX 壳(魔改壳),标准自动脱壳难以生效;改用其他脱壳方式并配合手动分析,最终得到脱壳文件 RaDa_unpacked.exe,并用 strings 验证作者信息等原始字符串已恢复,证明脱壳成功。
- 问题2:直接双击运行 crackme1.exe 时窗口一闪而过,看不到任何提示信息。
- 问题2解决方案:该程序是控制台程序且需要命令行参数,双击运行时 argc=1 只会走“参数缺失”分支;改为用 Win+R 打开 cmd,切换到程序所在目录后带参数运行(含空格的参数用英文双引号括起来),即可看到完整输出并验证结果。
- 问题3:在 IDA 中想通过搜索 WS2_32.dll 的网络函数判断 RaDa 是否有网络后门,但导入表和函数列表中找不到 socket、connect 等函数,一度以为分析方向错了。
- 问题3解决方案:结合函数列表中的 __vba* 系列函数判断程序由 VB6 编写,其网络功能可能经由 MSVBVM60.DLL 运行时或控件实现,导入表中不一定出现 WS2_32.dll 的直接导入;于是调整分析方向,转向字符串分析、反虚拟机检测与整体定性,最终将该程序定性为恶意代码演示样本。
- 问题4:用 Shift+F12 在 IDA 中搜索 --authors、VMware 等字符串时什么都搜不到。
- 问题4解决方案:VB6 程序的字符串默认以 Unicode(UTF-16LE)编码存储,而 IDA 的 Strings 窗口默认只显示 ASCII 字符串;在 Strings 窗口右键选择 Setup、把字符串类型改为 Unicode 后,即可看到 RaDa.exe、VMware Tools 安装路径、--authors、Content-Disposition 等敏感字符串。
- 问题5:取证分析时 tcpdump/tcpflow 报错“No such file or directory”,统计结果为空。
- 问题5解决方案:命令中使用相对路径时系统按当前工作目录解析,而 pcap 文件并不在该目录;先用 find / -name botnet_pcap_file.dat 2>/dev/null 定位文件绝对路径,再以 /home/huyue/botnet_pcap_file.dat 重新执行命令,最终统计出约 3461 台肉鸡和 165 个独立攻击源 IP,此后所有取证命令统一使用绝对路径。
5.学习感悟、思考等
5.1 学习感悟
这次实验让我体会到恶意代码分析是一个与样本作者“斗智”的过程。超级巡警在入口模拟跟踪阶段失败,迫使我先回到 UPX 存根和入口点本身去判断壳的状态;在 IDA 里搜不到 --authors 时,也是想到 VB6 程序使用 Unicode 字符串才把线索重新接上。取证阶段最有收获:在 Wireshark 里看到蜜罐上的 Bot 主动发送 NICK、USER 加入僵尸网络,再结合 353 名单统计出数千台肉鸡,抽象的“僵尸网络”一下子变得具体。整次实验把脱壳、逆向、样本定性和流量取证串了起来,也让我对加壳、反虚拟机和 IRC 控制机制有了更直观的认识。
5.2 思考与延伸
第一,静态分析与动态分析必须结合。RaDa 的“魔改壳 + Unicode + 加密数据”专门用来骗过只看表面的分析:如果只跑一下 strings 或只看导入表,很容易得出“程序很简单、没有网络功能”的错误结论。只有把查壳、脱壳、字符串编码、导入表和反虚拟机逻辑放在一起看,才能得到接近事实的判断。
第二,恶意代码分析的每一步都要有证据意识。脱壳是否成功,要用字符串是否恢复来验证;样本是否有网络功能,要看导入表、函数引用和实际行为,而不是凭某个字符串猜测;僵尸网络规模是多少,要用 353 名单去重后计数来支撑。实验报告中的每个结论最好都能对应到一条命令、一张截图或一段代码。
第三,从防御视角看,这次实验也提示了几个检测点:内网主机主动向外部 6667 端口发起连接、交互中出现 NICK/USER/JOIN 等 IRC 命令、单频道出现数千个成员,都是僵尸网络流量的典型特征;蜜罐作为一种主动防御手段,能够捕获攻击者的完整攻击链,为溯源和应急响应提供一手的 pcap 证据。实际工作中如果发现类似流量,应第一时间封禁 C&C 地址、隔离被控主机,并检查主机是否存在 SMB/RPC 等漏洞未修补的问题。
第四,技术是一把双刃剑。RaDa 的作者在程序中留下“安全挑战”留言,用恶意代码的技术做教学;但同样的加壳、反虚拟机、加密通信技术一旦被真实攻击者使用,就会显著提高检测和处置的难度。作为安全专业的学生,既要理解攻击技术,更要有法律和伦理边界意识:本次实验的样本分析全部在实验专用的 Kali 虚拟机与 Windows 11 主机上进行,未接入生产网络,样本与流量不对外传播。
参考资料
- 《网络与系统攻防技术》课程 PPT 与实验指导书.
- 《恶意代码分析实战》(Practical Malware Analysis),Michael Sikorski、Andrew Honig 著,电子工业出版社.