81、恶意软件分析(一):静态分析(字符串、导入表、YARA规则)
各位好,欢迎来到《逆向工程实战100例》的第81讲。今天咱们聊聊恶意软件分析的第一步——静态分析。
很多人一听到“恶意软件分析”,就觉得得开个虚拟机、挂上调试器、单步跟踪。其实不然。我个人习惯,拿到一个可疑样本,第一件事绝对不是双击运行,而是先做静态分析。说白了,就是“只看不动手”。
静态分析能帮你快速判断:这玩意儿是不是恶意的?它大概想干什么?有没有已知的家族特征?这些信息,往往在几分钟内就能拿到。
1. 字符串分析:恶意软件的“自白书”
字符串,是恶意软件最直接的“自白”。一个程序里硬编码的URL、IP地址、注册表路径、文件名、命令行参数……这些东西,几乎就是恶意行为的说明书。
我常用的工具是 strings 命令(Linux/macOS)或者 bintext(Windows)。
# 提取所有长度大于等于6的ASCII字符串
strings -n 6 sample.exe > strings.txt
# 提取Unicode字符串(很多恶意软件用Unicode隐藏关键信息)
strings -n 6 -e l sample.exe > unicode_strings.txt
拿到字符串列表后,我会重点关注以下几类:
- 网络相关:
http://、https://、ftp://、IP地址、域名。这些往往是C2(命令与控制)服务器的地址。 - 文件路径:
C:\Windows\、%APPDATA%、%TEMP%。恶意软件常把自己复制到这些目录。 - 注册表键:
HKEY_LOCAL_MACHINE、Run、RunOnce。这是持久化(开机自启动)的常用手段。 - API函数名:
CreateRemoteThread、WriteProcessMemory、VirtualAllocEx。这些是进程注入的标配。 - 加密密钥/算法标识:
AES、RC4、base64。恶意软件常用这些来加密通信或自身。
2. 导入表分析:看它“请了哪些外援”
一个PE文件(Windows可执行文件)的导入表(Import Table),记录了它调用了哪些外部DLL和函数。这就像看一个人的朋友圈——他认识谁,大概就能猜出他是什么样的人。
我用 PEview 或 Dependency Walker 来查看导入表。但更高效的是用Python脚本,配合 pefile 库。
import pefile
pe = pefile.PE('sample.exe')
for entry in pe.DIRECTORY_ENTRY_IMPORT:
print(f"[*] DLL: {entry.dll.decode()}")
for func in entry.imports:
if func.name:
print(f" -> {func.name.decode()}")
else:
print(f" -> Ordinal: {func.ordinal}")
重点关注以下“危险”API组合:
| API函数 | 所属DLL | 常见恶意用途 |
|---|---|---|
CreateRemoteThread |
kernel32.dll | 在远程进程中创建线程(进程注入) |
WriteProcessMemory |
kernel32.dll | 向远程进程写入数据(代码注入) |
VirtualAllocEx |
kernel32.dll | 在远程进程中分配内存 |
URLDownloadToFile |
urlmon.dll | 从网络下载文件到本地 |
RegSetValueEx |
advapi32.dll | 修改注册表(持久化) |
Socket / Connect / Send |
ws2_32.dll | 网络通信(C2连接) |
你想想看,一个普通的计算器程序,会去调用 CreateRemoteThread 吗?不会。所以,一旦导入表里出现这些“敏感”API,就得打起十二分精神。
LoadLibrary + GetProcAddress)来隐藏导入表。这种情况下,导入表里可能只有这两个函数,真正的恶意API是在运行时才解析的。所以,导入表干净,不代表程序干净。
3. YARA规则:自动化“指纹识别”
YARA,说白了就是恶意软件的“指纹识别系统”。你写一个规则,描述某个恶意家族的特征(比如特定的字符串、字节序列、导入表组合),然后让YARA去扫描样本,匹配上了就报警。
我自己的YARA规则库,积累了上千条。每次拿到新样本,第一件事就是跑一遍YARA。
# 一个简单的YARA规则示例
rule Suspicious_Strings_And_Imports
{
meta:
description = "检测包含可疑字符串和导入表的样本"
author = "蓝海资料掘金营"
date = "2025-01-01"
strings:
$s1 = "http://" nocase
$s2 = "cmd.exe" nocase
$s3 = "CreateRemoteThread" ascii wide
condition:
// 至少匹配两个字符串,并且导入表中包含CreateRemoteThread
(uint16(0) == 0x5A4D) and // 检查MZ头
(2 of ($s*)) and
(pe.imports("kernel32.dll", "CreateRemoteThread"))
}
YARA的威力在于组合。你可以把字符串、导入表、节区特征、甚至文件大小都组合起来。比如:
- 包含
http://+ 包含CreateRemoteThread+ 文件大小小于1MB → 很可能是下载者(Downloader)。 - 包含
Mutex字符串 + 包含RegSetValueEx+ 节区名为.upx0→ 可能是UPX加壳的恶意软件。
http:// 太常见了,误报率极高。我一般会加上 pe.imports 或者 pe.sections 来缩小范围。另外,规则要定期更新,恶意软件也在进化。
4. 知识体系:一张图看懂静态分析
下面这张图,是我自己总结的静态分析核心流程。你可以把它当作一个检查清单。
5. 实战:一个完整的静态分析流程
假设你拿到一个名为 update.exe 的样本。我会这么做:
- 查壳: 用
Detect It Easy (DiE)看一眼。如果显示UPX或VMProtect,先脱壳。 - 字符串: 跑
strings,发现http://malware.example.com/payload.exe和cmd.exe /c。嗯,有戏。 - 导入表: 用
pefile分析,发现导入了URLDownloadToFile和WinExec。这基本实锤了——它是一个下载者,下载后执行。 - YARA: 用我自己的规则库跑一遍,匹配到了
Trojan_Downloader_Generic这条规则。确认了。
整个过程,不到5分钟。我没运行它,但已经知道它是个下载者,C2地址也拿到了。接下来,我可以把这个IoC(威胁情报指标)提交给威胁情报平台,或者继续做动态分析。
好了,这一讲就到这里。希望这些经验对你有帮助。咱们下期见。
公众号:蓝海资料掘金营,微信deep3321