2012-02-15 3 views
6

Я создал локальный COM-сервер, который требует возвышения и должен быть создан изнутри невыполненного процесса.COM Elevation Moniker не может поднять сервер под Vista/Windows 7

Используя MSDN's article on the COM elevation moniker, я настроил класс сервера, следуя указанным требованиям. Сервер был успешно зарегистрирован в ульке HKLM.

Пример кода:

procedure CoCreateInstanceAsAdmin(const Handle: HWND; 
     const ClassID, IID: TGuid; PInterface: PPointer); 
var 
    rBindOpts: TBindOpts3; 
    sMonikerName: WideString; 
    iRes: HRESULT; 
begin 
    ZeroMemory(@rBindOpts, Sizeof(TBindOpts3)); 
    rBindOpts.cbStruct := Sizeof(TBindOpts3); 
    rBindOpts.hwnd := Handle; 
    rBindOpts.dwClassContext := CLSCTX_LOCAL_SERVER; 
    sMonikerName := 'Elevation:Administrator!new:' + GUIDToString(ClassID); 
    iRes := CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface); 
    OleCheck(iRes); 
end; 

class function CoIMyServer.Create: IMyServer; 
begin 
    CoCreateInstanceAsAdmin(HInstance, CLASS_IMyServer, IMyServer, @Result); 
end; 

Когда дело доходит до CoGetObject(PWideChar(sMonikerName), @rBindOpts, IID, PInterface) я получаю экран UAC и подтвердите запуск сервера в качестве администратора. Однако OleCheck(iRes) возвращает: «Требуемая операция требует превышения».

От that article Я читал о «надземном (OTS) возвышении».

Это единственный способ получить экземпляр моего сервера для невозбужденного процесса? Если да, то когда должно быть вызвано CoInitializeSecurity на сервере?


Полная информация о регистрации

HKLM\SOFTWARE\Wow6432Node\Classes\CLSID 
    {MyServer CLSID} 
     (Default) = IMyServer Object 
     LocalizedString = @C:\Program Files (x86)\MyServer\MyServer.exe,-15500 
    Elevation 
     Enabled = 0x000001 (1) 
    LocalServer32 
     (Default) = C:\PROGRA~2\MyServer\MYSERVER.EXE 
    ProgID 
     (Default) = uMyServer.IMyServer 
    TypeLib 
     (Default) = {TypeLib GUID} 
    Version 
     (Default) = 1.0 

HKLM\SOFTWARE\Wow6432Node\Classes\Interface 
    {GUID of IID_IMyServer} 
     (Default) = IMyServer 
    ProxyStubClsid32 
     (Default) = {Some GUID} 
    TypeLib 
     (Default) = {TypeLib GUID} 
     Version = 1.0 

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


Дополнительная информация

Пробовала без успеха вызова CoInitializeSecurity() неявных + установка разрешений на обед в соответствии с рекомендациями, используя следующий код:

function GetSecurityDescriptor(const lpszSDDL: LPWSTR; out pSD: PSecurityDescriptor): Boolean; 
begin 
    Result := ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, 
    pSD, nil); 
end; 

function GetLaunchActPermissionsWithIL(out pSD: PSecurityDescriptor): Boolean; 
var 
    lpszSDDL: LPWSTR; 
begin 
    // Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP 
    lpszSDDL := 'O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)'; 
    Result := GetSecurityDescriptor(lpszSDDL, pSD); 
end; 

function GetAccessPermissionsForLUAServer(out pSD: PSecurityDescriptor): Boolean; 
var 
    lpszSDDL: LPWSTR; 
begin 
    // Local call permissions to IU, SY 
    lpszSDDL := 'O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)'; 
    Result := GetSecurityDescriptor(lpszSDDL, pSD); 
end; 

function SetAccessPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean; 
var 
    dwLen: DWORD; 
    iRes: LONG; 
begin 
    dwLen := GetSecurityDescriptorLength(pSD); 
    iRes := RegSetValueExA(hAppKey, 'AccessPermission', 0, REG_BINARY, pSD, dwLen); 
    Result := iRes = ERROR_SUCCESS; 
end; 

function SetLaunchActPermissions(hAppKey: HKEY; pSD: PSECURITY_DESCRIPTOR): Boolean; 
var 
    dwLen: DWORD; 
    iRes: LONG; 
begin 
    dwLen := GetSecurityDescriptorLength(pSD); 
    iRes := RegSetValueExA(hAppKey, 'LaunchPermission', 0, REG_BINARY, pSD, dwLen); 
    Result := iRes = ERROR_SUCCESS; 
end; 

procedure Initialize; 
var 
    pSD: PSecurityDescriptor; 
    sSubKey: WideString; 
    hAppKey: HKEY; 
begin 
    sSubKey := 'AppID\{GUID}'; 
    RegOpenKeyW(HKEY_CLASSES_ROOT, PWideChar(sSubKey), hAppKey); 
    if GetAccessPermissionsForLUAServer(pSD) then 
    if not SetAccessPermissions(hAppKey, pSD) then 
     raise Exception.Create(Format('Access permissions aren''t set. System error: %d', 
     [GetLastError()])); 

    pSD := nil; 
    if GetLaunchActPermissionsWithIL(pSD) then 
    if not SetLaunchActPermissions(hAppKey, pSD) then 
     raise Exception.Create(Format('Launch permissions aren''t set. System error: %d', 
     [GetLastError()])); 
end; 

initialization 
    TAutoObjectFactory.Create(ComServer, TMyServer, Class_IMyServer, 
    ciMultiInstance, tmApartment); 
    Initialize; 

Как AppID GUID я пытался использовать как то же самое CLSID GUID моего интерфейса сервера и новый сгенерированный идентификатор GUID: результат был таким же. AccessPermission и LaunchPermission значения были указаны в указанном месте после регистрации сервера.

попытался также:

  • Указание ROTFlags = 1 в APPID ключа
  • Построение сервера, как 64-разрядное приложение

Дополнительные ключи реестра/значения I, созданные вручную:

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\MyServer.exe] 
@="MyServer" 
"AppID"="{My GUID}" 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{My GUID}] 
@="MyServer" 
"ROTFlags"=dword:00000001 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{My GUID}] 
@="MyServer Object" 
"AppID"="{My GUID}" 
+0

Вы действительно не должны писать прямо в HKEY_CLASSES_ROOT. Это нормально для чтения, но для записи вы должны использовать 'HKEY_LOCAL_MACHINE \ Software \ Classes' вместо этого. MSDN говорит так же. Помимо этого, где и как вы называете 'CoInitializeSecurity()'? –

+0

Хорошо о разделе реестра. Исправлено. Согласно разделу «Over-The-Shoulder (OTS) Elevation» раздел CoInitializeSecurity() 'называется неявным (см. Пример с кодом SetAccessPermissions), и поэтому я никогда не называл это сам. – AlexeyDaryin

+0

Вы пробовали еще раз называть это? –

ответ

7

Одна ошибка, которую вы делаете, заключается в том, что вы передаете globa RTL l HInstance переменная, где CoGetObject() рассчитывает вместо HWND. Ручка HINSTANCE не действительна. HWND ручка. Вам необходимо использовать фактический , такой как Handle property of TForm, или указать 0, чтобы позволить Elevation Moniker выбрать подходящее окно для вас.

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

CoInitializeSecurity() следует вызывать при запуске процесса сервера.

+0

Реми, спасибо. Я исправил проблему с помощью переменной HInstance. Я представил данные регистрации в первом сообщении. – AlexeyDaryin

+0

Вы создали 32-разрядный COM-сервер, работающий в 64-разрядной ОС. Вы пытались создать 64-битную версию своего COM-сервера, чтобы он больше не регистрировался в дереве 'Wow6432Node'? Кроме того, вы пытались добавить значение «ROTFlags» к вашей регистрации? См. Раздел «Повышенные серверы и учетные записи ROT» в статье. Наконец, ваше клиентское приложение работает на более низком уровне целостности? Если это так, см. Разделы «Разрешения COM-доступа и обязательного доступа» и «Уровни CoCreateInstance и Integrity Levels» статьи. –

+0

Я добавил дополнительные сведения к своему оригинальному сообщению. Я попытался применить все советы, однако результат не изменился. По-прежнему получается 'ERROR_ELEVATION_REQUIRED'. – AlexeyDaryin

 Смежные вопросы

  • Нет связанных вопросов^_^