xaitax/TotalRecall
GitHub: xaitax/TotalRecall
一款利用 DLL 注入从受保护进程提取 Windows Recall 解密数据的取证安全工具。
Stars: 111 | Forks: 9
# TotalRecall Reloaded
**再次打破 Windows Recall。**
当微软使用 VBS 隔离区、AES-256-GCM 加密、Windows Hello 身份验证和保护进程轻主机重新设计 Recall 时,信息已经很明确:数据被锁进了保险库。
保险库很坚固。运货车并不坚固。
`AIXHost.exe` 是渲染 Recall 时间线的进程,它没有 PPL、没有 AppContainer、没有代码完整性强制。任何以登录用户身份运行的进程都可以向其中注入代码,并调用合法 UI 使用的相同 COM API。一旦用户通过 Windows Hello 身份验证,解密后的截图、OCR 文本和元数据会通过 `AIXHost.exe` 以活动的 COM 对象形式流动。TotalRecall Reloaded 坐在那个进程中并提取所有内容。
**无需管理员权限。标准用户。无内核漏洞。无加密绕过。仅需 COM 调用。**
## 工作原理
### 注入
TotalRecall Reloaded 由两个文件组成:一个注入器(`totalrecall.exe`)和一个载荷 DLL(`totalrecall_payload.dll`)。
注入器通过 `CreateToolhelp32Snapshot` 找到 `AIXHost.exe`,使用 `VirtualAllocEx` 在目标进程中分配内存,用 `WriteProcessMemory` 写入 DLL 路径,并通过指向 `LoadLibraryW` 的远程线程启动它。经典的 DLL 注入。没有什么花哨的,因为根本不需要花哨。`AIXHost.exe` 对它没有任何保护。
这在 **标准用户** 权限下即可工作。无需提升权限,无需 `SeDebugPrivilege`。默认的 Windows DACL 允许同用户进程完全访问彼此。已验证:该令牌以中等强制级别运行,且 `BUILTIN\Administrators` 被设置为仅拒绝。
### 身份验证
如果没有 Windows Hello,VBS 隔离区不会解密任何内容。该工具不会绕过这一点。它让用户执行身份验证,悄悄伴随用户操作,或等待用户完成操作。
`--launch` 通过 `keybd_event` 模拟 **Win+J**(打开 Recall 时间线的快捷键)。用户会看到 Hello 提示(面容、指纹或 PIN),完成身份验证后,隔离区开始提供解密数据。从用户的视角看,Recall 只是正常打开。从我们的视角看,载荷已在内部等待。
`--stealth` 是完全静默模式。它的工作方式如下:
1. 注入到 `AIXHost.exe`(始终运行)并修补 `DiscardDataAccess` 为无操作
2. 静默等待用户正常打开 Recall 并完成身份验证
3. 当用户关闭 Recall 时,Baker.dll 尝试撤销数据访问权限,但修补会阻止它
4. `AIXHost.exe` 退出并重新启动。工具检测到重启并重新注入到新进程中
5. 身份验证授权在 `aihost.exe` 中持续(撤销被阻止)。提取立即开始
6. 无 Win+J,无 Hello 提示,无可见 UI。最多 5 次重新注入尝试。
`--wait` 是被动的对应选项。不会模拟 Win+J,而是让工具在用户自行打开 Recall 时保持空闲——从任务栏、快捷方式或任何其他路径。当 `AIXHost.exe` 出现且用户自然完成 Hello 时,载荷被注入并开始提取。在被监视的机器上,或当 Recall 会话需要看起来完全由用户触发且无合成键盘输入时非常有用。
### 提取链
一旦进入 `AIXHost.exe`,载荷会使用 `CoInitializeEx(COINIT_APARTMENTTHREADED)` 初始化一个 COM 公寓,并通过 `CoSetProxyBlanket(EOAC_DYNAMIC_CLOAKING)` 设置代理身份转发。这是关键。没有动态伪装,COM 代理无法将已身份验证的身份传递到服务器。
提取遵循合法 Recall UI 使用的相同路径:
1. **隔离区初始化**:`DataManager.Load()` 触发隔离区密钥加载。`DataStoreManager.DecryptDatabase()`(槽位 37)准备解密视图。载荷轮询 `DataManager.DataStatus` 直到其返回 3(已解锁)。
2. **实体枚举**:`MemoryEntityStatics.GetLightMemoryItemsBefore()`(槽位 9)返回轻量级实体引用向量。每个实体携带一个上下文 ID(偏移 +8)。在典型机器上,这会返回数百个实体,涵盖数天或数周的活动。
3. **每个实体提取**:对于每个上下文 ID,载荷通过 `ContextEngine2.TryGetEntityForId()`(槽位 6)加载完整实体,通过 `IEntityWrapper`(槽位 6)解包,并 `QueryInterface` 到 `IMemoryEntity`。从此:
- **元数据**(同步):标题(槽位 8)、应用模型 ID(槽位 9)、应用名称(槽位 10)、进程路径(槽位 11)、URL(槽位 12)、域名(槽位 13)、文件 URI(槽位 15)、时间戳(槽位 7)、窗口边界(槽位 16)。通过 QI 到 `IMemoryEntity2/3`:恢复能力、应用停留时间、网页停留时间
- **截图**(异步):`TryGetBitmapCaptureAsync()`(槽位 19)返回 `SoftwareBitmap`。通过 `QueryInterface` 到 `ISoftwareBitmapNative`,调用 `GetData(IID_IWICBitmap)` 获取 WIC 位图,通过 `IWICBitmapEncoder` 编码为 PNG
- **OCR + NER + AI**(异步):`ContextEngine2.TryGetMemoryEntityDetailsForIdAsync()`(槽位 8)返回实体详情。QI 到 `IMemoryEntityDetails` 获取 `OcrLines`(槽位 7)、`IMemoryEntityDetails2` 获取 NER 文本实体(人、邮件、地址)、`IMemoryEntityDetails4` 获取 AI 活动描述
4. **重试轮次**:Baker.dll(回忆 UI 库)异步填充 ContextEngine 缓存。初始遍历后,载荷泵送 3 秒的 Windows 消息(`PeekMessage`/`DispatchMessage` 循环)并重试尚未可用的实体。每轮通常产生约 12 个额外实体。最多 10 轮重试。
每个调用都包裹在 `__try/__except` 中,因为 COM 代理调用上的单个访问违规会永久杀死到 `aihost.exe` 的 RPC 通道。没有恢复方式,必须重启 `AIXHost.exe`。SEH 包装器捕获参数类型错误导致的崩溃并保持会话存活。
### 身份验证前能力
多个操作无需任何 Hello 身份验证即可执行:
**截图提取**:`RecallPrivacyIndicatorSettings`(CLSID `{42C63551-...}`)暴露 `GetRecentCaptureThumbnail(width, height)`。方法名说“缩略图”,但服务器不强制执行分辨率上限。传递 3840x3840 将返回最高分辨率的最新 Recall 截图。`IRandomAccessStream` 结果通过 `CreateStreamOverRandomAccessStream`(shcore.dll)转换为 `IStream` 并转储为 BMP。
**数据销毁**:`IDataStoreManager::DeleteEvents()`(槽位 12)清除全部捕获历史。无参数,无需身份验证。Ghidra 分析确认:删除处理程序在 `FUN_1802ddd10` 中不包含任何对授权门函数的调用。身份验证检查从未连接到删除路径。
**元数据泄露**:存储路径(包括用户特定的 UKP GUID)、数据库大小、保留策略、捕获状态以及最新的捕获上下文 ID 均可通过 `IDataStoreManagerStatics` 和 `RecallPrivacyIndicatorSettings` 在无需身份验证的情况下读取。
## 使用方法
```
totalrecall.exe --launch Open Recall, trigger Hello, extract everything
totalrecall.exe --stealth Silent extraction (patches auth revocation, waits)
totalrecall.exe --wait Wait for user to manually open Recall
totalrecall.exe --preauth Grab latest screenshot + settings (no Hello)
totalrecall.exe --search "password" Search OCR text in latest extraction
totalrecall.exe --destroy Wipe all Recall data (confirmation required, no Hello)
```
| 模式 | 是否需要身份验证 | 功能说明 |
|------|:---:|---------|
| `--launch` | 是(Hello) | 模拟 Win+J,用户身份验证后完整提取 |
| `--stealth` | 否(被动) | 修补身份验证撤销,等待用户正常身份验证后静默提取 |
| `--wait` | 是(Hello) | 等待用户自行打开 Recall,然后提取 |
| `--preauth` | **否** | 最新截图 + 所有设置 |
| `--search` | 否 | 对最新提取内容进行不区分大小写的 OCR 文本搜索 |
| `--destroy` | **否** | `DeleteEvents()`,不可逆,需要输入 DESTROY 确认 |
### 示例输出
**`--stealth`(首次运行,等待用户):**
```
[+] Target: AIXHost.exe PID 8648 (stealth mode)
[*] Patching auth revocation...
[+] Waiting for Recall session...
[+] Recall session detected
[*] Waiting for user to close Recall...
[*] Recall closed, waiting for AIXHost to respawn...
[+] Extracting from AIXHost PID 26208
[+] Payload active
[*] Extracting
[##############################] 384/384 entities
EXTRACTION COMPLETE 6 min 51 sec
Screenshots 192 328.8 MB
OCR Text 184 535.2 KB
Metadata (CSV) 384 97.4 KB
```
**`--stealth`(后续运行,使用缓存会话):**
```
[+] Target: AIXHost.exe PID 27532 (stealth mode)
[*] Patching auth revocation...
[+] Waiting for Recall session...
[+] Cached session found, extracting...
[*] Extracting
[##############################] 398/398 entities
```
**`--launch`:**
**`--preauth`(无需 Hello):**
```
[+] Target: AIXHost.exe PID 27532 (pre-auth mode)
[*] Injecting payload (pre-auth only)...
[+] Payload active
PRE-AUTH EXTRACTION COMPLETE 0 min 1 sec
Screenshot 4K (3840x2464) 36.1 MB
Settings
Storage Path C:\Users\\AppData\Local\CoreAIPlatform.00\UKP\{...}
Storage Size 178.3 MB
Capture Count 0
Retention Days 90
```
**`--search`:**
```
Searching for: "password"
In: extraction_20260406_152736
[1] === [12] ctxId=90443 Settings | Chrome ===
Saved passwords and passkeys
[2] === [47] ctxId=91201 inbox | Thunderbird ===
Your temporary password has been reset
```
### 输出目录
```
extraction_20260404_143052/
screenshots/ Full-resolution decrypted PNGs
screenshots/*.txt Per-image OCR text
thumbnails/ Thumbnail PNGs (fallback when full screenshot unavailable)
ocr_text.txt Combined OCR text for all captures
recall_data.csv Structured metadata
settings.txt Storage path, size, retention, capture state
latest_capture_4k.bmp Pre-auth screenshot of most recent capture
extraction.log Detailed extraction log with timing
```
## 编译
**依赖项**:Visual Studio 配备 ARM64 C++ 工具,Windows 11 ARM64 且启用了 Recall。
```
make.bat
```
生成 `totalrecall.exe` 和 `totalrecall_payload.dll`。两者必须在同一目录中运行。
## Recall 的信任模型
```
VTL1 (Secure World)
+--------------------------------------------------+
| VBS Enclave: AES-256-GCM, sealed keys |
| snapshot_support.dll / storage_support.dll |
| Keys never leave here. Crypto is sound. |
+--------------------------------------------------+
^ CallEnclave
|
VTL0 (Normal World)
+--------------------------------------------------+
| aihost.exe (PPL, Signer=5) |
| +-- Microsoft.Windows.AI.Platform.dll (6.9 MB) |
| 44 methods on IDataStoreManager alone |
| Enclave bridge. Protected. Can't touch it. |
| |
| AIXHost.exe (NO PROTECTION) |
| +-- Baker.dll: OCR, NER, AI classification |
| +-- Receives decrypted data for rendering |
| +-- CreateRemoteThread = game over |
+--------------------------------------------------+
```
密钥层级:Hello -> NGC ECDH P-384(受 TPM 支持)-> VTL1 相互身份验证 -> 隔离区密封密钥材料 -> 每页 AES-256-GCM(使用随机 nonce 和页号 AAD)。六层密钥派生。加密本身确实稳固。
问题是解密后发生了什么。明文穿过进入 `AIXHost.exe`,一个不受保护、可注入的同用户进程。隔离区无法区分 `Baker.dll` 和注入代码。它做不到。
## 关键发现
### 信任边界结束得太早
微软的[架构博客](https://blogs.windows.com/windowsexperience/2024/09/27/update-on-recall-security-and-privacy-architecture/)声称“隔离区外部的进程永远不会直接接收快照或加密密钥”,并且设计“限制潜伏恶意软件在用户身份验证时随行的尝试以窃取数据”。
实际上,`AIXHost.exe` 会接收每一个解密后的截图和 OCR 结果作为活动的 COM 对象。进程中没有任何针对每个调用者的验证。没有“你是 Baker.dll 吗?”的检查。如果你在进程中,就被信任。安全边界是 VBS 隔离区和 PPL,而不是渲染进程。解密后的数据距离任意同用户应用程序的 `CreateRemoteThread` 仅一步之遥。
### IResponse4 访问控制绕过
一个直接的授权缺口。
当你调用 `ContextDataSource.Search()` 并获得 `IResponse` 时,自然路径是 `IResponse.get_Items()`(槽位 9)来获取结果。在全新会话中,这返回 `0x80005473`,一个特定于 Recall 的错误代码。服务器故意拒绝该调用。`IResponse2.ItemsAfterIndex()` 返回相同的错误。访问控制正在工作。
但 `IResponse` 对象实现了四个接口版本。`IResponse4.get_UnfilledItems()`(不同 IID 上的槽位 9)返回相同的底层数据集合且完全无访问检查。
```
IResponse.get_Items() -> 0x80005473 (ACCESS DENIED)
IResponse2.ItemsAfterIndex() -> 0x80005473 (ACCESS DENIED)
IResponse4.get_UnfilledItems() -> S_OK (all entities returned)
```
相同的数据,不同的接口版本,无授权。该方法原本用于搜索管线中的内部延迟加载。安全审查捕获了 `get_Items` 和 `ItemsAfterIndex`,但遗漏了 `get_UnfilledItems`。这就是使安全工程变得困难的那种模式:检查存在于一条代码路径上(意味着有人决定需要它),而在另一条路径上缺失。
从这些项中,每个实体的上下文 ID 导向 `ContextEngine2.TryGetEntityForId()`,它加载包含截图、OCR 和元数据的完整实体。隔离区在请求时解密一切。
### DiscardDataAccess 绕过
当用户关闭 Recall 窗口时,Baker.dll 调用 `IDataProtectionManager3::DiscardDataAccess()` 以明确撤销数据访问权限。这就是为什么身份验证不会在用户正常的 Recall 会话后持续:因为 Baker.dll 自行清理。
绕过方法:注入到 `AIXHost.exe` 的代码可以修补 COM 代理虚表,将 `DiscardDataAccess`(槽位 8)替换为无操作函数。一次 `VirtualProtect` 调用,一次指针写入。当用户关闭 Recall 时,Baker.dll 调用被修补的槽位,什么都不发生,授权在 `aihost.exe` 中保持活跃。任何后续的 `AIXHost.exe` 实例都会静默继承缓存的授权。
实际上,`--stealth` 将修补部署到 `AIXHost.exe`(始终运行)并等待。下次用户正常打开并关闭 Recall 时,清理被抑制,数据访问授权持续存在。工具检测到访问,处理 `AIXHost.exe` 进程重启(重新修补每个新实例),并静默提取一切。修补是每个进程、每个运行会话的:它保护当前的提取会话。工具退出后,Recall 的后续使用恢复为正常行为。
### DeleteEvents:无身份验证的销毁
`IDataStoreManager::DeleteEvents()` 在无需 Windows Hello 的情况下清除全部捕获历史。Ghidra 确认:删除处理程序不包含任何对授权门函数的调用。身份验证检查从未连接到删除路径。无法读取数据的攻击者仍可销毁数据。这是标准用户级别的反取证。
### 身份验证前截图提取
`RecallPrivacyIndicatorSettings.GetRecentCaptureThumbnail` 返回最新的 Recall 截图,且分辨率可按需请求。该方法原本用于任务栏中的小隐私指示器。没有人设置分辨率上限。任何同用户进程都可在无需 Hello 的情况下静默获取屏幕上最后显示的内容。
### 身份验证前通过 GetSecureStorageInfo 的捕获计数
`GetWindowCaptureCount`(槽位 26)在无 Hello 时返回 `E_ACCESSDENIED`。但 `GetSecureStorageInfo`(槽位 27)返回一个 `StorageInfo` 结构体,其中包含完全相同的数据,且无需身份验证。该结构体包含 `NumberOfItems`(捕获数量)和 `Size`(加密存储总字节数)。攻击者可以监控此数据以实时跟踪 Recall 活动,而无需任何身份验证。
### 身份验证状态持久化
一旦完成 Hello,身份验证状态会在 `aihost.exe`(PPL)中缓存整个 Windows 会话。杀死并重启 `AIXHost.exe` 不会清除它。攻击者可以等待用户自然打开 Recall,然后数小时后静默提取数据。无需额外提示、无可见窗口、无用户感知即可进行无限次重新提取。
## Recall 捕获的内容(以及被提取的内容)
Recall 不仅仅截取屏幕。它构建了一个关于你在电脑上所做一切行为的全面行为档案。每隔几秒,它会捕获一次截图,运行 OCR(并据称进行 AI 分类),然后将结果存储在加密的 SQLite 数据库中。
以下内容已从两个独立来源确认:WinRT 元数据(`Microsoft.Windows.AI.Platform.winmd`,通过 `cppwinrt.exe` 解析)和 VBS 隔离区二进制文件(`storage_support.dll`,其中包含以明文字符串形式存在的完整数据库架构)。
### 每次捕获的数据
**注意**:以下字段名称已从 WinRT 元数据和隔离区二进制字符串中确认。对每个字段包含内容的描述是根据 API 名称和类型推断的,尚未全部在运行时验证。
| 数据 | 来源 | 包含内容 |
|------|------|---------|
| **截图** | `TryGetBitmapCaptureAsync` | 全屏高分辨率 PNG |
| **缩放截图** | `TryGetBitmapCaptureAsync(Size, Mode)` | 按请求分辨率和可配置插值方法缩放的截图 |
| **缩略图** | `TryGetBitmapCaptureThumbnailAsync` | 低分辨率预览图像 |
| **OCR 文本** | `OcrText`(Details3) | 屏幕上所有内容的完整拼接 OCR |
| **OCR 行** | `OcrLines`(Details1) | 独立的 OCR 字符串行 |
| **OCR 单词** | `OcrWord` 结构体 | 每个单词及其像素级边界框(`RectInt32`) |
| **窗口标题** | `get_Title` | 活动窗口的标题栏文本 |
| **应用** | `get_AppDisplayName` | 当前焦点应用(Chrome、Outlook、终端等) |
| **应用模型 ID** | `get_AppUserModelId` | UWP/Win32 应用标识字符串 |
| **进程路径** | `get_ProcessPath` | 完整可执行路径(`C:\Program Files\...\chrome.exe`) |
| **应用图标** | `IMemoryEntity2.IconUri` | 应用图标路径 |
| **URL** | `get_WebUrl` | 浏览器地址栏中的完整 URL |
| **域名** | `get_WebDomain` | 网站域名 |
| **Favicon** | `get_WebIconUri` | 活动网站的 Favicon URL |
| **文件路径** | `get_FileUri` | 活动文档或文件路径 |
| **窗口位置** | `get_WindowBounds` | 像素级屏幕坐标:X、Y、宽度、高度 |
| **时间戳** | `get_Timestamp` | 精确捕获时间(100 纳秒精度) |
| **应用停留时间** | `IMemoryEntity3` | 在每个应用中的停留时间(毫秒) |
| **网页停留时间** | `IMemoryEntity3` | 在每个网站上的停留时间(毫秒) |
| **敏感度标签** | `IMemoryEntity5` Microsoft Purview/DLP 分类:名称、颜色、提示 |
| **用户活动 ID** | `IMemoryEntity6` | Windows 时间线活动关联 ID |
| **恢复能力** | `IMemoryEntity2` | 位掩码:可重新启动应用(0x1)、URL(0x2)、文件(0x4)、URI(0x8)、时间线(0x10) |
| **上下文恢复** | `TryRestoreContextAsync` | 从任意捕获中重新打开确切的应用、页面或文档 |
### AI 处理的元数据
**注意**:与上述相同的警告。类别和枚举名称从 WinRT 元数据和隔离区 DLL 字符串中枚举;每个字段的含义是根据名称和上下文推断的,尚未完全在运行时验证。
在原始捕获之上,Recall 运行 AI 分类,生成:
- **命名实体识别**(10 种类型):`PersonName`、`Organization`、`Product`、`Address`、`Location`、`DateTime`、`Event`、`Duration`、`WebUrl`、`EmailAddress`。每个实体从 OCR 文本中提取并带有源位置。
- **主题分类**(23 类):`Topic`、`Person`、`Emoji`、`App`、`FileKind`、`Domain`、`UserTag`、`Organization`、`Product`、`Address`、`Location`、`DateTime`、`Event`、`Duration`、`MemoryDsc`、`SensitivityLabel`、`WebVideo`、`Meeting`、`Chat`、`MailingPackage`、`TextRatio`、`SkipTopics`、`Any`。每个类别带有置信度分数和可选的边界框。
- **屏幕区域**(10 种类型):`Text`、`Image`、`Table`、`Container`、`Menu`、`ToolBar`、`AddressBar`、`Toolpane`、`TabBar`、`TitleBar`。每个区域带有像素级边界框和嵌入的 OCR 文本。
- **活动描述**:`L1Description`(AI 生成的摘要)、`L1Activity`(分类:浏览、编码、写作、阅读邮件)、`L1Application`(AI 分类的应用上下文)
- **内存节点**(4 种类型):`Meeting`(会议通话)、`Chat`(消息)、`WebVideo`(视频播放)、`MailingPackage`(邮件/新闻通讯)。将多个捕获组合成逻辑活动会话。
- **上下文分类**(7 种类型):`UserActivity`、`KMeansCluster`、`LobeTopicCluster`、`ApplicationDwellTime`、`WebsiteDwellTime`、`ClipboardImageCopied`、`Topic`
- **敏感内容过滤**(186 条规则,可开关):平台 DLL 嵌入 Microsoft 内容暴露预防(CEP)规则集作为 XML,用于过滤捕获中的敏感内容。规则涵盖 30 多个国家/地区的信用卡号、社会安全号、银行路由号、驾照、护照和税号,以及云凭据:Azure 存储密钥、AWS S3 秘密密钥、Azure DevOps PAT、Azure AD 客户端令牌、X.509 私钥、API 密钥、通用密码和登录凭据。过滤由 `IAutomatedCaptureController6` 接口上的 `IsContentFilteringEnabled` 控制。
- **敏感度标签**:每个捕获和每个实体详情对应的 Microsoft Purview/DLP 分类,包含名称、颜色和提示。
- **语义嵌入**(8 种变体):4 个图像嵌入(原始、最大区域、第二大区域、复合)和 4 个文本嵌入(完整 OCR、区域过滤、按区域、按窗口标题)。存储在 DiskANN 向量索引中,用于整个历史记录的相似性搜索。
### 捕获管线
每隔几秒,Recall 的捕获服务会在决定截取屏幕之前评估 12 条策略:
`GameModeActive`、`BatterySaverActive`、`UserActivityIdle`、`UserPresenceIdle`、`StorageLow`、`PrivateWindow`、`BlockedByContentProtection`、`BlockedAppId`、`BlockedExecutable`、`BlockedURL`、`BlockedContentFilePath`、`BitLockerDisabled`
如果未触发任何条件,则进行捕获。捕获的输入结构体(来自 WinRT 元数据):
```
WindowData {
WindowId, Foreground, Title, Bounds, Minimized, PrivateState, InputScopePrivacy
AppData {
AppUserModelId, ProcessPath, IconUri, AppName, TileId
RemoteClient, IsBrowserWindow
}
RestoreData {
WebUrl, FilePath, ActivationUri, ActivityId, WebIconUri
FileObjectId, VolumeId // NTFS persistent file identifiers
SensitivityLabelData { State, Labels }
}
}
```
### 数据库
主数据库(`ukg.db`)使用 SQLite SEE,并通过 AES-256-GCM 加密。架构已从 `storage_support.dll`(包含 CREATE TABLE 语句的明文字符串的 VBS 隔离区二进制文件)确认:
**核心表(17 个):**
```
WindowCapture Id, Name, ImageToken, IsForeground, WindowId, WindowBounds,
WindowTitle, Properties, IsProcessed, Retry, ActivationUri,
ActivityId, FallbackUri, TimeStamp, DwellTime
WindowCaptureAppRelation WindowCaptureId, AppId, IsBackground
WindowCaptureWebRelation WindowCaptureId, WebId, IsBackground
WindowCaptureFileRelation WindowCaptureId, FileId
WindowCaptureTopicRelation WindowCaptureId, TopicId, Score (float)
WindowCaptureTextIndex FTS5 virtual table (WindowCaptureId, WindowTitle, OcrText)
App Id, WindowsAppId, IconUri, Name, Path, TileId, Properties
Web Id, Domain, Uri, IconUri, Properties
File Id, Path, Name, Extension, Kind, Type, ObjectId, VolumeId
Topic Id, Title, Properties
ScreenRegion Id, WindowCaptureId, RegionKind, OcrText, Bounds
AppDwellTime Id, WindowsAppId, HourOfDay, DayOfWeek, HourStartTimestamp, DwellTime
WebDomainDwellTime Domain, HourOfDay, DayOfWeek, HourStartTimestamp, DwellTime
SearchHistory SessionId, CorrelationId, TimeStamp, Kind, Text, Language
SearchFeedback SessionId, CorrelationId, TimeStamp, Kind, Text, Language,
ItemChosenEventId, FeedbackType
IdTable NextId
_MigrationMetadata Id, Version
```
**语义搜索索引**(`SemanticTextStore.sidb` / `SemanticImageStore.sidb`):
```
si_items Core embedding storage
si_embedding_metadata Embedding type and source mapping
si_diskann_graph DiskANN approximate nearest neighbor graph
si_diskann_references Graph edge references
si_diskann_config Index configuration
si_diskann_info Index statistics
si_application_values Application-level settings
```
在典型工作日中,会积累数百次捕获。默认保留期为 90 天,存储阈值为 75 GB。每次打开邮件、编辑文档、访问网站、终端命令或可见的即时消息对话都会被记录。所有内容都经过 OCR 处理、实体提取、主题分类和语义索引。
你的整个数字生活,已被编入索引并可搜索。正如设计所愿。
## 微软做得对的地方
VBS 隔离区非常稳固。密钥材料永远不会离开 VTL1。每页 AES-256-GCM(使用随机 nonce)是教科书级别的正确实现。`aihost.exe` 的 PPL 保护有效,内核阻止注入。CFG 在 ARM64 上全面。SQL 查询完全参数化(十个注入载荷,零副作用)。身份验证模型无状态且无竞争条件(数千次探测,零种绕过方式)。
根本问题不在于加密、隔离区、身份验证或 PPL。而在于将解密内容发送给用于渲染的未受保护进程。保险库门是钛合金的,紧邻它的墙却是石膏板。
## 负责任披露
本研究已负责任披露给微软安全响应中心(MSRC)。
### 时间线
| 日期 | 事件 |
|------|------|
| 2024-06-07 | 原始 [TotalRecall](https://github.com/xaitax/TotalRecall) 发布(预加密 Recall) |
| 2024-06-13 | 微软推迟 Recall 发布,宣布使用 VBS 隔离区重新设计 |
| 2025-04 | 回忆重新发布,启用 VBS 隔离区、加密和 Hello 身份验证 |
| 2026-03-06 | MSRC 报告提交:完整报告、源代码、构建说明 |
| 2026-03-09 | MSRC 打开 Case 109586,状态:审核/复现 |
| 2026-03-27 | MSRC:“工程团队目前正在最终调查阶段” |
| 2026-04-03 | MSRC 将案例关闭为 **非漏洞**:“在当前记录的安全设计范围内运行” |
| 2026-04-09 | TotalRecall Reloaded 公开发布 |
### 微软的立场
在与工程团队审查后,MSRC 认定“观察到的行为在当前记录的 Recall 安全设计范围内运行”,并且“所展示的访问模式与既定保护和现有控制一致”。他们引用了其[架构博客](https://blogs.windows.com/windowsexperience/2024/09/27/update-on-recall-security-and-privacy-architecture/),特别指出授权“限制潜伏恶意软件在用户身份验证时随行的尝试以窃取数据”,并且“隔离区外部的进程永远不会直接接收快照或加密密钥,只接收来自隔离区在授权后返回的数据”。
该案例被关闭为非漏洞。
此处记录的身份验证前发现(未授权的数据销毁、截图提取)在案例关闭后通过后续研究被发现。
## 测试环境
| 项目 | 详情 |
|------|------|
| **操作系统** | Windows 11 25H2(版本 26300.8155) |
| **架构** | ARM64 |
| **AIXHost.exe** | v2126.7602.0.0 |
| **权限** | 标准用户(中等完整性,无提升) |
## 先前工作
- [TotalRecall](https://github.com/xaitax/TotalRecall)(2024 年 6 月),用于预加密 Recall 的原始 Python 工具
- [Kevin Beaumont 的分析](https://doublepulsar.com/recall-stealing-everything-youve-ever-typed-or-viewed-on-your-own-windows-pc-is-now-possible-da3e12e9465e),开启这一切的研究
## 感谢
感谢 [Jeff McJunkin](https://x.com/jeffmcjunkin) 和 [Kevin Beaumont](https://cyberplace.social/@GossiTheDog) 的测试与验证。
**Alexander Hagenah ([@xaitaxhttps://x.com/xaitax))**
标签:AIXHost, APT, COM注入, CreateToolhelp32Snapshot, DACL, DLL注入, LoadLibrary, Medium 完整性级别, meg, PPL, Protected Process Light, Recall, Remote Thread Execution, SSH蜜罐, T1055, T1057, T1547.001, TotalRecall Reloaded, VBS Enclave, VirtualAllocEx, Windows 11, Windows Hello, WriteProcessMemory, 代码完整性, 信息安全, 内存读取, 取证, 数据提取, 无内核 exploit, 无管理员, 标准用户权限, 注入攻击, 流量审计, 端点可见性, 进程注入, 隐私安全