Поделиться через


Моникер повышения уровня COM

Моникер повышения прав COM позволяет приложениям, работающим под контролем учетных записей пользователей (UAC), активировать классы COM с повышенными привилегиями. Дополнительные сведения см. в разделе "Фокус на наименьшие привилегии".

Когда следует использовать Моникер повышения высоты

Моникер повышения прав используется для активации класса COM для выполнения определенной и ограниченной функции, требующей повышенных привилегий, таких как изменение даты и времени системы.

Для повышения прав требуется участие как класса COM, так и его клиента. Класс COM должен быть настроен для поддержки повышения прав, заметив его запись реестра, как описано в разделе "Требования". Клиент COM должен запрашивать повышение прав с помощью моникера повышения.

Моникер повышения прав не предназначен для обеспечения совместимости приложений. Например, если вы хотите запустить устаревшее COM-приложение, например WinWord как сервер с повышенными привилегиями, необходимо настроить исполняемый файл COM-клиента, чтобы требовать повышение прав, а не активировать класс устаревшего приложения с моникером повышения прав. Когда клиент CoCreateInstance с повышенными привилегиями вызывает CLSID устаревшего приложения, состояние клиента будет передаваться в процесс сервера.

Не все функции COM совместимы с повышением прав. Функциональные возможности, которые не будут работать, включают:

  • Повышение прав не происходит от клиента к удаленному COM-серверу. Если клиент активирует удаленный COM-сервер с моникером повышения прав, сервер не будет повышен, даже если он поддерживает повышение прав.
  • Если класс COM с повышенными привилегиями использует олицетворение во время вызова COM, он может потерять свои повышенные привилегии во время олицетворения.
  • Если сервер COM с повышенными привилегиями регистрирует класс в работающей таблице объектов (ROT), этот класс не будет доступен для клиентов с повышенными привилегиями.
  • Процесс, повышенный с помощью механизма UAC, не загружает классы на пользователя во время активации COM. Для com-приложений это означает, что классы COM приложения должны быть установлены в кусте реестра HKEY_LOCAL_MACHINE , если приложение должно использоваться как не привилегированными, так и привилегированными учетными записями. Классы COM приложения должны быть установлены только в HKEY_USERS hive, если приложение никогда не используется привилегированными учетными записями.
  • Перетаскивание не допускается для приложений с повышенными привилегиями.

Требования

Чтобы использовать моникер повышения прав для активации COM-класса, класс должен быть настроен для запуска от имени запуска пользователя или удостоверения приложения "Активировать от имени активатора". Если класс настроен для запуска под любым другим удостоверением, активация возвращает ошибку CO_E_RUNAS_VALUE_MUST_BE_AAA.

Класс также должен быть аннотирован с понятным отображаемым именем, совместимым с многоязычным пользовательским интерфейсом (MUI). Для этого требуется следующая запись реестра:

HKEY_LOCAL_MACHINE\Software\Classes\CLSID
   {CLSID}
      LocalizedString = displayName

Если эта запись отсутствует, активация возвращает ошибку CO_E_MISSING_DISPLAYNAME. Если файл MUI отсутствует, возвращается код ошибки из функции RegLoadMUIStringW.

При необходимости, чтобы указать значок приложения, отображаемый пользовательским интерфейсом UAC, добавьте следующий раздел реестра:

HKEY_LOCAL_MACHINE\Software\Classes\CLSID
   {CLSID}
      Elevation
         IconReference = applicationIcon

IconReference использует тот же формат, что и LocalizedString:

@pathtobinary,-resourcenumber

Кроме того, компонент COM должен быть подписан для отображения значка.

Класс COM также должен быть аннотирован как LUA-Enabled. Для этого требуется следующая запись реестра:

HKEY_LOCAL_MACHINE\Software\Classes\CLSID
   {CLSID}
      Elevation
         Enabled = 1

Если эта запись отсутствует, активация возвращает ошибку CO_E_ELEVATION_DISABLED.

Обратите внимание, что эти записи должны существовать в HKEY_LOCAL_MACHINE кусте, а не в HKEY_CURRENT_USER или HKEY_USERS кусте. Это позволяет пользователям повысить уровень com-классов, которые они также не имели привилегий для регистрации.

Моникер повышения прав и пользовательский интерфейс повышения прав

Если клиент уже повышен, использование моникера повышения не приведет к отображению пользовательского интерфейса повышения прав.

Как использовать моникер повышения высоты

Моникер повышения уровня — это стандартный моникер COM, аналогичный сеансу, секции или моникерам очередей. Он направляет запрос активации на указанный сервер с указанным уровнем повышения прав. Идентификатор CLSID, который будет активирован, отображается в строке моникера.

Моникер повышения прав поддерживает следующие токены уровня выполнения:

  1. Администратор
  2. Наиболее высокий

Для этого используйте следующий синтаксис.

Elevation:Administrator!new:{guid}
Elevation:Highest!new:{guid}

Предыдущий синтаксис использует моникер new для возврата экземпляра класса COM, указанного guid. Обратите внимание, что моникер "new" внутренне использует интерфейс IClassFactory для получения объекта класса, а затем вызывает IClassFactory::CreateInstance в нем.

Моникер повышения прав также можно использовать для получения объекта класса, реализующего IClassFactory. Затем вызывающий объект вызывает CreateInstance , чтобы получить экземпляр объекта. Для этого используйте следующий синтаксис.

Elevation:Administrator!clsid:{guid}

Пример кода

В следующем примере кода показано, как использовать моникер повышения прав. Предполагается, что вы уже инициализировали COM в текущем потоке.

HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
    BIND_OPTS3 bo;
    WCHAR  wszCLSID[50];
    WCHAR  wszMonikerName[300];

    StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0])); 
    HRESULT hr = StringCchPrintf(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
    if (FAILED(hr))
        return hr;
    memset(&bo, 0, sizeof(bo));
    bo.cbStruct = sizeof(bo);
    bo.hwnd = hwnd;
    bo.dwClassContext  = CLSCTX_LOCAL_SERVER;
    return CoGetObject(wszMonikerName, &bo, riid, ppv);
}

BIND_OPTS3 является новым в Windows Vista. Он является производным от BIND_OPTS2.

Единственное дополнение — это поле HWND, навешаное. Этот дескриптор представляет окно, которое становится владельцем пользовательского интерфейса повышения прав, если применимо.

Если hwnd имеет значение NULL, COM вызовет GetActiveWindow , чтобы найти дескриптор окна, связанный с текущим потоком. Это может произойти, если клиент является скриптом, который не может заполнить структуру BIND_OPTS3 . В этом случае COM попытается использовать окно, связанное с потоком скрипта.

Повышение высоты над плечом (OTS)

Повышение прав на плечо (OTS) относится к сценарию, в котором клиент запускает COM-сервер с учетными данными администратора, а не его или ее собственными. (Термин "через плечо" означает, что администратор следит за плечом клиента, как клиент запускает сервер.)

Этот сценарий может вызвать проблему для вызовов COM на сервере, так как сервер не может вызывать CoInitializeSecurity явным образом (то есть программным способом) или неявно (то есть декларативно с помощью реестра). Для таких серверов COM вычисляет дескриптор безопасности, который позволяет выполнять вызовы COM только SELF, SYSTEM и Buildin\Администратор istrator. Это соглашение не будет работать в сценариях OTS. Вместо этого сервер должен вызывать CoInitializeSecurity ( явно или неявно) и указать ACL, включающий идентификатор безопасности интерактивной группы и СИСТЕМУ.

В следующем примере кода показано, как создать дескриптор безопасности (SD) с идентификатором БЕЗОПАСНОСТИ интерактивной группы.

BOOL GetAccessPermissionsForLUAServer(SECURITY_DESCRIPTOR **ppSD)
{
// Local call permissions to IU, SY
    LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)";
    SECURITY_DESCRIPTOR *pSD;
    *ppSD = NULL;

    if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL))
    {
        *ppSD = pSD;
        return TRUE;
    }

    return FALSE;
}

В следующем примере кода показано, как вызывать CoInitializeSecurity неявно с SD из предыдущего примера кода:

// hKey is the HKCR\AppID\{GUID} key
BOOL SetAccessPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD)
{
    BOOL bResult = FALSE;
    DWORD dwLen = GetSecurityDescriptorLength(pSD);
    LONG lResult;
    lResult = RegSetValueExA(hkey, 
        "AccessPermission",
        0,
        REG_BINARY,
        (BYTE*)pSD,
        dwLen);
    if (lResult != ERROR_SUCCESS) goto done;
    bResult = TRUE;
done:
    return bResult;
}

В следующем примере кода показано, как явно вызывать CoInitializeSecurity с помощью приведенного выше SD:

// Absolute SD values
PSECURITY_DESCRIPTOR pAbsSD = NULL;
DWORD AbsSdSize = 0;
PACL  pAbsAcl = NULL;
DWORD AbsAclSize = 0;
PACL  pAbsSacl = NULL;
DWORD AbsSaclSize = 0;
PSID  pAbsOwner = NULL;
DWORD AbsOwnerSize = 0;
PSID  pAbsGroup = NULL;
DWORD AbsGroupSize = 0;

MakeAbsoluteSD (
    pSD,
    pAbsSD,
    &AbsSdSize,
    pAbsAcl,
    &AbsAclSize,
    pAbsSacl,
    &AbsSaclSize,
    pAbsOwner,
    &AbsOwnerSize,
    pAbsGroup,
    &AbsGroupSize
);

if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
    pAbsSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, AbsSdSize);
    pAbsAcl = (PACL)LocalAlloc(LMEM_FIXED, AbsAclSize);
    pAbsSacl = (PACL)LocalAlloc(LMEM_FIXED, AbsSaclSize);
    pAbsOwner = (PSID)LocalAlloc(LMEM_FIXED, AbsOwnerSize);
    pAbsGroup = (PSID)LocalAlloc(LMEM_FIXED, AbsGroupSize);

    if ( ! (pAbsSD && pAbsAcl && pAbsSacl && pAbsOwner && pAbsGroup))
    {
        hr = E_OUTOFMEMORY;
        goto Cleanup;
    }
    if ( ! MakeAbsoluteSD(
        pSD,
        pAbsSD,
        &AbsSdSize,
        pAbsAcl,
        &AbsAclSize,
        pAbsSacl,
        &AbsSaclSize,
        pAbsOwner,
        &AbsOwnerSize,
        pAbsGroup,
        &AbsGroupSize
        ))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Cleanup;
    }
}
else
{
    hr = HRESULT_FROM_WIN32(GetLastError());
    goto Cleanup;
}

// Call CoInitializeSecurity .

Разрешения COM и обязательные метки доступа

Windows Vista представляет понятие обязательных меток доступа в дескрипторах безопасности. Метка определяет, могут ли клиенты получить доступ к com-объекту. Метка указана в системном списке управления доступом (SACL) дескриптора безопасности. В Windows Vista COM поддерживает метку SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP. SACLs в разрешениях COM игнорируются в операционных системах до Windows Vista.

По состоянию на Windows Vista dcomcnfg.exe не поддерживает изменение уровня целостности (IL) в разрешениях COM. Он должен быть установлен программным способом.

В следующем примере кода показано, как создать дескриптор безопасности COM с меткой, которая позволяет запрашивать запуск и активацию от всех клиентов LOW IL. Обратите внимание, что метки допустимы для разрешений запуска и активации и вызова. Таким образом, можно написать COM-сервер, который запрещает запуск, активацию или вызовы от клиентов с определенным IL. Дополнительные сведения о уровнях целостности см. в разделе "Общие сведения о механизме целостности Windows Vista" статьи "Понимание и работа в защищенном режиме в Интернете Обозреватель".

BOOL GetLaunchActPermissionsWithIL (SECURITY_DESCRIPTOR **ppSD)
{
// Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP
    LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)";
    if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL))
    {
        *ppSD = pSD;
        return TRUE;
    }
}

BOOL SetLaunchActPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD)
{
    
    BOOL bResult = FALSE;
    DWORD dwLen = GetSecurityDescriptorLength(pSD);
    LONG lResult;
    lResult = RegSetValueExA(hkey, 
        "LaunchPermission",
        0,
        REG_BINARY,
        (BYTE*)pSD,
        dwLen);
    if (lResult != ERROR_SUCCESS) goto done;
    bResult = TRUE;
done:
    return bResult;
};

Уровни целостности и coCreateInstance

Поведение CoCreateInstance изменилось в Windows Vista, чтобы предотвратить привязку клиентов Low IL к COM-серверам по умолчанию. Сервер должен явно разрешить такие привязки, указав SACL. Изменения в CoCreateInstance приведены следующим образом:

  1. При запуске процесса COM-сервера для маркера процесса сервера в качестве маркера обработки сервера устанавливается клиентский или серверный маркер IL, в зависимости от того, что ниже.
  2. По умолчанию COM предотвращает привязку клиентов Low IL к запущенным экземплярам любых COM-серверов. Чтобы разрешить привязку, дескриптор безопасности запуска и активации COM-сервера должен содержать saCL, указывающий метку Low IL (см. предыдущий раздел примера кода для создания такого дескриптора безопасности).

Повышенные привилегии серверов и регистрация ROT

Если COM-сервер хочет зарегистрировать в запущенной таблице объектов (ROT) и разрешить любому клиенту доступ к регистрации, он должен использовать флаг ROTFLAGS_ALLOWANYCLIENT. COM-сервер "Активировать от имени активации" не может указать ROTFLAGS_ALLOWANYCLIENT, так как диспетчер управления службами DCOM (DCOMSCM) применяет спуф проверка к этому флагу. Таким образом, в Windows Vista COM добавляет поддержку новой записи реестра, которая позволяет серверу указать, что регистрация ROT доступна любому клиенту:

HKEY_LOCAL_MACHINE\Software\Classes\AppID
   {APPID}
      ROTFlags

Единственное допустимое значение для этой записи REG_DWORD:

ROTREGFLAGS_ALLOWANYCLIENT 0x1

Запись должна существовать в HKEY_LOCAL_MACHINE кусте.

Эта запись предоставляет сервер "Активировать от имени активации" с той же функциональностью, что и ROTFLAGS_ALLOWANYCLIENT предоставляет для сервера RunAs.

Безопасность в COM

Понимание принципов защищенного режима Internet Explorer и работа в нем