MS Paint and Photos inivisibly watermark even locally generated output with GUID

MS Paint and Photos inivisibly watermark even locally generated output with GUID

Reverse engineering reveals how Paint and Photos embed a server-issued GUID into the pixels of locally generated AI images. This research started with my curiosity about Paint. I recently had some success looking into less-explored Windows features like UCPD , WHESCVC , and I have long known that Microsoft added a bunch of AI features into the Paint app. I do not know if anyone actually uses Paint + AI to generate images, but I wanted to see how exactly the image generation works. Before I started, I expected that it simply called a remote API to do the image generation. However, after I set up Binary Ninja MCP with Codex and started the analysis, I soon realized that Microsoft actually shipped local models in Windows as part of Copilot. The Paint App is sitting in the following path (yes, they are all Windows Apps now): seg.onnxe 23.1 MB inseg_enc.onnxe 28.0 MB inseg_dec.onnxe 16.5 MB mager.onnxe 302.4 MB The format of seg.onnxe was previously known , i.e., when it is XORed with the string Microsoft_2023 , it becomes a normal ONNX file.

However, the format of the other three .onnxe files initially looked different. It turned out that Microsoft had not changed the algorithm, only the key. segapi.dll contains a small key registry: ps_enc_key.1.0.80-main -> "Microsoft_2023" ps_enc_key.1.0.81-main -> a 4,096-byte alphanumeric string After decryption, onnx.checker.check_model() works on all of them: While walking through these files, I found a Watermarker.dll : This is not super surprising to me, because while I interacted with the Paint app, I already discovered that it has a setting to embed a visible watermark to the image that it produces: The visible watermark is just a small Copilot logo at the bottom right of the image, which is totally normal. Then, out of nowhere, I decided to ask AI to analyze the DLL and see if it could also be embedding an invisible watermark. This is part of my intuition as a reverse engineer, because the file is 1.67 MB in size, which is unusually large for such trivial functionality (arguably, the visible watermark does not even require a separate DLL). Apparently, the recent Claude Code text-watermark announcement also played a role in prompting me to think about this possibility. To begin with, the visible watermark is added by Add Perceptible Watermark : CPBDoc::Save(...) | `-- perceptible-watermark save helper(bitmap, Watermark Setting) | +-- Watermark Setting::Never | `-- return the original bitmap | +-- Watermark Setting::Ask Every Time | `-- show the Yes / No confirmation popup | +-- No: return the original bitmap | `-- Yes: continue | `-- Always or confirmed Yes +-- Paint::AI::Get Perceptible Watermark Svg() `-- Paint::AI::Add Perceptible Watermark(bitmap, SVG stream) `-- composite the visible Copilot logo Then there is also a different Wmk Write Watermark function: Watermarker.dll !

Wmk Write Watermark ( output_pixels, payload, payload_length, width, height, stride, input_pixels, pixel_format); Tracing the call tree, we can see Wmk Write Watermark is called after a local Stable Diffusion image generation. And if Wmk Write Watermark fails, Paint converts the entire generation into an error rather than returning the image without it: Cocreator View Model::Generate Image Async(...) | `-- Paint::AI::Stable Diffusion Helpers::Generate Async(..., watermark Id, ...) | `-- Microsoft. Image Creation. Image Generator | `-- NPU-generated image result | +-- output safety/moderation checks | +-- Paint::AI::Add Watermark(bitmap, watermark Id) | | | `-- Watermarker.dll! Wmk Write Watermark(...) | | | +-- success: return the watermarked bitmap | `-- failure: turn generation into an error | `-- construct successful Stable Diffusion Result Then it is natural to ask what the incoming payload actually is. It quickly becomes apparent that it must be 16 bytes: if (payload_length 16 ) return - 5 ; It is funny to me that the code is using two different error codes when the payload is too short or too long.

Sources cited: ๐Ÿ“ฐ Hacker News โ†—

โšก Effects Interpreter

๐ŸŒWorld Economy

  • โ–ถA story like this rarely stays local for long in a connected economy.
  • โ–ถWorld markets have a habit of reading between the lines of stories like this.

๐Ÿ™๏ธLocal Economy

  • โ–ถThe cost of a weekly food shop can creep up in the background.
  • โ–ถYour local economy has a way of catching these currents eventually.

๐ŸฆRates & Banks

  • โ–ถRate decisions tend to follow data, not headlines, so patience is the norm.
  • โ–ถBase rate decisions are usually made on data trends, not single headlines.

โค๏ธHealth

  • โ–ถA short walk or a chat with a friend can do wonders when headlines feel heavy.
  • โ–ถWorry has a way of spreading faster than the facts sometimes.

๐Ÿ’ทWealth

  • โ–ถYour overall wealth picture is unlikely to be defined by a single story like this.
  • โ–ถMarkets have a habit of overreacting first and settling down further down the line.

๐Ÿ Housing

  • โ–ถRental yields in the area could shift only slightly, if at all, from this.
  • โ–ถAny effect on bricks and mortar is likely to be slow and modest.
Share: ๐• Twitter Facebook LinkedIn WhatsApp

Editorial note: This analysis was produced by the News Effects Interpreter, an AI editorial tool that cross-references 1 independent news sources and contextualises events in terms of their real-world impact on ordinary people. Original reporting is linked above. News Effects does not alter the facts of source reports.