最近遇到要做回傳服務內增加開關,可以自定義運行一些腳本已方便收集PC狀態,發現Bat始終無法運行,上網找了半天才發現和Session0有關,也就是程序有不同級別的訪問權限,Vista以上版本為了安全因素,限制了不同Session間的訪問,可以使用Windows API還直接穿透Session0,也就是獲得最高權限
相關類如下
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Runtime.InteropServices; 5 using System.Security.Principal; 6 using System.Text; 7 8 namespace IctInfo 9 { 10 /// <summary> 11 /// 解決vista和win7在windows服務中交互桌面權限問題:穿透Session 0 隔離 12 /// </summary> 13 public class Interop 14 { 15 public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; 16 17 public static void ShowMessageBox(string message, string title) 18 { 19 int resp = 0; 20 WTSSendMessage( 21 WTS_CURRENT_SERVER_HANDLE, 22 WTSGetActiveConsoleSessionId(), 23 title, title.Length, 24 message, message.Length, 25 0, 0, out resp, false); 26 } 27 28 [DllImport("kernel32.dll", SetLastError = true)] 29 public static extern int WTSGetActiveConsoleSessionId(); 30 31 [DllImport("wtsapi32.dll", SetLastError = true)] 32 public static extern bool WTSSendMessage( 33 IntPtr hServer, 34 int SessionId, 35 String pTitle, 36 int TitleLength, 37 String pMessage, 38 int MessageLength, 39 int Style, 40 int Timeout, 41 out int pResponse, 42 bool bWait); 43 //在ShowMessageBox 函數中調用了WTSSendMessage 來發送信息窗口,這樣我們就可以在Service 的OnStart 函數中使用,打開Service1.cs 加入下面代碼: 44 public static void CreateProcess(string app, string path) 45 { 46 bool result; 47 IntPtr hToken = WindowsIdentity.GetCurrent().Token; 48 IntPtr hDupedToken = IntPtr.Zero; 49 50 PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 51 SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); 52 sa.Length = Marshal.SizeOf(sa); 53 54 STARTUPINFO si = new STARTUPINFO(); 55 si.cb = Marshal.SizeOf(si); 56 57 int dwSessionID = WTSGetActiveConsoleSessionId(); 58 result = WTSQueryUserToken(dwSessionID, out hToken); 59 60 if (!result) 61 { 62 ShowMessageBox("WTSQueryUserToken failed", "AlertService Message"); 63 } 64 65 result = DuplicateTokenEx( 66 hToken, 67 GENERIC_ALL_ACCESS, 68 ref sa, 69 (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, 70 (int)TOKEN_TYPE.TokenPrimary, 71 ref hDupedToken 72 ); 73 74 if (!result) 75 { 76 ShowMessageBox("DuplicateTokenEx failed", "AlertService Message"); 77 } 78 79 IntPtr lpEnvironment = IntPtr.Zero; 80 result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false); 81 82 if (!result) 83 { 84 ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message"); 85 } 86 87 result = CreateProcessAsUser( 88 hDupedToken, 89 app, 90 String.Empty, 91 ref sa, ref sa, 92 false, 0, IntPtr.Zero, 93 path, ref si, ref pi); 94 95 if (!result) 96 { 97 int error = Marshal.GetLastWin32Error(); 98 string message = String.Format("CreateProcessAsUser Error: {0}", error); 99 ShowMessageBox(message, "AlertService Message"); 100 } 101 102 if (pi.hProcess != IntPtr.Zero) 103 CloseHandle(pi.hProcess); 104 if (pi.hThread != IntPtr.Zero) 105 CloseHandle(pi.hThread); 106 if (hDupedToken != IntPtr.Zero) 107 CloseHandle(hDupedToken); 108 } 109 110 [StructLayout(LayoutKind.Sequential)] 111 public struct STARTUPINFO 112 { 113 public Int32 cb; 114 public string lpReserved; 115 public string lpDesktop; 116 public string lpTitle; 117 public Int32 dwX; 118 public Int32 dwY; 119 public Int32 dwXSize; 120 public Int32 dwXCountChars; 121 public Int32 dwYCountChars; 122 public Int32 dwFillAttribute; 123 public Int32 dwFlags; 124 public Int16 wShowWindow; 125 public Int16 cbReserved2; 126 public IntPtr lpReserved2; 127 public IntPtr hStdInput; 128 public IntPtr hStdOutput; 129 public IntPtr hStdError; 130 } 131 132 [StructLayout(LayoutKind.Sequential)] 133 public struct PROCESS_INFORMATION 134 { 135 public IntPtr hProcess; 136 public IntPtr hThread; 137 public Int32 dwProcessID; 138 public Int32 dwThreadID; 139 } 140 141 [StructLayout(LayoutKind.Sequential)] 142 public struct SECURITY_ATTRIBUTES 143 { 144 public Int32 Length; 145 public IntPtr lpSecurityDescriptor; 146 public bool bInheritHandle; 147 } 148 149 public enum SECURITY_IMPERSONATION_LEVEL 150 { 151 SecurityAnonymous, 152 SecurityIdentification, 153 SecurityImpersonation, 154 SecurityDelegation 155 } 156 157 public enum TOKEN_TYPE 158 { 159 TokenPrimary = 1, 160 TokenImpersonation 161 } 162 163 public const int GENERIC_ALL_ACCESS = 0x10000000; 164 165 [DllImport("kernel32.dll", SetLastError = true, 166 CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 167 public static extern bool CloseHandle(IntPtr handle); 168 169 [DllImport("advapi32.dll", SetLastError = true, 170 CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] 171 public static extern bool CreateProcessAsUser( 172 IntPtr hToken, 173 string lpApplicationName, 174 string lpCommandLine, 175 ref SECURITY_ATTRIBUTES lpProcessAttributes, 176 ref SECURITY_ATTRIBUTES lpThreadAttributes, 177 bool bInheritHandle, 178 Int32 dwCreationFlags, 179 IntPtr lpEnvrionment, 180 string lpCurrentDirectory, 181 ref STARTUPINFO lpStartupInfo, 182 ref PROCESS_INFORMATION lpProcessInformation); 183 184 [DllImport("advapi32.dll", SetLastError = true)] 185 public static extern bool DuplicateTokenEx( 186 IntPtr hExistingToken, 187 Int32 dwDesiredAccess, 188 ref SECURITY_ATTRIBUTES lpThreadAttributes, 189 Int32 ImpersonationLevel, 190 Int32 dwTokenType, 191 ref IntPtr phNewToken); 192 193 [DllImport("wtsapi32.dll", SetLastError = true)] 194 public static extern bool WTSQueryUserToken( 195 Int32 sessionId, 196 out IntPtr Token); 197 198 [DllImport("userenv.dll", SetLastError = true)] 199 static extern bool CreateEnvironmentBlock( 200 out IntPtr lpEnvironment, 201 IntPtr hToken, 202 bool bInherit); 203 204 } 205 }
特別感謝以下大牛的技術分享