.Net offers multiple ways to manage impersonation and its level. The important point to understand is what is being impersonated: the thread or the process also is the impersonation happening on the process or is it happening only on the network. Below classes will show you how to impersonate in all this cases.

First class: ImpersonateManager – allows starting impersonation and will apply to the thread scope. You will need to allow unsafe code in your project build properties.  Below program is an example of using the ImpersonateManager.

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);

            try
            {
                ImpersonateManager.ImpersonateUser("domainName", "userName", "password");
                Console.WriteLine("Impersonated User: " + WindowsIdentity.GetCurrent().Name);
            }
            catch (System.ComponentModel.Win32Exception e)
            {
                Console.WriteLine("Exception while trying to impersonate: " + e);
            }

            ImpersonateManager.StopImpersonation();
            Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);

            Console.ReadKey();
        }
    }

The ImpersonateManager.cs is like this:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

[assembly: SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode = true)]
[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "FullTrust")]
namespace ImpersonateThread
{
    public class ImpersonateManager
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource,
            int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr* Arguments);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
            int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

        // OurIdentity
        private static WindowsImpersonationContext _impersonatedUser;

        // Tokens
        private static IntPtr tokenHandle = new IntPtr(0);
        private static IntPtr dupeTokenHandle = new IntPtr(0);

        // If you incorporate this code into a DLL, be sure to demand FullTrust.
        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        public static void ImpersonateUser(string domainName, string userName, string password)
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int LOGON32_LOGON_INTERACTIVE = 2;

            tokenHandle = IntPtr.Zero;

            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = LogonUser(userName, domainName, password,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle);

            if (false == returnValue)
            {
                // Logon failure
                int ret = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(ret);
            }

            // Use the token handle returned by LogonUser.
            WindowsIdentity newId = new WindowsIdentity(tokenHandle);

            // Now the thread is impersonated.
            _impersonatedUser = newId.Impersonate();
        }

        public static void StopImpersonation()
        {
            // Stop impersonating the thread.
            _impersonatedUser.Undo();

            // Free the tokens.
            if (tokenHandle != IntPtr.Zero)
            {
                CloseHandle(tokenHandle);
            }
        }
    }
}



Now this might not be enough for your need, you might need more than thread impersonation.

There are basically two main logon scenarios in this case:

1)      The user you want to impersonate is on the same domain as the current process

  • Load the profile in the registry (like runas /profile)
  • Sample with: ProcessImpersonator.ImpersonateProcess_WithProfile()

2)      The user you want to impersonate is on a domain without trust relationship

  • Use the specified credentials on the network only (like runas /netuse)
  • Sample with : ProcessImpersonator.ImpersonateProcess_NetCredentials()

Below program do exactly this, it will start another executable (located in the same folder and having a name of test.exe).

class Program
    {
        static void Main(string[] args)
        {
            // Will impersonate the process based on a user existing on the same domain
            ProcessImpersonator.ImpersonateProcess_WithProfile(@"C:\test.exe",
                "domain", "user", "password");

            // Will impersonate the call from the process based on a user on a domain
            // with no trust relationship.
            ProcessImpersonator.ImpersonateProcess_NetCredentials(@"C:\test.exe",
                "Otherdomain", "user", "password");
            Console.ReadKey();
        }
    }

ProcessImpersonator.cs looks like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using System.Text;

namespace ImpersonateThread
{
    public class ProcessImpersonator
    {
        [Flags]
        enum LogonFlags
        {
            LOGON_WITH_PROFILE = 0x00000001,
            LOGON_NETCREDENTIALS_ONLY = 0x00000002
        }

        [Flags]
        enum CreationFlags
        {
            CREATE_SUSPENDED = 0x00000004,
            CREATE_NEW_CONSOLE = 0x00000010,
            CREATE_NEW_PROCESS_GROUP = 0x00000200,
            CREATE_UNICODE_ENVIRONMENT = 0x00000400,
            CREATE_SEPARATE_WOW_VDM = 0x00000800,
            CREATE_DEFAULT_ERROR_MODE = 0x04000000,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct ProcessInfo
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct StartupInfo
        {
            public int cb;
            public string reserved1;
            public string desktop;
            public string title;
            public uint dwX;
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize;
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;
            public uint dwFlags;
            public ushort wShowWindow;
            public short reserved2;
            public int reserved3;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true,
         SetLastError = true)]
        static extern bool CreateProcessWithLogonW(
            string principal,
            string authority,
            string password,
            LogonFlags logonFlags,
            string appName,
            string cmdLine,
            CreationFlags creationFlags,
            IntPtr environmentBlock,
            string currentDirectory,
            ref StartupInfo startupInfo,
            out ProcessInfo processInfo);

        [DllImport("kernel32.dll")]
        static extern bool CloseHandle(IntPtr h);

        ///
        /// This will use the Logon_NetCredentials_only value.
        /// Usefull for inter-domain scenario without trust relationship
        /// but the system does not validate the credentials.
        ///
        public static void ImpersonateProcess_NetCredentials(string appPath, string domain,
            string user, string password)
        {
            ImpersonateProcess(appPath, domain, user, password,
             LogonFlags.LOGON_NETCREDENTIALS_ONLY);
        }

        ///
        /// This will use the Logon_With_Profile value.
        /// Useful to get the identity of an user in the same domain.
        ///
        public static void ImpersonateProcess_WithProfile(string appPath, string domain,
            string user, string password)
        {
            ImpersonateProcess(appPath, domain, user, password, LogonFlags.LOGON_WITH_PROFILE);
        }

        ///
        /// Call CreateProcessWithLogonW
        ///
        private static void ImpersonateProcess(string appPath, string domain, string user,
            string password, LogonFlags lf)
        {
            StartupInfo si = new StartupInfo();
            si.cb = Marshal.SizeOf(typeof(StartupInfo));
            ProcessInfo pi = new ProcessInfo();

            //
            if (CreateProcessWithLogonW(user, domain, password,
            lf,
            appPath, null,
            0, IntPtr.Zero, null,
            ref si, out pi))
            {
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
            }
            else
            {
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            }
        }
    }
}

For more information on the topic:

MSDN – CreateProcessWithLogonW.
MSDN – WindowsIdentity.
Geeks with blogs – Managed CreateProcessWithLogonW.

 

In the two previous posts (Enumerate all classes from a namespace and Enumerate all Namespaces from Root) we gather enough information to enumerate namespaces and classes. In this post we are going to see how to enumerate all the instances from a class via WQL.

using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace WmiNamespace
{
    class Program
    {
        static void Main(string[] args)
        {
            //Represents the scoop for management operations
            ManagementScope ms = new ManagementScope();

            //Represents the management query
            ObjectQuery wql = new ObjectQuery("select * from Win32_DiskDrive");

            //Retrieve a collection of management objects
            ManagementObjectSearcher searcher =
                new ManagementObjectSearcher(ms, wql);

            //Represents different collections
            ManagementObjectCollection oc = searcher.Get();

            //The enumerator of the collection
            ManagementObjectCollection.ManagementObjectEnumerator oe =
                oc.GetEnumerator();

            Console.WriteLine("This class got " + oc.Count + " instance(s)\n");

            //Enumerate the collection
            while (oe.MoveNext())
            {
                Console.WriteLine("\n********* " +
                                  oe.Current.GetPropertyValue("Name") + "\n");

                //Foreach of the properties existing in one of our instance
                //display the propety name and her value
                foreach (PropertyData prop in oe.Current.Properties)
                {
                    Console.WriteLine("> " + prop.Name + " (" + prop.Value + ")");
                }
            }

            Console.ReadLine();
        }
    }
}

Below is a screenshot of what I get after executing this program:

wmi Class Instance Screenshoot

Next step will be to add, update or delete instance from a class.

Ahmet

 

Now that we know how to enumerate all the namespace from root, let’s have a look on how to enumerate all the classes from a namespace.

using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace WmiNamespace
{
    class Program
    {
        static void Main(string[] args)
        {
            //Represents the scoop for management operations
            ManagementScope ms = new ManagementScope();

            //Provides a wrapper for building paths to WMI objects
            //Here we connect to the namespace called "CIMV2"
            ManagementPath path = new ManagementPath(@"\\localhost\root\CIMV2");

            //Represents a CIM management class
            ManagementClass newClass = new ManagementClass(path);

            //Provides a base class for query and enumeration-related options objects
            EnumerationOptions options = new EnumerationOptions();

            //Return class members that are immediately related to the class
            options.EnumerateDeep = false;

            //Retrieve the  sbuclasses using the specified options
            foreach (ManagementObject o in newClass.GetSubclasses(options))
            {
                Console.WriteLine(Convert.ToString(o["__Class"]));
            }
            Console.ReadLine();
        }
    }
}

You should see this:

wmi Namespace Classes Screenshoot

Next step is to enumerate all the instances from a class.

Ahmet

 

I like to understand WMI (Windows Management Instrumentation) as a database, main concepts are:

Namespaces: Databases

Classes: Tables

Properties: Columns

Instances: Lines

Values: Fields

With this in mind, we can start enumerating all the namespaces we can access locally.

using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace WmiNamespace
{
    class Program
    {
        static void Main(string[] args)
        {
            //Represents the scoop for management operations
            ManagementScope ms = new ManagementScope();

            //Provides a wrapper for building paths to WMI objects
            ManagementPath path = new ManagementPath(@"\\localhost\root");
            ms.Path = path;

            ms.Connect();

            if (ms.IsConnected)
            //At this point we are connected to WMI
            {
                //Represents a management query that returns instances or classes
                ObjectQuery wql = new ObjectQuery("select * from __Namespace");

                //Retrieves a collection of
                //management objects based on the specified query
                ManagementObjectSearcher searcher =
                    new ManagementObjectSearcher(ms, wql);

                //Represents different collections
               //of management objects retrieved through WMI
                ManagementObjectCollection oc = searcher.Get();

                //Represents the enumerator on the collection
                ManagementObjectCollection.ManagementObjectEnumerator oe =
                    oc.GetEnumerator();

                while (oe.MoveNext())
                {
                    foreach (PropertyData prop in oe.Current.Properties)
                    {
                        Console.WriteLine("\t{0}", prop.Value);
                    }
                }
            }
            Console.ReadLine();
        }
    }
}

Running this program will display:

WMI Namespace Screenshoot

Next step is to enumerate all classes from a Namespace. This will come at next post :)

Ahmet