最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vista和win7在windows服務(wù)中交互桌面權(quán)限問(wèn)題解決方法:穿透Session 0 隔離

 更新時(shí)間:2016年04月20日 21:52:46   作者:李敬然  
服務(wù)(Service)對(duì)于大家來(lái)說(shuō)一定不會(huì)陌生,它是Windows 操作系統(tǒng)重要的組成部分。我們可以把服務(wù)想像成一種特殊的應(yīng)用程序,它隨系統(tǒng)的“開(kāi)啟~關(guān)閉”而“開(kāi)始~停止”其工作內(nèi)容,在這期間無(wú)需任何用戶參與

Windows 服務(wù)在后臺(tái)執(zhí)行著各種各樣任務(wù),支持著我們?nèi)粘5淖烂娌僮鳌S袝r(shí)候可能需要服務(wù)與用戶進(jìn)行信息或界面交互操作,這種方式在XP 時(shí)代是沒(méi)有問(wèn)題的,但自從Vista 開(kāi)始你會(huì)發(fā)現(xiàn)這種方式似乎已不起作用。

Session 0 隔離實(shí)驗(yàn)

下面來(lái)做一個(gè)名叫AlertService 的服務(wù),它的作用就是向用戶發(fā)出一個(gè)提示對(duì)話框,我們看看這個(gè)服務(wù)在Windows 7 中會(huì)發(fā)生什么情況。

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()
  {
  }
 }
}

程序編譯后通過(guò)Installutil 將其加載到系統(tǒng)服務(wù)中:

在服務(wù)屬性中勾選“Allow service to interact with desktop” ,這樣可以使AlertService 與桌面用戶進(jìn)行交互。

在服務(wù)管理器中將AlertService 服務(wù)“啟動(dòng)”,這時(shí)任務(wù)欄中會(huì)閃動(dòng)一個(gè)圖標(biāo):

點(diǎn)擊該圖標(biāo)會(huì)顯示下面窗口,提示有個(gè)程序(AlertService)正在試圖顯示信息,是否需要瀏覽該信息:

flashmeg

嘗試點(diǎn)擊“View the message”,便會(huì)顯示下圖界面(其實(shí)這個(gè)界面我已經(jīng)不能從當(dāng)前桌面操作截圖了,是通過(guò)Virtual PC 截屏的,其原因請(qǐng)繼續(xù)閱讀)。注意觀察可以發(fā)現(xiàn)下圖的桌面背景已經(jīng)不是Windows 7 默認(rèn)的桌面背景了,說(shuō)明AlertService 與桌面系統(tǒng)的Session 并不相同,這就是Session 0 隔離作用的結(jié)果。

Session 0 隔離原理

在Windows XP、Windows Server 2003 或早期Windows 系統(tǒng)時(shí)代,當(dāng)?shù)谝粋€(gè)用戶登錄系統(tǒng)后服務(wù)和應(yīng)用程序是在同一個(gè)Session 中運(yùn)行的。這就是Session 0 如下圖所示:

但是這種運(yùn)行方式提高了系統(tǒng)安全風(fēng)險(xiǎn),因?yàn)榉?wù)是通過(guò)提升了用戶權(quán)限運(yùn)行的,而應(yīng)用程序往往是那些不具備管理員身份的普通用戶運(yùn)行的,其中的危險(xiǎn)顯而易見(jiàn)。

從Vista 開(kāi)始Session 0 中只包含系統(tǒng)服務(wù),其他應(yīng)用程序則通過(guò)分離的Session 運(yùn)行,將服務(wù)與應(yīng)用程序隔離提高系統(tǒng)的安全性。如下圖所示:

這樣使得Session 0 與其他Session 之間無(wú)法進(jìn)行交互,不能通過(guò)服務(wù)向桌面用戶彈出信息窗口、UI 窗口等信息。這也就是為什么剛才我說(shuō)那個(gè)圖已經(jīng)不能通過(guò)當(dāng)前桌面進(jìn)行截圖了。

Session 檢查

在實(shí)際開(kāi)發(fā)過(guò)程中,可以通過(guò)Process Explorer 檢查服務(wù)或程序處于哪個(gè)Session,會(huì)不會(huì)遇到Session 0 隔離問(wèn)題。我們?cè)赟ervices 中找到之前加載的AlertService 服務(wù),右鍵屬性查看其Session 狀態(tài)。

可看到AlertService 處于Session 0 中:

再來(lái)看看Outlook 應(yīng)用程序:

很明顯在Windows 7 中服務(wù)和應(yīng)用程序是處于不同的Session,它們之間加隔了一個(gè)保護(hù)墻,在下篇文章中將介紹如何穿過(guò)這堵保護(hù)墻使服務(wù)與桌面用戶進(jìn)行交互操作。

如果在開(kāi)發(fā)過(guò)程中確實(shí)需要服務(wù)與桌面用戶進(jìn)行交互,可以通過(guò)遠(yuǎn)程桌面服務(wù)的API 繞過(guò)Session 0 的隔離完成交互操作。

對(duì)于簡(jiǎn)單的交互,服務(wù)可以通過(guò)WTSSendMessage 函數(shù),在用戶Session 上顯示消息窗口。對(duì)于一些復(fù)雜的UI 交互,必須調(diào)用CreateProcessAsUser或其他方法(WCF、.NET遠(yuǎn)程處理等)進(jìn)行跨Session 通信,在桌面用戶上創(chuàng)建一個(gè)應(yīng)用程序界面。

WTSSendMessage 函數(shù)

如果服務(wù)只是簡(jiǎn)單的向桌面用戶Session 發(fā)送消息窗口,則可以使用WTSSendMessage 函數(shù)實(shí)現(xiàn)。首先,在上一篇下載的代碼中加入一個(gè)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 函數(shù)中調(diào)用了WTSSendMessage 來(lái)發(fā)送信息窗口,這樣我們就可以在Service 的OnStart 函數(shù)中使用,打開(kāi)Service1.cs 加入下面代碼:

protected override void OnStart(string[] args)
{
 Interop.ShowMessageBox("This a message from AlertService.",
       "AlertService Message");
}

編譯程序后在服務(wù)管理器中重新啟動(dòng)AlertService 服務(wù),從下圖中可以看到消息窗口是在當(dāng)前用戶桌面顯示的,而不是Session 0 中。

CreateProcessAsUser 函數(shù)

如果想通過(guò)服務(wù)向桌面用戶Session 創(chuàng)建一個(gè)復(fù)雜UI 程序界面,則需要使用CreateProcessAsUser 函數(shù)為用戶創(chuàng)建一個(gè)新進(jìn)程用來(lái)運(yùn)行相應(yīng)的程序。打開(kāi)Interop 類繼續(xù)添加下面代碼:

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 函數(shù)中同時(shí)也涉及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函數(shù)的使用,有興趣的朋友可通過(guò)MSDN 進(jìn)行學(xué)習(xí)。完成CreateProcess 函數(shù)創(chuàng)建后,就可以真正的通過(guò)它來(lái)調(diào)用應(yīng)用程序了,回到Service1.cs 修改一下OnStart 我們來(lái)打開(kāi)一個(gè)CMD 窗口。如下代碼:

復(fù)制代碼 代碼如下:

protected override void OnStart(string[] args)
{
    Interop.CreateProcess("cmd.exe",@"C:\Windows\System32\");
}

     重新編譯程序,啟動(dòng)AlertService 服務(wù)便可看到下圖界面。至此,我們已經(jīng)可以通過(guò)一些簡(jiǎn)單的方法對(duì)Session 0 隔離問(wèn)題進(jìn)行解決。大家也可以通過(guò)WCF 等技術(shù)完成一些更復(fù)雜的跨Session 通信方式,實(shí)現(xiàn)在Windows 7 及Vista 系統(tǒng)中服務(wù)與桌面用戶的交互操作。

相關(guān)文章

  • C#中Dictionary的作用及用法講解

    C#中Dictionary的作用及用法講解

    這篇文章主要介紹了C#中Dictionary的作用及用法講解,本文還對(duì)dictionary類用什么接口實(shí)現(xiàn)、Dictionary的基本用法做了講解,需要的朋友可以參考下
    2014-10-10
  • 基于C#實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地接口調(diào)用

    基于C#實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地接口調(diào)用

    這篇文章主要介紹了基于C#實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地接口調(diào)用的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • 淺聊一下C#中內(nèi)存映射文件的玩法

    淺聊一下C#中內(nèi)存映射文件的玩法

    內(nèi)存映射文件是怎么玩的,說(shuō)實(shí)話這東西理論我相信很多朋友都知道,就是將文件映射到進(jìn)程的虛擬地址,說(shuō)起來(lái)很容易,那如何讓大家眼見(jiàn)為實(shí)呢,本文就來(lái)和大家簡(jiǎn)單聊聊
    2023-06-06
  • C# 三種序列化方法分享

    C# 三種序列化方法分享

    這篇文章主要介紹了C# 三種序列化方法,需要的朋友可以參考下
    2014-02-02
  • C# L型棋牌覆蓋實(shí)現(xiàn)代碼與效果

    C# L型棋牌覆蓋實(shí)現(xiàn)代碼與效果

    C# L型棋牌覆蓋實(shí)現(xiàn)代碼與效果,需要的朋友可以參考一下
    2013-04-04
  • 詳解c# PLINQ中的分區(qū)

    詳解c# PLINQ中的分區(qū)

    這篇文章主要介紹了c# PLINQ中的分區(qū)的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • C# DES加密算法中向量的作用詳細(xì)解析

    C# DES加密算法中向量的作用詳細(xì)解析

    以下是對(duì)C#中DES加密算法中向量的作用進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-09-09
  • 如何在C#中使用 CancellationToken 處理異步任務(wù)

    如何在C#中使用 CancellationToken 處理異步任務(wù)

    這篇文章主要介紹了如何在C#中使用 CancellationToken 處理異步任務(wù),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C#基礎(chǔ)之委托詳解(Delegate)

    C#基礎(chǔ)之委托詳解(Delegate)

    這篇文章主要介紹了C#基礎(chǔ)之委托(Delegate),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • jQuery uploadify在谷歌和火狐瀏覽器上傳失敗的解決方案

    jQuery uploadify在谷歌和火狐瀏覽器上傳失敗的解決方案

    jquery.uploadify插件是一個(gè)基于jquery來(lái)實(shí)現(xiàn)上傳的,這個(gè)插件很好用,每一次向后臺(tái)發(fā)送數(shù)據(jù)流請(qǐng)求時(shí),ie會(huì)自動(dòng)把本地cookie存儲(chǔ)捆綁在一起發(fā)送給服務(wù)器。但firefox、chrome不會(huì)這樣做,他們會(huì)認(rèn)為這樣不安全,下面介紹下jQuery uploadify上傳失敗的解決方案
    2015-08-08

最新評(píng)論

六盘水市| 长岭县| 和平区| 凤山县| 邮箱| 红安县| 稻城县| 吐鲁番市| 铁力市| 淮阳县| 平阴县| 谷城县| 九寨沟县| 保康县| 江川县| 中阳县| 马山县| 淳化县| 邵东县| 扎囊县| 金川县| 商城县| 阿拉善右旗| 平顶山市| 桦川县| 太白县| 竹北市| 隆安县| 德清县| 西畴县| 福清市| 孟连| 阳春市| 平定县| 登封市| 酒泉市| 海林市| 正安县| 吉安市| 青海省| 昂仁县|