窗口站和桌面的概念


窗口站(WindowsStation)和桌面(Desktop)是Windows操作系统底层暴露给Windows API的执行体对象(Windows内部有两种类型的对象:执行体对象和内核对象。执行体对象指由执行体的各种组件如进程管理器、内存管理器等等所实现的对象。内核对象是由Windows内核实现的一组更基本的对象)。

其中,窗口站对象包含了一个剪贴板、一组全局原子和一组桌面对象。桌面对象是一个被包含在窗口站内部的对象,桌面对象有一个逻辑显示器表面,其中包含了窗口、菜单和钩子。

0号窗口站(WinSta0)和默认的桌面对象(default desktop)是由Winlogon进程创建的。窗口站是会话(Session)的下一层组织结构。一个会话可以有多个窗口站,但同一时刻只能有一个窗口站可以与用户进行交互。每个窗口站有自己的剪贴板,可以有多个桌面。Winlogon进程调用NtUserCreateWindowsStation函数创建窗口站,再调用NtUserCreateDesktop来创建桌面。它首先会创建一个名为Winlogon的桌面供自己使用(Windows登录界面就属于属于这个桌面),然后再创建一个名为Default的桌面给应用程序使用。创建完桌面后,Winlogon调用SetActiveDesktop函数将Winlogon桌面设置为当前的活动桌面。

之后,Winlogon会创建用于管理系统服务的服务管理器(Service.exe)和本地安全认证子系统(LSASS.exe)。用户登录信息被验证后,Winlogon会将应用程序桌面激活,启动UserInit程序,UserInit会运行注册表中定义的登录脚本,然后启动操作系统外壳程序(Shell-默认是explorer.exe)。这是SYSTEM权限进程和普通用户进程逻辑显示器桌面分离的开始。在以后进程创建CreateProcess的过程中,如果没有指定桌面,那么进程就会与调用者的当前桌面关联在一起。

在实际测试中,发现services、svchost这些进程似乎没有关联任何桌面(截的屏都是黑屏)。普通的进程都是Default桌面,登录界面是Winlogon桌面。所以,当dll插入到service.exe等进程中的时候,要想实现截屏必须将进程与Default桌面关联,用户注销、离开或未登录时就要将进程与Winlogon桌面关联。

Windows给我们提供的一些API允许我们干这些事。

首先可以通过OpenWindowStation打开一个窗口站对象,然后通过SetProcessWindowStation将进程与窗口站关联,通过OpenDesktop打开一个桌面对象,再通过SetThreadDesktop将线程与这个桌面关联。这样service.exe就可以实现截屏了。但如何才能知道当前用户在哪个桌面呢?可以通过下列函数实现:
OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, MAXIMUM_ALLOWED);//打开输入桌面
GetUserObjectInformation(hActiveDesktop, UOI_NAME, pvInfo, sizeof(pvInfo), &dwLen); //获取指定桌面对象的信息,一般情况和屏保状态为default,登陆界面为winlogon
pvInfo缓冲区包含的就是当前桌面。这样就可以放心的调用OpenDesktop打开它了。

view plain copy to clipboard print ?
  1. BOOL OpenDesktop(LPCWSTR szName)  
  2. {  
  3.     WCHAR pvInfo[128] = {0};  
  4.     WCHAR tmp[1024] = {0};  
  5.   
  6.     if(szName != NULL)  
  7.         lstrcpy(pvInfo, szName);  
  8.     else  
  9.     {  
  10.   
  11.         HDESK hActiveDesktop;  
  12.         DWORD dwLen;  
  13.         hActiveDesktop = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, MAXIMUM_ALLOWED);  
  14.         if(!hActiveDesktop)//打开失败  
  15.         {  
  16.              return FALSE;  
  17.         }  
  18.         //获取指定桌面对象的信息,一般情况和屏保状态为default,登陆界面为winlogon  
  19.         GetUserObjectInformation(hActiveDesktop, UOI_NAME, pvInfo, sizeof(pvInfo), &dwLen);  
  20.         if(dwLen==0)//获取失败  
  21.         {  
  22.             return FALSE;  
  23.         }  
  24.         CloseDesktop(hActiveDesktop);  
  25. //打开winsta0  
  26.     m_hwinsta = OpenWindowStation(_T("winsta0"), FALSE,                            
  27.                                   WINSTA_ACCESSCLIPBOARD   |  
  28.                                   WINSTA_ACCESSGLOBALATOMS |  
  29.                                   WINSTA_CREATEDESKTOP     |  
  30.                                   WINSTA_ENUMDESKTOPS      |  
  31.                                   WINSTA_ENUMERATE         |  
  32.                                   WINSTA_EXITWINDOWS       |  
  33.                                   WINSTA_READATTRIBUTES    |  
  34.                                   WINSTA_READSCREEN        |  
  35.                                   WINSTA_WRITEATTRIBUTES);  
  36.     if (m_hwinsta == NULL){  
  37.         return FALSE;  
  38.        }  
  39.   
  40.     if (!SetProcessWindowStation(m_hwinsta)){  
  41.           return FALSE;  
  42.        }  
  43.   
  44. //打开desktop  
  45. m_hdesk = OpenDesktop(pvInfo, 0, FALSE,                  
  46.                             DESKTOP_CREATEMENU |  
  47.                             DESKTOP_CREATEWINDOW |  
  48.                             DESKTOP_ENUMERATE    |  
  49.                             DESKTOP_HOOKCONTROL |  
  50.                             DESKTOP_JOURNALPLAYBACK |  
  51.                             DESKTOP_JOURNALRECORD |  
  52.                             DESKTOP_READOBJECTS |  
  53.                             DESKTOP_SWITCHDESKTOP |  
  54.                             DESKTOP_WRITEOBJECTS);  
  55.        if (m_hdesk == NULL){  
  56.            return FALSE;  
  57.        }  
  58.   
  59.        SetThreadDesktop(m_hdesk);  
  60.        return TRUE;  
  61. }  

 

你可能感兴趣的:(windows,api,session,null,System,dll)