CoCreateInstanceAsAdmin or CreateElevatedComObject sample



The COM elevation moniker is one of the three recommended ways to have a user application do tasks that require admin privileges. The UAC document from September 2006 refers to it as the Admin COM Object model under the section “Key Decisions for Designing Administrator-Only Applications”.  


Apparently CoCreateInstanceAsAdmin from the SDK documentation has been rebranded as CreateElevatedComObject in the UAC doc. I have a sample with an ATL component and a console client attached that show this working. (Disclaimer: It is for demo purposes only and the code does not do any error or exception handling.)


The only changes I had to make was in the two rgs files. In order to make the inproc COM component run in the dllhost.exe surrogate, I had to add this to MyElevatedCOM.rgs:


 


   val DllSurrogate = s ”


 


I also had to add this to the MyElevated.rgs file to make it both Elevation capable and MUI aware respectively:


 


      Elevation


      {


            val Enabled = d 1


      }


      val LocalizedString = s  ‘@%MODULE%,-101’


 


Finally to match up the LocalizedString entry with an entry from the resource, I added a new string in the String table with a matching entry of 101.


 


The client side is literally copied from the SDK docs.


[updated]


If you try to launch this application from a real standard user (so not a filtered admin), you will get an E_ACCESSDENIED on the actual method call. In order to get around this you will need to give the interactive user access permission to the COM component.


Steps:




  1. Launch COM+ explorer (start, run, dcomcnfg)


  2. Navigate to Component Services\Computers\My Computer\DCOM Config and get to MyElevatedCOM (for this demo app that is)


  3. Select Properties and go to security tab.


  4. Under Access Permissions, select the Customize button radio button and click Edit.


  5. Click Add. Change the “locations” to the local machine.


  6. Enter “Interactive” and OK out of all the dialogs.

If you need to script this you can use DCOMPERM from the platform SDK.


Maarten

MyElevatedCom.zip

Comments (13)

  1. justinf says:

    i ran this sample code on vista rc1 (build 5600), and it worked except the 2nd ShowMe() call failed with E_ACCESSDENIED. i was prompted for admin credentials during the CoGetObject() call and it succeeded. any ideas?

    thanks,

    justin

  2. MSDN Archive says:

    Someone reported the same issue to me. i will update the blog.

  3. NickM says:

    Just curious: Given the significant gotcha with the custom DCOM setup being required for this approach to work when running as a standard user, would you still recommend this COM-based technique for commercial software to achieve elevation to administrator?

    If so, do you recommend basically doing the COM permission changes described in steps 1-6 (or, more precisely their programmatic equivalent) during setup?  How?  As an MSI custom action?  

    What security implications are there of granting INTERACTIVE (effectively the same as EVERYONE on the local machine) access in this way?  Any security gotchas there?  Is this how standard Microsoft applications (like the Windows shell) achieve elevation to administrator when running parts of their UI inside of a DLLHOST?

    Nick

  4. robgarrett says:

    Is there anything else other than VS2005 SP1 and Vista RTM to install to get this sample to work?  I get a compilation error for BIND_OPTS3.

    Thanks.

    Rob.

  5. rodream says:

    My had some test about this attachments with Vista (no development tools installed)

    Compiled with WinXP SP2 (with Vista SDK) and run with Vista (no dev tools installed)

    But regsvr32 cannot register dll file to registry

    regsvr32 says, ‘there is no library to run.’,

    but I copied files such as ‘atl80.dll’, ‘msvcr80.dll’ and i checked dependency with depends.exe.

    What was wrong with my work?

    please let me know. :'(

  6. cxp9315 says:

    I have everything working with the Elevation Moniker except getting the Icon specified by the IconReference registry key. This ICON should (If I understand it correctly) display my ICON in the admin login dialog when elevation is requested by my app.

    What format should I use ? The MyElevatedCom example doesn’t specify one.

    So far, I have tried by making a reference to the icon to display the same way I specified the LocalizedString key for "Friendly Name" (Replacing the String ID with the constant that is generated in my DLL for the ICON I want). but it doesn’t seem to work.

  7. cxp9315 says:

    I have everything working with the Elevation Moniker except getting the Icon specified by the IconReference registry key. This ICON should (If I understand it correctly) display my ICON in the admin login dialog when elevation is requested by my app.

    What format should I use ? The MyElevatedCom example doesn’t specify one.

    So far, I have tried by making a reference to the icon to display the same way I specified the LocalizedString key for "Friendly Name" (Replacing the String ID with the constant that is generated in my DLL for the ICON I want). but it doesn’t seem to work.

  8. WalkOfDeadMan says:

    Hi,

    //justinf — Are you trying second method on XP?

    //VistaCompatTeam what option did you included in ATL project wizard and Atl simple object wizard? I’m trying to do the same on vista and your example works weel, but mine not ( in moment I’m trying to obtain pointer to IMyElevatedCom) it says me "Element not found" ( works fine on XP) Tryied regsvr32 to my dll and no changes…

    Best regards

  9. BenST says:

    I think I’ve got my implementation working. This blog was very useful. Some feedback for others who might read it:

    Lots of good information also at http://msdn2.microsoft.com/en-us/library/ms679687.aspx ("The COM Elevation moniker"). This shows how to solve the E_ACCESSDENIED problem without resorting to dcomcnfg. You need to add registry keys to your class AppId registry key to set up the AccessPermission and LaunchPermission ACLs. The ACLs allow the Interactive group access, and also allow low integrity applications to launch. I found the best way to do this was to add code to call SetAccessPermissions() and SetLaunchActPermissions() during DLLRegisterServer time.

    Also, regarding the presence of the custom icon in the elevation prompt dialog: the custom icon will only appear if the DLL is signed.

  10. jsl123 says:

    I tried using DCOMCNFG to set the interactive user but i still got Access Denied however following the instructions given in the link above does allow non-admin access.

    However, is it possible to stop the Elevation warning dialogs popping up? Does signing either the client/server make a difference.

  11. Andy Bantly says:

    I couldn’t make the ‘CoCreateInstanceAsAdmin’ work from a DLL so I implemented it the way the docs suggested.

    HRESULT CoCreateAdminInstance(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 = NULL;

    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]));

    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 RIID to bind to the object

    IDispatch * pv = NULL;

    hr = Moniker->BindToObject(pBindCtx,NULL,riid,ppv);

    }

    }

    }

    return hr;

    }

  12. Amol Mane says:

    Hi

    I tried to use the given example on windows 7 with VS2005 running in normal user mode(without Admin privilege) it is giving error PRJ0050: Failed to register output. Please try to register the component from a command prompt with elevated permissions then i manually registered COM in Admin cmd prompt with regsvr32

    i have added 2 more functions in COM along with ShowMe()

    1) one function creates registry and enter a value into registry but i m getting strange behavior registry is editable in both modes and not giving me E_ACCESSDENIED message in normal user mode

    2)other function creates new file on C driver in normal user its not able to create file but still returning S_OK from elevation COM i even checked file physically present or not using cmd->edit file name its present but not showing physically in windows 7 – i think it is one of the biggest BUG of windows 7; where as in Administrator mode it is creating file and returning S_OK

    function should return E_ACCESSDENIED when it is failed to create file with normal user mode