COM Elevation Moniker не удается поднять сервер под Vista / Windows 7 - PullRequest
6 голосов
/ 15 февраля 2012

Я создал локальный COM-сервер, который требует повышения прав и должен быть создан из процесса без повышенных прав.

Используя статью MSDN о моникере высот COM , я настроил класс сервера в соответствии с указанными требованиями.Сервер был успешно зарегистрирован в кусте 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) возвращает: «Запрошенная операция требует повышения прав».

Начиная с этой статьи Я читал о «Возвышении за плечом».

Это единственный способ сделать мой экземпляр сервера доступным для процесса без повышенных прав?Если да, то когда 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;  

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

Также пробовал:

  • Указание ROTFlags = 1 в ключе AppId
  • Сборка сервера как 64-битного приложения

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

[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}"

1 Ответ

7 голосов
/ 15 февраля 2012

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

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

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

...