4、静态分析基础:文件类型识别、字符串提取、哈希计算、PE头解析、导入表与导出表分析

静态分析是恶意代码分析的起点,也是整个分析流程中最安全、最可控的环节。它不执行样本,而是通过检查文件的二进制结构、元数据、字符串和代码特征来获取情报。对于Windows平台下的恶意软件,PE(Portable Executable)格式是绕不开的核心。本章将围绕五个基础动作展开:文件类型识别、字符串提取、哈希计算、PE头解析以及导入表与导出表分析。掌握这些技能,你就能在沙箱运行或动态调试之前,快速判断样本的“身份”和“意图”。

静态分析基础工作流与PE结构映射 1. 文件类型识别 2. 字符串提取 3. 哈希计算 4. PE头解析 5. 导入/导出表分析 PE 文件结构(简化) DOS头 (e_magic: MZ) → 判断PE文件起始 NT头 (Signature: PE\0\0) → 文件头+可选头 节表 (.text, .data, .rdata, .rsrc) → 各节属性与偏移 导入表 (IAT/INT) → 调用的外部API 导出表 (EAT) → 对外提供的函数 资源节 (.rsrc: 图标/版本/清单) → 元数据与图标 解析 定位 关键偏移:e_lfanew → NT头 → OptionalHeader → DataDirectory[0]=导出表, [1]=导入表 工具:file, strings, sha256sum, pefile, DIE, CFF Explorer

上图展示了静态分析五个基础步骤与PE文件内部结构的对应关系。在实际分析中,这五个动作并非严格串行,而是互相印证。例如,哈希值用于确定样本唯一性,而导入表则揭示其行为倾向。下面我们逐一深入。

4.1 文件类型识别:从魔数到真实格式

核心原理

文件扩展名是最不可信的属性。恶意代码常伪装成图片、文档或PDF。文件类型识别的本质是检查文件头部的“魔数”(Magic Number)。Windows可执行文件的魔数是MZ(0x4D 0x5A),这是DOS头的起始标记。Linux下的ELF文件以\x7FELF开头,PDF以%PDF开头。识别文件类型是后续所有分析的前提——如果样本是PowerShell脚本或VBS脚本,则无需进行PE解析。

判断方法

  • 使用file命令:Linux下最便捷的工具,能识别PE32、PE32+、MS-DOS可执行文件、安装包等。
  • 十六进制查看:用xxd或hexdump查看前64字节,人工确认魔数。
  • DIE(Detect It Easy):Windows下图形化工具,能识别编译器、加壳器(如UPX、ASPack)。
# 示例:识别一个可疑文件
$ file malware.bin
malware.bin: PE32 executable (GUI) Intel 80386, for MS Windows

$ xxd malware.bin | head -2
00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000  MZ..............
00000010: b800 0000 0000 0000 4000 0000 0000 0000  ........@.......

案例拆解

某次应急响应中,分析师收到一个名为invoice.pdf.exe的文件。扩展名看似PDF,但file命令输出为PE32 executable。进一步用DIE检查,发现节区名为UPX0和UPX1,确认是UPX加壳的PE文件。这一识别结果直接决定了后续步骤:先脱壳,再分析导入表。

风险提示:不要双击运行未知文件来“看效果”。即使扩展名是.txt或.jpg,也可能通过文件关联漏洞执行恶意代码。始终使用静态工具识别。

常见误区

误区一:认为file命令输出“data”就是安全的。实际上,加密或混淆后的恶意脚本常被识别为“data”。误区二:忽略复合文档格式(如Office宏病毒)。file命令可能输出Composite Document File V2 Document,此时应使用oleid或oletools进一步分析。

4.2 字符串提取:发现线索与行为暗示

核心原理

字符串是程序中的可打印字符序列。恶意代码中常包含URL、IP地址、注册表路径、文件名、命令行参数、加密密钥等关键情报。提取字符串是快速了解样本“意图”的最廉价手段。但需注意,加壳或加密的样本会隐藏真实字符串,提取结果可能只有壳的提示信息。

操作流程

  1. 使用strings命令提取ASCII字符串:strings -n 8 sample.exe(仅显示长度≥8的字符串)。
  2. 提取Unicode字符串:strings -el sample.exe(针对UTF-16LE编码)。
  3. 结合grep过滤关键词:strings sample.exe | grep -iE "http|https|cmd|powershell|reg|mutex"。
  4. 使用FLOSS(FireEye Labs Obfuscated String Solver)自动解码混淆字符串。

案例拆解

分析一个疑似远控木马时,strings输出中出现以下关键内容:

C:\Windows\System32\cmd.exe
/k ping 1.1.1.1 -t
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
http://malicious-domain.com/update.php
Mutex: Global\MyMutex_2024

这些字符串揭示了:持久化机制(注册表Run键)、C2地址(HTTP)、互斥体名称(防止多实例运行)、可能的DDoS行为(ping -t)。虽然尚未执行样本,但已能形成初步判断。

经验提醒:字符串提取应区分“静态字符串”和“动态构造字符串”。恶意代码常通过strcat或sprintf拼接URL,此时静态提取只能看到片段。可结合导入表中的sprintf、strcat函数来推测拼接逻辑。

常见误区

误区一:认为字符串越多越好。加壳样本的字符串几乎全是壳的版权信息,此时应优先脱壳。误区二:忽略字符串的上下文。例如,字符串123456可能是密码,也可能是某个加密算法的盐值。需要结合其他信息判断。

4.3 哈希计算:样本的唯一指纹

核心原理

哈希算法(MD5、SHA-1、SHA-256)将任意长度的文件映射为固定长度的摘要。哈希值用于:① 确认样本唯一性;② 在威胁情报平台(如VirusTotal)查询历史分析结果;③ 验证文件完整性。恶意代码分析中,SHA-256是主流标准,因为其碰撞概率极低。

计算方法

# Linux
sha256sum sample.exe
md5sum sample.exe

# Windows (PowerShell)
Get-FileHash sample.exe -Algorithm SHA256
Get-FileHash sample.exe -Algorithm MD5

案例拆解

在VirusTotal上提交一个勒索软件样本,其SHA-256为7f9c...a3d2。查询结果显示:该样本已被全球37家杀毒引擎标记为Trojan.Ransom.Cerber。同时,关联分析发现该哈希与2023年某次钓鱼邮件攻击中使用的样本完全一致。这为溯源提供了直接证据。

重要提示:不要仅依赖MD5。MD5已被证明存在碰撞攻击,恶意代码可构造两个不同文件但MD5相同。在安全场景中,至少使用SHA-256,并同时记录文件大小作为辅助验证。

常见误区

误区一:混淆“哈希值”与“模糊哈希”。模糊哈希(如ssdeep)用于相似性比较,而非唯一性标识。误区二:在分析过程中修改了样本文件(如脱壳后),导致哈希变化。应始终保留原始样本的哈希,并在报告中注明脱壳后的新哈希。

4.4 PE头解析:理解文件骨架

核心原理

PE文件格式是Windows可执行文件的标准结构。解析PE头能获取编译时间、链接器版本、节区权限、入口点地址、目标架构(32/64位)等关键信息。PE头由DOS头、NT头(Signature + FileHeader + OptionalHeader)和节表组成。其中,e_lfanew字段(DOS头偏移0x3C)指向NT头的起始位置。

解析流程

偏移字段关键信息
0x00e_magic必须为0x5A4D(MZ)
0x3Ce_lfanewNT头偏移量
e_lfanewSignature必须为0x00004550(PE\0\0)
e_lfanew+0x04FileHeader.Machine0x014C=32位,0x8664=64位
e_lfanew+0x18OptionalHeader.AddressOfEntryPoint程序入口点RVA
e_lfanew+0x5COptionalHeader.ImageBase首选加载基址
e_lfanew+0x60OptionalHeader.SectionAlignment内存中对齐粒度

案例拆解

使用Python的pefile库解析一个样本:

import pefile
pe = pefile.PE("sample.exe")
print("Machine:", hex(pe.FILE_HEADER.Machine))  # 0x14c 表示32位
print("EntryPoint:", hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint))
print("ImageBase:", hex(pe.OPTIONAL_HEADER.ImageBase))
print("CompileTime:", pe.FILE_HEADER.TimeDateStamp)
for section in pe.sections:
    print(section.Name.decode().rstrip('\x00'), 
          "VA:", hex(section.VirtualAddress),
          "Size:", hex(section.Misc_VirtualSize),
          "Flags:", hex(section.Characteristics))

输出显示:入口点位于0x1000,节区.text具有可执行权限,.data可读写。编译时间戳为2024-03-15,说明样本较新。若发现节区名异常(如.UPX0)或节区权限异常(如.data节可执行),则高度怀疑加壳或注入。

风险说明:解析PE头时,注意“节区大小”与“文件大小”的差异。恶意代码可能利用节区头部声明的虚拟大小大于实际文件大小,造成内存中节区重叠,从而隐藏代码。

常见误区

误区一:混淆RVA(相对虚拟地址)与文件偏移。RVA是相对于ImageBase的地址,需通过节表转换为文件偏移才能定位数据。误区二:忽略OptionalHeader中的DataDirectory数组。该数组的第0项指向导出表,第1项指向导入表,是后续分析的关键入口。

4.5 导入表与导出表分析:窥探API调用

核心原理

导入表(Import Table)列出了PE文件运行时需要从其他DLL加载的函数。恶意代码通过导入表调用Windows API,因此导入表直接反映了样本的行为能力。例如,导入CreateRemoteThread和VirtualAllocEx暗示进程注入;导入URLDownloadToFile暗示下载执行。导出表(Export Table)则列出DLL对外提供的函数,恶意DLL的导出表可能伪装成合法DLL(如DllRegisterServer)以迷惑分析。

分析方法

  • 使用pefile库:遍历pe.DIRECTORY_ENTRY_IMPORT,获取DLL名称和导入函数。
  • 使用CFF Explorer:图形化查看导入/导出表,支持排序和搜索。
  • 关注“延迟导入”:某些样本使用延迟加载,只有在调用时才解析API,静态分析可能遗漏。

案例拆解

分析一个键盘记录器样本,导入表关键项如下:

DLL导入函数行为暗示
user32.dllGetAsyncKeyState, GetForegroundWindow键盘钩子、窗口监控
kernel32.dllWriteFile, CreateFileW文件写入(日志)
ws2_32.dllsend, connect网络发送(数据外传)
ntdll.dllNtQueryInformationProcess反调试检测

这四组导入函数组合起来,几乎可以断定样本会记录键盘输入、写入本地文件并通过网络外传。进一步检查导出表,发现该样本没有导出函数,说明它是EXE而非DLL。

经验提醒:导入表可以被伪造或混淆。高级恶意代码可能使用GetProcAddress动态获取API地址,此时导入表中只有LoadLibrary和GetProcAddress。遇到这种情况,需要结合字符串分析(如API名称字符串)和动态分析。

常见误区

误区一:认为导入表越少越安全。实际上,恶意代码可能通过LoadLibrary在运行时加载DLL,静态导入表仅显示少量API。误区二:忽略导出表。对于DLL型恶意代码(如勒索软件加载器),导出表可能包含DllMain或Start等入口函数,分析这些函数的导出序号有助于理解调用约定。

4.6 综合复盘:静态分析的局限与衔接

静态分析并非万能。加壳、混淆、动态API解析、反虚拟机技术都会削弱静态分析的效果。但作为分析流程的第一步,它能提供低成本、高安全性的情报。在实际工作中,建议将本章五个基础动作组合成“快速筛查清单”:先识别类型,再提取字符串,计算哈希,解析PE头,最后深入导入导出表。若静态分析结果指向明确的恶意行为(如窃密、下载器),则可直接撰写报告;若结果模糊,则需进入动态分析阶段。

总结清单:
  • 文件类型识别:file命令 + DIE,确认是否为PE文件及是否加壳。
  • 字符串提取:strings + FLOSS,收集URL、路径、注册表项。
  • 哈希计算:SHA-256,用于情报查询与样本追踪。
  • PE头解析:pefile,获取入口点、节区权限、编译时间。
  • 导入/导出表:分析API调用,推断行为意图。

静态分析的质量取决于分析者的经验与耐心。一个看似无害的导入表,结合字符串中的异常URL,往往能拼凑出完整的攻击链条。下一阶段,我们将把这些静态线索带入动态分析环境,验证行为并提取网络IOC。