首页
社区
课程
招聘
[原创]Windows照片应用擦除功能分析
发表于: 2026-5-11 16:25 3758

[原创]Windows照片应用擦除功能分析

2026-5-11 16:25
3758

某天想去除图片浮水印,找了挺多方案,无意中发现最新的Windows照片应用居然带了AI擦除修复功能哇!天助我也。使用了一下发现效果挺哇塞的哦。出于好奇分析它一波!

经过断网分析后发现是本地功能,先对程序目录进行定位。然后按大小排序一下,很明显发现了onnxruntime.dll,也看到了mager.onnxeseg.onnxe

然后搜索一下这个模型名字、顺便问一下老师傅(GPT)。大概也能知道这两个模型是什么咯。一个是抠图扣背景的,一个是咱们需要的擦除模型。

有一个网站它可以在线分析模型有多少层,大概是什么样子嘟。模型X光照射!

正常把可以识别的模型丢进去后可以可视化得出当前模型的一些图和参数。

恰巧这个模型不能被识别,说明加密了或者非标准onnx呗。

先瞅一眼二进制再说!

赶脚有点不太对劲,应该是加密或者混淆了,不像正常的onnx,正常的onnx应该包含很多protobuf的序列化数据。

现在继续分析是谁加载调用了onnxruntime.dll从而分析加载过程和调用代码。

还有一些小意外,加载原来不是根目录的onnxruntime

很明显了东西都在一起!还有NPU相关的。

先抓一下调用链,确定一下整个大概流程是什么样的。

微软这一类的东西应该都不会加壳。直接基于调用链ida静态分析就完了!可以使用ida-pro-mcp搭配任意模型都可以分析出来调用链。

思路很直接:DLL 加载模型文件 → 肯定要解密 → 解密就离不开密钥 → 密钥要么硬编码在 DLL 里要么从某处读取。既然没加壳没混淆,直接 IDA 往里冲。

先拿 seg.onnxe 开刀,因为它小(22MB),而且它是抠图的模型,逻辑应该比擦除模型简单。

第一个关键入口是 segapi.dll。用 IDA 打开后搜 CreateSession 或者 OrtCreateSession 之类的 onnxruntime API 调用,很快锁定了 sub_1800032B0 这个函数——它负责注册模型密钥:

有趣的是 seg 模型只用到了 "key" 这一个键,对应的值就是短短 14 个字节:Microsoft_2023

这就是说 seg 模型的加密方案是 14 字节 ASCII 字符串的循环 XOR——不是 AES,就是普通的异或混淆。

具体在 DLL 里的位置:

注意 segapi.dll 用了 PE section 映射。.rdata 段的 VA 基址是 0x180075000,文件偏移是 0x74000,所以 IDA 地址减 VA 再加文件偏移才能定位到文件。

有了密钥,解密就是一行 Python:

跑完把结果丢进 onnx.load() — 过了!IR=6,1094 个节点,输入 (1,3,512,512),输出 (1,512,512)。丢 Netron 也能正常可视化了:

seg 模型解密搞定,接下来攻 mager。

magerapi.dll 里的密钥管理架构和 segapi 几乎一样——同一个 sub_180002BC0(对应 segapi 的 sub_1800032B0)负责注册密钥表。但 mager 多了一层:

开头我也以为 mager 的密钥是前缀 + long_key 拼接起来(14+10+4096),还算了半天偏移。直到手工 XOR 了一轮发现不对——解密出来的文件头对不上 ONNX 的protobuf 08 魔数。

后来仔细核对才发现:**mager 根本不用 "Microsoft_2023" 前缀!**它只用 "long_key" 那个 4096 字节的数据块。那个 "key""Microsoft_2023" 的映射是给 seg 模型用的,mager 的 InitModelKeyTable 里虽然也注册了 "key",但实际加载模型时只取了 "long_key"

正确位置:

之前写的 0x7BAC0 是个 typo,PE section 映射算偏了。正确的文件偏移是 VA 减 .rdata 基址再加 raw offset:0x18007AAC0 - 0x180075000 + 0x74000 = 0x7AAC0

用这 4096 字节去 XOR mager.onnxe(295MB),出来的结果 onnx.load() 直接过:

加密算法都一样:静态循环 XORplaintext[i] = ciphertext[i] XOR key[i % key_len]

XOR 属于混淆而非密码学加密,安全强度不高。但对于本地模型保护来说,能挡住大部分直接拷贝文件的人就算达到目的了。

解密完不跑一下怎么行。用 onnxruntime CPU 模式加载两个模型测试:

Seg 模型配合视频逐帧处理,CPU 下约 4 FPS(1280×720)。如果装上 CUDA 版 onnxruntime 配合更好的 GPU,预计 40-80 FPS,实时抠图够用了。

期间踩了两个坑:

飞书安装在 %LOCALAPPDATA%\Feishu\app\ 下,也有不少 AI 模型:

有意思的是飞书用的是 Apache TVM 作为底层推理引擎(VolcEngineRTC.dll 里导出了 tvm::runtime::GraphRuntimetvm::runtime::ModuleNode 等全套 TVM 的 C++ 类),外面包了一层 ByteDance 自研的 ByteNN 容器格式(BM 魔数)。体积极致压缩 — 抠图模型 831KB vs 我们的 seg 模型 22MB,差了 27 倍。

不过这 .model 格式不是 ONNX,解析起来需要逆向 BM 容器结构,先记一笔,以后再挖。

前面我们拆解的方案建立在 XOR 混淆的基础上,密钥直接硬编码在 DLL 里。万一碰到 AES-256-GCM 等强加密的模型——密钥通过白盒加密保护或者服务端动态下发——直接逆向提取密钥的工作量就会大很多。

这时候换个思路:不跟密钥死磕,等程序自己解密完了,在它喂给推理引擎之前截胡

核心逻辑是这样的:

ONNX Runtime 加载模型有两个关键 API:

程序如果先解密到内存再调 OrtCreateSessionFromArray,那这个函数的参数里就已经是明文模型了。Hook 它,直接把 model_data 指针指向的内存 dump 出来,就是一个完整可用的 .onnx 文件。

Windows 上的实操方案 — MinHook

MinHook 是个轻量级 inline hook 库,几行代码就能劫持任意 DLL 导出函数。思路:

把这个逻辑编译成 DLL,注入到目标进程(照片应用或任何加载 onnxruntime 的程序),触发一次 AI 功能,dump.onnx 就到手了。

更极端的情况 — 程序用自定义推理引擎


[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回