共用方式為


COM 提高許可權Moniker

COM 提高許可權 Moniker 可讓在使用者帳戶控制 (UAC) 下執行的應用程式啟用具有更高許可權的 COM 類別。 如需詳細資訊,請參閱 將焦點放在最低許可權

使用提高許可權Moniker的時機

提高許可權 Moniker 可用來啟用 COM 類別,以完成需要提高許可權的特定有限函式,例如變更系統日期和時間。

提高許可權需要 COM 類別及其客戶端的參與。 COM 類別必須設定為藉由標註其登錄項目來支援提高許可權,如需求一節所述。 COM 客戶端必須使用提高許可權Moniker要求提高許可權。

提高許可權Moniker並非用來提供應用程式相容性。 例如,如果您想要以提升許可權的伺服器身分執行 WinWord 之類的舊版 COM 應用程式,您應該將 COM 用戶端可執行檔設定為需要提高許可權,而不是使用提高許可權 Moniker 來啟用舊版應用程式的類別。 當提升許可權的 COM 用戶端使用舊版應用程式的 CLSID 呼叫 CoCreateInstance 時,用戶端提升許可權的狀態將會流向伺服器進程。

並非所有 COM 功能都與提高許可權相容。 無法運作的功能包括:

  • 提高許可權不會從用戶端流向遠端 COM 伺服器。 如果客戶端啟動具有提高許可權 Moniker 的遠端 COM 伺服器,即使伺服器支援提高許可權,也不會提升伺服器。
  • 如果提升許可權的 COM 類別在 COM 呼叫期間使用模擬,它可能會在模擬期間失去其提升的許可權。
  • 如果提升許可權的 COM 伺服器在執行中的物件數據表中註冊類別 (ROT),則類別將無法供未提升許可權的用戶端使用。
  • 使用UAC機制提升許可權的程式不會在 COM 啟用期間載入每個使用者類別。 針對 COM 應用程式,這表示如果應用程式要同時由非特殊許可權帳戶和特殊許可權帳戶使用,則必須在HKEY_LOCAL_MACHINE登錄區中安裝應用程式的 COM 類別。 如果特殊許可權帳戶從未使用應用程式,則應用程式 COM 類別只需要安裝在 HKEY_USERS Hive 中。
  • 不允許從未提高許可權的拖放到提升許可權的應用程式。

需求

若要使用提高許可權 Moniker 來啟動 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。 這需要下列登錄專案:

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

如果遺漏這個專案,則啟用會傳回錯誤CO_E_ELEVATION_DISABLED。

請注意,這些項目必須存在於HKEY_LOCAL_MACHINE區中,而不是HKEY_CURRENT_USER或HKEY_USERS Hive。 這可防止使用者提高他們沒有註冊許可權的 COM 類別。

提高許可權Moniker和提高許可權UI

如果用戶端已提高許可權,則使用提高許可權 Moniker 不會讓提高許可權 UI 顯示。

如何使用提高許可權 Moniker

提高許可權Moniker是標準 COM Moniker,類似於工作階段、資料分割或佇列Moniker。 它會將啟用要求導向具有指定提高許可權層級的指定伺服器。 要啟動的 CLSID 會出現在 Moniker 字串中。

提高權限 Moniker 支援下列執行層級令牌:

  1. 系統管理員
  2. 最高

此語法如下所示:

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

上述語法會使用 「new」 Moniker 傳回 guid指定 COM 類別的實例。 請注意,“new” Moniker 會在內部使用 IClassFactory 介面來取得類別對象,然後在該物件上呼叫 IClassFactory::CreateInstance。

提高許可權Moniker也可以用來取得實作IClassFactory類別物件。 呼叫端接著會呼叫 CreateInstance 以取得物件實例。 此語法如下所示:

Elevation:Administrator!clsid:{guid}

範例指令碼

下列程式代碼範例示範如何使用提高許可權Moniker。 它假設您已在目前的線程上初始化 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。 此句柄代表視窗,如果適用,會成為提高許可權 UI 的擁有者。

如果 hwndNULL,COM 會呼叫 GetActiveWindow 來尋找與目前線程相關聯的視窗句柄。 如果客戶端是無法填入 BIND_OPTS3 結構的腳本,就可能發生此情況。 在此情況下,COM 會嘗試使用與腳本線程相關聯的視窗。

肩膀上方 (OTS) 海拔

過度肩膀 (OTS) 提升是指用戶端以系統管理員認證執行 COM 伺服器,而不是其本身的案例。 (「肩上」一詞表示系統管理員正在監看用戶端的肩膀,因為客戶端執行伺服器。

此案例可能會導致 COM 呼叫伺服器發生問題,因為伺服器可能不會 明確呼叫 CoInitializeSecurity (也就是以程式設計方式)或隱含方式(亦即,以宣告方式使用登錄)。 針對這類伺服器,COM 會計算只允許 SELF、SYSTEM 和 Builtin\管理員 istrators 對伺服器進行 COM 呼叫的安全性描述元。 這項安排不適用於 OTS 案例。 相反地,伺服器必須明確或隱含地呼叫 CoInitializeSecurity,並指定包含 INTERACTIVE 群組 SID 和 SYSTEM 的 ACL。

下列程式代碼範例示範如何使用 INTERACTIVE 群組 SID 建立安全性描述元 (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;
}

下列程式代碼範例示範如何使用先前程式代碼範例中的 SD 隱含呼叫 CoInitializeSecurity

// 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;
}

下列程式代碼範例示範如何使用上述 SD 明確呼叫 CoInitializeSecurity

// 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標籤。 在 Windows Vista 之前,COM 許可權中的 SCL 會在作業系統上忽略。

從 Windows Vista 起,dcomcnfg.exe不支援在 COM 許可權中變更完整性層級 (IL)。 它必須以程式設計方式設定。

下列程式代碼範例示範如何使用允許從所有LOW IL用戶端啟動/啟用要求的標籤來建立 COM 安全性描述元。 請注意,標籤適用於啟動/啟用和通話許可權。 因此,可以撰寫不允許使用特定 IL 之用戶端啟動、啟用或呼叫的 COM 伺服器。 如需完整性層級的詳細資訊,請參閱瞭解及使用受保護模式 Internet Explorer 中的<瞭解 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 中已變更,以防止低 IL 用戶端預設系結至 COM 伺服器。 伺服器必須藉由指定 SACL 明確允許這類系結。 CoCreateInstance變更如下所示:

  1. 啟動 COM 伺服器進程時,伺服器進程令牌中的 IL 會設定為用戶端或伺服器令牌 IL,以較低者為準。
  2. 根據預設,COM 會防止低 IL 用戶端系結至任何 COM 伺服器的執行實例。 若要允許系結,COM 伺服器的啟動/啟用安全性描述元必須包含指定低 IL 標籤的 SACL(請參閱上一節,以瞭解建立這類安全性描述元的範例程式代碼)。

提升許可權的伺服器和 ROT 註冊

如果 COM 伺服器想要在執行中的對象數據表中註冊,並允許任何用戶端存取註冊,則必須使用 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 Hive 中

這個專案提供「啟動為啟動器」伺服器,其功能與 RunAs 伺服器ROTFLAGS_ALLOWANYCLIENT所提供的功能相同。

COM 中的安全性

了解「受保護模式」Internet Explorer 並在此模式下工作