用 Windows 画图在 Copilot+ PC 上生成一张图,扩散模型的推理确实跑在你的本地 NPU 上——但安全研究员 Xusheng Li 的逆向分析显示,这张图并不是纯粹的"本地产物":像素深处埋着一个由微软服务器在提示词审核时下发的唯一 GUID。完整分析见原文(https://xusheng.dev/posts/reversing/mspaint_invisible_watermark/main/)。
本地生成 ≠ 本地完成
画图和照片应用都内置了本地 AI 模型,四个 .onnxe 文件加起来约 370MB,其中承担生成主干的 mager.onnxe 就占 302MB。这些模型文件被 XOR 混淆过一层,密钥之一是字符串 Microsoft_2023,解开后即是标准 ONNX 模型。
关键在于:即便走本地生成路径,用户输入的提示词仍会先发往微软的审核服务(端点路径为 /v1/paint-cocreator/moderate-prompt)。服务器返回改写后的提示词、promptGenerationId、watermarkId 等字段。图片在本机生成完毕后,watermarkId 会被写进像素——"本地"的只有模型推理,提示词审核与身份标识签发都在云端完成。
水印是怎么写进像素的
水印由 Watermarker.dll 中的 WmkWriteWatermark 函数完成。它强制要求 payload 恰好 16 字节——正是一个 GUID 的长度。实际嵌入的是 18 字节消息:魔数 0x4c、16 字节 GUID、再加一字节校验和,展开成 144 个比特,每个比特至少要成功嵌入三次;图像宽高均不得低于 192 像素,否则直接返回容量不足。
编码器做的是内容自适应的块域量化修改。作者用一张 512×512 合成图测试:262,144 个像素中有 193,376 个被改动——肉眼不可见,但约四分之三的像素都变了。失败语义更能说明设计意图:画图里水印写入失败会让整次生成直接报错,而不是返回一张无水印图片;照片应用则宽松些,失败仅记日志、照常出图。
两层溯源,同一个 GUID
保存文件时,画图还会调用在线签名服务附加 C2PA 内容凭证。作者解析了真实生成图片的 PNG 块:18,979 字节的 caBX 清单里,c2pa.soft-binding 字段的算法标注为 com.microsoft.invismark.1,其 value 正是审核服务返回的那个 watermarkId。像素层隐形水印与文件层签名清单,是同一套溯源系统的两层。
AI 生成结果的保存格式被限制为 PNG、JPEG、GIF 与 .paint(BMP 无法内嵌 C2PA 清单);连续生成时,上一次的 promptGenerationId 还会随下一次请求回传,把多轮操作串成链。
所以呢
微软的支持页面披露了内容过滤与 C2PA 凭证的存在,但没有说明清单里藏着与提示词审核绑定的 GUID,更没提它写进了像素。这与欧盟 AI Act 第 50 条(2026 年 8 月 2 日生效)并不冲突——法规要求 AI 内容带可检测、机读的标记,却没有要求逐次生成、可关联审核会话的身份码。对用户,启示很直接:在系统级 AI 工具里,"本地生成"这个词需要重新审视;对行业,水印正在从"内容是否由 AI 生成"滑向"是谁、在哪次会话生成的"——前者是透明度,后者是可追溯性,两者混着谈,知情权就容易被稀释。