Skip to content

docs: VBA 注入的 document-module 綁定陷阱 — codeName 缺失讓巨集「看似正常、執行全滅」(429/靜默 no-op) #138

Description

@kiki830621

Problem

Original text:
「幫我放進macdoc」
— Source: 使用者(2026-07-17,VBA 注入 no-op 之謎破案後)

zip 注入 vbaProject.bin 到 openpyxl 產的 xlsx 時,document-module 綁定缺失會讓 VBA 專案「看似正常、執行全滅」——巨集清單看得到、run VB macro 回成功,但沒有任何巨集真的執行。這個 gotcha 在網路上的 xlsm 注入教程幾乎沒人提,實戰花了一整個下午才破案,必須沉澱。

Type

docs

根因

vbaProject.binPROJECT stream(明文,MBCS 編碼)宣告 document modules:

Document=ThisWorkbook/&H00000000
Document=<carrier 的 sheet codeName>/&H00000000

綁定鍵在宿主端 XML:

bin 宣告 宿主綁定鍵 缺失時的後果
Document=ThisWorkbook xl/workbook.xml<workbookPr codeName="ThisWorkbook"/> 致命:ThisWorkbook 物件無法解析 → 任何巨集一觸碰它就拋 429「ActiveX 元件無法產生物件」
Document=<sheet> xl/worksheets/sheetN.xml<sheetPr codeName="..."/> 次要:配對未定義(懸空 module 通常無害)

openpyxl / LibreOffice 產的檔都不寫 codeName → 注入的 VBA 天生殘廢。

三個惡性疊加(為什麼難診斷)

  1. 429 被巨集自己的 On Error handler 吃掉 → 錯誤 MsgBox 一閃而過或被忽略,表面「執行完成」
  2. Mac Excel AppleScript run VB macro 對解析失敗靜默回 exit 0(對不存在的巨集名也一樣!);詭異的是帶 module 限定名(Module.Sub)反而能觸發真執行並暴露錯誤
  3. 輸出恰好等於預期值時,no-op 與成功不可區分——靜態預填值本來就正確,巨集沒跑也「全對」

修法(注入器一併縫,純檔案層)

# xl/workbook.xml
<workbookPr/><workbookPr codeName="ThisWorkbook"/>
# xl/worksheets/sheetN.xml(每張)
<sheetPr .../><sheetPr codeName="工作表N" .../>

注意 <sheetPr> 可能帶既有屬性或不存在——regex 要處理三種形態,且絕不能產生重複的 sheetPr 元素(schema 違規 → Excel 靜默拒開,又是一個無聲失敗)。

驗收方法論(本案最大教訓)

驗收必須要求可觀察的狀態改變,不能只驗「結果正確」:

改輸入(利率 1.75% → 3%)→ 跑巨集 → 輸出必須改變(且與獨立實作的理論值一致)
→ 改回 → 輸出必須復原

實測修復後:42,112 格中恰好 310 格如 Python 引擎理論預測地改變——雙實作逐格吻合才算驗證完成。「跑了沒報錯 + 結果正確」在這個 bug class 面前毫無鑑別力。

Expected

Impact

  • 沒有這頁,任何人(包括未來的 AI session)做 xlsm 注入都會掉進同一個「看似成功實為全滅」的洞,且平均要數小時才爬得出來
  • 適用整個 OPC 家族(.docm/.pptm 的 document module 同理)

Refs #135, #136

Priority

P2

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions