vista和win7在windows辦事中交互桌面權限成績處理辦法:穿透Session 0 隔離。本站提示廣大學習愛好者:(vista和win7在windows辦事中交互桌面權限成績處理辦法:穿透Session 0 隔離)文章只能為提供參考,不一定能成為您想要的結果。以下是vista和win7在windows辦事中交互桌面權限成績處理辦法:穿透Session 0 隔離正文
Windows 辦事在後台履行著各類各樣義務,支撐著我們平常的桌面操作。有時刻能夠須要辦事與用戶停止信息或界面交互操作,這類方法在XP 時期是沒有成績的,但自從Vista 開端你會發明這類方法仿佛已不起感化。
Session 0 隔離試驗
上面來做一個名叫AlertService 的辦事,它的感化就是向用戶收回一個提醒對話框,我們看看這個辦事在Windows 7 中會產生甚麼情形。
using System.ServiceProcess;
using System.Windows.Forms;
namespace AlertService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
MessageBox.Show("A message from AlertService.");
}
protected override void OnStop()
{
}
}
}
法式編譯後經由過程Installutil 將其加載到體系辦事中:

在辦事屬性中勾選“Allow service to interact with desktop” ,如許可使AlertService 與桌面用戶停止交互。

在辦事治理器中將AlertService 辦事“啟動”,這時候義務欄中會明滅一個圖標:
![]()
點擊該圖標會顯示上面窗口,提醒有個法式(AlertService)正在試圖顯示信息,能否須要閱讀該信息:

測驗考試點擊“View the message”,便會顯示下圖界面(其實這個界面我曾經不克不及從以後桌面操作截圖了,是經由過程Virtual PC 截屏的,其緣由請持續浏覽)。留意不雅察可以發明下圖的桌面配景曾經不是Windows 7 默許的桌面配景了,解釋AlertService 與桌面體系的Session 其實不雷同,這就是Session 0 隔離感化的成果。

Session 0 隔離道理
在Windows XP、Windows Server 2003 或晚期Windows 體系時期,當第一個用戶登錄體系後辦事和運用法式是在統一個Session 中運轉的。這就是Session 0 以下圖所示:

然則這類運轉方法進步了體系平安風險,由於辦事是經由過程晉升了用戶權限運轉的,而運用法式常常是那些不具有治理員身份的通俗用戶運轉的,個中的風險不言而喻。
從Vista 開端Session 0 中只包括體系辦事,其他運用法式則經由過程分別的Session 運轉,將辦事與運用法式隔離進步體系的平安性。以下圖所示:

如許使得Session 0 與其他Session 之間沒法停止交互,不克不及經由過程辦事向桌面用戶彈出信息窗口、UI 窗口等信息。這也就是為何適才我說誰人圖曾經不克不及經由過程以後桌面停止截圖了。

Session 檢討
在現實開辟進程中,可以經由過程Process Explorer 檢討辦事或法式處於哪一個Session,會不會碰到Session 0 隔離成績。我們在Services 中找到之前加載的AlertService 辦事,右鍵屬性檢查其Session 狀況。

可看到AlertService 處於Session 0 中:

再來看看Outlook 運用法式:

很顯著在Windows 7 中辦事和運用法式是處於分歧的Session,它們之間加隔了一個掩護牆,鄙人篇文章中將引見若何穿過這堵掩護牆使辦事與桌面用戶停止交互操作。
假如在開辟進程中確切須要辦事與桌面用戶停止交互,可以經由過程長途桌面辦事的API 繞過Session 0 的隔離完成交互操作。
關於簡略的交互,辦事可以經由過程WTSSendMessage 函數,在用戶Session 上顯示新聞窗口。關於一些龐雜的UI 交互,必需挪用CreateProcessAsUser或其他辦法(WCF、.NET長途處置等)停止跨Session 通訊,在桌面用戶上創立一個運用法式界面。
WTSSendMessage 函數
假如辦事只是簡略的向桌面用戶Session 發送新聞窗口,則可使用WTSSendMessage 函數完成。起首,在上一篇下載的代碼中參加一個Interop.cs 類,並在類中參加以下代碼:
public static void ShowMessageBox(string message, string title)
{
int resp = 0;
WTSSendMessage(
WTS_CURRENT_SERVER_HANDLE,
WTSGetActiveConsoleSessionId(),
title, title.Length,
message, message.Length,
0, 0, out resp, false);
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int WTSGetActiveConsoleSessionId();
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSSendMessage(
IntPtr hServer,
int SessionId,
String pTitle,
int TitleLength,
String pMessage,
int MessageLength,
int Style,
int Timeout,
out int pResponse,
bool bWait);
在ShowMessageBox 函數中挪用了WTSSendMessage 來發送信息窗口,如許我們便可以在Service 的OnStart 函數中應用,翻開Service1.cs 參加上面代碼:
protected override void OnStart(string[] args)
{
Interop.ShowMessageBox("This a message from AlertService.",
"AlertService Message");
}
編譯法式後在辦事治理器中從新啟動AlertService 辦事,從下圖中可以看到新聞窗口是在以後用戶桌面顯示的,而不是Session 0 中。

CreateProcessAsUser 函數
假如想經由過程辦事向桌面用戶Session 創立一個龐雜UI 法式界面,則須要應用CreateProcessAsUser 函數為用戶創立一個新過程用來運轉響應的法式。翻開Interop 類持續添加上面代碼:
public static void CreateProcess(string app, string path)
{
bool result;
IntPtr hToken = WindowsIdentity.GetCurrent().Token;
IntPtr hDupedToken = IntPtr.Zero;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
int dwSessionID = WTSGetActiveConsoleSessionId();
result = WTSQueryUserToken(dwSessionID, out hToken);
if (!result)
{
ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
}
result = DuplicateTokenEx(
hToken,
GENERIC_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref hDupedToken
);
if (!result)
{
ShowMessageBox("DuplicateTokenEx failed" ,"AlertService Message");
}
IntPtr lpEnvironment = IntPtr.Zero;
result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
if (!result)
{
ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
}
result = CreateProcessAsUser(
hDupedToken,
app,
String.Empty,
ref sa, ref sa,
false, 0, IntPtr.Zero,
path, ref si, ref pi);
if (!result)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
ShowMessageBox(message, "AlertService Message");
}
if (pi.hProcess != IntPtr.Zero)
CloseHandle(pi.hProcess);
if (pi.hThread != IntPtr.Zero)
CloseHandle(pi.hThread);
if (hDupedToken != IntPtr.Zero)
CloseHandle(hDupedToken);
}
[StructLayout(LayoutKind.Sequential)]
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 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 Int32 dwProcessID;
public Int32 dwThreadID;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
public const int GENERIC_ALL_ACCESS = 0x10000000;
[DllImport("kernel32.dll", SetLastError = true,
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", SetLastError = true,
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle,
Int32 dwCreationFlags,
IntPtr lpEnvrionment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel,
Int32 dwTokenType,
ref IntPtr phNewToken);
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern bool WTSQueryUserToken(
Int32 sessionId,
out IntPtr Token);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(
out IntPtr lpEnvironment,
IntPtr hToken,
bool bInherit);
在CreateProcess 函數中同時也觸及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函數的應用,有興致的同伙可經由過程MSDN 停止進修。完成CreateProcess 函數創立後,便可以真實的經由過程它來挪用運用法式了,回到Service1.cs 修正一下OnStart 我們來翻開一個CMD 窗口。以下代碼:
protected override void OnStart(string[] args)
{
Interop.CreateProcess("cmd.exe",@"C:\Windows\System32\");
}
從新編譯法式,啟動AlertService 辦事即可看到下圖界面。至此,我們曾經可以經由過程一些簡略的辦法對Session 0 隔離成績停止處理。年夜家也能夠經由過程WCF 等技巧完成一些更龐雜的跨Session 通訊方法,完成在Windows 7 及Vista 體系中辦事與桌面用戶的交互操作。
