2. 固件解包与内核镜像分析
任务说明
本案例以一个典型的IoT路由器固件为例,完成以下目标:解包固件文件系统、定位Linux内核镜像、分析内核版本与CPU架构、提取内核编译配置。通过该流程掌握固件逆向分析的基础步骤。
环境准备
- 操作系统:Ubuntu 22.04(或任意Linux发行版)
- 工具:
binwalk、file、strings、extract-vmlinux脚本(Linux内核源码scripts目录下) - 示例固件:
router_fw.bin(可从公开固件库获取,如DD-WRT或OpenWrt的工厂镜像)
固件解包
使用binwalk扫描固件结构并提取文件系统:
binwalk router_fw.bin
binwalk -Me router_fw.bin
-M递归扫描,-e自动提取。解包后目录中通常包含squashfs-root(根文件系统)和若干原始内核镜像文件。
定位内核镜像
在解包产物中查找内核镜像:
find _router_fw.bin.extracted -type f -name "*kernel*" -o -name "*vmlinux*" -o -name "*zImage*"
file _router_fw.bin.extracted/* | grep -i kernel
常见位置:_router_fw.bin.extracted/<offset>.kernel(binwalk根据偏移命名)。若未直接识别,可用strings搜索内核特征字符串:
strings _router_fw.bin.extracted/* | grep -i "Linux version"
分析内核版本与架构
对定位到的内核镜像执行:
file _router_fw.bin.extracted/12345.kernel
strings _router_fw.bin.extracted/12345.kernel | grep "Linux version"
file输出显示架构(如ARM、MIPS、x86),strings输出包含完整版本字符串,例如:Linux version 3.10.14 (builder@host) (gcc version 4.8.3) #1 SMP Wed Jul 30 10:23:45 CST 2014。
提取内核配置
内核配置(.config)通常嵌入在镜像的IKCONFIG段中。使用内核官方脚本提取:
wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/extract-ikconfig
chmod +x extract-ikconfig
./extract-ikconfig _router_fw.bin.extracted/12345.kernel > kernel.config
若镜像被压缩(如gzip、lzma),需先解压。使用extract-vmlinux脚本还原未压缩内核:
wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/extract-vmlinux
chmod +x extract-vmlinux
./extract-vmlinux _router_fw.bin.extracted/12345.kernel > vmlinux
./extract-ikconfig vmlinux > kernel.config
验证方法
完成以上步骤后,通过以下条件判定成功:
kernel.config文件非空,且包含以CONFIG_开头的有效配置项(如CONFIG_ARM=y);- 从配置中能确认架构:
grep CONFIG_ARM kernel.config或grep CONFIG_MIPS kernel.config; - 版本字符串与
file输出架构一致,且版本号完整可读。
关键代码实现
以下脚本将上述步骤整合为自动化流程,输入固件路径,输出内核版本、架构和配置文件:
#!/bin/bash
# usage: ./analyze_kernel.sh router_fw.bin
FW="$1"
if [ -z "$FW" ]; then echo "Usage: $0 <firmware.bin>"; exit 1; fi
# 1. 解包
binwalk -Me "$FW" > /dev/null 2>&1
EXTRACT_DIR="_${FW}.extracted"
# 2. 查找内核镜像(优先匹配zImage/内核偏移文件)
KERNEL_IMG=""
for f in $(find "$EXTRACT_DIR" -type f); do
if file "$f" | grep -qE "Linux kernel|kernel image|uImage|zImage"; then
KERNEL_IMG="$f"
break
fi
done
if [ -z "$KERNEL_IMG" ]; then
# 回退:用strings搜索版本字符串定位
for f in $(find "$EXTRACT_DIR" -type f -size +100k); do
if strings "$f" 2>/dev/null | grep -q "Linux version"; then
KERNEL_IMG="$f"
break
fi
done
fi
if [ -z "$KERNEL_IMG" ]; then
echo "[-] Kernel image not found"
exit 1
fi
echo "[+] Kernel image: $KERNEL_IMG"
# 3. 版本与架构
echo "[+] File info:"
file "$KERNEL_IMG"
echo "[+] Version string:"
strings "$KERNEL_IMG" | grep -m1 "Linux version"
# 4. 提取配置
# 先尝试直接提取
./extract-ikconfig "$KERNEL_IMG" > kernel.config 2>/dev/null
if [ ! -s kernel.config ]; then
# 失败则先解压vmlinux
./extract-vmlinux "$KERNEL_IMG" > vmlinux 2>/dev/null
if [ -s vmlinux ]; then
./extract-ikconfig vmlinux > kernel.config 2>/dev/null
fi
fi
if [ -s kernel.config ]; then
echo "[+] Config extracted to kernel.config"
echo "[+] Architecture from config:"
grep -E "CONFIG_(ARM|ARM64|MIPS|X86_32|X86_64|RISCV)=" kernel.config | head -5
else
echo "[-] Config extraction failed (kernel may not have IKCONFIG enabled)"
fi
运行前确保extract-ikconfig和extract-vmlinux已下载并赋予执行权限,且与脚本同目录。
预期输出示例
[+] Kernel image: _router_fw.bin.extracted/30720.kernel
[+] File info:
_router_fw.bin.extracted/30720.kernel: Linux kernel ARM boot executable zImage (little-endian)
[+] Version string:
Linux version 3.10.49 (root@buildhost) (gcc version 4.8.3 (Buildroot 2014.08) ) #1 SMP PREEMPT Fri Aug 22 10:15:22 CST 2014
[+] Config extracted to kernel.config
[+] Architecture from config:
CONFIG_ARM=y
以上输出为基于代码逻辑的预期结果,实际内容取决于固件本身。若kernel.config提取失败,说明该内核未启用CONFIG_IKCONFIG,此时可通过strings vmlinux | grep "CONFIG_"部分恢复配置项,但无法获得完整.config文件。