4

Our application needs to communicate with another program through a COM interface. The interface will not work if the other program is started with "Run as Administrator". Would like to detect if this other process is in this state and warn the user. Any ideas?

Looking for .NET languages (C# or VB.NET).

TIA

Randy N.
  • 43
  • 1
  • 3
  • 1
    Your problem seems to be why doesn't COM cross the bridge between the applications running at the different levels, not how to detect it. Did you properly secure the COM channel? – Remus Rusanu Mar 29 '11 at 22:16
  • COM makes it impossible to discover what process is hosting the server. Very much by design, it allows all kind of hosting tricks. You'll have to use secret knowledge you have about the process. – Hans Passant Mar 29 '11 at 22:46

2 Answers2

7

You can try something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Security.Principal;
using System.Reflection;

namespace WindowsFormsApplication2
{

    public class ProcessHelper
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr hObject);

        private const int STANDARD_RIGHTS_REQUIRED      = 0xF0000;
        private const int TOKEN_ASSIGN_PRIMARY           =0x1;
        private const int TOKEN_DUPLICATE                 = 0x2;
        private const int TOKEN_IMPERSONATE              = 0x4;
        private const int TOKEN_QUERY                     = 0x8;
        private const int TOKEN_QUERY_SOURCE             = 0x10;
        private const int TOKEN_ADJUST_GROUPS           = 0x40;
        private const int TOKEN_ADJUST_PRIVILEGES        = 0x20;
        private const int TOKEN_ADJUST_SESSIONID          = 0x100;
        private const int TOKEN_ADJUST_DEFAULT          = 0x80;
        private const int TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_SESSIONID | TOKEN_ADJUST_DEFAULT);

        public static bool IsProcessOwnerAdmin(string processName)
        {
            Process proc = Process.GetProcessesByName(processName)[0];

            IntPtr ph = IntPtr.Zero;

            OpenProcessToken(proc.Handle, TOKEN_ALL_ACCESS, out ph);

            WindowsIdentity iden = new WindowsIdentity(ph);

            bool result = false;

            foreach (IdentityReference role in iden.Groups)
            {
                if (role.IsValidTargetType(typeof(SecurityIdentifier)))
                {
                    SecurityIdentifier sid = role as SecurityIdentifier;

                    if (sid.IsWellKnown(WellKnownSidType.AccountAdministratorSid) || sid.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid))
                    {
                        result = true;
                        break;
                    }
                }
            }

            CloseHandle(ph);

            return result;
        }
    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            bool isAdmin = ProcessHelper.IsProcessOwnerAdmin("outlook");
        }
    }
}

This could also be a good thing to have: Well-known security identifiers in Windows operating systems

That should be a good start point :-)

HABJAN
  • 9,212
  • 3
  • 35
  • 59
  • Thanks for the starting point. It works accept when when the process is started by using RUN AS. I get Access Denied on OpenProcess Token. Guessing since it's being run by built-in admin the current user (is admin user) dosn't have privileges to access. I can hack it and say when I get access denied I know it's being run-as. If you have any other suggestions would appreciate a more elegant solutino. – Randy N. Mar 31 '11 at 11:57
  • Still same access denied. BTW, I added private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000; – Randy N. Mar 31 '11 at 12:26
  • @Randy N.: Can you try to run your application as Admin to see if that will work? If yes, then i can suggest you to do application impersonation before you check process user info and when you are done dismiss impersonation. Got the point? – HABJAN Mar 31 '11 at 12:51
  • Yes, it works and I get the SID of "S-1-5-32-544" which tells me it's being run as Admin. However, the impersonation is a non-starter because then my app will popup the UAC screen. – Randy N. Mar 31 '11 at 13:56
  • I also tried to GetSecurityInfo instead of openprocesstoken and it also returns access denied. Thanks for your help. – Randy N. Mar 31 '11 at 13:57
  • Well, from what i can see, with this code only way you can determine if app is started using "Run as" is if you get "Access Denied" error. That means that running app has rights that your app does not have. ( in this case ADMIN rights ). – HABJAN Mar 31 '11 at 16:53
  • Agreed. Will use your code and if I get access denied the other process is running at a different privilege level so it must be Run As. Not clean solution but at least I can pseudo point a user to the issue. Thanks for your help – Randy N. Apr 01 '11 at 17:13
  • @Randy N.: Sorry i could not help you to solve this problem much cleaner. – HABJAN Apr 01 '11 at 17:24
-2

May be late, but i created this for me (bad code... try n catch, i know, but it works):

private void Msg_Click(object sender, RoutedEventArgs e)
    {
        //running at all
        if (Process.GetProcessesByName("OUTLOOK").Any())
        {
            try
            {
                var app = (Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Outlook.Application");
            }

            //running normally
            catch (InvalidCastException)
            {
              
            }

            //running as admin
            catch (System.Runtime.InteropServices.COMException)
            {

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

    }
Blubbll
  • 17
  • 4