다음을 통해 공유


COM 권한 상승 모니커

COM 권한 상승 모니커를 사용하면 UAC(사용자 계정 제어)에서 실행되는 애플리케이션이 상승된 권한으로 COM 클래스를 활성화할 수 있습니다. 자세한 내용은 최소 권한에 초점을 참조하세요.

권한 상승 모니커를 사용해야 하는 경우

권한 상승 모니커는 COM 클래스를 활성화하여 시스템 날짜 및 시간 변경과 같이 상승된 권한이 필요한 특정하고 제한된 함수를 수행하는 데 사용됩니다.

권한 상승을 위해서는 COM 클래스와 해당 클라이언트 모두의 참여가 필요합니다. 요구 사항 섹션에 설명된 대로 레지스트리 항목에 주석을 추가하여 권한 상승을 지원하도록 COM 클래스를 구성해야 합니다. COM 클라이언트는 권한 상승 모니커를 사용하여 권한 상승을 요청해야 합니다.

권한 상승 모니커는 애플리케이션 호환성을 제공하기 위한 것이 아닙니다. 예를 들어 WinWord와 같은 레거시 COM 애플리케이션을 관리자 권한 서버로 실행하려면 권한 상승 모니커를 사용하여 레거시 애플리케이션의 클래스를 활성화하는 대신 권한 상승이 필요하도록 COM 클라이언트 실행 파일을 구성해야 합니다. 관리자 권한 COM 클라이언트가 레거시 애플리케이션의 CLSID를 사용하여 CoCreateInstance 를 호출하면 클라이언트의 상승된 상태가 서버 프로세스로 흐릅니다.

모든 COM 기능이 권한 상승과 호환되는 것은 아닙니다. 작동하지 않는 기능에는 다음이 포함됩니다.

  • 권한 상승은 클라이언트에서 원격 COM 서버로 흐르지 않습니다. 클라이언트가 권한 상승 모니커를 사용하여 원격 COM 서버를 활성화하는 경우 상승이 지원되더라도 서버는 상승되지 않습니다.
  • 승격된 COM 클래스가 COM 호출 중에 가장을 사용하는 경우 가장하는 동안 상승된 권한이 손실될 수 있습니다.
  • 관리자 권한 COM 서버가 ROT(실행 중인 개체 테이블)에 클래스를 등록하는 경우 상승되지 않은 클라이언트에서는 클래스를 사용할 수 없습니다.
  • UAC 메커니즘을 사용하여 상승된 프로세스는 COM 활성화 중에 사용자별 클래스를 로드하지 않습니다. COM 애플리케이션의 경우 권한 없는 계정과 권한 있는 계정 모두에서 애플리케이션을 사용하려면 애플리케이션의 COM 클래스를 HKEY_LOCAL_MACHINE 레지스트리 하이브에 설치해야 합니다. 애플리케이션의 COM 클래스는 권한 있는 계정에서 애플리케이션을 사용하지 않는 경우에만 HKEY_USERS 하이브에 설치해야 합니다.
  • 끌어서 놓기는 상승되지 않은 애플리케이션에서 관리자 권한 애플리케이션으로 허용되지 않습니다.

요구 사항

권한 상승 모니커를 사용하여 COM 클래스를 활성화하려면 클래스가 시작 사용자 또는 'Activator로 활성화' 애플리케이션 ID로 실행되도록 구성되어야 합니다. 클래스가 다른 ID로 실행되도록 구성된 경우 활성화는 오류 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

IconReferenceLocalizedString과 동일한 형식을 사용합니다.

@ pathtobinary,-resourcenumber

또한 아이콘을 표시하려면 COM 구성 요소에 서명해야 합니다.

COM 클래스에도 LUA 사용으로 주석을 추가해야 합니다. 이렇게 하려면 다음 레지스트리 항목이 필요합니다.

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

이 항목이 없으면 활성화에서 오류 CO_E_ELEVATION_DISABLED 반환합니다.

이러한 항목은 HKEY_CURRENT_USER 또는 HKEY_USERS 하이브가 아닌 HKEY_LOCAL_MACHINE 하이브에 있어야 합니다. 이렇게 하면 사용자가 등록할 수 있는 권한도 없는 COM 클래스를 승격할 수 없습니다.

권한 상승 모니커 및 권한 상승 UI

클라이언트가 이미 관리자 권한인 경우 권한 상승 모니커를 사용하면 권한 상승 UI가 표시되지 않습니다.

권한 상승 모니커를 사용하는 방법

권한 상승 모니커는 세션, 파티션 또는 큐 모니커와 유사한 표준 COM 모니커입니다. 지정된 권한 상승 수준이 있는 지정된 서버로 활성화 요청을 전달합니다. 활성화할 CLSID가 모니커 문자열에 나타납니다.

권한 상승 모니커는 다음 실행 수준 토큰을 지원합니다.

  1. 관리자
  2. 가장 높음

이를 위한 구문은 다음과 같습니다.

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

앞의 구문은 "new" 모니커를 사용하여 guid로 지정된 COM 클래스의 instance 반환합니다. "new" 모니커는 내부적으로 IClassFactory 인터페이스를 사용하여 클래스 개체를 가져온 다음 IClassFactory::CreateInstance 를 호출합니다.

권한 상승 모니커를 사용하여 IClassFactory를 구현하는 클래스 개체를 가져올 수도 있습니다. 그런 다음 호출자는 CreateInstance를 호출하여 개체 instance 가져옵니다. 이를 위한 구문은 다음과 같습니다.

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입니다. 이 핸들은 해당하는 경우 권한 상승 UI의 소유자가 되는 창을 나타냅니다.

hwndNULL인 경우 COM은 GetActiveWindow를 호출하여 현재 스레드와 연결된 창 핸들을 찾습니다. 이 경우 클라이언트가 스크립트인 경우 BIND_OPTS3 구조를 채울 수 없습니다. 이 경우 COM은 스크립트 스레드와 연결된 창을 사용하려고 합니다.

OTS(Over-The-Shoulder) 권한 상승

OTS(오버더숄더) 권한 상승은 클라이언트가 자신의 자격 증명이 아닌 관리자의 자격 증명으로 COM 서버를 실행하는 시나리오를 나타냅니다. ("어깨 너머"라는 용어는 클라이언트가 서버를 실행할 때 관리자가 클라이언트의 어깨를 감시하고 있음을 의미합니다.)

이 시나리오에서는 서버에서 CoInitializeSecurity 를 명시적으로(즉, 프로그래밍 방식으로) 또는 암시적으로(즉, 선언적으로 레지스트리를 사용하여) 호출하지 않을 수 있으므로 COM 호출에 문제가 발생할 수 있습니다. 이러한 서버의 경우 COM은 SELF, SYSTEM 및 Builtin\Administrators만 서버에 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 레이블을 지원합니다. COM 권한의 SACL은 Windows Vista 이전의 운영 체제에서 무시됩니다.

Windows Vista를 기준으로 dcomcnfg.exe COM 권한에서 IL(무결성 수준) 변경을 지원하지 않습니다. 프로그래밍 방식으로 설정해야 합니다.

다음 코드 예제에서는 모든 LOW IL 클라이언트에서 시작/활성화 요청을 허용하는 레이블을 사용하여 COM 보안 설명자를 만드는 방법을 보여 줍니다. 레이블은 시작/활성화 및 호출 권한에 유효합니다. 따라서 특정 IL을 사용하는 클라이언트에서 시작, 활성화 또는 호출을 허용하지 않는 COM 서버를 작성할 수 있습니다. 무결성 수준에 대한 자세한 내용은 보호 모드 인터넷 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의 동작은 기본적으로 낮은 IL 클라이언트가 COM 서버에 바인딩되지 않도록 Windows Vista에서 변경되었습니다. 서버는 SACL을 지정하여 이러한 바인딩을 명시적으로 허용해야 합니다. CoCreateInstance의 변경 내용은 다음과 같습니다.

  1. COM 서버 프로세스를 시작할 때 서버 프로세스 토큰의 IL은 클라이언트 또는 서버 토큰 IL 중 더 낮은 값으로 설정됩니다.
  2. 기본적으로 COM은 낮은 IL 클라이언트가 COM 서버의 실행 중인 인스턴스에 바인딩하는 것을 방지합니다. 바인딩을 허용하려면 COM 서버의 시작/활성화 보안 설명자에 낮은 IL 레이블을 지정하는 SACL이 포함되어야 합니다(이러한 보안 설명자를 만들려면 샘플 코드의 이전 섹션 참조).

관리자 권한 서버 및 ROT 등록

COM 서버가 ROT(실행 중인 개체 테이블)에 등록하고 모든 클라이언트가 등록에 액세스하도록 허용하려는 경우 ROTFLAGS_ALLOWANYCLIENT 플래그를 사용해야 합니다. DCOMSCM(서비스 제어 관리자)이 이 플래그에 대해 스푸핑 검사 적용하므로 "Activator로 활성화" COM 서버는 ROTFLAGS_ALLOWANYCLIENT 지정할 수 없습니다. 따라서 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 보호 모드 이해 및 작업(영문)