Не удалось создать COM-объект повышения в Windows Seven
Я разрабатываю суррогатный объект COM в C, он будет использоваться моими приложениями для вызова диалога повышения прав UAC для определенных действий, которые требуют административных прав.
План состоит в том, чтобы экспортировать функцию, которая получает указатель на функцию с переменным числом аргументов и выполняет ее в другом контексте. Таким образом, приложение может использовать этот объект для выполнения некоторых действий с правами администратора, все, что им нужно сделать, это использовать этот объект и передать ему указатель на функцию, которая должна быть выполнена с указанными правами.
Это работает частично, вызов CoCreateInstance проходит нормально, указатель на функцию передается, и моя функция выполняется. Однако, когда я создаю экземпляр этого объекта с помощью CoCreateInstanceAsAdmin, возникают проблемы; вот код:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
// Manual implementation of CreateInstanceAsAdmin
CComPtr BindCtx;
HRESULT hr = CreateBindCtx(0,&BindCtx);
BIND_OPTS3 bo;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.grfMode = STGM_READWRITE;
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
hr = BindCtx->SetBindOptions(&bo);
if (SUCCEEDED(hr))
{
// Use the passed in CLSID to help create the COM elevation moniker string
CComPtr Moniker;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid,wszCLSID,sizeof(wszCLSID) / sizeof(wszCLSID[0]));
//Elevation:Administrator!new
hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (SUCCEEDED(hr))
{
// Create the COM elevation moniker
ULONG ulEaten = 0;
ULONG ulLen = (ULONG)wcslen(wszMonikerName);
LPBC pBindCtx = BindCtx.p;
hr = MkParseDisplayName(pBindCtx,wszMonikerName,&ulEaten,&Moniker);
if (SUCCEEDED(hr) && ulEaten == ulLen)
{
// Use passed in reference to IID to bind to the object
IDispatch * pv = NULL;
hr = Moniker->BindToObject(pBindCtx,NULL,riid,ppv);
}
}
}
return hr;
}
Вызов CoCreateInstanceAsAdmin завершается с ошибкой "Класс не зарегистрирован".
Объект регистрируется путем создания следующих ключей реестра (вот тело файла REG)
[HKEY_CLASSES_ROOT\COMsurrogate]
@="COMsurrogate Class"
[HKEY_CLASSES_ROOT\COMsurrogate\CurVer]
@="COMsurrogate.1"
[HKEY_CLASSES_ROOT\COMsurrogate\CLSID]
@="{686B6F70-06AE-4dfd-8C26-4564684D9F9F}"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}]
@="COMsurrogate Class"
"LocalizedString"="@C:\\Windows\\system32\\COMsurrogate.dll,-101"
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\ProgID]
@="COMsurrogate.1"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\VersionIndependentProgID]
@="COMsurrogate"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\InprocServer32]
@="@C:\\windows\system32\COMsurrogate.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\NotInsertable]
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\Programmable]
Я полагаю, что некоторые записи в реестре отсутствуют - к этому я и пришел, прочитав сообщение об ошибке. Однако этот список разделов реестра был составлен после изучения документации на MSDN и других сайтах - так что я почти уверен, что ничего не пропустили.
Среди вещей, которые я пытался решить, это реализовать его через ATL (чтобы регистрация была автоматизированной). Это работает, но проблема в том, что я не могу передать указатель функции на прототип сгенерированной функции MIDL.
Я попытался передать его, используя тип VARIANT:
v.vt = VT_PTR;
void (*myptr)(void);
myptr = &DoTheStuff;
v.byref = myptr;
hr = theElevated->CoTaskExecuter(0, v);
В результате я получаю "Неверный тип аргумента".
Может ли кто-то пролить свет на эту тему? Возможно, то, что я пытаюсь достичь, не возможно по замыслу?
2 ответа
Я полагаю, что проблемы, с которыми вы столкнулись, связаны с разработкой и целью улучшения безопасности окна было помочь избежать потенциальных угроз безопасности.
Microsoft на самом деле не хочет, чтобы вы повышали свои привилегии, если это может помешать вам сделать это. Выполнение произвольных функций от имени привилегированного пользователя не должно быть легким, даже если Windows - даже прилично защищенная система. Вы могли бы попытаться выдать себя за другого пользователя, используя токены и получить лучший доступ таким образом, но даже тогда это будет растяжкой. Если я правильно помню, персонификация пользователей даже не гарантирует, что вы получите полный доступ. Лучшее решение в этом случае - просто использовать учетную запись суперпользователя и правильно запрашивать правильные привилегии.