
Этот инструмент извлекает и отображает данные из функции Recall в Windows 11, предоставляя простой способ доступа к информации о снимках активности вашего ПК.
Breaking Windows Recall. Again.
image
Когда Microsoft переработала Recall с VBS-анклавами, шифрованием AES-256-GCM, аутентификацией Windows Hello и хост-процессом Protected Process Light, сообщение было ясным: данные заперты в хранилище.
Хранилище надёжно. А грузовик доставки — нет.
AIXHost.exe — процесс, отображающий временную шкалу Recall, — не имеет PPL, AppContainer и проверки целостности кода. Любой процесс, работающий от имени текущего пользователя, может внедрить в него код и вызвать те же COM API, которые использует легитимный интерфейс. Как только пользователь проходит аутентификацию с помощью Windows Hello, расшифрованные скриншоты, OCR-текст и метаданные проходят через AIXHost.exe как живые COM-объекты. TotalRecall Reloaded внедряется в этот процесс и извлекает всё.
Не требуется прав администратора. Стандартный пользователь. Без эксплуатации ядра. Без обхода криптографии. Просто COM-вызовы.
TotalRecall Reloaded состоит из двух файлов: инжектора (totalrecall.exe) и DLL-нагрузки (totalrecall_payload.dll).
Инжектор находит AIXHost.exe через CreateToolhelp32Snapshot, выделяет память в целевом процессе с помощью VirtualAllocEx, записывает путь к DLL через WriteProcessMemory и запускает удалённый поток, указывающий на LoadLibraryW. Классическое DLL-внедрение. Ничего сложного, потому что ничего сложного не требуется. AIXHost.exe не имеет никакой защиты от этого.
Это работает с привилегиями стандартного пользователя. Без повышения, без SeDebugPrivilege. Стандартный DACL Windows предоставляет процессам одного пользователя полный доступ друг к другу. Проверено: токен работает на уровне Medium Mandatory Level, при этом BUILTIN\Administrators установлен как deny-only.
VBS-анклав не расшифрует ничего без Windows Hello. Инструмент не обходит это. Он заставляет пользователя сделать это, молча следует за пользователем, когда тот это делает, или ждёт, пока пользователь это сделает.
--launch имитирует Win+J с помощью keybd_event — сочетания клавиш, открывающего временную шкалу Recall. Пользователь видит приглашение Hello (лицо, отпечаток пальца или PIN), аутентифицируется, и анклав начинает выдавать расшифрованные данные. С точки зрения пользователя, Recall просто открылся как обычно. С нашей — нагрузка уже внутри и ждёт.
--stealth — полностью бесшумный режим. Работает так:
AIXHost.exe (всегда запущен) и патчит DiscardDataAccess в no-opAIXHost.exe завершается и перезапускается. Инструмент обнаруживает перезапуск и повторно внедряется в новый процессaihost.exe (отзыв был заблокирован). Извлечение начинается немедленно--wait — пассивный аналог --launch. Вместо имитации Win+J инструмент бездействует, пока пользователь сам открывает Recall — с панели задач, ярлыка или любым другим способом. Когда появляется AIXHost.exe и пользователь естественным образом проходит Hello, нагрузка внедряется, и начинается извлечение. Полезно на машине, за которой наблюдают, или когда сеанс Recall должен выглядеть полностью инициированным пользователем без синтетического ввода с клавиатуры.
Как только нагрузка оказывается внутри AIXHost.exe, она инициализирует COM-апартамент с помощью CoInitializeEx(COINIT_APARTMENTTHREADED) и настраивает перенаправление идентификатора прокси с помощью CoSetProxyBlanket(EOAC_DYNAMIC_CLOAKING). Это критически важно. Без динамического маскирования COM-прокси не передаёт аутентифицированную идентификацию на сервер.
Извлечение следует тому же пути, который использует легитимный интерфейс Recall:
Инициализация анклава: DataManager.Load() запускает загрузку ключа анклава. DataStoreManager.DecryptDatabase() (слот 37) подготавливает расшифрованные представления. Нагрузка опрашивает DataManager.DataStatus, пока он не вернёт 3 (разблокировано).
Перечисление сущностей: MemoryEntityStatics.GetLightMemoryItemsBefore() (слот 9) возвращает вектор лёгких ссылок на сущности. Каждая содержит идентификатор контекста по смещению +8. На типичной машине это возвращает сотни сущностей, охватывающих дни или недели активности.
Извлечение каждой сущности: Для каждого идентификатора контекста нагрузка загружает полную сущность через ContextEngine2.TryGetEntityForId() (слот 6), распаковывает её через IEntityWrapper (слот 6) и использует QueryInterface для IMemoryEntity. Оттуда:
TryGetBitmapCaptureAsync() (слот 19) возвращает SoftwareBitmap. QueryInterface к ISoftwareBitmapNative, вызов GetData(IID_IWICBitmap) для получения WIC-битмапа, кодирование в PNG через IWICBitmapEncoderContextEngine2.TryGetMemoryEntityDetailsForIdAsync() (слот 8) возвращает детали сущности. QI к IMemoryEntityDetails для OcrLines (слот 7), IMemoryEntityDetails2 для NER-текстовых сущностей (люди, email, адреса) и IMemoryEntityDetails4 для AI-описаний активностиЦиклы повторных попыток: Baker.dll (библиотека интерфейса Recall) асинхронно заполняет кеш ContextEngine. После начального прохода нагрузка запускает цикл обработки сообщений Windows на 3 секунды (PeekMessage/DispatchMessage) и повторяет попытки для тех сущностей, которые не были доступны. Каждый цикл обычно даёт ~12 дополнительных сущностей. До 10 циклов повторных попыток.
Каждый вызов обёрнут в __try/__except, потому что одно нарушение доступа при вызове COM-прокси навсегда убивает RPC-канал к aihost.exe. Восстановление невозможно. Пришлось бы перезапускать AIXHost.exe. Обработчики SEH ловят сбои от неправильных типов параметров и поддерживают сеанс активным.
Некоторые операции работают без какой-либо аутентификации Hello:
Извлечение скриншотов: RecallPrivacyIndicatorSettings (CLSID {42C63551-...}) предоставляет GetRecentCaptureThumbnail(width, height) в слоте 13. В названии метода сказано «эскиз», но сервер не ограничивает разрешение. Передача 3840x3840 возвращает последний снимок Recall в полном разрешении. Результат IRandomAccessStream преобразуется в IStream через CreateStreamOverRandomAccessStream (shcore.dll) и сохраняется как BMP.
Уничтожение данных: IDataStoreManager::DeleteEvents() (слот 12) стирает всю историю захватов. Без параметров, без аутентификации. Анализ в Ghidra подтвердил: обработчик удаления по адресу FUN_1802ddd10 не содержит вызовов функции проверки авторизации. Проверка авторизации никогда не была подключена.
Раскрытие метаданных: Пути хранения (включая UKP GUID, специфичный для пользователя), размер базы данных, политика хранения, состояние захвата и идентификатор контекста последнего захвата — всё это читаемо без аутентификации через IDataStoreManagerStatics и RecallPrivacyIndicatorSettings.