微軟小畫家生成圖片暗藏GUID浮水印

Vector 35的軟體開發者Xusheng Li在8月20日公開一份逆向工程分析,結論是Windows內建的小畫家(Paint)與相片(Photos)在生成AI影像時,會把一串來自微軟伺服器的16位元組GUID編碼進像素,形成肉眼看不見的浮水印。The Register在8月25日跟進報導後,這件事才在開發者圈擴散開來。

按照Li的拆解,流程從提示詞離開本機那一刻就開始了。使用者在小畫家的Cocreator裡輸入描述,程式先把提示詞送到微軟的一個Azure Front Door端點做審核,伺服器端回傳三樣東西:一段修訂後的提示詞、一個promptGenerationId,以及一個叫watermarkId的值。watermarkId就是後來被寫進像素的那個GUID。

浮水印是怎麼埋進去的

負責編碼的元件叫Watermarker.dll,體積1.67 MB,搭配一個302.4 MB的加密模型檔mager.onnxe。16位元組的GUID前面加上一個0x4c標記、後面綴上檢查碼,湊成18位元組,展開成144個位元。每一位元至少需要8×8的像素區塊來承載,所以能打上浮水印的影像最小得是192×192。

代價不算輕。Li統計了一張512×512的圖,26萬2000個像素裡有19萬3000個被更動過,佔比約74%。更動手法是內容自適應的區塊SVD類演算法,肉眼看不出來,但確實改寫了大半張圖。

同一個GUID還會以soft-binding(軟性綁定)的形式寫進C2PA Content Credentials中繼資料,演算法識別碼寫作com.microsoft.invismark.1,由微軟簽署。像素裡一份、中繼資料裡一份,兩條線互為備份——把C2PA中繼資料剝掉,像素浮水印依然存在。

支援的格式是PNG、JPEG、GIF與小畫家自己的.paint。BMP被排除在外,Li判斷原因是BMP存不下完整的C2PA manifest。

兩款程式的態度不一樣

小畫家與相片對浮水印失敗的處理方式不同,這個落差透露不少訊息:

  • 小畫家:浮水印打不上,整次生成就算失敗,圖片根本不會回傳給使用者。
  • 相片:記一筆錯誤日誌,然後照樣把沒有浮水印的圖給你。

相片裡的Image Creator與Restyle Image用的是同一個Watermarker.dll。小畫家那種「寧可不出圖也要有浮水印」的設定說明,在微軟的產品邏輯裡,浮水印是生成流程的必要環節,不是事後附加的可選項。

Li還注意到一個細節:小畫家會把上一次的promptGenerationId當作lastPromptGenerationId,隨下一次審核請求一起送出。連續幾次生成因此被伺服器端明確串成一條鏈。

連網這件事

這套機制最容易被誤解的地方在Copilot+ PC。這類機器有本機NPU,影像生成確實跑在裝置端,微軟也一直拿「本機生成」當賣點。但提示詞審核與溯源簽署這兩步都在雲端——GUID得從伺服器領,C2PA簽署得由微軟來簽。圖是在本機畫的,通行證卻是連網領來的。

隱私上的推論並不複雜:只要微軟那端把每條提示詞和發出它的帳號對上,理論上拿到一張外流的圖,反查浮水印就能定位是誰、在哪一次生成的。Li的批評並非針對浮水印技術本身,落點在揭露的充分性——微軟公開談過自家的AI安全措施,但沒有講清楚C2PA manifest裡那個GUID其實與使用者的提示詞綁在一起。The Register聯繫微軟置評,截稿前未獲回應。

溯源與追蹤之間的那條線

歐盟對AI生成內容的透明度要求,重點在於「讓人知道這是AI生成的」。C2PA這類標準的設計目的也是如此,標註來源與生成方式。微軟這套做法在標註之外又多走了一步:它為每一次生成都發了一個唯一編號。

兩件事的技術實作幾乎一樣,用途卻差得很遠。粗略算一下,要區分「AI生成/非AI生成」這種二元資訊,一個位元就夠用了;16位元組的GUID有2^128種可能值,多出來的位元寬度只能用來編碼更細的東西。位元寬度本身就說明了設計意圖——它不是內容標籤,而是生成事件的身分證。

對一般Windows使用者來說,短期影響有限,多數人不會拿小畫家生成的圖去做需要匿名的事。但對把小畫家當成順手工具的人來說,有一點現在可以確定:本機生成不等於本機不留痕,每張圖出門時都帶著一個只有微軟才能解釋的編號。

參考來源:Xusheng Li公開的逆向工程分析報告、The Register、CocoLoop;已核對GUID位元組長度、浮水印位元數、512×512影像的像素更動數量與C2PA演算法識別碼寫法。