Перезапуск службы после открытия провайдера разрывает соединение и заставляет перезапускать все приложение.
Шаг за шагом:
Откройте провайдера NCryptOpenStorageProvider(myProvider, MS_KEY_STORAGE_PROVIDER, 0)
— будет «00000000» (ERROR_SUCCESS)
Перезапустите службу CNG Key Isolation
.
Снова откройте провайдера NCryptOpenStorageProvider(myProvider, MS_KEY_STORAGE_PROVIDER, 0)
— будет «80070006» (ERROR_INVALID_HANDLE)
Как правильно открыть провайдер после перезапуска службы без перезапуска приложения?
Я это понимаю. Чего я не понимаю, так это как остальной софт выдерживает перезапуск этого сервиса и не требует последующего перезапуска? Как мне научить свое приложение тоже не умирать, а автоматически переподключаться к провайдеру после перезапуска сервиса?
действительно, когда NCryptOpenStorageProvider
с MS_KEY_STORAGE_PROVIDER
вызывается в первый раз, MsProvCryptOpenProvider_KeyIso
вызывается из ncryptprov.dll
и внутри этой функции KeyIsoServerBind
вызывается. при следующих вызовах MsProvCryptOpenProvider_KeyIso
также вызывался, но KeyIsoServerBind
вызывался только один раз в первый раз, и это дескриптор кеша. для uncache нужен KeyIsoServerUnbind
, но, судя по моему быстрому взгляду, он звонил только из MSProvModuleUninit
< UninitializeCNGProv
, который вызывал ncryptprov.dll
выгружался. и похоже, что нет возможности выгрузить эту dll после ее загрузки в качестве провайдера.
и не только ваше приложение, если оно затронуто. системные службы тоже. после перезапуска службы keyiso я больше не могу разблокировать / войти в Windows с помощью PIN-кода. у меня возникла ошибка, что-то пошло не так, ваш пин-код недоступен (код 0x80070006..)
когда ты впервые звонишь
NCryptOpenStorageProvider(&hProvider, MS_KEY_STORAGE_PROVIDER, 0);
ncryptprov.dll загружается, и когда его функция MsProvCryptOpenProvider_KeyIso
вызывается (это NCryptOpenStorageProviderFn
из NCRYPT_KEY_STORAGE_FUNCTION_TABLE) в первый раз (MsProvCryptOpenProvider_KeyIso
вызывается каждый раз, когда вы открываете MS_KEY_STORAGE_PROVIDER
), он вызывает KeyIsoServerBind
и кэширует некоторый дескриптор службы KeyIso. который, конечно, стал недействительным после перезапуска службы. насколько я понимаю, KeyIsoServerUnbind
(внутренняя функция в ncryptprov.dll) вызывается только тогда, когда ncryptprov.dll выгружается. и сам ncrypt никогда не выгружает уже загруженных провайдеров, даже после того, как все дескрипторы к нему были закрыты (через NCryptFreeObject
). так что на самом деле это невозможно исправить без перезапуска процесса.
однако я отмечаю, что некоторые встроенные компоненты Windows также повлияли. когда я блокирую рабочую станцию, а затем пытаюсь разблокировать ее снова с помощью поставщика PIN-кода, я получаю следующую ошибку
Спасибо большое 👍 Даже не верится... Я (вы, мы, они) можем написать простую утилиту, которая будет просто перезапускать этот сервис раз в минуту — и заставлять пользователей по всему миру постоянно перезагружать свои системы? Приятно 🥲
@kazuser можно написать и утилиту, которая будет крашить систему. и что? смысл ? в случае входа в систему с помощью PIN-кода LogonUI — ngccredprovider вызывает службу NgcSvc (отображаемое имя «Microsoft Passport»). и эта служба выполняет еще один удаленный вызов к NgcCtnrSvc («Контейнер паспорта Microsoft»), и здесь уже ncryptprov.dll выполняет третий удаленный вызов службы KeyIso («Изоляция ключей CNG»), который не выполняет кэшированный дескриптор. однако после перезапуска вход в систему по PIN-коду NgcCtnrSvc снова работает нормально
Ошибка ERROR_INVALID_HANDLE связана с недопустимым дескриптором привязки RPC между NCrypt (BCrypt) и службой. Я не думаю, что существует задокументированный способ сброса этого дескриптора привязки RPC, он статически кэшируется dll в памяти вашего процесса, это также может быть сделано специально, чтобы избежать некоторых проблем с безопасностью.