20253902 吴晨宇 2025-2026-2 《网络攻防实践》第八周作业

一、知识点总结

1.1 相关工具

本次实验主要涉及程序逆向分析和网络流量分析两个方向,因此需要使用 IDA Pro 和 tshark 等工具对可执行文件和网络数据包进行分析。IDA Pro 主要用于对程序样本进行反汇编和逻辑分析,tshark 则主要用于对网络流量进行筛选、提取和统计。二者分别对应恶意代码分析中的程序层面和网络层面,可以相互补充,帮助分析者从不同角度理解样本行为和攻击过程。

1.1.1 IDA Pro

IDA Pro 是一款常用的交互式反汇编与逆向分析工具,广泛应用于恶意代码分析、漏洞研究和软件逆向工程中。它可以将可执行文件中的机器码转换为汇编代码,并自动识别程序中的函数、字符串、代码段、数据段和交叉引用关系。通过 IDA Pro,分析人员可以观察程序的控制流程、函数调用关系、条件判断逻辑以及关键字符串的使用位置,从而逐步还原程序的真实执行逻辑。

在恶意代码分析中,IDA Pro 不仅可以用于查看汇编代码,还可以帮助分析者定位关键行为。例如,通过字符串窗口可以快速发现程序中隐藏的提示信息、路径、命令参数、网络地址或作者信息;通过函数窗口可以查看程序中存在的函数结构;通过交叉引用可以分析某个字符串或函数在程序中的调用位置。对于经过脱壳后的程序,IDA Pro 通常能够更加清晰地展示程序逻辑,是理解样本内部行为的重要工具。

1.1.2 tshark

tshark 是 Wireshark 的命令行版本,主要用于网络数据包的捕获、过滤、解析和字段提取。相比图形化的 Wireshark,tshark 更适合在命令行环境下处理大量数据包,尤其适用于批量分析、自动化统计和脚本化处理。

在网络流量分析中,tshark 可以根据 IP 地址、端口、协议类型和数据包内容对流量进行筛选,也可以直接提取源 IP、目的 IP、端口号、协议字段和 TCP 负载等信息。它常常与 grep、sort、uniq、wc 等命令配合使用,用于统计通信主机数量、筛选特定协议数据、提取可疑字符串以及分析异常连接关系。对于分析僵尸网络通信、C2 连接、攻击源 IP 和受害主机通信行为,tshark 具有较高的效率。

1.2 恶意代码静态分析相关知识

恶意代码静态分析是指在不直接运行程序主要功能的情况下,对可执行文件本身进行分析。通过静态分析,可以在较低风险下初步判断程序的运行平台、文件格式、编译特征、是否存在加壳现象,以及程序中可能包含的路径、命令、提示信息、网络地址等关键线索。本实验涉及的相关知识主要包括 PE 文件格式、加壳与脱壳、字符串分析、程序逆向分析、网络行为分析以及攻击链还原等内容。

1.2.1 PE 文件格式与样本基础识别

PE 文件是 Windows 系统下常见的可执行文件格式,通常包括 DOS 头、PE 头、节区表、代码段、数据段、导入表、导出表和资源信息等结构。分析 PE 文件时,需要关注程序入口点、节区名称、节区权限、导入函数和字符串等内容,从而判断程序的基本属性、运行环境和潜在异常特征。

样本基础识别是恶意代码分析的起点。通过判断文件类型、程序位数、目标平台和文件结构,可以确定后续应选择的分析工具和分析环境。例如,如果样本是 Windows PE 文件,则后续可以使用 IDA Pro 等工具进行反汇编分析;如果发现节区信息异常、入口点位置可疑或可读字符串较少,则可能说明程序经过加壳或混淆处理。

1.2.2 加壳、脱壳与代码隐藏

加壳是恶意代码中常见的保护和隐藏手段,通常通过压缩、加密或保护的方式隐藏程序真实代码和数据,使分析者难以直接看到程序原始逻辑。恶意代码使用加壳技术,一方面可以减小文件体积,另一方面也可以增加逆向分析难度,甚至逃避部分安全软件的静态检测。

脱壳的目的则是尽可能恢复程序的真实代码和数据,使后续的字符串分析、反汇编分析和逻辑判断更加准确。对于脱壳后的程序,分析工具通常能够识别出更多函数、字符串和代码结构,有助于进一步理解程序真实行为。因此,在静态分析过程中,是否存在加壳现象以及能否成功脱壳,往往会直接影响后续分析效果。

1.2.3 字符串分析与程序逻辑逆向

字符串分析是静态分析中非常常用的方法。程序中的明文字符串往往能够暴露出大量有价值的信息,例如提示语、错误信息、文件路径、注册表项、作者信息、URL、IP 地址、命令参数等。通过字符串分析,可以快速发现程序中的关键线索,并为后续逆向分析提供定位依据。

程序逻辑逆向是在静态分析基础上进一步理解程序行为的过程。通过 IDA Pro 等工具,可以将机器码转换为汇编代码,并结合函数调用、条件跳转、参数传递、字符串引用和 API 调用等信息,还原程序的执行流程。在分析过程中,需要关注程序如何判断输入、如何进入不同分支、如何调用系统 API、如何处理文件和网络资源,以及是否存在隐藏逻辑或恶意行为。

部分程序中的关键字符串可能不会直接以明文形式出现,而是通过异或、编码或加密等方式进行隐藏。异或混淆是一种较常见的简单字符串隐藏方式,由于异或运算具有可逆性,只要找到对应密钥或运算规律,就可以还原被隐藏的字符串内容,从而进一步理解程序逻辑。

1.2.4 网络行为与 C2 通信分析

网络行为分析是恶意代码分析中的重要组成部分。许多恶意程序运行后会与外部主机通信,用于下载文件、上传信息、接收命令或加入僵尸网络。因此,需要结合网络流量分析判断程序是否存在异常连接、C2 通信或远程控制行为。

常见端口和协议识别是流量分析的基础。例如,80 端口通常对应 HTTP 服务,139 和 445 端口常与 NetBIOS、SMB 文件共享相关,1433 端口对应 SQL Server,6667 端口常见于 IRC 通信。掌握这些端口和协议特征,有助于判断恶意程序的网络通信方式。

C2 即 Command and Control,指攻击者对被感染主机进行命令控制的通信机制。恶意程序可能会主动连接控制服务器,接收攻击者下发的命令并执行相应操作。IRC 协议曾经被许多早期僵尸网络用作控制通道,被感染主机可能通过 NICK、USER、JOIN 等命令连接服务器并加入指定频道,等待攻击者控制。通过识别这些通信特征,可以判断主机是否已经被恶意程序控制。

1.2.5 攻击链还原与综合分析

攻击链分析强调将单个证据点按照时间顺序和逻辑关系串联起来,例如端口扫描、漏洞探测、认证尝试、文件上传、远程执行、恶意程序启动和 C2 通信等。单独的流量或程序特征可能只能说明某一阶段行为,而将多个线索结合起来,才能较完整地还原攻击者的入侵过程和恶意程序的后续行为。

在综合分析过程中,需要将程序样本中的静态特征与网络流量中的通信行为相互印证。例如,程序中发现的字符串、IP 地址、端口或命令信息,可以与抓包文件中的连接行为进行对应;网络流量中发现的异常连接、远程执行或 C2 通信,也可以反向帮助定位程序中的相关逻辑。通过这种交叉验证,可以提高分析结论的可靠性。

二、操作流程

2.1 RaDa 样本静态分析与脱壳实验

2.1.1 实验目标、环境与整体思路

本节实验主要对恶意代码样本 RaDa.exe 进行基础静态分析和脱壳处理。整体分析思路是:首先确认样本的文件类型和运行平台,然后通过字符串分析寻找样本身份和可疑特征;接着在隔离的 Windows XP 虚拟机中验证样本说明信息,并使用 UPX 判断样本是否存在加壳;最后使用 VM Unpacker 对样本进行自动脱壳,再将脱壳后的样本导入 IDA 中继续观察程序结构。

本次实验中,我主要使用 Kali Linux 和 Windows XP 虚拟机配合完成分析。Kali Linux 用于执行 file、strings 等基础静态分析命令;Windows XP 虚拟机用于执行样本参数、查壳、脱壳以及 IDA 分析。

实验环境 / 工具 作用
Kali Linux 使用 file、strings 等命令进行基础静态分析
Windows XP 虚拟机 用于运行样本、查壳、脱壳和 Windows 环境下分析
RaDa.exe 本节实验分析的恶意代码样本
file 判断文件格式、平台和架构
strings 提取样本中的可见字符串
UPX 检测样本是否具有 UPX 加壳特征
VM Unpacker / 超级巡警脱壳工具 对样本进行自动脱壳
IDA Pro 对脱壳后的样本进行反汇编分析

这一部分的实验流程可以概括为:

步骤 操作 目的
1 使用 file 查看文件类型 判断样本平台、架构和文件格式
2 使用 strings 查看原始样本字符串 寻找样本身份和可疑线索
3 在 Windows XP 中运行 rada --authors 验证样本说明信息
4 使用 UPX 检测加壳情况 判断样本是否经过压缩或保护
5 使用 VM Unpacker 自动脱壳 获取更适合分析的脱壳样本
6 查看脱壳后生成的文件 确认原始样本、转储文件和脱壳样本
7 对脱壳样本再次做字符串分析 观察真实程序特征
8 使用 IDA 打开脱壳样本 为后续反汇编分析做准备

本节重点不是直接分析恶意行为,而是完成“样本识别—字符串分析—样本信息验证—加壳判断—脱壳—IDA 载入”的基础逆向分析流程。
在运行样本之前,我先保存了虚拟机快照。这样即使样本运行后修改系统环境,也可以快速回滚。

2.1.2 原始样本基础静态分析

在正式分析样本之前,我先在 Kali Linux 中进入样本所在目录,使用 file 命令查看 RaDa.exe 的文件类型。这样做的目的不是直接判断它是否恶意,而是先确认它属于哪一类文件,避免后续分析工具选错方向。

file RaDa.exe

命令执行后,终端返回如下结果:

RaDa.exe: PE32 executable for MS Windows 4.00 (GUI), Intel i386, 3 sections

file 命令识别 RaDa.exe 文件类型

图 2-1-1 使用 file 命令查看 RaDa.exe 的文件类型。

从这条输出中,可以先整理出样本的几个基础属性:

字段 分析结果
文件格式 PE32 executable
运行平台 Microsoft Windows
程序类型 GUI 图形界面程序
CPU 架构 Intel i386,32 位
节区数量 3 个 sections

这里可以明确一点:RaDa.exe 不是 Linux 可执行文件,也不是普通脚本文件,而是一个 Windows 平台下的 32 位 PE 可执行程序。也就是说,后续如果需要运行样本,应该放到 Windows 虚拟机中进行,而不能直接在宿主机或 Kali 环境中随意执行。

file 命令虽然只能给出比较基础的信息,但它在静态分析开始阶段很有用。至少通过这一步,我可以先确定样本的大致类型,再决定后面应该使用 Windows PE 分析思路,而不是把它当作 Linux 程序处理。

确认样本类型之后,我继续使用 strings 命令提取原始样本中的可见字符串:

strings RaDa.exe

strings 的作用是从二进制文件中提取可打印字符。对于没有加壳或混淆程度较低的程序,通常可以直接看到路径、URL、注册表项、函数名、错误提示等信息。不过在这个样本中,输出内容并不算非常清晰,既有少量有意义的字符串,也夹杂着不少难以理解的字符片段。

strings 命令查看原始样本字符串

图 2-1-2 使用 strings 命令提取原始样本中的可见字符串。

在输出结果中,我观察到了一些比较值得注意的内容:

This program is the binary of SotM 32...
Rich
JDR0
JDR1
.rsrc
Form1
Module1
ORaDa

其中最直接的信息是:

This program is the binary of SotM 32...

这说明样本与 SotM 32 有关。SotM 通常指 Honeynet Project 的 Scan of the Month 分析样本,所以这里可以初步判断,RaDa.exe 很可能是 Honeynet Project 提供的恶意代码分析训练样本。

此外,输出中还出现了 Form1、Module1 这类字符串。它们不像是普通命令行程序中的提示信息,更接近某些带图形界面程序或 Visual Basic 程序中常见的窗体、模块命名方式。因此,这里可以把它们作为判断程序开发特征的线索,但还不能只凭这几个字符串下最终结论。

同时,原始样本的 strings 输出中也存在不少没有明显语义的字符,例如:

6B@>CEC
YMOm0./
RmR].G^
W81b'#

这些内容不像常规程序中的路径、URL、注册表键值或函数名,更像是程序经过压缩、加壳或混淆后残留下来的片段。结合 strings 中可读信息较少这一现象,我认为该样本可能经过了加壳或一定程度的保护处理。

观察现象 初步分析
出现 SotM 32 样本可能与 Honeynet Project 的 Scan of the Month 有关
出现 Form1、Module1 样本可能具有 Visual Basic 程序特征
存在较多无明显语义的字符串 样本可能经过加壳、压缩或混淆
直接可读的信息较少 原始样本不适合直接依赖 strings 继续深入分析

如果一个程序没有经过明显的加壳或混淆,strings 通常能提取出较多清晰的程序逻辑信息;而这个样本的可读内容较少,所以后面需要继续检查它是否存在加壳情况。

2.1.3 样本说明信息验证与 UPX 查壳

前面通过 strings 已经发现了 SotM 32 字符串,但单靠这一点还不够稳妥。为了进一步验证样本本身提供的说明信息,我将 RaDa.exe 放入 Windows XP 虚拟机中,在样本所在目录下运行作者信息参数:

rada --authors

执行后,系统弹出了 Internet Explorer 页面,页面标题显示为:

RaDa Usage - Windows Internet Explorer

页面中可以看到样本的说明信息:

RaDa

Scan Of The Month 32 (SotM) - September 2004
http://www.honeynet.org/scans/index.html

Copyright (C) 2004 Raul Siles & David Perez

运行 rada --authors 查看作者信息

图 2-1-3 在 Windows XP 虚拟机中运行 rada --authors 后,浏览器页面显示 RaDa 样本的说明信息。

根据页面内容,可以整理出样本的基本说明:

项目 内容
样本名称 RaDa
所属项目 Scan Of The Month 32
时间 September 2004
来源 Honeynet Project
作者 Raul Siles & David Perez

这个结果与前面 strings 命令中发现的 SotM 32 字符串可以相互印证。也就是说,前面通过字符串得到的判断不是孤立线索,样本自身的参数说明也指向了 Honeynet Project 的 RaDa 分析样本。

需要注意的是,虽然这里只是运行 --authors 参数查看说明信息,但它依然属于执行样本的行为。恶意样本在不同参数下可能表现不同,所以这一步必须在隔离的 Windows 虚拟机中完成,不能放在真实主机环境里运行。

对恶意样本来说,“只是查看说明参数”也不能掉以轻心。只要涉及运行样本,就应该默认存在风险,并放到可回滚、可隔离的实验环境中完成。

由于原始样本中存在较多不可读字符串,并且可直接分析的信息有限,我接着使用 UPX 工具检查样本是否存在加壳情况。执行命令如下:

upx -l RaDa.exe

终端输出中出现了如下提示:

UPX 3.06w
Ultimate Packer for eXecutables

upx: RaDa.exe: CantUnpackException: file is modified/hacked/protected; take care!!!

使用 UPX 检测样本加壳情况

图 2-1-4 使用 UPX 工具检查 RaDa.exe 时,命令行中出现 CantUnpackException 提示。

从这段输出可以看出,UPX 并没有正常列出该文件的压缩信息,而是提示:

file is modified/hacked/protected

这说明标准 UPX 工具无法直接处理当前样本。这里不能简单理解为“样本没有加壳”,反而更应该考虑另一种情况:样本可能使用了 UPX 或类似 UPX 的壳,但壳结构被修改过,导致标准 UPX 无法正常识别或解包。

输出信息 分析理解
UPX 3.06w 当前使用的是 UPX 工具
CantUnpackException UPX 无法正常列出或解包该文件
file is modified/hacked/protected 文件可能被修改、保护或做过反脱壳处理
take care!!! 工具提示处理该样本时需要谨慎

因此,我这里的判断是:RaDa.exe 很可能与 UPX 加壳有关,但它不是一个可以被标准 UPX 直接处理的普通压缩文件。壳结构可能被修改过,或者样本本身加入了某种保护,使得直接使用 UPX 解包失败。

如果继续尝试使用普通 UPX 解包命令:

upx -d RaDa.exe

从前面的检测结果来看,大概率无法顺利完成。因此,后续分析不能只依赖标准 UPX 工具,而需要考虑使用其他脱壳工具或结合动态分析方法继续处理。

UPX 解包失败并不等于样本没有加壳。对于恶意代码分析来说,这类失败信息本身也是一种线索:它提示样本可能存在修改版壳、保护壳,或者故意破坏了标准脱壳流程。

2.1.4 使用 VM Unpacker 对样本进行脱壳

前面使用标准 UPX 对 RaDa.exe 进行检测时,工具提示 CantUnpackException,说明它无法按照普通 UPX 文件直接处理。因此,我没有继续强行使用 upx -d,而是换用 VM Unpacker,也就是超级巡警自动脱壳工具,对样本进行脱壳尝试。

这一步仍然是在 Windows XP 虚拟机中完成的。原因很简单:脱壳工具在处理样本时,可能会运行或模拟执行样本代码,如果放在真实主机上操作,风险会明显增大。

整体操作流程如下:

步骤 操作内容
1 打开 VM Unpacker
2 选择原始样本 RaDa.exe
3 设置脱壳后的输出文件名
4 点击“给我脱”开始处理
5 中间弹出的选项保持默认
6 等待工具完成脱壳
7 查看目录,确认是否生成脱壳相关文件
8 对脱壳后的文件执行 strings,检查可见字符串变化

首先打开 VM Unpacker 工具。工具主界面中主要需要关注三个位置:待处理文件路径、脱壳后的输出路径,以及右侧用于启动脱壳的按钮。这里我将输出文件设置为:

RaDa_unpacked.exe

打开 VM Unpacker 脱壳工具

图 2-1-5 VM Unpacker 主界面中显示待处理文件路径、输出文件路径和脱壳执行按钮。

随后,通过文件选择窗口定位样本所在目录。该目录中包含原始样本 RaDa.exe,后续生成的转储文件和脱壳文件也会保存在同一目录下,便于对比分析。

选择 RaDa.exe 作为待脱壳文件

图 2-1-6 在文件选择窗口中查看样本目录中的相关可执行文件。

配置好输入文件和输出文件后,点击工具中的“给我脱”开始脱壳。中间如果弹出配置选项,我没有额外修改,而是保持默认设置继续执行。这样做是为了先观察工具在默认策略下能否完成处理,避免因为手动修改参数引入新的不确定因素。

脱壳结束后,我回到样本目录中查看文件生成情况。目录中可以看到原始样本、转储文件以及脱壳后的文件,其中脱壳结果文件为:

RaDa_unpacked.exe

VM Unpacker 已载入待脱壳样本

图 2-1-7 样本目录中可以看到原始样本、转储文件和脱壳后的 RaDa_unpacked.exe。

这里还不能只凭文件名就断定脱壳一定完全成功,所以我继续对脱壳后的文件执行 strings,查看它是否暴露出比原始样本更多的可读字符串。

strings RaDa_unpacked.exe

查看脱壳后文件的字符串

图 2-1-8 对 RaDa_unpacked.exe 执行 strings 后,终端中出现多条 Visual Basic 运行时相关字符串。

从输出内容来看,脱壳后的文件中出现了大量以 __vba 开头的字符串,例如:

__vbaVarTstGt
__vbaVarSub
__vbaFreeVar
__vbaAryMove
__vbaLenBstr
__vbaPut3

这些字符串和 Visual Basic 运行时关系比较密切。结合前面原始样本中出现的 Form1、Module1 等信息,这里可以进一步判断:RaDa.exe 很可能是一个具有 Visual Basic 程序特征的样本。和原始样本相比,RaDa_unpacked.exe 中的字符串明显更有分析价值,说明脱壳操作至少让一部分真实程序内容暴露了出来。

对比对象 字符串观察结果 分析意义
原始样本 RaDa.exe 可读内容较少,并且夹杂较多乱码 可能受到加壳、压缩或混淆影响
脱壳样本 RaDa_unpacked.exe 出现大量 __vba... 字符串 更接近程序真实逻辑,适合继续静态分析
目录生成结果 出现 rada_dump_.exe 和 RaDa_unpacked.exe VM Unpacker 已生成脱壳相关文件

脱壳完成后,不能只看工具有没有生成文件,还要继续检查生成文件中是否出现更多有效字符串。这里 RaDa_unpacked.exe 中大量 Visual Basic 运行时字符串的出现,说明后续可以把它作为主要分析对象。

2.1.5 使用旧版 IDA 加载脱壳后的样本

完成脱壳后,我将 RaDa_unpacked.exe 导入旧版 IDA Pro 进行反汇编分析。这里没有继续优先分析原始的 RaDa.exe,因为原始样本很可能仍然主要呈现壳代码逻辑;如果直接分析原始样本,看到的内容可能不是程序真正的功能代码。

在启动 IDA 后,首先进入新建反汇编数据库的界面。由于 RaDa_unpacked.exe 是 Windows 平台下的 PE 可执行文件,所以这里选择 PE Executable 类型。

IDA 新建反汇编数据库并选择 PE Executable

图 2-1-9 IDA 新建反汇编数据库时选择 PE Executable 文件类型。

随后进入文件选择窗口。在样本目录中可以看到多个文件,包括原始样本和脱壳后样本。这里我选择的是:

RaDa_unpacked.exe

这样可以保证后续 IDA 分析的对象是脱壳后的文件,而不是仍然带壳的原始样本。

IDA 选择 RaDa_unpacked.exe 作为分析目标

图 2-1-10 在 IDA 文件选择窗口中选中脱壳后的 RaDa_unpacked.exe。

样本加载后,IDA 进入主分析界面,并开始对文件进行自动分析。从界面中可以看到代码区域、名称窗口和字符串窗口等内容,底部日志区域也显示了 IDA 对文件的加载和分析过程。到这一步,说明脱壳后的样本已经能够被 IDA 正常识别。

IDA 确认 PE 文件加载方式

图 2-1-11 旧版 IDA 加载 RaDa_unpacked.exe 后显示代码区域、名称窗口和字符串窗口。

IDA 自动分析完成后,我优先查看字符串窗口。字符串是恶意代码静态分析中很常用的入口,因为命令参数、文件路径、URL、注册表项、窗口标题、作者信息等内容都有可能直接以字符串形式暴露出来。

在字符串窗口中,可以直接看到与作者相关的字符串:

Raul Siles && David Perez

同时还能看到和前面样本说明信息相互对应的内容,例如:

SotM 32 - September 2004

IDA 自动分析样本并生成数据库

图 2-1-12 IDA 字符串窗口中定位到 Raul Siles && David Perez 等文本信息。

这一点比较有价值。前面运行 rada --authors 时,浏览器页面中显示了样本作者信息;现在在 IDA 的静态字符串窗口中也能看到同样的作者字符串。二者相互印证,说明脱壳后的文件中已经能够直接观察到样本真实程序信息,而不是只有壳代码或无意义字符。

为了让 IDA 更完整地识别字符串,我还查看了字符串样式设置界面。这里可以看到 IDA 支持多种字符串类型,例如 C-style、DOS style、Pascal style、Unicode 等。对于 Visual Basic 程序来说,字符串形式可能不完全是普通 C 字符串,因此字符串识别设置也会影响后续查看效果。

IDA 中查看脱壳样本字符串信息

图 2-1-13 IDA 的字符串样式设置窗口中列出了多种字符串识别类型。

回到 IDA 的 Strings 窗口后,可以看到样本中的多类字符串信息,包括 Visual Basic 运行时函数、命令参数、窗体或模块名称,以及作者信息等内容。

旧版 IDA 中查看 RaDa_unpacked.exe 反汇编结果

图 2-1-14 旧版 IDA 的 Strings 窗口中显示 RaDa_unpacked.exe 的可见字符串。

从旧版 IDA 的加载和字符串查看结果来看,脱壳后的样本已经具备继续分析的条件。后续可以围绕字符串交叉引用、函数入口和命令参数处理逻辑继续展开。

我在旧版 IDA 中主要关注以下几类内容:

观察内容 分析意义
代码区域 判断样本是否能够被 IDA 正常反汇编
名称窗口 查看 IDA 自动识别出的函数、变量和导入符号
字符串窗口 寻找命令参数、作者信息、路径、URL 等线索
程序入口点 便于后续分析样本启动后的执行流程
__vba... 相关字符串 判断样本是否具有 Visual Basic 运行时特征
字符串交叉引用 从可疑字符串反推相关代码逻辑

到这里,我的分析对象已经从原始样本 RaDa.exe 转移到了脱壳后的 RaDa_unpacked.exe。相比原始样本,脱壳后的文件能暴露出更多真实字符串,更适合作为后续静态分析入口。

2.1.6 使用新版 IDA 辅助观察样本结构

除了旧版 IDA 外,我也使用新版 IDA 对脱壳后的 RaDa_unpacked.exe 进行了辅助查看。这里使用新版 IDA 的目的不是替代前面的旧版分析结果,而是通过更清晰的界面确认样本的加载过程,并为后续截图说明提供补充。

首先打开新版 IDA,可以看到当前使用的是 IDA 7.7 版本。相比旧版 IDA,新版界面布局更接近现代软件,窗口显示和操作入口也更加直观。

新版 IDA 主界面中打开脱壳样本

图 2-1-15 新版 IDA 的版本信息窗口显示当前使用的是 IDA 7.7。

关闭版本信息窗口后,可以看到新版 IDA 的初始主界面。此时界面中还没有加载样本,中央区域提示可以将文件拖入窗口进行反汇编分析。

新版 IDA 中查看函数列表和程序结构

图 2-1-16 新版 IDA 初始界面中提示可以拖放文件进行反汇编。

接下来,在新版 IDA 中选择脱壳后的样本文件。这里仍然使用前面生成的:

RaDa_unpacked.exe

这样可以保证新版 IDA 和旧版 IDA 分析的是同一个脱壳后样本,避免因为分析对象不同导致结果无法对比。

新版 IDA 中查看字符串窗口

图 2-1-17 在新版 IDA 中选择或加载脱壳后的 RaDa_unpacked.exe。

选择文件后,IDA 会弹出“加载一个新的文件”窗口。这里可以看到文件被识别为:

Portable executable for 80386 (PE)

同时处理器类型选择为:

MetaPC

这与前面 file 命令识别出的 Windows 32 位 PE 程序结论是对应的。这里我保持默认分析选项继续加载,因为当前目标只是让 IDA 正常识别并建立分析数据库,不需要在加载阶段手动调整复杂参数。

新版 IDA 中查看综合分析面板

图 2-1-18 新版 IDA 在加载 RaDa_unpacked.exe 时识别出 PE 文件类型和处理器类型。

从新版 IDA 的加载过程来看,RaDa_unpacked.exe 可以被识别为普通 PE 可执行文件,并按照 80386 架构进行分析。这一点与旧版 IDA 的加载结果一致,也进一步说明脱壳后的样本已经不再只是难以分析的壳外层文件。

2.1.7 本节实验总结

本节实验中,我完成了 RaDa.exe 的基础静态分析、样本信息验证、加壳判断、自动脱壳以及 IDA 载入分析。整个过程不是直接跳到结论,而是按照“确认文件类型—提取字符串—验证样本信息—判断加壳—尝试脱壳—载入 IDA”的顺序逐步推进。

整体流程可以整理如下:

阶段 操作 得到的信息
文件识别 使用 file RaDa.exe 确认样本为 Windows 32 位 PE GUI 程序
原始字符串分析 使用 strings RaDa.exe 发现 SotM 32、Form1、Module1 等信息,同时存在较多不可读字符串
样本信息验证 运行 rada --authors 页面显示样本名称、项目来源、发布时间和作者信息
加壳检测 使用 upx -l RaDa.exe UPX 提示 CantUnpackException,标准 UPX 无法直接解包
自动脱壳 使用 VM Unpacker 生成 rada_dump_.exe 和 RaDa_unpacked.exe 等脱壳相关文件
脱壳后字符串分析 使用 strings RaDa_unpacked.exe 发现大量 __vba... 相关字符串
旧版 IDA 分析 加载 RaDa_unpacked.exe 查看字符串窗口、代码区域和作者信息
新版 IDA 辅助查看 加载 RaDa_unpacked.exe 确认样本能够被识别为 PE 文件并进入分析流程

这一节让我体会比较深的是,恶意代码静态分析不能一开始就急着看反汇编代码。对于带壳样本来说,前面的文件识别、字符串对比和脱壳验证非常重要。只有先确认自己分析的是更接近真实逻辑的文件,后续在 IDA 中看到的函数、字符串和交叉引用才更有意义。

2.2 新样本参数识别与程序交互逻辑分析

2.2.1 crackme1.exe 参数校验逻辑分析

在完成前面 RaDa.exe 样本的基础静态分析、脱壳和 IDA 查看之后,我继续分析实验中提供的另外两个样本:crackme1.exe 和 crackme2.exe。这一小节先分析 crackme1.exe,主要目标是通过命令行运行、字符串提取和 IDA 分析,还原程序对命令行参数的判断过程。

和前面的 RaDa.exe 不同,这里分析的重点不是脱壳,而是理解程序如何根据用户输入的参数进入不同分支。也就是说,本节更关注“程序为什么输出这句话”,而不是单纯记录“程序输出了什么”。

本节分析的是新的 crackme 样本,不是前面脱壳后的 RaDa_unpacked.exe。这里重点放在参数识别、字符串定位和程序交互逻辑还原上。

1. 确认实验样本与哈希值

首先,我在实验目录下查看了两个新样本,并使用 md5sum 计算它们的 MD5 值。这样做主要是为了在报告中明确样本身份,避免后续把 crackme1.exe 和 crackme2.exe 的分析结果混在一起。

md5sum crackme1.exe crackme2.exe

计算 crackme 样本 MD5 值

图 2-2-1 使用 md5sum 计算 crackme1.exe 和 crackme2.exe 的 MD5 值。

从命令输出可以看到,两个样本对应的 MD5 值并不相同,说明它们是两个不同的可执行文件。后续分析时,我先从 crackme1.exe 入手。

样本文件 MD5 值
crackme1.exe 4357bf8c20fabb642fafc0b73fb0abfb
crackme2.exe 46aa577172d8f37ae2ae281515c99afb

在逆向分析或恶意代码分析实验中,记录哈希值是一个很有必要的习惯。文件名有时可能被修改,但哈希值可以帮助确认当前分析的到底是哪一个样本。

2. 判断样本文件类型

接着,我使用 file 命令查看两个样本的文件类型:

file crackme1.exe
file crackme2.exe

查看 crackme 样本文件类型

图 2-2-2 使用 file 命令查看两个 crackme 样本的文件类型。

终端输出结果如下:

crackme1.exe: PE32 executable (console) Intel 80386, for MS Windows
crackme2.exe: PE32 executable (console) Intel 80386, for MS Windows

根据这两行结果,可以确认 crackme1.exe 和 crackme2.exe 都是 Windows 平台下的 32 位 PE 可执行文件,并且属于控制台程序。和前面分析的 RaDa.exe GUI 程序不同,这两个样本更适合通过命令行传入参数,再观察程序返回的输出内容。

项目 分析结果
文件格式 PE32 executable
程序类型 console 控制台程序
运行平台 MS Windows
架构 Intel 80386,32 位
初步分析方向 命令行参数与输出逻辑

由于样本是控制台程序,所以我没有一开始就进入 IDA,而是先通过命令行运行它,观察不同输入方式对应的输出差异。

3. 直接运行 crackme1.exe 观察程序输出

确认文件类型后,我先在 Windows 命令行中直接运行 crackme1.exe,并尝试传入不同数量的参数。这样可以先从程序外部表现入手,初步判断它对参数数量是否有要求。

直接运行 crackme1.exe 观察输出

图 2-2-3 在命令行中运行 crackme1.exe,并尝试输入不同数量的参数。

从运行结果可以整理出以下输出:

crackme1.exe
I think you are missing something.

crackme1.exe 1
Pardon? What did you say?

crackme1.exe 1 2
I think you are missing something.

crackme1.exe 1 2 3
I think you are missing something.

根据这些现象,可以先做一个初步分析:

运行方式 输出结果 初步判断
不带参数运行 I think you are missing something. 程序认为缺少必要输入
输入 1 个参数 Pardon? What did you say? 参数数量可能符合要求,但参数内容不正确
输入 2 个参数 I think you are missing something. 参数数量不符合要求
输入 3 个参数 I think you are missing something. 参数数量不符合要求

这里有一个容易忽略的细节:在 C/C++ 程序中,argc 会把程序名本身也算进去。例如用户在命令行输入:

crackme1.exe 1

程序内部看到的参数数量并不是 1,而是:

argc = 2
argv[0] = crackme1.exe
argv[1] = 1

所以结合运行结果可以初步判断,程序很可能要求 argc == 2,也就是用户只能输入一个真正的命令行参数。如果参数数量不是一个,程序就会输出:

I think you are missing something.

而当参数数量符合要求、但参数内容不符合程序预期时,就会输出:

Pardon? What did you say?

单纯从运行结果看,还不能直接确定正确参数是什么,但可以先判断出程序应该对参数数量做了检查,而且很可能只接受一个用户输入参数。

4. 使用 strings 提取可疑字符串

为了进一步确认程序内部是否存在提示文本或可疑参数,我使用 strings 命令查看 crackme1.exe 中的可见字符串:

strings crackme1.exe

使用 strings 查看 crackme1.exe 字符串

图 2-2-4 使用 strings 提取 crackme1.exe 中的可见字符串。

在输出结果中,我发现了几条与程序交互相关的字符串:

I think you are missing something.
I know the secret
Pardon? What did you say?
You know how to speak to programs, Mr. Reverse-Engineer

这些字符串和前面命令行运行时看到的输出能够对应起来。其中,I think you are missing something. 和 Pardon? What did you say? 已经在运行过程中出现过;而 You know how to speak to programs, Mr. Reverse-Engineer 尚未出现,更像是某个条件满足之后才会输出的成功提示。

比较值得注意的是:

I know the secret

这句话不像普通提示语,更像程序希望用户输入的特定内容。因此,这里可以初步判断,crackme1.exe 可能会将用户输入的参数与 I know the secret 进行比较。

字符串 可能含义
I think you are missing something. 参数数量不正确时的提示
I know the secret 可能是程序期望的输入参数
Pardon? What did you say? 参数数量正确但内容错误时的提示
You know how to speak to programs, Mr. Reverse-Engineer 参数正确时可能出现的成功输出

strings 并不能直接证明程序一定使用了这些字符串,但它提供了很明确的方向:后续可以在 IDA 中围绕这些字符串的引用位置继续分析。

5. 在 IDA 中查看整体分支结构

虽然 strings 已经给出了比较强的线索,但只看字符串仍然不够严谨。为了确认程序到底是如何判断参数的,我继续将 crackme1.exe 放入 IDA 中查看反汇编结果和整体分支结构。

IDA 中查看 crackme1.exe 分支结构

图 2-2-5 在 IDA 中打开 crackme1.exe,图形视图中可以看到程序的条件跳转结构。

从 IDA 的图形视图可以看到,程序整体结构并不复杂,主要由几个条件判断分支组成。结合前面的运行结果和字符串提取结果,可以把这些分支暂时对应到下面几种情况:

分支情况 对应现象 分析理解
参数数量不正确 输出 I think you are missing something. 程序没有继续比较参数内容
参数数量正确但内容错误 输出 Pardon? What did you say? 程序进行了参数内容比较,但比较失败
参数数量正确且内容正确 输出 You know how to speak to programs, Mr. Reverse-Engineer 程序进入成功分支

这种结构和前面通过命令行测试得到的现象是匹配的。程序应该先判断参数数量,再判断参数内容。如果参数数量不符合要求,就直接进入错误提示分支;只有参数数量满足条件后,才会继续比较用户输入的字符串。

IDA 的图形视图适合先看程序的大致流程。对于这种小型 crackme 程序,不需要一开始就逐条指令硬看,而是可以先结合运行现象和字符串线索,把几个分支的大概含义对应起来。

6. 定位 main 函数

在确认程序存在多个条件分支之后,我继续在 IDA 的函数列表中定位 _main 函数。对于这种 Windows 控制台程序来说,命令行参数一般会在 main 函数中处理,因此先看 _main 是比较直接的分析入口。

IDA 函数列表中定位 main 函数

图 2-2-6 IDA 函数列表中可以看到 _main、_strcmp、_printf 等函数名称。

从函数列表中可以看到,程序中包含 _main、_strcmp、_printf、_fprintf 等函数。其中,_main 是主要逻辑入口;_strcmp 通常用于字符串比较;_printf 和 _fprintf 则与文本输出有关。这些函数名和前面通过运行现象得到的判断是能够对应起来的:程序很可能先检查参数,再根据比较结果输出不同提示。

函数名 作用判断
_main 程序主要逻辑入口
_strcmp 可能用于比较用户输入和目标字符串
_printf 与普通输出有关
_fprintf 与格式化输出有关,可能用于错误提示
_exit / _cexit 与程序退出流程有关

看到 _strcmp 之后,分析方向就比较明确了:程序大概率不是只判断参数数量,还会继续比较用户输入的字符串内容。

7. 通过伪代码还原判断逻辑

进入 _main 函数后,我通过 Fn + F5 查看 IDA 生成的伪代码。相比直接看汇编指令,伪代码更容易观察整体逻辑,尤其适合这种结构较简单的 crackme 程序。

IDA 伪代码中查看参数判断逻辑

图 2-2-7 IDA 伪代码窗口中显示 argc 判断和 strcmp 字符串比较逻辑。

从伪代码可以看出,程序首先判断 argc 是否等于 2。如果参数数量不符合要求,程序会直接输出缺少参数的提示;只有当参数数量正确时,程序才会继续使用 strcmp 比较 argv[1] 和固定字符串。

根据伪代码,核心逻辑可以还原为下面的形式:

if (argc != 2) {
    printf("I think you are missing something.");
} else if (strcmp(argv[1], "I know the secret") == 0) {
    printf("You know how to speak to programs, Mr. Reverse-Engineer");
} else {
    printf("Pardon? What did you say?");
}

这里需要特别注意 strcmp 的返回值。strcmp 在两个字符串相等时返回 0,所以判断语句中的:

strcmp(argv[1], "I know the secret") == 0

表示用户输入的第一个参数必须等于:

I know the secret

否则就会进入参数内容错误的分支。

判断条件 程序行为
argc != 2 输出 I think you are missing something.
argc == 2 且 argv[1] == "I know the secret" 输出成功提示
argc == 2 但参数内容不匹配 输出 Pardon? What did you say?

这样一来,前面运行测试中出现的现象就都能解释清楚了。不带参数、两个参数或更多参数时,程序都会认为参数数量不正确;只有输入一个参数时,程序才会继续判断这个参数的内容是否正确。

这里不是单纯从字符串中“猜”正确参数,而是通过伪代码确认了程序确实调用 strcmp 将用户输入和固定字符串进行了比较。

8. 使用正确参数进行运行验证

根据前面的分析,正确运行方式应该是给程序传入一个命令行参数:

crackme1.exe "I know the secret"

由于参数内容中包含空格,所以必须使用英文双引号包裹。如果不加双引号,Windows 命令行会把 I know the secret 拆成多个参数,导致程序内部的 argc 不再等于 2,最终仍然会进入参数数量错误的分支。

输入正确参数验证程序输出

图 2-2-8 在命令行中为 crackme1.exe 输入参数 "I know the secret"。

运行后,程序输出如下内容:

You know how to speak to programs, Mr. Reverse-Engineer

这个结果与前面的静态分析结论一致,说明通过 strings、IDA 分支结构和伪代码还原得到的判断逻辑是成立的。

运行命令 输出结果 原因
crackme1.exe I think you are missing something. 没有输入用户参数,argc != 2
crackme1.exe 1 Pardon? What did you say? 参数数量正确,但内容错误
crackme1.exe 1 2 I think you are missing something. 参数数量过多,argc != 2
crackme1.exe "I know the secret" You know how to speak to programs, Mr. Reverse-Engineer 参数数量和内容都符合判断条件

对带空格的命令行参数进行测试时,引号非常重要。这里如果不加英文双引号,程序收到的就不是一个完整参数,而是多个被空格分隔开的参数。

9. 本小节流程总结

本小节通过运行观察、字符串分析和 IDA 反编译,完成了对 crackme1.exe 参数校验逻辑的还原。整个过程不是直接从字符串中找答案,而是先观察程序外部行为,再回到 IDA 中确认判断逻辑,最后重新运行程序验证结果。

整体流程如下:

步骤 操作 得到的信息
1 计算 MD5 确认两个 crackme 样本的文件身份
2 使用 file 查看类型 确认样本为 Windows 32 位控制台程序
3 直接运行样本 发现不同参数数量会触发不同输出
4 使用 strings 提取字符串 找到疑似正确参数 I know the secret
5 使用 IDA 查看图形视图 观察程序存在多个条件分支
6 定位 _main 函数 找到参数处理逻辑所在位置
7 查看伪代码 还原 argc 与 strcmp 判断逻辑
8 命令行验证 使用正确参数触发成功输出

最终可以得到结论:crackme1.exe 要求用户输入且只输入一个命令行参数。当参数内容为:

I know the secret

时,程序会输出成功提示:

You know how to speak to programs, Mr. Reverse-Engineer

如果参数数量不正确,程序会输出:

I think you are missing something.

如果参数数量正确但内容不匹配,程序会输出:

Pardon? What did you say?

这一小节体现了逆向分析中比较典型的一条路径:先运行样本观察现象,再用 strings 找字符串线索,接着用 IDA 定位判断逻辑,最后回到命令行验证分析结果。这样得到的结论比单纯根据字符串猜测要可靠得多。

2.2.2 crackme2.exe 文件名校验与隐藏字符串还原

在完成 crackme1.exe 的参数校验逻辑分析后,我继续分析第二个样本 crackme2.exe。和 crackme1.exe 相比,crackme2.exe 的逻辑更绕一些。它不仅会检查命令行参数,还会检查程序自身的文件名,并且最终的成功输出并不是完整明文字符串,而是通过异或运算动态还原出来的。

这一小节的分析思路如下:

步骤 操作 目的
1 直接运行 crackme2.exe 观察不同参数数量下的输出
2 输入 I know the secret 参数 判断它是否沿用 crackme1.exe 的参数逻辑
3 根据提示关注文件名问题 分析 identity problem 是否与程序名有关
4 使用 IDA 查看程序结构 判断程序是否存在额外校验分支
5 查看伪代码 确认文件名检查、参数检查和隐藏字符串还原逻辑
6 查看静态字节数据 找到参与异或运算的字节数组
7 辅助还原十六进制数据 得到程序隐藏输出内容
8 修改文件名并运行验证 验证静态分析结论是否正确

crackme2.exe 的重点不只是“输入正确参数”。它还要求程序运行时的文件名符合条件,否则即使命令行参数正确,也无法进入最终成功分支。

1. 直接运行 crackme2.exe 观察输出

首先,我在 Windows 命令行中直接运行 crackme2.exe,并尝试传入不同数量的参数。这样可以先从程序外部表现入手,判断它是否仍然和 crackme1.exe 一样对参数数量有要求。

直接运行 crackme2.exe 观察输出

图 2-2-9 在命令行中运行 crackme2.exe,并尝试输入不同数量的参数。

从运行结果可以整理出以下输出:

crackme2.exe
I think you are missing something.

crackme2.exe 1
I have an identity problem.

crackme2.exe 1 2
I think you are missing something.

crackme2.exe 1 2 3
I think you are missing something.

根据结果可以先做一个初步判断:程序仍然要求用户只输入一个真正的命令行参数。因为当不输入参数、输入两个参数或输入更多参数时,程序都会输出:

I think you are missing something.

但是,当只输入一个参数时,程序没有输出 Pardon? What did you say?,而是输出了另一条提示:

I have an identity problem.

这说明程序在确认参数数量正确后,又进入了另一个判断分支。也就是说,crackme2.exe 不只是检查参数数量和参数内容,还可能检查程序自身名称、路径或运行环境。

运行方式 输出结果 初步判断
crackme2.exe I think you are missing something. 没有提供必要参数
crackme2.exe 1 I have an identity problem. 参数数量正确,但程序身份检查失败
crackme2.exe 1 2 I think you are missing something. 参数数量不符合要求
crackme2.exe 1 2 3 I think you are missing something. 参数数量不符合要求

I have an identity problem. 这句话比较重要。它不像普通参数错误提示,更像是程序发现“自己不是预期的身份”,所以后面需要重点检查它是否对文件名做了判断。

2. 使用 crackme1 的正确参数进行尝试

由于前面已经分析出 crackme1.exe 的正确参数是:

I know the secret

所以我继续对 crackme2.exe 输入同样的参数,观察它是否沿用了相同的参数校验逻辑:

crackme2.exe "I know the secret"

对 crackme2.exe 输入 I know the secret 参数

图 2-2-10 在命令行中对 crackme2.exe 输入参数 "I know the secret"。

运行结果为:

I have an identity problem.

这个结果说明,即使输入了 crackme1.exe 中的正确参数,crackme2.exe 仍然没有进入成功输出分支。这里有两种可能:第一,crackme2.exe 的正确参数并不是 I know the secret;第二,参数可能是正确的,但程序在检查参数之前,还存在另一层更靠前的判断。

结合输出中的 identity problem,我更倾向于第二种可能:程序可能先检查自身文件名或运行身份,如果这一层检查不通过,就不会继续进入后面的参数比较逻辑。

这一步不能直接说明 I know the secret 一定是正确参数,但它暴露出一个新的分析方向:crackme2.exe 很可能存在文件名或身份校验。

3. 根据提示关注程序文件名校验

既然程序一直提示:

I have an identity problem.

我接下来把分析重点放在“程序如何判断自己的身份”上。对于控制台程序来说,常见做法是通过 argv[0] 获取程序启动时的文件名,然后和某个固定字符串进行比较。如果文件名不匹配,就输出身份错误提示。

在进入 IDA 之前,我先关注样本所在目录中的文件名情况。当前运行的程序名是:

crackme2.exe

如果程序内部确实对 argv[0] 做了比较,那么只靠输入正确参数还不够,还需要把样本复制或重命名为程序期望的名称。

准备分析 crackme2.exe 的文件名校验逻辑

图 2-2-11 样本目录中显示当前待分析文件 crackme2.exe。

这里不能直接靠猜文件名完成实验。文件名到底应该是什么,必须回到 IDA 中查看程序实际比较的字符串,这样得到的结论才可靠。

运行现象只能提示分析方向,不能替代静态分析。这里真正要确认的是:程序是否调用了字符串比较函数,以及它拿当前文件名和哪个字符串进行比较。

4. 在 IDA 中查看 crackme2.exe 的整体结构

接着,我将 crackme2.exe 导入 IDA,先从图形视图观察程序整体结构。相比 crackme1.exe,这个样本的分支明显多了一些,因此先看流程图比直接逐条阅读汇编更清楚。

IDA 中查看 crackme2.exe 分支结构

图 2-2-12 IDA 图形视图中显示 crackme2.exe 的多个条件跳转分支。

从图形视图可以看到,crackme2.exe 的结构比 crackme1.exe 稍复杂。它并不是简单地判断用户输入是否等于某个字符串,而是多了一层额外判断。结合前面的运行结果,可以暂时把这些分支理解为下面几类:

分支 可能含义
参数数量判断 判断 argc 是否等于 2
程序身份判断 判断程序自身名称或路径是否符合要求
参数内容判断 判断 argv[1] 是否为指定字符串
隐藏输出逻辑 满足所有条件后还原并输出隐藏字符串
错误输出逻辑 条件不满足时输出对应错误提示

这一步主要是建立整体认识:程序至少不是单层判断,而是存在多层条件控制。后面还需要进入伪代码,确认每一层具体比较的内容。

图形视图适合用来判断程序大致有几层分支。真正的比较对象,比如文件名和参数字符串,还需要通过伪代码或汇编指令进一步确认。

5. 通过伪代码确认文件名和参数校验逻辑

接着,我查看 IDA 生成的伪代码。这里可以比较清楚地看到 crackme2.exe 的核心判断逻辑:程序先检查参数数量,再检查程序文件名,最后才检查用户输入的参数内容。

IDA 伪代码中查看文件名和参数校验逻辑

图 2-2-13 IDA 伪代码窗口中显示 argc 判断、argv 比较和循环输出相关代码。

根据伪代码,可以将程序主要逻辑整理为下面的形式:

if (argc == 2) {
    if (!strcmp(*argv, "crackmeplease.exe")) {
        if (!strcmp(argv[1], "I know the secret")) {
            for (i = 0; i <= 0x21; ++i) {
                putchar((char)(byte_403080[i] ^ 0x42));
            }
            puts(Buffer);
            return 0;
        } else {
            fprintf(stderr, "Pardon? What did you say?\n");
            return 3;
        }
    } else {
        fprintf(stderr, "I have an identity problem.\n");
        return 2;
    }
} else {
    fprintf(stderr, "I think you are missing something.\n");
}

这段逻辑说明程序主要进行了三层判断:

判断顺序 判断内容 不满足时的输出
第 1 层 argc == 2 I think you are missing something.
第 2 层 程序名是否为 crackmeplease.exe I have an identity problem.
第 3 层 参数是否为 I know the secret Pardon? What did you say?
全部满足 对 byte_403080 中的数据逐字节异或 0x42 并输出 输出还原后的隐藏字符串

其中最关键的是这一句:

!strcmp(*argv, "crackmeplease.exe")

*argv 等价于 argv[0],也就是程序启动时的文件名。strcmp 在两个字符串相等时返回 0,而前面的 ! 会把 0 转换为真。因此,这句代码的含义是:只有当程序名等于下面这个字符串时,文件名检查才会通过。

crackmeplease.exe

这就解释了前面的运行现象。当前运行的文件名是:

crackme2.exe

而程序期望的文件名是:

crackmeplease.exe

所以即使输入:

crackme2.exe "I know the secret"

程序仍然会输出:

I have an identity problem.

原因并不是参数一定错误,而是文件名检查没有通过。

到这里,identity problem 的含义就比较清楚了:程序认为当前文件名不是它期望的名字。后续只需要将样本复制或重命名为 crackmeplease.exe,再配合正确参数运行,就可以验证这一判断。

6. 分析隐藏字符串的静态字节数据

继续查看伪代码时,可以发现程序在成功分支中并不是直接输出一段完整的明文字符串,而是通过循环逐字节处理 byte_403080 数组中的数据:

putchar((char)(byte_403080[i] ^ 0x42));

这句代码的含义比较明确:程序会依次取出 byte_403080 数组中的每个字节,然后与 0x42 进行异或运算,最后把得到的字符输出到屏幕上。也就是说,真正的成功提示并没有直接以明文形式保存在程序中,而是经过了简单的异或混淆。

随后,我在 IDA 中定位到 byte_403080 对应的静态数据区域,查看数组中保存的原始十六进制字节。

IDA 中查看 byte_403080 静态字节数据

图 2-2-14 IDA 数据窗口中显示 byte_403080 附近的十六进制字节数据。

从数据区可以提取出下面这一组十六进制字节:

15 27 62 2A 23 34 27 62 23 62 2E 2B 36 36 2E 27 62 31 27 21 30 27 36 78 62 01 2A 2D 21 2D 2E 23 36 27

根据伪代码中的逻辑,每个字节都需要执行下面的运算:

byte ^ 0x42

为了确认这个过程,我先手动计算了前几个字节:

原始字节 异或值 运算结果 字符
0x15 0x42 0x57 W
0x27 0x42 0x65 e
0x62 0x42 0x20 空格
0x2A 0x42 0x68 h
0x23 0x42 0x61 a

从前几个字节的结果来看,解码后的内容已经开始呈现出可读英文文本:

We ha...

因此,这段数据并不是随机字节,而是经过 0x42 异或处理后的隐藏字符串。程序只有在文件名和参数都满足条件后,才会进入这个循环并逐字节输出真实内容。

这里的隐藏字符串没有直接以明文形式保存,所以普通 strings 不一定能直接提取出完整结果。虽然异或 0x42 这种方式并不复杂,但它足够让字符串在静态查看时变得不那么直观。

7. 借助 DeepSeek 辅助还原十六进制结果

为了更快确认整段十六进制数据异或后的结果,我将 byte_403080 中的字节序列交给 DeepSeek 辅助处理,让它按照伪代码逻辑逐字节执行:

byte ^ 0x42

将十六进制结果交给 DeepSeek 辅助分析

图 2-2-15 使用 DeepSeek 对十六进制字节序列进行异或还原。

还原后的字符串为:

We have a little secret: Chocolate

这个结果与前面手动计算前几个字节得到的 We ha... 是能够对应上的,说明异或还原方向是正确的。不过这里我没有直接把辅助工具的输出当成最终结论,而是继续回到命令行中进行实际运行验证。

AI 工具适合辅助处理重复性的字节运算,但最终结论仍然需要回到程序本身验证。逆向分析里比较稳妥的做法是:静态分析得到推断,动态运行确认结果。

8. 修改文件名并运行验证

根据前面 IDA 伪代码的分析,程序要求自身文件名为:

crackmeplease.exe

同时,用户输入的参数需要为:

I know the secret

因此,我将原来的 crackme2.exe 复制或重命名为 crackmeplease.exe,然后在命令行中输入正确参数运行:

crackmeplease.exe "I know the secret"

重命名后输入正确参数运行验证

图 2-2-16 将样本命名为 crackmeplease.exe 后,在命令行中输入参数 "I know the secret"。

程序输出结果为:

We have a little secret: Chocolate

这个输出与前面通过 IDA 伪代码和异或解码得到的字符串一致,说明分析过程是成立的。此时程序能够进入最终分支,是因为三个条件同时满足:

条件 是否满足
只输入 1 个用户参数 满足
程序名为 crackmeplease.exe 满足
参数内容为 I know the secret 满足
byte_403080 中的数据与 0x42 异或后输出 成功执行

如果只满足其中一部分条件,程序就不会输出最终字符串。例如,文件名仍然是 crackme2.exe 时,即使输入 "I know the secret",程序仍然会提示:

I have an identity problem.

最终正确运行方式是:先让程序以 crackmeplease.exe 这个文件名运行,再输入参数 "I know the secret"。文件名检查和参数检查都通过后,程序才会执行隐藏字符串还原逻辑。

9. 本小节流程总结

本小节完成了对 crackme2.exe 的文件名校验、参数校验和隐藏字符串还原分析。和 crackme1.exe 相比,这个样本多了一层对程序自身名称的检查,并且把最终输出内容做了简单异或混淆。

整体流程可以总结如下:

阶段 操作 得到的信息
运行观察 直接运行 crackme2.exe 发现程序会提示缺少参数或身份错误
参数测试 输入 "I know the secret" 程序仍然提示 I have an identity problem.
IDA 分析 查看图形视图和伪代码 发现程序存在文件名检查逻辑
文件名判断 分析 strcmp(*argv, "crackmeplease.exe") 确认程序期望文件名为 crackmeplease.exe
参数判断 分析 strcmp(argv[1], "I know the secret") 确认正确参数仍是 I know the secret
隐藏字符串分析 查看 byte_403080 静态数据 发现字节数据需要与 0x42 异或
辅助解码 对十六进制字节执行异或还原 得到 We have a little secret: Chocolate
运行验证 重命名并输入正确参数 成功输出隐藏字符串

最终可以得到结论:crackme2.exe 的成功条件比 crackme1.exe 多了一层文件名校验。只有当程序运行时的文件名为:

crackmeplease.exe

并且输入参数为:

I know the secret

时,程序才会进入最终成功分支,对静态字节数组执行异或解码,并输出:

We have a little secret: Chocolate

这一小节比较完整地体现了从运行现象到代码逻辑再到结果验证的分析过程。程序表面上只是提示 identity problem,但通过 IDA 可以确认真正原因是文件名不匹配;而最终输出字符串也不是直接暴露在明文中,需要结合静态数据和异或运算才能还原出来。

2.3 Windows 2000 蜜罐加入 IRC 僵尸网络流量分析

本节实验围绕 Windows 2000 蜜罐主机被攻破并加入 IRC 僵尸网络的过程展开。实验数据来自 Snort 采集到的网络流量文件,分析目标是借助 Wireshark 和 tshark 还原蜜罐主机的网络行为,重点关注它是否连接了 IRC 服务器、是否加入了僵尸网络频道,以及该 IRC 僵尸网络在观察期间大致涉及多少主机。

本节分析对象可以先整理如下:

对象 说明
蜜罐主机 IP 172.16.134.191
主要分析工具 Wireshark、tshark、strings、grep、sort、uniq
重点协议 IRC、SMB、NetBIOS、HTTP/IIS、RAdmin、SQL Server
重点端口 6667、445、139、80、4899、1433
分析目标 还原蜜罐被攻破并加入 IRC 僵尸网络的过程

本节的分析思路是:先确认蜜罐是否连接 IRC C2,再定位 IRC 服务器和相关通信内容,随后统计访问该 IRC 服务器的不同主机标识数量,为后续分析攻击链提供基础。

2.3.1 IRC 是什么?客户端加入 IRC 网络时会发送什么消息?IRC 一般使用哪些 TCP 端口?

IRC 的全称是 Internet Relay Chat,即互联网中继聊天协议。它是一种较早出现的实时文本聊天协议,用户可以连接到 IRC 服务器,并加入不同频道进行交流。在正常场景中,IRC 用于多人聊天;但在安全事件中,IRC 也经常被僵尸网络用作 C2,也就是命令与控制通道。

在 IRC 僵尸网络中,被感染主机会像普通 IRC 客户端一样主动连接 IRC 服务器,然后进入攻击者指定的频道。攻击者可以在频道中发送命令,受控主机则根据命令执行扫描、下载、攻击或其他操作。

IRC 客户端连接服务器并加入频道时,常见消息如下:

IRC 消息 作用
NICK <nickname> 设置客户端昵称
USER <username> <hostname> <servername> :<realname> 注册用户信息
JOIN <channel> 加入指定 IRC 频道
PRIVMSG 发送频道消息或私聊消息

IRC 常见 TCP 端口如下:

TCP 端口 说明
6660-6669 IRC 常见端口范围
6667 最常见的 IRC 端口之一
7000 部分 IRC 服务可能使用
6697 常见 SSL/TLS IRC 端口

在本实验中,我优先关注 6667 端口,因为它是 IRC 通信中很常见的端口,也更容易作为定位蜜罐加入 IRC 僵尸网络的入口。

为了查看蜜罐主机是否发送了 IRC 注册和加入频道相关消息,我在 Wireshark 中使用如下过滤器:

ip.addr == 172.16.134.191 && tcp.port == 6667 && (tcp contains "NICK" || tcp contains "USER" || tcp contains "JOIN")

Wireshark 过滤 IRC 注册与加入频道消息

图 2-3-1 在 Wireshark 中过滤蜜罐主机与 6667 端口相关的 IRC 注册和加入频道消息。

过滤结果中出现了与 NICK、USER、JOIN 相关的数据包。为了进一步查看完整通信内容,我继续对相关数据包进行 TCP 流追踪。

跟踪 IRC TCP 流查看 NICK USER JOIN

图 2-3-2 跟踪 IRC 通信对应的 TCP 流后,窗口中显示 NICK、USER、JOIN 等文本内容。

从 TCP 流内容可以看出,蜜罐主机确实向 IRC 服务器发送了注册昵称、提交用户信息和加入频道的请求。这些行为与普通 IRC 客户端加入 IRC 网络的流程一致,但结合蜜罐被攻击的场景来看,它更像是被植入恶意程序后主动连接 IRC C2。

观察内容 分析理解
出现 NICK 蜜罐主机向 IRC 服务器注册昵称
出现 USER 蜜罐主机提交用户信息
出现 JOIN 蜜罐主机加入指定 IRC 频道
通信端口为 6667 符合常见 IRC 通信端口特征

这里可以初步判断,蜜罐主机已经表现出 IRC bot 的典型行为:主动连接 IRC 服务器,并加入指定频道等待后续控制命令。

2.3.2 僵尸网络是什么?僵尸网络通常用于什么?

僵尸网络,英文为 Botnet,是指大量被恶意程序感染并被攻击者远程控制的主机集合。被感染的主机通常被称为 bot、zombie、僵尸主机或肉鸡。

在僵尸网络中,攻击者通常会通过 C2 服务器向受控主机下发命令。受控主机收到命令后,可能会继续扫描其他目标、下载恶意程序、发起攻击、转发流量,或者执行攻击者指定的其他操作。

常见用途可以整理如下:

用途 说明
DDoS 攻击 控制大量主机同时访问目标,造成拒绝服务
发送垃圾邮件 利用受控主机批量发送垃圾邮件
扫描和传播蠕虫 搜索更多可感染主机
远程控制 攻击者可以远程操控受感染主机
下载并执行恶意程序 在受害主机上安装更多恶意组件
暴力破解 对其他主机进行口令猜测
代理跳板 将受控主机作为攻击跳板
窃取信息 收集账号、密码、系统信息等

僵尸网络通信特征示意

图 2-3-3 僵尸网络中攻击者、C2 服务器和受控主机之间的通信关系示意。

结合本实验流量来看,蜜罐主机在被攻破后主动连接 IRC 服务器,并进入 IRC 频道。这种行为说明它很可能已经成为 IRC 僵尸网络中的一台 bot。IRC 服务器在这里不再只是普通聊天服务器,而是承担了攻击者下发命令的控制中心角色。

僵尸网络的核心特点是“集中控制、批量执行”。本实验中,IRC 服务器就是受控主机和攻击者之间的中转控制节点。

2.3.3 蜜罐主机与哪些 IRC 服务器进行了通信?

为了找出蜜罐主机与哪些 IRC 服务器进行了通信,我先在 Wireshark 中过滤蜜罐主机在 6667 端口上的所有通信:

ip.addr == 172.16.134.191 && tcp.port == 6667

过滤蜜罐主机 IRC 端口通信

图 2-3-4 使用过滤器查看蜜罐主机与 6667 端口相关的通信数据包。

过滤后可以看到,蜜罐主机与远程主机之间存在多条 6667 端口通信记录。为了更直观地统计通信双方,我继续使用 Wireshark 的会话统计功能:

Statistics -> Conversations -> TCP

打开 Wireshark TCP Conversations

图 2-3-5 在 Wireshark 中打开 Statistics -> Conversations -> TCP 会话统计功能。

在 TCP Conversations 统计窗口中,可以按地址、端口、数据包数量和字节数查看通信双方。这里重点关注蜜罐主机 172.16.134.191 与远程 6667 端口之间的连接关系。

查看蜜罐 IRC 通信服务器

图 2-3-6 TCP Conversations 统计窗口中显示蜜罐主机与远程 IRC 服务器之间的会话信息。

结合过滤结果和 TCP 会话统计,可以确认蜜罐主机主要与以下 IRC 服务器进行了通信:

IRC 服务器 IP 端口 说明
209.196.44.172 6667 蜜罐连接的主要 IRC C2 服务器

这说明后续分析可以围绕 209.196.44.172:6667 展开。因为蜜罐主机连接 IRC 网络、注册身份、加入频道等行为,都与该服务器相关。

这里先确定 IRC 服务器地址,是为了后面继续统计僵尸网络规模和还原 C2 通信内容。否则直接在全部流量中查找 IRC 文本,范围会比较散。

2.3.4 在观察期间,有多少不同主机访问了以 209.196.44.172 为服务器的僵尸网络?

为了统计在观察期间有多少不同主机访问了 209.196.44.172 这个 IRC 服务器,我使用 tshark 从流量文件中提取与该服务器和 6667 端口相关的 TCP payload,并将其转换为原始 IRC 文本。

首先导出 IRC 通信中的 TCP payload:

tshark -r botnet_pcap_file.dat \
-Y "ip.addr == 209.196.44.172 && tcp.port == 6667" \
-T fields -e tcp.payload \
| xxd -r -p > irc_209.raw

这条命令的作用可以拆开理解:

命令部分 作用
tshark -r botnet_pcap_file.dat 读取流量文件
-Y "ip.addr == 209.196.44.172 && tcp.port == 6667" 过滤与指定 IRC 服务器和端口相关的通信
-T fields -e tcp.payload 提取 TCP payload 字段
xxd -r -p 将十六进制 payload 还原为原始字节
> irc_209.raw 将结果保存为原始 IRC 数据文件

随后,从导出的 IRC 数据中提取出现过的主机标识,并进行去重统计:

strings -a irc_209.raw \
| grep -E "JOIN|QUIT|PRIVMSG" \
| grep -oE ':[^! ]+![^@ ]+@[^ ]+' \
| sed 's/^://' \
| sed -E 's/^[^!]+![^@]+@//' \
| sort -u \
| wc -l

这条命令主要是从 IRC 消息前缀中提取 nickname!user@host 形式的主机标识,再保留 host 部分并去重计数。这里统计到的是流量中出现过的不同主机标识,可以用来估计该 IRC 僵尸网络在观察窗口内涉及的主机规模。

统计访问 IRC 僵尸网络的不同主机数量

图 2-3-7 使用 tshark 和字符串处理命令统计 IRC 消息中的不同主机标识数量。

最终统计结果为:

5587

因此,在这段观察流量中,统计到访问 209.196.44.172:6667 IRC 僵尸网络的不同主机标识数量为 5587。这里需要注意,命令统计的是 IRC 消息中的 host 字段去重结果,因此更严谨地说,它表示观察期间捕获到的不同主机标识数量,而不是绝对意义上的全球僵尸主机总数。

统计对象 结果
IRC 服务器 209.196.44.172
IRC 端口 6667
统计依据 IRC 消息中的 nickname!user@host 标识
去重对象 host 部分
不同主机标识数量 5587

5587 这个结果说明,在当前流量观察范围内,连接到该 IRC 服务器的主机数量已经相当多。它不是蜜罐主机的单独行为,而是一个具有一定规模的 IRC 僵尸网络活动。

2.3.5 哪些 IP 地址被用于攻击蜜罐主机?

为了找出哪些 IP 地址访问过蜜罐主机,我首先统计所有发往蜜罐 172.16.134.191 的 TCP 连接源 IP。这里先不急着判断“谁攻击成功”,而是先从整体访问情况入手,找出哪些外部主机与蜜罐发生过 TCP 通信。

tshark -r botnet_pcap_file.dat \
-Y "ip.dst == 172.16.134.191 && tcp" \
-T fields -e ip.src \
| sort | uniq -c | sort -nr

统计所有访问蜜罐的源 IP

图 2-3-8 使用 tshark 统计发往蜜罐主机 172.16.134.191 的 TCP 连接源 IP。

这个统计结果可以帮助我先了解哪些 IP 与蜜罐通信较频繁。不过,仅统计源 IP 还不够,因为不同端口代表的服务不同,访问 80 端口、445 端口和 1433 端口的含义并不一样。为了进一步判断这些连接更可能对应哪些服务,我继续统计源 IP 和目标端口的组合。

tshark -r botnet_pcap_file.dat \
-Y "ip.dst == 172.16.134.191 && tcp" \
-T fields -e ip.src -e tcp.dstport \
| sort | uniq -c | sort -nr

统计访问蜜罐的源 IP 和目标端口

图 2-3-9 使用 tshark 统计访问蜜罐主机的源 IP 与目标端口组合。

通过源 IP 和目标端口的组合,可以进一步判断外部主机主要在访问蜜罐上的哪些服务。由于本实验分析的是 Windows 2000 蜜罐,下面这些端口需要重点关注:

端口 服务 可能风险
80 IIS / HTTP Web 漏洞探测与利用
139 NetBIOS Windows 文件共享相关攻击
445 SMB Windows 远程共享、认证和服务执行
4899 RAdmin 远程控制工具相关攻击
1433 SQL Server 数据库弱口令或漏洞攻击
21 FTP 文件传输服务攻击
25 SMTP 邮件服务攻击或滥用
110 POP3 邮件账号相关攻击
135 RPC Windows RPC 相关攻击
6129 DameWare 远程管理工具相关攻击

为了缩小范围,我进一步只统计访问这些敏感端口的源 IP 和端口组合:

tshark -r botnet_pcap_file.dat \
-Y "ip.dst == 172.16.134.191 && tcp && (tcp.dstport == 80 || tcp.dstport == 139 || tcp.dstport == 445 || tcp.dstport == 4899 || tcp.dstport == 1433 || tcp.dstport == 21 || tcp.dstport == 25 || tcp.dstport == 110 || tcp.dstport == 135 || tcp.dstport == 6129)" \
-T fields -e ip.src -e tcp.dstport \
| sort | uniq -c | sort -nr

统计访问蜜罐敏感端口的源 IP

图 2-3-10 使用 tshark 统计访问蜜罐敏感端口的源 IP 和目标端口组合。

从统计结果可以看到,多个外部 IP 访问了蜜罐的敏感端口。这些访问行为中有一部分可能只是扫描或探测,有一部分则可能进入了更深入的攻击阶段。因此,不能只根据“访问过端口”就直接判断攻击成功,还需要继续查看是否存在认证、文件写入、远程服务创建或程序执行等后续证据。

在后续流量中,最值得重点关注的攻击源 IP 是:

61.111.101.78

原因是该 IP 不只是访问了蜜罐的 SMB/445 端口,后续还出现了与认证、管理共享、服务控制以及远程执行相关的痕迹。因此,后面会围绕该 IP 继续深入分析。

分析层次 作用
统计所有 TCP 源 IP 找出与蜜罐通信的外部主机
统计源 IP 与目标端口 判断访问集中在哪些服务
筛选敏感端口 缩小可能攻击行为的范围
结合后续行为验证 判断是否进入认证、写入或远程执行阶段

端口扫描或服务访问本身不一定代表攻击成功。真正判断入侵是否成功,需要继续寻找认证通过、共享访问、文件投递、服务创建和恶意程序执行等证据。

2.3.6 攻击者尝试攻击了哪些安全漏洞?

为了判断攻击者尝试利用哪些服务或漏洞,我分别从 Web/IIS、SMB/NetBIOS、RAdmin、SQL Server 等方向查看流量。本小节先重点分析 Web/IIS 和 SMB/NetBIOS 两类比较明显的攻击尝试。

1. Web / IIS 攻击尝试

首先查看针对蜜罐 HTTP/IIS 服务的流量。Windows 2000 上的 IIS 服务历史上存在较多典型漏洞,因此攻击者经常会通过异常 URL、特殊扩展名、目录穿越路径或 cmd.exe 调用来探测和利用 Web 服务。

在 Wireshark 中查看 HTTP 请求时,可以看到多个比较可疑的访问路径,例如 .ida、.idq、.printer、目录穿越路径以及对 cmd.exe 的调用。

查看 Web IIS 攻击流量

图 2-3-11 Wireshark 中显示针对蜜罐 Web/IIS 服务的 HTTP 请求记录。

继续查看相关请求内容,可以看到部分 URL 中出现了典型的 IIS 漏洞探测特征。

查看 IIS 漏洞探测请求

图 2-3-12 HTTP 请求中出现 .IDA、.idq、.printer 和目录穿越相关路径。

可疑请求包括:

GET /NULL.IDA?CCCCCCCC...
GET /NULL.idq?AAAAAAAA...
GET /NULL.printer
/scripts/../../../../../../winnt/system32/cmd.exe?/c+dir
/msadc/../../../../../../winnt/system32/cmd.exe?/c+dir

这些请求大致可以分成几类:

攻击类型 请求特征 初步分析
IIS .ida/.idq 探测 URL 中出现 .IDA、.idq 可能与 IIS Indexing Service 相关漏洞探测有关
IIS 打印服务探测 URL 中出现 .printer 可能与 IIS 打印相关组件漏洞探测有关
目录穿越尝试 URL 中出现多层 ../ 试图跳出 Web 目录访问系统路径
远程命令执行尝试 请求中调用 cmd.exe?/c+dir 试图通过 Web 服务执行系统命令

从当前流量中可以整理出涉及 Web/IIS 攻击尝试的源 IP:

24.197.194.106
210.22.204.101
68.169.174.108
213.23.49.158
218.25.147.83
192.130.71.66
66.8.163.125

这些请求说明攻击者确实尝试过针对蜜罐的 IIS 服务进行探测或利用。不过,从后续流量来看,这部分暂时没有看到明显的成功控制证据,例如后续反连、文件写入或稳定交互。因此,这里更稳妥的说法是:这些 IP 对蜜罐 Web/IIS 服务进行了漏洞探测或利用尝试,但不能仅凭这些请求判断 Web 攻击已经成功。

Web/IIS 请求中的异常路径很容易暴露攻击意图,但是否成功还要看后续行为。只有出现命令执行结果、文件投递或反向连接等证据时,才能进一步判断攻击取得了实际效果。

2. SMB / NetBIOS 攻击尝试

接着,我查看 SMB / NetBIOS 相关流量。对于 Windows 2000 这类较老的系统来说,SMB 和 NetBIOS 是非常常见的攻击入口。攻击者可能通过这些端口进行远程认证、访问管理共享、上传文件,甚至创建远程服务执行程序。

查看 SMB NetBIOS 攻击者

图 2-3-13 Wireshark 中显示多个外部 IP 与蜜罐的 SMB / NetBIOS 相关通信。

从流量中可以看到,多个外部 IP 与蜜罐的 Windows 文件共享相关端口发生了通信。可疑 SMB / NetBIOS 攻击源 IP 包括:

61.111.101.78
210.22.204.101
195.36.247.77
66.139.10.15
209.45.125.69
129.116.182.239
80.181.116.202
66.8.163.125

其中,后续最值得重点分析的是:

61.111.101.78

因为它不仅访问了蜜罐的 SMB 服务,还在后续流量中出现了更深入的交互痕迹。

SMB 攻击源 IP 61.111.101.78

图 2-3-14 Wireshark 中显示源 IP 61.111.101.78 与蜜罐之间的 SMB / NetBIOS 通信记录。

为了单独查看该 IP 与蜜罐之间的 SMB 通信,我使用如下 Wireshark 过滤器:

ip.addr == 172.16.134.191 && ip.addr == 61.111.101.78 && tcp.port == 445

单独确认 61.111.101.78 与蜜罐的 SMB 通信

图 2-3-15 使用过滤器单独查看 61.111.101.78 与蜜罐之间的 SMB/445 通信。

在该会话中,可以看到与 SMB 认证和远程执行有关的关键字符串:

NTLMSSP
Administrator
PSEXESVC

这些字符串的含义如下:

关键字符串 含义
NTLMSSP Windows NTLM 认证相关协议标识
Administrator 管理员账户名称
PSEXESVC PsExec 远程服务组件相关名称

这些内容说明 61.111.101.78 与蜜罐之间的通信已经不只是简单的端口扫描。特别是 Administrator 和 PSEXESVC 的出现,说明该会话可能进入了管理员认证、远程服务创建或远程执行相关阶段。结合后续流量继续分析,可以进一步判断攻击是否真正成功。

到这里可以初步判断,61.111.101.78 是本次 SMB 方向最关键的攻击源。它与蜜罐之间的通信已经出现了认证和远程执行相关线索,后续需要继续检查是否存在文件写入、服务启动和恶意程序执行证据。

3. RAdmin 远程控制尝试

除了 Web/IIS 和 SMB/NetBIOS 之外,我继续检查流量中是否存在 RAdmin 相关特征。RAdmin 是一种远程控制工具,正常情况下可以用于系统管理,但在入侵事件中也可能被攻击者当作后门或远程控制工具使用。

这里我使用如下 Wireshark 过滤器,查找包含 RAdmin 字符串的通信内容:

ip.addr == 172.16.134.191 && tcp contains "RAdmin"

过滤 RAdmin 相关流量

图 2-3-16 使用 Wireshark 过滤包含 RAdmin 字符串的流量记录。

从过滤结果中可以看到,与该特征相关的源 IP 包括:

210.22.204.101

这里可以初步判断,210.22.204.101 与 RAdmin 相关访问或远程控制尝试有关。不过,仅凭 RAdmin 字符串本身,还不能直接断定该方向攻击已经成功。它更像是一个需要关注的远程控制工具痕迹,后续如果要进一步确认,还需要结合文件传输、服务安装、登录成功或持续连接等证据。

观察对象 分析理解
RAdmin 字符串 可能与远程控制工具相关
源 IP 210.22.204.101 需要关注的可疑访问来源
当前证据状态 有远程控制相关迹象,但成功证据不足

RAdmin 本身不一定是恶意工具,关键要看它出现在什么场景中。对于蜜罐流量来说,如果外部主机主动触发 RAdmin 相关通信,就需要把它作为远程控制尝试来关注。

4. SQL Server 探测

最后,我查看是否存在针对 SQL Server 的探测行为。SQL Server 默认服务端口通常是 1433,攻击者访问该端口,可能是在探测数据库服务、尝试弱口令登录,或者寻找已知漏洞利用机会。

使用的 Wireshark 过滤器如下:

ip.addr == 172.16.134.191 && tcp.port == 1433

查看 SQL Server 1433 端口探测

图 2-3-17 使用 Wireshark 查看蜜罐主机与 1433 端口相关的 TCP 通信。

从过滤结果来看,蜜罐的 1433 端口确实存在被访问的情况。由于 1433 与 SQL Server 服务高度相关,因此这些流量可以初步归入数据库服务探测方向。

不过,从当前截图和上下文来看,这部分主要表现为端口访问或探测,没有看到后续明确的登录成功、命令执行或数据库交互证据。因此,这里更稳妥的判断是:攻击者尝试探测 SQL Server 服务,但暂时不能确认攻击成功。

攻击方向 观察到的特征 是否发现成功证据
Web / IIS .ida、.idq、.printer、目录穿越、cmd.exe 调用 未发现明显成功证据
SMB / NetBIOS NTLMSSP、Administrator、PSEXESVC 后续发现较完整的成功入侵证据
RAdmin 出现 RAdmin 字符串 有远程控制相关迹象
SQL Server 访问 1433 端口 主要表现为探测

多个方向都存在攻击尝试,但从证据完整性来看,最关键的一条攻击链仍然是来自 61.111.101.78 的 SMB/445 方向。

2.3.7 哪些攻击成功了?是如何成功的?

从前面的分析结果来看,最明确、证据最完整的成功攻击来自:

61.111.101.78

该 IP 与蜜罐主机 172.16.134.191 之间存在大量 SMB/445 通信,并且后续流量中出现了 Windows 认证、管理共享访问、远程服务控制、PsExec 组件以及可疑程序执行等痕迹。因此,本小节重点围绕该攻击源还原成功攻击过程。

首先过滤攻击者与蜜罐之间的 SMB 通信:

ip.addr == 61.111.101.78 && ip.addr == 172.16.134.191 && tcp.port == 445

过滤攻击者与蜜罐之间的 SMB 通信

图 2-3-18 使用 Wireshark 过滤 61.111.101.78 与蜜罐主机之间的 SMB/445 通信。

过滤结果中可以看到双方之间存在多条 SMB 数据交互。和单纯的端口探测相比,这种持续的 SMB 会话更值得关注,因为后续认证、共享访问和远程执行行为都可能在 SMB 会话中完成。

1. 发现 NTLMSSP 与 Administrator 认证

为了查看 SMB 会话中是否存在认证行为,我继续过滤包含 NTLMSSP 的数据包:

ip.addr == 61.111.101.78 && ip.addr == 172.16.134.191 && tcp contains "NTLMSSP"

跟踪相关 TCP 流后,可以看到如下关键字符串:

NTLMSSP
Administrator

NTLMSSP 是 Windows NTLM 认证协议相关标识,Administrator 则是 Windows 系统中的管理员账户名称。二者同时出现在 SMB 会话中,说明攻击者至少尝试通过管理员账户进行 SMB 认证。

关键内容 分析理解
NTLMSSP SMB 会话中出现 NTLM 认证相关内容
Administrator 攻击者使用或尝试使用管理员账户
SMB/445 认证发生在 Windows 文件共享相关通信中

这里之所以重要,是因为后续访问 ADMIN$、创建远程服务以及执行程序,通常都需要较高权限。如果攻击者能够继续完成这些动作,就可以进一步说明认证阶段很可能已经通过。

Administrator 认证线索不能单独证明最终入侵成功,但它是后续远程服务执行能够发生的重要前置条件。

2. 访问 IPC$ 与 ADMIN$ 管理共享

接着,我查看攻击者是否访问了 Windows 管理共享。使用的过滤器如下:

ip.addr == 61.111.101.78 && ip.addr == 172.16.134.191 && (tcp contains "IPC" || tcp contains "ADMIN")

攻击者访问 IPC 管理共享

图 2-3-19 Wireshark 过滤结果中出现与 IPC$ 相关的 SMB 共享访问内容。

攻击者访问 ADMIN 管理共享

图 2-3-20 Wireshark 过滤结果中出现与 ADMIN$ 相关的 SMB 共享访问内容。

其中,IPC$ 和 ADMIN$ 都是 Windows 环境中比较敏感的管理共享:

管理共享 作用
IPC$ 用于远程进程间通信、命名管道访问、远程服务控制等
ADMIN$ 通常映射到 Windows 系统目录,常用于远程管理和文件写入

如果攻击者能够访问 ADMIN$,通常意味着它具备较高权限,因为 ADMIN$ 往往对应系统目录。结合前面的 Administrator 认证线索,这里可以初步判断攻击者已经进入了 SMB 管理访问阶段。

访问 IPC$ 和 ADMIN$ 是 PsExec 风格远程执行中非常常见的前置步骤。攻击者先建立 SMB 连接和认证,再通过管理共享与远程服务接口实现命令执行。

3. 发现 PsExec 风格远程服务执行

为了继续确认是否存在远程服务控制行为,我过滤与远程服务相关的字符串:

ip.addr == 61.111.101.78 && ip.addr == 172.16.134.191 && tcp contains "ntsvcs"

过滤 ntsvcs 远程服务控制相关流量

图 2-3-21 Wireshark 过滤结果中出现与远程服务控制相关的字符串内容。

在相关流量中可以看到如下关键字符串:

\svcctl
PSEXESVC
\System32\PSEXESVC.EXE
Sysinternals PsExec

其中,\svcctl 是 Windows Service Control Manager 的远程接口,常用于远程创建、启动、停止或删除服务。PSEXESVC 则是 PsExec 远程执行过程中常见的服务组件名称。

为了进一步确认该线索,我继续单独过滤 PSEXESVC:

ip.addr == 61.111.101.78 && ip.addr == 172.16.134.191 && tcp contains "PSEXESVC"

过滤 PSEXESVC 相关流量

图 2-3-22 Wireshark 过滤结果中出现 PSEXESVC、PSEXESVC.EXE 和 Sysinternals PsExec 字符串。

结合这些字符串,可以判断攻击者采用了类似 PsExec 的远程服务执行方式。典型流程一般包括:

步骤 行为
1 使用管理员账户连接目标 SMB
2 访问 ADMIN$ 管理共享
3 将 PSEXESVC.EXE 写入目标系统目录
4 通过 svcctl 创建远程服务
5 启动服务
6 借助该服务远程执行命令或程序

这里的证据链比较连续:前面出现了 Administrator、IPC$、ADMIN$,这里又出现 svcctl、PSEXESVC 和 Sysinternals PsExec。这些线索连在一起后,可以较有把握地判断攻击者已经进入远程服务执行阶段。

PSEXESVC.EXE 的出现是判断 PsExec 风格远程执行的重要证据。它不是普通扫描流量中常见的字符串,而是和远程服务创建、远程命令执行密切相关。

4. 发现恶意程序 inst.exe 和 Devlr32.exe

在确认攻击者具备远程执行能力后,我继续查找是否存在被投递或执行的可疑程序文件名。这里使用如下过滤器:

ip.addr == 61.111.101.78 && ip.addr == 172.16.134.191 && (tcp contains "inst.exe" || tcp contains "Devlr32.exe")

发现 inst.exe 和 Devlr32.exe

图 2-3-23 Wireshark 过滤结果中出现 inst.exe 和 Devlr32.exe 等可执行文件名。

相关流量中可以看到如下命令或文件名:

inst.exe
Devlr32.exe
attrib.exe -r inst.exe
attrib.exe -r Devlr32.exe

其中,attrib.exe -r 的作用是去除文件只读属性。攻击者在执行或修改文件前使用该命令,说明这些可执行文件很可能已经被放置到目标主机上,并且后续需要调整属性后继续操作。

文件或命令 分析理解
inst.exe 可疑安装或执行程序
Devlr32.exe 可疑恶意程序名称
attrib.exe -r inst.exe 去除 inst.exe 的只读属性
attrib.exe -r Devlr32.exe 去除 Devlr32.exe 的只读属性

结合前面远程服务执行的证据,这里可以进一步判断,攻击者并不只是建立了 SMB 连接,而是已经进行了可疑程序投递或执行操作。后续蜜罐连接 IRC C2 的行为,也很可能与这些可疑程序有关。

Devlr32.exe 是本次攻击链中非常重要的恶意程序线索。它很可能是导致蜜罐后续连接 IRC 僵尸网络的关键文件之一。

5. 发现攻击者删除管理共享

继续查看后续命令时,可以发现攻击者还执行了删除管理共享的操作。

攻击者删除管理共享

图 2-3-24 Wireshark 流量内容中出现删除 Windows 管理共享相关命令。

相关命令包括:

share /delete C$ /y
share /delete D$ /y
share /delete E$ /y
share /delete ADMIN$ /y

这些命令会删除 Windows 默认管理共享。攻击者在入侵后执行这类操作,可能有几种目的:一是减少管理员远程访问入口,二是阻止其他攻击者继续利用同样方式进入,三是干扰后续排查。这里只能结合上下文做初步判断,不能单独认定其具体动机。

命令 作用
share /delete C$ /y 删除 C$ 管理共享
share /delete D$ /y 删除 D$ 管理共享
share /delete E$ /y 删除 E$ 管理共享
share /delete ADMIN$ /y 删除 ADMIN$ 管理共享

删除管理共享通常发生在攻击者已经获得一定系统控制能力之后。它既可能是为了隐藏痕迹,也可能是为了阻断其他人继续通过管理共享访问目标主机。

6. 攻击成功路径还原

综合前面的流量证据,可以把本次成功攻击路径还原为:

61.111.101.78
    ↓
通过 SMB/445 连接蜜罐 172.16.134.191
    ↓
使用 Administrator 进行 SMB/NTLM 认证
    ↓
访问 IPC$ / ADMIN$ 管理共享
    ↓
通过 svcctl 进行远程服务控制
    ↓
使用 PSEXESVC / PsExec 风格远程执行
    ↓
运行 inst.exe / Devlr32.exe
    ↓
蜜罐主动连接 IRC 服务器
    ↓
连接 209.196.44.172:6667
    ↓
发送 NICK / USER / JOIN
    ↓
加入 IRC 频道
    ↓
成为 IRC 僵尸网络中的一台 bot

这一过程也可以整理成表格:

阶段 证据 说明
初始连接 tcp.port == 445 攻击者连接蜜罐 SMB 服务
身份认证 NTLMSSP、Administrator 出现管理员账户相关认证信息
共享访问 IPC$、ADMIN$ 访问 Windows 管理共享
远程服务 svcctl、PSEXESVC 出现 PsExec 风格远程服务执行痕迹
可疑程序 inst.exe、Devlr32.exe 流量中出现可疑可执行文件名
后续操作 share /delete C$ /y 等 删除 Windows 管理共享
加入僵尸网络 NICK、USER、JOIN 蜜罐连接 IRC C2 并加入频道

最终可以得到较完整的判断:蜜罐 Windows 2000 主机主要是通过 SMB/445 方向被攻破的。攻击者 61.111.101.78 通过管理员身份相关的 SMB 认证,访问 IPC$ 和 ADMIN$ 管理共享,并使用 PsExec 风格的远程服务执行方式运行可疑程序。随后,蜜罐主动连接 IRC C2 服务器 209.196.44.172:6667,发送 NICK、USER、JOIN 等 IRC 消息,最终加入 IRC 僵尸网络。

这一条攻击链比较完整:从 SMB 连接、管理员认证、管理共享访问,到远程服务执行、可疑程序运行,再到 IRC C2 连接,多个证据之间能够相互支撑。

2.3.8 本节实验总结

本节通过 Wireshark 和 tshark 对蜜罐网络流量进行分析,逐步还原了 Windows 2000 主机被攻击并加入 IRC 僵尸网络的过程。整个分析不是只看某一个数据包,而是把不同阶段的通信证据串联起来:先确认 IRC 行为,再定位 C2 服务器,接着统计僵尸网络规模,最后回到入侵流量中分析攻击者是如何进入蜜罐的。

整体分析流程如下:

分析步骤 使用方法 得到结论
IRC 协议识别 查看 NICK、USER、JOIN 蜜罐表现出 IRC bot 行为
IRC 服务器定位 过滤 tcp.port == 6667 蜜罐连接 209.196.44.172:6667
僵尸网络规模统计 tshark 提取 IRC payload 并去重 观察期间统计到 5587 个不同主机标识
攻击源筛选 统计访问蜜罐敏感端口的 IP 找到多个可疑访问来源
漏洞方向分析 查看 IIS、SMB、RAdmin、SQL Server 流量 多种服务遭到探测或攻击尝试
成功攻击确认 分析 61.111.101.78 与 SMB/445 通信 发现认证、管理共享和远程服务执行证据
攻击链还原 综合 SMB、PsExec、可疑程序和 IRC 行为 蜜罐被攻破后加入 IRC 僵尸网络

最终结论如下:

序号 结论
1 蜜罐主机 172.16.134.191 被攻破后连接了 IRC 服务器 209.196.44.172:6667
2 蜜罐发送了 NICK、USER、JOIN 等 IRC 消息,说明其已经加入 IRC 频道
3 在观察期间,统计到 5587 个不同主机标识访问该 IRC 僵尸网络
4 多个外部 IP 对蜜罐的 Web、SMB、RAdmin、SQL Server 等服务进行了探测或攻击尝试
5 最关键的成功攻击源是 61.111.101.78
6 该攻击者通过 SMB/445、Administrator 认证、IPC$ / ADMIN$、svcctl 和 PSEXESVC 实现远程执行
7 流量中出现了 inst.exe、Devlr32.exe 等可疑程序名称
8 可疑程序运行后,蜜罐主动连接 IRC C2,并成为 IRC 僵尸网络中的一台 bot

本节实验让我体会比较深的是,流量分析不能只盯着单个协议或单个数据包。一次成功入侵往往是由多个阶段串起来的:端口访问只是开始,真正重要的是后面的认证、共享访问、远程服务创建、文件执行和 C2 连接。只有把这些证据按时间和逻辑顺序连起来,才能比较完整地还原攻击过程。

三、遇到的问题

3.1 IDA 分析问题

在使用 IDA 对程序进行分析之前,我发现不能直接把样本丢进 IDA 就开始看反汇编结果,而是要先确认目标程序到底是 32 位还是 64 位。程序位数不同,后续选择的 IDA 版本、加载方式和反编译结果都会受到影响。

如果程序架构判断错误,可能会出现函数识别不准确、反汇编结果不完整、伪代码生成异常等问题。尤其是在分析 Windows PE 文件时,最好先通过 file 命令或 PE 工具确认样本架构,再选择合适的 IDA 版本进行加载。

IDA 分析前确认程序架构

图 3-1-1 在分析样本前查看程序位数与文件类型信息。

这次实验中的样本多为 Windows 平台下的 32 位 PE 程序,因此后续分析时应优先按照 32 位 PE 程序的思路进行处理。这样可以减少 IDA 识别异常带来的干扰,也更方便后面查看函数、字符串和伪代码。

这一步看起来比较基础,但实际分析时很重要。如果一开始程序架构判断错了,后面看到的反汇编结果很可能会偏离真实逻辑。

3.2 checksec 无法使用

在做 pwn 题时,我平时会习惯先使用 checksec 查看程序开启了哪些保护机制,例如 NX、Canary、PIE、RELRO 等。这样可以快速判断后续利用时需要绕过哪些安全保护。

但是在本实验中,目标程序并不是 Linux 下的 ELF 文件,而是 Windows 平台下的 PE 可执行文件。因此,直接使用 checksec 无法正常识别和分析这些样本。

checksec 无法识别 PE 文件

图 3-2-1 对 Windows PE 样本使用 checksec 时无法得到正常的保护机制分析结果。

这个问题说明,分析工具不能脱离文件格式来使用。checksec 更适合用于 ELF 程序保护机制分析,而本实验中的样本属于 PE 文件,更适合使用 file、strings、IDA、PE 分析工具等进行静态分析。

文件类型 更适合使用的工具 分析重点
ELF 文件 checksec、GDB、objdump、readelf NX、Canary、PIE、RELRO 等保护机制
PE 文件 IDA、strings、PE 工具、Wireshark 程序结构、字符串、导入函数、网络行为等

这次问题提醒我,不能把 pwn 题中的分析流程直接套到 Windows 样本上。不同文件格式对应的分析工具和关注点是不一样的。

3.3 字符串参数需要加引号

在终端执行程序并传入参数时,我还遇到了一个容易忽略的问题:如果参数中包含空格,必须使用引号把完整字符串括起来。否则,终端会按照空格把内容拆成多个参数,导致程序接收到的参数数量和内容都与预期不一致。

例如在分析 crackme1.exe 和 crackme2.exe 时,正确参数是:

I know the secret

如果直接输入:

crackme1.exe I know the secret

程序内部接收到的不是一个完整参数,而是多个参数:

argv[1] = I
argv[2] = know
argv[3] = the
argv[4] = secret

这样会导致 argc 的值不符合程序判断条件,程序自然无法进入正确分支。

正确写法应该是:

crackme1.exe "I know the secret"

或者在 crackme2.exe 中配合正确文件名运行:

crackmeplease.exe "I know the secret"

这样程序内部接收到的才是一个完整字符串参数:

argv[1] = I know the secret

四、心得体会

这次实验中,PE文件的逆向部分对我而言是最具挑战性也最有收获的一环。本科打CTF的时候,接触的样本几乎清一色是ELF文件,Linux下的那套调试思路和工具链已经形成了一定的操作惯性,但这次算是第一次真正意义上进入PE文件的逆向领域。此前用010Editor翻看过PE文件头,对节表、导入表这类结构并不算陌生,但那种程度的接触,充其量只是识别结构,距离脱壳这种真正与保护机制正面交手的操作,中间还有相当大的差距。第一次把加壳样本一层一层剥离,再放进IDA中进行反汇编分析,整个过程带来的体验相当直观——每剥开一层,都无法预判下一层等待自己的是花指令还是别的干扰手段,这种不确定性本身就是一种学习。这次经历让我更加确信一点:pwn和逆向从来不是彼此独立的技能,脱壳、反汇编这些看似基础的动作,实际上是支撑后续所有漏洞利用分析的根基,对于一个真正合格的二进制方向研究者而言,逆向能力是无法绕开的基本功。稍显遗憾的是,此次流程中尚未引入GDB这类动态调试工具,如果能在脱壳的同时结合动态跟踪,实时观察寄存器与栈的变化情况,对执行流的理解应当会更加立体和完整,这也是我接下来希望补齐的部分。

流量分析部分,则让我对"僵尸网络"这一概念背后的流量规模有了更为直观的认识。这次的样本分析也让我联想起自己此前的一段经历。当时为了图方便,在阿里云服务器上部署CTFd平台,安全组的端口几乎全部开放,并未细究可能带来的风险,只是觉得这是一台用于练习的测试机,无关紧要。结果不久后,服务器就被境外不明身份的攻击者植入了一个博彩类网站,机器本身也在不知不觉中被悄然接管,最终变成了对方控制体系下的一个节点。发现这一情况时,心理上确实产生了一定程度的警觉,最终选择直接释放了那台服务器。回过头来看这段经历,与此次作业中分析的僵尸网络样本在逻辑上高度一致——攻击者往往正是借助一个看似无关紧要的权限疏漏获取入口,随后悄无声息地将受控主机纳入自身的控制体系,成为庞大僵尸网络中的一个节点。当年自己是那台受控服务器的所有者,而这次则是站在分析者的角度,重新还原并理解这一整套渗透与控制逻辑,视角的转换让体会更为深刻,也让我对"权限最小化"这一原则有了更为切实的认识。

完成这次实验后,让我印象最深的并非某一项具体工具的操作方法——无论脱壳还是流量分析,工具本身的使用大多可以通过实践迅速掌握。真正具有价值的,是在面对一系列杂乱现象时的处理方式:比如一段经过混淆处理的代码,或是一批表面上毫无规律的流量数据。能否先提出一个合理的假设,再回溯寻找证据加以验证或推翻,逐步排除干扰因素,最终得出一个站得住脚的结论,这种分析思路本身,比单一技能的掌握更为关键,也是我在后续深入学习网络攻防方向时,希望重点提升的能力。

五、参考资料

[1] 恶意代码分析实战学习笔记(一)

[2] 恶意代码分析实战二:静态分析基础技术

[3] UPX脱壳

[4] 恶意代码分析实战:加壳与脱壳

[5] UPX 可执行文件压缩工具

[6] IDA pro简单入门使用

[7] 菜鸟的逆向工程学习之路——逆向工具IDA的使用

[8] 用IDA静态分析和定位strcmp参数

[9] 流量分析工具Wireshark学习笔记

[10] tshark命令行使用手册

[11] IRC协议学习笔记

[12] IRC僵尸网络原理

posted @ 2026-05-24 12:23  20253902吴晨宇  阅读(34)  评论(0)    收藏  举报