4. 固件二进制文件元数据提取

任务目标

对给定的固件二进制文件执行元数据提取,获取其架构、字节序、编译选项(如栈保护、PIE、NX)以及链接器特征,用于后续漏洞分析前的初步评估。

环境依赖

本案例使用 readelf、file 与 objdump(binutils 套件),以及 checksec 脚本。在 Kali Linux 或 Ubuntu 上执行:

sudo apt install binutils file checksec

核心实现

以下 Bash 脚本对目标固件二进制执行完整元数据提取,输出架构、端序、入口点、编译时保护选项及链接器版本:

#!/bin/bash
# firmware_meta.sh — 固件二进制元数据提取
# 用法: ./firmware_meta.sh <binary_path>

if [ $# -ne 1 ]; then
    echo "用法: $0 <binary_path>"
    exit 1
fi

BIN="$1"

if [ ! -f "$BIN" ]; then
    echo "错误: 文件不存在"
    exit 1
fi

echo "===== [1] 文件类型与架构 ====="
file "$BIN"

echo -e "\n===== [2] ELF 头关键字段 ====="
readelf -h "$BIN" | grep -E "Class|Data|Machine|Entry point"

echo -e "\n===== [3] 安全保护机制 ====="
# 使用 readelf 检查 GNU_STACK / GNU_RELRO 段
readelf -l "$BIN" | grep -E "GNU_STACK|GNU_RELRO"

# 检查 BIND_NOW (full RELRO)
if readelf -d "$BIN" | grep -q "BIND_NOW"; then
    echo "RELRO: Full RELRO"
elif readelf -l "$BIN" | grep -q "GNU_RELRO"; then
    echo "RELRO: Partial RELRO"
else
    echo "RELRO: No RELRO"
fi

# 检查 NX (栈不可执行)
if readelf -l "$BIN" | grep "GNU_STACK" | grep -q "RWE"; then
    echo "NX: Disabled (栈可执行)"
else
    echo "NX: Enabled (栈不可执行)"
fi

# 检查 PIE
if readelf -h "$BIN" | grep -q "DYN"; then
    echo "PIE: Enabled (ET_DYN)"
else
    echo "PIE: Disabled (ET_EXEC)"
fi

echo -e "\n===== [4] 编译选项特征 ====="
# 检查栈保护 (canary)
if readelf -s "$BIN" | grep -q "__stack_chk_fail"; then
    echo "Stack Canary: Enabled"
else
    echo "Stack Canary: Disabled"
fi

# 检查 FORTIFY
if readelf -s "$BIN" | grep -q "_chk@"; then
    echo "FORTIFY: Enabled"
else
    echo "FORTIFY: Disabled"
fi

# 检查链接器版本
echo -e "\n===== [5] 链接器与工具链 ====="
readelf -p .comment "$BIN" 2>/dev/null | grep -E "GCC|GNU" || echo "无 .comment 段"

echo -e "\n===== [6] 导入函数摘要 ====="
readelf -s "$BIN" | grep "UND" | awk '{print $8}' | grep -v "^$" | sort -u | head -20

运行方式

chmod +x firmware_meta.sh
./firmware_meta.sh ./sample_firmware.bin

验证方法

以一份已知编译选项的测试二进制验证脚本正确性。例如,用以下命令编译两个对照样本:

# 开启全部保护的样本
gcc -o test_full -fstack-protector-all -pie -fPIE -z relro -z now test.c

# 关闭保护的样本
gcc -o test_none -fno-stack-protector -no-pie -z execstack test.c

对 test_full 运行脚本,预期输出应包含:NX: Enabled、PIE: Enabled、Stack Canary: Enabled、RELRO: Full RELRO。对 test_none 运行,预期输出应包含:NX: Disabled、PIE: Disabled、Stack Canary: Disabled、RELRO: No RELRO。若输出与上述预期一致,则脚本功能正确。

常见问题

  • readelf 提示 "File format not recognized":目标可能不是 ELF 格式(如 U-Boot 裸镜像或 TRX 固件),需先用 binwalk 解包或使用 arm-linux-gnueabi-readelf 等交叉工具。
  • 脚本对 ARM 固件输出异常:ARM 架构的 NX 检查需确认内核是否支持 XN 位,部分旧 ARM 固件无 GNU_STACK 段,此时应结合 readelf -A 检查属性段。