1322 字
7 分鐘
Gigabyte BMC 韌體逆向分析
拆包流程概覽
這篇主要記錄我怎麼把技嘉 BMC 的韌體拆包、找到 devmaps,再產生後續會用到的 models.json。
使用 binwalk 掃描韌體
先用 binwalk 看看韌體裡有什麼東西:
binwalk -e <BMC firmware>實際輸出(節錄):
DECIMAL HEXADECIMAL DESCRIPTION--------------------------------------------------------------------------------42092 0xA46C LZMA compressed data, properties: 0x5D, dictionary size: -1073741824 bytes, uncompressed size: 124 bytes42164 0xA4B4 Flattened device tree, size: 3615 bytes, version: 1767616 0x10820 CRC32 polynomial table, little endian118453 0x1CEB5 Certificate in DER format (x509 v3), header length: 4, sequence length: 259422460 0x6723C SHA256 hash constants, little endian586693 0x8F3C5 AES Inverse S-Box597830 0x91F46 AES S-Box730664 0xB2628 Flattened device tree, size: 33400 bytes, version: 171179648 0x120000 JFFS2 filesystem, little endian5111808 0x4E0000 JFFS2 filesystem, little endian5636096 0x560000 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 49067396 bytes, 7496 inodes, blocksize: 131072 bytes, created: 2025-08-29 14:54:4254722624 0x3430040 Flattened device tree, size: 4856980 bytes, version: 1754722852 0x3430124 Linux kernel ARM boot executable zImage (little-endian)54738476 0x3433E2C xz compressed data54738707 0x3433F13 xz compressed data59205388 0x387670C Flattened device tree, size: 53626 bytes, version: 1759703296 0x38F0000 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 5241502 bytes, 107 inodes, blocksize: 131072 bytes, created: 2025-08-29 14:54:39可以看到在 offset = 59703296 的位置有一個 SquashFS 檔案系統,把它解開就能拿到裡面的 rootfs 來研究。
找到 devmaps 與風扇對應關係
解開 SquashFS 之後,可以在 rootfs 裡找到:
- 位置:
/etc/devmaps/MZB3/ - 其中包含:
G494-ZB4-AAP2-000.xml
搭配之前備份的 fanprofile.json 來看,可以發現 XML 裡有各種風扇的 mapping 設定。這些 mapping 可以用來把 fan profile 解析成「真正的風扇名稱」,方便之後做 UI 顯示或 Debug。
extract.sh:自動解包並提取 devmaps
為了不要每次都手動找 offset、解 SquashFS,我寫了一個 extract.sh,自動:
- 用 binwalk 掃出韌體中的 SquashFS 區塊
- 用 dd 把 SquashFS 切出來
- 用 unsquashfs 解壓
- 搜尋
devmaps資料夾並拷貝到指定目錄
#!/bin/bash
FILE="$1"TARGET_DIR="extracted_devmaps"
if [ -z "$FILE" ]; then echo "用法: $0 <firmware.bin>" exit 1fi
# 檢查工具for cmd in binwalk unsquashfs dd grep awk; do if ! command -v $cmd &> /dev/null; then echo "錯誤: 缺少必要工具 $cmd" exit 1 fidone
echo "[*] 正在掃描 $FILE (僅讀取表頭,不解壓)..."
# 讀取 binwalk 輸出binwalk "$FILE" | grep "Squashfs filesystem" | while read -r line; do
# 1. 抓取 Offset (十進位) OFFSET=$(echo "$line" | awk '{print $1}')
# 2. 抓取 Size (使用嚴格 Regex 避開 blocksize) SIZE=$(echo "$line" | grep -oP '\bsize: \K[0-9]+' | head -n 1)
if [ -z "$OFFSET" ] || [ -z "$SIZE" ]; then continue fi
echo "---------------------------------------------------" echo "[+] 發現 SquashFS -> Offset: $OFFSET, Size: $SIZE"
IMG_NAME="rootfs_${OFFSET}.sqfs"
# 3. 使用 dd 切割檔案 (高效能模式) # bs=1M: 每次讀寫 1MB,大幅降低 I/O overhead # iflag=skip_bytes,count_bytes: 告訴 dd 雖然 bs=1M,但 skip/count 的單位是 bytes echo "[*] 正在切割檔案 (高效能 dd)..."
dd if="$FILE" bs=1M skip="$OFFSET" count="$SIZE" iflag=skip_bytes,count_bytes of="$IMG_NAME" status=none
if [ $? -ne 0 ]; then echo "[-] dd 切割失敗,請檢查 dd 版本是否支援 iflag (GNU dd)" rm -f "$IMG_NAME" continue fi
# 4. 解壓 SquashFS echo "[*] 正在解壓 SquashFS..." TEMP_EXTRACT_DIR="sqfs_out_${OFFSET}"
# 加上 -no-xattrs 避免 WSL 下的權限屬性報錯 unsquashfs -d "$TEMP_EXTRACT_DIR" -f -no-xattrs "$IMG_NAME" > /dev/null 2>&1
if [ ! -d "$TEMP_EXTRACT_DIR" ]; then echo "[-] 解壓失敗 (可能是缺少 sasquatch),跳過..." rm -f "$IMG_NAME" continue fi
# 5. 搜尋並提取 devmaps FOUND_PATH=$(find "$TEMP_EXTRACT_DIR" -type d -name "devmaps" | head -n 1)
if [ -n "$FOUND_PATH" ]; then echo "[!] 成功在 $IMG_NAME 中找到 devmaps!" echo "[*] 路徑: $FOUND_PATH"
mkdir -p "$TARGET_DIR" cp -r "$FOUND_PATH/"* "$TARGET_DIR/" echo "[ok] 已複製到: $TARGET_DIR"
# 清理暫存 rm -rf "$TEMP_EXTRACT_DIR" "$IMG_NAME" echo "[*] 已清理暫存檔案,任務完成。"
exit 0 else echo "[-] 此分區未找到 devmaps,清理並繼續搜尋下一個..." rm -rf "$TEMP_EXTRACT_DIR" "$IMG_NAME" fi
done
echo "---------------------------------------------------"if [ -d "$TARGET_DIR" ]; then echo "掃描結束。請檢查 $TARGET_DIR"else echo "掃描結束。未在任何 SquashFS 分區中找到 devmaps。"figen_models.py:從 devmaps 生成 models.json
有了 devmaps 裡一堆 XML 檔之後,接下來用 gen_models.py 生成一個整理好的 models.json,之後可以給前端或其他工具使用。
腳本會:
- 遞迴掃描目標目錄
- 找出所有非
empty.xml的 XML 檔 - 以檔名當作
id/name - 輸出每個檔案在目標目錄下的相對路徑
import osimport jsonimport argparse
def generate_models_json(target_dir, output_file): models_list = []
# 確保目標目錄存在 if not os.path.exists(target_dir): print(f"錯誤: 找不到目錄 '{target_dir}'") return
print(f"[*] 正在掃描目錄: {target_dir} ...")
# 遞迴遍歷目錄 (os.walk) for root, dirs, files in os.walk(target_dir): for file in files: # 只處理 xml 檔案,並忽略 empty.xml if file.endswith(".xml") and file != "empty.xml":
# 取得完整路徑 (例如: ./extracted_devmaps/MZ93/R183-Z90.xml) full_path = os.path.join(root, file)
# 取得檔名不含副檔名 (ID) # os.path.splitext("R183.xml") -> ("R183", ".xml") file_id = os.path.splitext(file)[0]
# 取得所在的資料夾名稱 (例如 MZ93),這是主板系列代號 series_folder = os.path.basename(root)
# 建立 JSON 物件結構 model_entry = { "id": file_id, "name": file_id, "file": os.path.relpath(full_path, target_dir), # "series": series_folder, # (可選) 主板系列 # "path": os.path.relpath(full_path, target_dir) # (可選) 相對路徑 }
models_list.append(model_entry)
# 根據 ID 排序,讓 JSON 比較整齊 models_list.sort(key=lambda x: x['id'])
# 寫入 JSON 檔案 try: with open(output_file, 'w', encoding='utf-8') as f: json.dump(models_list, f, indent=2, ensure_ascii=False)
print(f"---------------------------------------------------") print(f"[OK] 成功生成: {output_file}") print(f"[+] 總共找到 {len(models_list)} 個機型定義檔") print(f"---------------------------------------------------")
except IOError as e: print(f"寫入檔案錯誤: {e}")
if __name__ == "__main__": # 設定參數解析 parser = argparse.ArgumentParser(description="掃描目錄並生成 models.json") parser.add_argument("directory", nargs="?", default="extracted_devmaps", help="要掃描的 devmaps 資料夾路徑 (預設: extracted_devmaps)") parser.add_argument("-o", "--output", default="models.json", help="輸出檔案名稱 (預設: models.json)")
args = parser.parse_args()
generate_models_json(args.directory, args.output)小結
- 用 binwalk 找到韌體中的 SquashFS 區塊
- 用
extract.sh自動切出並解開 rootfs,抽出devmaps - 用
gen_models.py掃描 devmaps,產生models.json
這樣之後只要拿到新的 BMC 韌體,整個「拆包 → 抽資料 → 生成 models.json」流程就可以一鍵跑完。
Gigabyte BMC 韌體逆向分析
https://blog.rainchi.tw/posts/gigabyte-bmc-analytics/