恶意固件样本分析:固件提取、逆向工程与动静分析

各位同学,欢迎来到第三章。前两章我们搭好了沙箱环境,也聊了固件安全的基础威胁模型。从这章开始,咱们要真正动手了——面对一个恶意固件样本,你第一步该做什么?

说白了,就是三件事:把固件从硬件里弄出来、看懂它里面是什么、判断它到底干了什么坏事。我做了这么多年固件分析,见过太多人一上来就反汇编,结果发现固件根本提错了,白忙活一整天。所以,顺序很重要。

核心思路:固件分析不是一锤子买卖。提取→逆向→分析,每一步都可能让你回头修正前面的判断。保持迭代心态。

恶意固件分析三阶段流程 阶段一:固件提取 物理/逻辑/调试接口 阶段二:逆向工程 文件系统/CPU指令/数据结构 阶段三:动静分析 静态扫描 + 沙箱动态执行 迭代反馈:分析结果修正提取/逆向策略 💡 我的经验: 别想着一次搞定。我见过最坑的案例是提取时少读了一个分区,逆向两天才发现—— 回头重提,半天就解决了。先快速过一遍三阶段,再深入。

3.1 固件提取技术:把固件从硬件里「请」出来

固件提取是分析的基础。你拿不到固件,后面全是空谈。提取方式分三大类,我按实战中遇到的频率排序讲。

3.1.1 物理提取:直接读芯片

最直接的方法。把Flash芯片吹下来,用编程器读。适合SPI Flash、NAND、NOR等常见存储芯片。

  • SPI Flash编程器:CH341A、FT2232H,便宜好用。我习惯用树莓派的GPIO直接怼SPI,速度更快。
  • NAND读取:注意坏块管理。我曾经因为没处理坏块表,读出来的固件校验一直不过,折腾了两天。
  • JTAG/SWD:如果芯片没锁,直接通过调试接口dump内存。适合MCU类固件。

避坑指南:我曾经遇到过芯片有「读保护」Level 1/2。这时候别硬来,先查芯片手册,看看有没有后门或漏洞可以利用。比如STM32的读保护,某些老版本可以通过电压毛刺绕过。

3.1.2 逻辑提取:通过软件接口获取

如果设备还能跑,通过UART、USB、网络等接口把固件拉出来。常见手法:

  • U-Boot救砖:很多嵌入式设备启动时按任意键进U-Boot,然后 tftp 或 loadb 把固件传出来。
  • 固件更新包:从官网下载的.bin/.hex文件,或者OTA抓包。但要注意,更新包可能被加密或签名。
  • 漏洞利用:通过命令注入、缓冲区溢出等漏洞,在设备上执行 cat /dev/mtdblock0 之类的命令。

⚠️ 注意:逻辑提取依赖设备正常运行。如果设备已经被恶意固件搞瘫痪了,这条路走不通。我建议先试逻辑提取,不行再上物理提取。

3.1.3 高级提取:对付加密和压缩

现在很多固件出厂就加密或压缩了。提取只是第一步,你还得解包。

技术 适用场景 常用工具
binwalk 自动识别文件系统、压缩算法 binwalk -Me firmware.bin
固件加密分析 识别AES、RSA等加密特征 findcrypt、哈希匹配
LZMA/gzip解压 常见压缩固件 7z、dd + unlzma
自定义格式 厂商魔改的固件头 010 Editor + 模板

我个人习惯:拿到固件先跑 binwalk -Me,看看能不能自动解出文件系统。如果不行,再用 hexdump 看头部特征。你想想看,很多厂商只是把标准Linux内核+根文件系统打包一下,binwalk基本都能搞定。

3.2 固件逆向工程基础:从二进制到逻辑

固件提出来了,接下来就是逆向。这一步的核心是:搞清楚固件里有哪些模块,它们怎么交互的。

3.2.1 识别CPU架构和操作系统

不同架构的指令集完全不同。ARM、MIPS、x86、RISC-V……你得先知道目标是什么。

  • 看入口点:ARM的Reset Vector通常在0x0或0x8000附近;MIPS的入口一般在0x80001000附近。
  • 用工具自动识别:file 命令、binwalk 的架构检测、readelf(如果有ELF头)。
  • 字符串搜索:搜 "Linux version"、"U-Boot"、"VxWorks" 等关键字。

实战技巧:我遇到过固件头被故意抹掉的情况。这时候可以看中断向量表——ARM的异常向量表有固定模式(0xEA000000等),一眼就能认出来。

3.2.2 文件系统提取与分析

大多数固件包含一个完整的文件系统。常见的有:

  • SquashFS:只读压缩文件系统,Linux嵌入式最爱。用 unsquashfs 解压。
  • JFFS2/UBIFS:针对NAND Flash的日志型文件系统。需要 jefferson 或 ubi_reader。
  • CPIO:initramfs常用。直接用 cpio -idmv 解。
  • 自定义格式:有些厂商自己魔改的文件系统。这时候得手动分析超级块结构。

举个例子,解压SquashFS的命令:

# 先用binwalk找到偏移
binwalk firmware.bin | grep SquashFS

# 假设偏移是0x123456,大小是0x800000
dd if=firmware.bin bs=1 skip=$((0x123456)) count=$((0x800000)) of=rootfs.squashfs
unsquashfs rootfs.squashfs

3.2.3 关键二进制文件逆向

文件系统解开后,重点关注这些文件:

  1. /bin/、/sbin/下的主程序:比如httpd、telnetd、upnp服务。
  2. /etc/init.d/下的启动脚本:看恶意固件改了哪些启动项。
  3. /lib/下的动态库:特别是被hook的系统调用。
  4. /dev/下的特殊设备:有些恶意固件会创建隐藏字符设备。

用IDA Pro或Ghidra打开主程序,先看字符串窗口。我习惯搜 "password"、"backdoor"、"debug"、"shell" 这些关键词。你想想看,恶意固件作者也是人,他们也会偷懒,字符串往往暴露一切。

3.3 静态分析与动态分析:双管齐下

逆向工程让你理解了固件的结构,但真正判断它是不是恶意,还得靠分析。静态分析和动态分析是两条腿,缺一不可。

3.3.1 静态分析:不动手,先看代码

静态分析就是不运行固件,直接看二进制代码。好处是安全,不会触发恶意行为。坏处是可能漏掉加壳或混淆的逻辑。

  • 特征匹配:用YARA规则扫描固件,匹配已知恶意特征。我维护了一个固件专用的YARA规则库,覆盖了常见的后门、挖矿、DDoS模块。
  • 控制流分析:在IDA/Ghidra里看函数调用图。重点关注网络接收、系统命令执行、文件读写等敏感函数。
  • 数据流分析:追踪用户输入到敏感函数的路径。比如recv()的数据直接传给system(),这基本就是命令注入。
  • 加密算法识别:用findcrypt插件找硬编码的密钥或S盒。

我的习惯:静态分析时先跑一遍自动化脚本。我会用 cwe_checker 扫描常见漏洞模式,再用 firmwalker 检查敏感文件。自动化筛一遍,人工再聚焦可疑点。

3.3.2 动态分析:让固件跑起来

动态分析就是在沙箱里执行固件(或固件中的某个程序),观察它的行为。这是验证静态分析结论的关键一步。

动态分析的核心手段:

技术 监控内容 常用工具
系统调用跟踪 文件、网络、进程操作 strace、ltrace、sysdig
网络流量分析 C2通信、DNS查询、数据外传 tcpdump、Wireshark、FakeNet
内存快照 运行时数据、解密后的payload avocado、QEMU + GDB
API Hook 拦截特定函数调用 Frida、LD_PRELOAD

举个例子,用QEMU模拟运行一个MIPS架构的恶意固件程序:

# 安装QEMU用户态模拟
sudo apt install qemu-user-static

# 运行MIPS程序,用strace跟踪
qemu-mips-static -L ./squashfs-root/ ./squashfs-root/bin/httpd &
strace -p $(pidof qemu-mips-static) -e trace=network,file,process

⚠️ 安全警告:动态分析必须在隔离的沙箱环境中进行。我曾经见过一个固件样本,它检测到自己在QEMU里就跑,但一旦发现是真实网络,立刻开始扫描内网。所以,网络隔离是底线。

3.3.3 动静结合:交叉验证

静态分析告诉你「可能有什么」,动态分析告诉你「实际做了什么」。两者结合才能下结论。

我常用的工作流:

  1. 静态扫描,列出所有可疑文件和函数。
  2. 在沙箱里运行关键程序,抓系统调用和网络包。
  3. 对比静态分析的结果和动态行为。如果静态说某个函数是加密函数,但动态发现它在连接外部IP,那就有问题了。
  4. 根据动态结果,回头细化静态分析。比如动态发现了一个隐藏的配置文件路径,再回固件里找这个文件。

核心原则:不要相信任何单一分析结果。静态可能漏掉加壳代码,动态可能被反沙箱技术欺骗。只有交叉验证过的结论,才值得写进报告。