Failure to create elevation COM object on Windows Seven
Asked Answered
P

2

15

I am developing a COM surrogate object in C, it will be used by my applications to call the UAC elevation dialog for certain actions that require administrative rights.

The plan is to make this it export a function that takes a pointer to a function with a variable number of arguments and executes it in a different context. This way, an application can use this object to perform some actions with admin rights, all they need to do is use that object and pass it a pointer to the function that has to be executed with said rights.

This works partially, calling CoCreateInstance goes fine, the function pointer is passed and my function is executed.

However, when I create an instance of this object using the COM Elevation Moniker archive, and Microsoft's sample code for CoCreateInstanceAsAdmin, problems occur.

Here is the code:

HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
 // Manual implementation of CreateInstanceAsAdmin
 CComPtr<IBindCtx> 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<IMoniker> 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;
}

Calling CoCreateInstanceAsAdmin fails with "Class not registered".

The object is registered by creating the following registry keys (here's the body of the REG file)


[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]

I suppose that some registry entries are missing - that's the conclusion I reach when reading the error message. However, this list of registry keys was compiled after exploring the documentation on MSDN and other sites - so I am pretty certain that nothing was missed.

Among the things I've tried to solve this is to implement it via ATL (such that registration is automated). That works, but the problem is that I can't pass a funtion pointer to the MIDL generated function prototype.

I tried to pass it using the VARIANT type:


 v.vt = VT_PTR;
 void (*myptr)(void);
 myptr = &DoTheStuff;
 v.byref = myptr;
 hr = theElevated->CoTaskExecuter(0, v);

as result I get "Invalid argument type".

Could someone shed some light on the subject? Perhaps what I am trying to achieve is not possible by design?

Phototelegraph answered 10/11, 2010 at 13:30 Comment(3)
Yuck. Is this supposed to run as a separate process? Is this on a 64-bit version of Windows? A blank DllSurrogate is a problem on x64 Win7. No sign of an AppID or proxy/stub either. Ref: msdn.microsoft.com/en-us/library/ms686606%28VS.85%29.aspxBreaking
Yuck! This thing is a security hole of massive proportions. If you need something to execute code with elevated privileges then give it fixed functions to execute. Having it execute arbitrary function pointers means you may as well have elevated the original program!Hoi
You can't pass a meaningful pointer to an out-of-process COM object, the "out-of-process" bit should clue you into that one. The best you can do in this sort of scenario is to have a pre-registered object which does the work and you marshal it across the boundary, but then you might as well just elevate that COM object in the first place. As for the error double check it is registering it in HKEY_LOCAL_MACHINE (navigate to Software\Classes\CLSID\...) rather than HKEY_CURRENT_USER. If it is in current user then the elevated user can't see it due to the way they implement COM in vista+.Nishanishi
G
1

I believe the issues you are having is by design and that the intent of window's security improvements were to help avoid potential security risks.

Granule answered 15/11, 2013 at 0:24 Comment(0)
U
1

Microsoft doesn't really want you to elevate your privileges if it can stop you from doing so. Executing arbitrary functions as a privileged user shouldn't be easy in any way if Windows is even a decently secured system. You might could try impersonating a different user using tokens and getting better access that way, but even then it would be a stretch. If I remember right, user impersonations won't even guarantee that you'll get full access. The best solution in this case is just to use the super user account and properly request the correct privileges.

Utica answered 16/1, 2014 at 23:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.