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.2 万个像素里有 19.3 万个被改动过,占比约 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 算法标识写法。