NativeMethods.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 using System.Diagnostics.CodeAnalysis; 7 using System.Runtime.InteropServices; 8 using System.Security; 9 using System.ServiceProcess; 10 11 namespace MouseWithoutBordersService 12 { 13 internal sealed class NativeMethods 14 { 15 private NativeMethods() 16 { 17 } 18 19 private const string MY_KEY = @"SOFTWARE\Microsoft\MouseWithoutBorders"; 20 private const string MY_KEY_EX = @"S-1-5-19\SOFTWARE\Microsoft\MouseWithoutBorders"; 21 22 [StructLayout(LayoutKind.Sequential)] 23 private struct SECURITY_ATTRIBUTES 24 { 25 internal int Length; 26 internal IntPtr lpSecurityDescriptor; 27 internal bool bInheritHandle; 28 } 29 30 private enum TOKEN_TYPE : int 31 { 32 TokenPrimary = 1, 33 TokenImpersonation = 2, 34 } 35 36 private enum TOKEN_INFORMATION_CLASS : int 37 { 38 TokenUser = 1, 39 TokenGroups, 40 TokenPrivileges, 41 TokenOwner, 42 TokenPrimaryGroup, 43 TokenDefaultDacl, 44 TokenSource, 45 TokenType, 46 TokenImpersonationLevel, 47 TokenStatistics, 48 TokenRestrictedSids, 49 TokenSessionId, 50 TokenGroupsAndPrivileges, 51 TokenSessionReference, 52 TokenSandBoxInert, 53 TokenAuditPolicy, 54 TokenOrigin, 55 MaxTokenInfoClass, // MaxTokenInfoClass should always be the last enum 56 } 57 58 [StructLayout(LayoutKind.Sequential)] 59 private struct STARTUPINFO 60 { 61 internal int cb; 62 internal string lpReserved; 63 internal string lpDesktop; 64 internal string lpTitle; 65 internal uint dwX; 66 internal uint dwY; 67 internal uint dwXSize; 68 internal uint dwYSize; 69 internal uint dwXCountChars; 70 internal uint dwYCountChars; 71 internal uint dwFillAttribute; 72 internal uint dwFlags; 73 internal short wShowWindow; 74 internal short cbReserved2; 75 internal IntPtr lpReserved2; 76 internal IntPtr hStdInput; 77 internal IntPtr hStdOutput; 78 internal IntPtr hStdError; 79 } 80 81 [StructLayout(LayoutKind.Sequential)] 82 private struct SID_AND_ATTRIBUTES 83 { 84 internal IntPtr Sid; 85 internal int Attributes; 86 } 87 88 [StructLayout(LayoutKind.Sequential)] 89 private struct TOKEN_MANDATORY_LABEL 90 { 91 internal SID_AND_ATTRIBUTES Label; 92 } 93 94 [StructLayout(LayoutKind.Sequential)] 95 internal struct PROCESS_INFORMATION 96 { 97 internal IntPtr hProcess; 98 internal IntPtr hThread; 99 internal uint dwProcessId; 100 internal uint dwThreadId; 101 } 102 103 private enum SECURITY_IMPERSONATION_LEVEL : int 104 { 105 SecurityAnonymous = 0, 106 SecurityIdentification = 1, 107 SecurityImpersonation = 2, 108 SecurityDelegation = 3, 109 } 110 111 [StructLayout(LayoutKind.Sequential)] 112 internal struct LUID 113 { 114 internal int LowPart; 115 internal int HighPart; 116 }// end struct 117 118 [StructLayout(LayoutKind.Sequential)] 119 internal struct LUID_AND_ATTRIBUTES 120 { 121 internal LUID Luid; 122 internal int Attributes; 123 }// end struct 124 125 [StructLayout(LayoutKind.Sequential)] 126 internal struct TOKEN_PRIVILEGES 127 { 128 internal int PrivilegeCount; 129 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 130 internal int[] Privileges; 131 } 132 133 private const int READ_CONTROL = 0x00020000; 134 135 private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000; 136 137 private const int STANDARD_RIGHTS_READ = READ_CONTROL; 138 private const int STANDARD_RIGHTS_WRITE = READ_CONTROL; 139 private const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL; 140 141 private const int STANDARD_RIGHTS_ALL = 0x001F0000; 142 143 private const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF; 144 145 private const int TOKEN_ASSIGN_PRIMARY = 0x0001; 146 private const int TOKEN_DUPLICATE = 0x0002; 147 private const int TOKEN_IMPERSONATE = 0x0004; 148 private const int TOKEN_QUERY = 0x0008; 149 private const int TOKEN_QUERY_SOURCE = 0x0010; 150 private const int TOKEN_ADJUST_PRIVILEGES = 0x0020; 151 private const int TOKEN_ADJUST_GROUPS = 0x0040; 152 private const int TOKEN_ADJUST_DEFAULT = 0x0080; 153 private const int TOKEN_ADJUST_SESSIONID = 0x0100; 154 155 private const int TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED | 156 TOKEN_ASSIGN_PRIMARY | 157 TOKEN_DUPLICATE | 158 TOKEN_IMPERSONATE | 159 TOKEN_QUERY | 160 TOKEN_QUERY_SOURCE | 161 TOKEN_ADJUST_PRIVILEGES | 162 TOKEN_ADJUST_GROUPS | 163 TOKEN_ADJUST_DEFAULT; 164 165 private const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID; 166 167 private const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY; 168 169 private const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE | 170 TOKEN_ADJUST_PRIVILEGES | 171 TOKEN_ADJUST_GROUPS | 172 TOKEN_ADJUST_DEFAULT; 173 174 private const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE; 175 176 private const uint MAXIMUM_ALLOWED = 0x2000000; 177 178 private const int CREATE_NEW_PROCESS_GROUP = 0x00000200; 179 private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400; 180 181 private const int IDLE_PRIORITY_CLASS = 0x40; 182 private const int NORMAL_PRIORITY_CLASS = 0x20; 183 private const int HIGH_PRIORITY_CLASS = 0x80; 184 private const int REALTIME_PRIORITY_CLASS = 0x100; 185 186 private const int CREATE_NEW_CONSOLE = 0x00000010; 187 188 private const string SE_DEBUG_NAME = "SeDebugPrivilege"; 189 private const string SE_RESTORE_NAME = "SeRestorePrivilege"; 190 private const string SE_BACKUP_NAME = "SeBackupPrivilege"; 191 192 private const int SE_PRIVILEGE_ENABLED = 0x0002; 193 194 private const int ERROR_NOT_ALL_ASSIGNED = 1300; 195 196 [StructLayout(LayoutKind.Sequential)] 197 private struct PROCESSENTRY32 198 { 199 internal uint dwSize; 200 internal uint cntUsage; 201 internal uint th32ProcessID; 202 internal IntPtr th32DefaultHeapID; 203 internal uint th32ModuleID; 204 internal uint cntThreads; 205 internal uint th32ParentProcessID; 206 internal int pcPriClassBase; 207 internal uint dwFlags; 208 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 209 internal string szExeFile; 210 } 211 212 private const uint TH32CS_SNAPPROCESS = 0x00000002; 213 214 [DllImport("kernel32.dll", SetLastError = true)] 215 [return: MarshalAs(UnmanagedType.Bool)] 216 private static extern bool CloseHandle(IntPtr hSnapshot); 217 218 [DllImport("kernel32.dll")] 219 internal static extern uint WTSGetActiveConsoleSessionId(); 220 221 [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")] 222 [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 223 [return: MarshalAs(UnmanagedType.Bool)] 224 private static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid); 225 226 [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Justification = "Dotnet port with style preservation")] 227 [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] 228 [return: MarshalAs(UnmanagedType.Bool)] 229 private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); 230 231 [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")] 232 [return: MarshalAs(UnmanagedType.Bool)] 233 private static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); 234 235 [DllImport("kernel32.dll")] 236 private static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId); 237 238 [DllImport("advapi32", SetLastError = true)] 239 [SuppressUnmanagedCodeSecurityAttribute] 240 [return: MarshalAs(UnmanagedType.Bool)] 241 private static extern bool OpenProcessToken( 242 IntPtr ProcessHandle, // handle to process 243 int DesiredAccess, // desired access to process 244 ref IntPtr TokenHandle); // handle to open access token 245 246 [DllImport("advapi32.dll", SetLastError = true)] 247 [return: MarshalAs(UnmanagedType.Bool)] 248 private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 249 250 [DllImport("userenv.dll", SetLastError = true)] 251 [return: MarshalAs(UnmanagedType.Bool)] 252 private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit); 253 254 [DllImport("sas.dll", SetLastError = true)] 255 internal static extern IntPtr SendSAS([MarshalAs(UnmanagedType.Bool)] bool AsUser); 256 257 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Dotnet port with style preservation")] 258 [return: MarshalAs(UnmanagedType.Bool)] 259 internal static bool CreateProcessAsSystemAccountOnSpecificDesktop(string CommandLine, string Desktop, int NoOfTry, int sessionId = -1) 260 { 261 int lastError; 262 int dwSessionId = sessionId < 0 ? (int)WTSGetActiveConsoleSessionId() : sessionId; 263 int winlogonPid = 0; 264 IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; 265 266 try 267 { 268 int noTry = 0; 269 270 // At startup, services may start before winlogon. 271 do 272 { 273 Process[] p = Process.GetProcessesByName("winlogon"); 274 if (p != null) 275 { 276 for (int i = 0; i < p.Length; i++) 277 { 278 if (p[i].SessionId == dwSessionId) 279 { 280 winlogonPid = p[i].Id; 281 break; 282 } 283 } 284 } 285 286 noTry++; 287 if (winlogonPid == 0 && noTry < NoOfTry) 288 { 289 Thread.Sleep(1000); 290 } 291 } 292 while (winlogonPid == 0 && noTry < NoOfTry); 293 294 if (winlogonPid == 0) 295 { 296 return false; 297 } 298 299 STARTUPINFO si = default(STARTUPINFO); 300 si.cb = (int)Marshal.SizeOf(si); 301 si.lpDesktop = "winsta0\\" + Desktop; 302 303 hProcess = OpenProcess(MAXIMUM_ALLOWED, false, (uint)winlogonPid); 304 305 if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken)) 306 { 307 lastError = Marshal.GetLastWin32Error(); 308 CloseHandle(hProcess); 309 return false; 310 } 311 312 SECURITY_ATTRIBUTES sa = default(SECURITY_ATTRIBUTES); 313 sa.Length = Marshal.SizeOf(sa); 314 315 if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) 316 { 317 lastError = Marshal.GetLastWin32Error(); 318 CloseHandle(hProcess); 319 CloseHandle(hPToken); 320 return false; 321 } 322 323 uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; 324 IntPtr pEnv = IntPtr.Zero; 325 326 if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true)) 327 { 328 dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; 329 } 330 else 331 { 332 lastError = Marshal.GetLastWin32Error(); 333 pEnv = IntPtr.Zero; 334 } 335 336 // Launch the process 337 PROCESS_INFORMATION pi = default(PROCESS_INFORMATION); 338 bool rv = CreateProcessAsUser( 339 hUserTokenDup, // client's access token 340 null, // file to execute 341 CommandLine, // command line 342 ref sa, // pointer to process SECURITY_ATTRIBUTES 343 ref sa, // pointer to thread SECURITY_ATTRIBUTES 344 false, // handles are not inheritable 345 (int)dwCreationFlags, // creation flags 346 pEnv, // pointer to new environment block 347 null, // name of current directory 348 ref si, // pointer to STARTUPINFO structure 349 out pi); // receives information about new process 350 351 // GetLastError should be nonezero 352 int createProcessAsUserRv = Marshal.GetLastWin32Error(); 353 354 // Close handles task 355 CloseHandle(hProcess); 356 CloseHandle(hUserTokenDup); 357 CloseHandle(hPToken); 358 359 if (rv) 360 { 361 return true; 362 } 363 else 364 { 365 return false; 366 } 367 } 368 catch (Exception) 369 { 370 return false; 371 } 372 } 373 374 #if DESKTOP_STUFFS 375 [DllImport("kernel32.dll")] 376 private static extern UInt32 GetCurrentThreadId(); 377 378 [DllImport("user32.dll", SetLastError = true)] 379 private static extern IntPtr GetThreadDesktop(UInt32 dwThreadId); 380 381 [DllImport("user32.dll", SetLastError = true)] 382 private static extern bool SetThreadDesktop(IntPtr hDesktop); 383 384 [DllImport("user32.dll", SetLastError = true)] 385 private static extern IntPtr OpenInputDesktop(UInt32 dwFlags, bool fInherit, UInt32 dwDesiredAccess); 386 387 private const int UOI_FLAGS = 1; 388 private const int UOI_NAME = 2; 389 private const int UOI_TYPE = 3; 390 private const int UOI_USER_SID = 4; 391 private const UInt32 DESKTOP_WRITEOBJECTS = 0x0080; 392 private const UInt32 DESKTOP_READOBJECTS = 0x0001; 393 394 [DllImport("user32.dll", SetLastError = true)] 395 private static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [Out] byte[] pvInfo, int nLength, out UInt32 lpnLengthNeeded); 396 397 internal static string GetMyDesktop() 398 { 399 UInt32 nLengthNeeded; 400 byte[] arThreadDesktop = new byte[256]; 401 IntPtr hD = GetThreadDesktop(GetCurrentThreadId()); 402 if (hD != IntPtr.Zero) 403 { 404 GetUserObjectInformation(hD, UOI_NAME, arThreadDesktop, arThreadDesktop.Length, out nLengthNeeded); 405 return ASCIIEncoding.ASCII.GetString(arThreadDesktop); 406 } 407 return ""; 408 } 409 410 internal static string GetInputDesktop() 411 { 412 UInt32 nLengthNeeded; 413 byte[] arInputDesktop = new byte[256]; 414 IntPtr hD = OpenInputDesktop(0, false, DESKTOP_READOBJECTS); 415 if (hD != IntPtr.Zero) 416 { 417 GetUserObjectInformation(hD, UOI_NAME, arInputDesktop, arInputDesktop.Length, out nLengthNeeded); 418 return ASCIIEncoding.ASCII.GetString(arInputDesktop); 419 } 420 return ""; 421 } 422 #endif 423 } 424 }