基于 Windows 7 的高低权限进程通信的研究与实现

来源:互联网 发布:农村淘宝服务站流程 编辑:程序博客网 时间:2024/04/29 06:19

与 Windows XP 以及 Windows Vista 相比,Windows 7 为用户提供了一个更易用、更简单、更安全的操作系统。在享受 Windows 7 便利的同时,偶尔会碰到在Windows XP系统上正常运行的程序却在 Windows 7 上出现非正常行为的兼容性问题。从 Windows Vista 开始,Windows操作系统提供了如下安全特性:用户帐户控制、强制完整性检测、用户界面特权隔离和IE保护模式等,Windows 7结合了XP的易用与低耗和Vista的美观与安全。基于 Windows 程序开发中最常遇到的进程通信问题,本文讨论了在 Windows 7 相比 Windows XP 底层安全机制发生改变的情况下,用户进程之间以及系统服务与用户进程之间这两种场景下的进程通信机制的变化,最后解决了软件从 Windows XP 移植到 Windows 7 时高低权限进程通信导致的的软件兼容性问题。

引言

  Windows 7 是微软公司开发的具有革命性变化的操作系统,该系统旨在让人们日常电脑操作更加简单高效。Windows 7 一面世,就受到广大用户的喜爱,很多软件开发商把握住这一契机,相继开发出在 Windows 7 平台上运行的软件,以满足用户各种需求。由于 Windows 7 操作系统相对于 Windows XP 有很大变化,在 Windows 7 的软件开发过程中就会碰到许多在 Windows XP 上未曾遇到的问题,其中包括进程通信、访问控制等等。

Windows进程通信介绍

  Windows 系统本身提供了多种进程通信的机制,比如共享内存,管道,剪贴板,WM_COPYDATA 消息等等。这些机制本质上都是通过文件映射来实现的。文件映射能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件 I/O 操作,只需简单的指针操作就可读取和修改文件的内容。Windows 允许多个进程访问同一文件映射对象,各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针,不同进程就可以读或修改文件的内容,实现对文件中数据的共享。应用程序可以通过文件映射对象句柄的继承性、命名的文件映射对象、复制文件映射对象句柄等三种方式来完成进程通信。

Windows 7 消息完整性检查与用户界面特权隔离

  消息完整性检查(Message Integrity Check),是 Windows 7 增加的 Windows 安全对象访问控制安全机制,系统利用完整性级别对一个安全对象进行标记,通过降低进程的完整性级别可以限制其对安全对象的写入权限,这一点类似于用户帐户组的成员被限制访问系统组件这种方式。完整性检查机制使得用更少的权限或以更低的完整性级别运行一些程序,会降低进程修改系统或损害用户数据文件的可能性。在 Windows 7 中消息完整性检查分为 6 个等级,如表 1 所示:

表1 MIC等级
MIC等级说明SECURITY_MANDATORY_UNTRUSTED_RID不信任的MIC等级SECURITY_MANDATORY_LOW_RID低MIC等级,如IESECURITY_MANDATORY_MEDIUM_RID中MIC等级,默认为这个等级,如ExplorerSECURITY_MANDATORY_HIGH_RID高MIC等级,以管理员身份运行的程序SECURITY_MANDATORY_SYSTEM_RID系统MIC等级,一般是服务应用程序SECURITY_MANDATORY_PROTECTED_PROCESS_RID被保护进程的MIC等级

  MIC 等级的获取是和创建该对象的进程完整性级别相关的。比如在 Windows 7 系统中 Explorer.exe 的完整性级别是中 MIC 等级,因为权限继承的关系,其启动的进程具有的 MIC 等级也都默认是中 MIC 等级。一个安全对象的 MIC 等级由其访问控制列表项中的某一项标识,可以使用工具 Process Explorer 察看一个进程的 MIC 等级。

  用户界面特权隔离(User Interface Privilege Isolation),则是 Windows 7 通过 MIC 机制新引入的一种安全特性,用于拦截接收比自身进程 MIC 等级低的进程发来的消息。UIPI 的目的是为了规范不同进程窗口之间的窗口消息处理过程,默认情况下,高权限进程不会接收到低权限进程发送的窗口消息的,但是低权限进程能够接收到高权限进程的窗口消息。UIPI 的本质是系统检查目标窗口和发送方是否具有相同的 MIC 等级或者发送方具有更高的 MIC 等级,如果符合上述条件,则允许消息的传递,否则将消息丢弃。

  因此,在 Windows 7 操作系统中运行的用户进程,如果运行时具有不同的完整性等级,即具有不同的 MIC 等级,那么相互间的通信将会无法像 Windows XP 那样正常进行。

Windows 7 系统服务、会话隔离以及访问控制列表

  Windows 系统服务(Service)是遵照 Windows 服务控制管理接口要求,能够在系统启动时自动启动,用户能够通过服务控制面板控制的那些即使没有一个用户登录也能够运作的程序。Windows XP 下面,服务可以运行于不同的帐户下面,常见的有 Local System、NetworkService 和 Local Service,根据需要也可以配置运行于 Administrator 或其他帐户下面。会话(Session)是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间。在 Windows Vista 以前的系统版本中,Windows 服务和应用程序使用相同的会话运行,这个会话是由第一个登录到控制台的用户启动的,叫做Session0,如图 1 所示:

  服务是经过提升的特权运行的,运行权限比一般的应用程序要高,不少服务甚至运行在 System 权限,在这种情况下,如果某个以低权限运行的恶意软件将某个服务做为攻击目标,通过“劫持”该服务,就可以提升自己的权限级别,因此在同一个会话中运行系统服务和用户应用程序会导致安全风险。 在 Windows 7 系统中,以上机制发生了改变,服务被托管到了 Session 0 中,用户应用程序运行在用户登录到系统时创建的后续会话中,用户应用程序和服务之间被隔离开了,这就是所谓的 Windows 7 会话 0 隔离。如图 2 所示:

  这样的变化增加了 Windows 的安全性,却会导致一个兼容性问题:一些原本为 WindowsXP 设计的需要服务的应用程序,在服务的设计上可能选择使用了交互式方式,当程序移植到 Windows 7 上的时候,由于 Windows 7 系统服务运行在 Session 0,而用户进程则运行在 Session 0 后续的登录会话中,桌面应用程序将无法像 Windows XP 那样与 Windows 服务正常通信了。如图 3 所示:

  一个对象的访问控制列表(Access Control List)是一个 ACE(Access Control Entry)链表。ACE 标示一个托管以及指定允许的访问权限、否定或托管的设计。一个对象的安全描述符号包含两种类型的 ACL:任意访问控制链表(DACL)和系统访问控制链表(SACL)。一个任意访问控制链表标示允许或拒绝访问一个安全对象的托管。当一个进程尝试访问一个安全对象的时候,系统检查对象的 DACL 中的 ACE 来决定是否赋予访问权限。如果对象没有 DACL,系统赋予完全的访问权限,如果对象的 DACL 没有 ACE,那么系统拒绝所有访问对象的尝试,因为 DACL 不允许任何访问权限。系统检查 ACE 序列直到找到一到多个 ACE,或者直到任何请求的访问权限被否定。一个系统访问控制链表是管理员登录尝试访问一个安全对象。每个 ACE 指定一个指定的托管尝试的访问类型,这个访问会导致系统产生一个安全事件日志。Windows 允许修改一个对象的 ACL,通过添加或者删除 ACE 改变 ACL,从而达到修改对该对象的访问控制目的。

Windows 7 高低权限进程通信的实现

  通过以上分析可以看出,Windows 7 为了保证系统的安全性,严格地限制了高低权限进程间的通信。以下就进程是否属于同一个会话给出 Windows 7 高低权限进程通信的方案。

  一、同会话下的高低权限进程通信的实现

  基于 Windows XP 应用程序经常需要互相之间能传递消息,Windows Vista 引入了 Change WindowMessageFilter(UINT message, UINT dwFlag)编程接口,用来添加或删除隔离级别的消息。Windows 7 引入一个新的编程接口 ChangeWindowMessageFilterEx(HWND hWnd, UINT message, DWORD action,PCHANGEFILTERSTRUCT pChangeFilterStruct),事件的参数可以是 MSGFLT_ALLOW、MSGFLT_DISALLOW 和 MSGFLT_RESET,将窗口重设成默认筛选器,可选的架构允许操作结果以接收更多的信息。通过在高权限进程中对指定的某一个低权限进程所创建的窗口进行这样的设置,则低权限进程就可以通过发消息的形式与高权限进程通信了。以下是在 Windows 7 下两个进程通过窗口消息通信的测试结果:

表2 通过窗口消息完成进程通信的测试结果
发送方进程权限接收方进程权限进程通信结果低成功成功成功
失败失败成功
成功中/高 + ChangeWindowMessageFilterEx + MSGFLT_ALLOW成功高 + ChangeWindowMessageFilterEx + MSGFLT_ALLOW 成功

实例验证:

  • VS与Win7共舞:用户界面特权隔离
  • 解决Win7系统下以管理员身份运行的程序接收不到拖放文件消息[WM_DROPFILES]问题的方法

  二、跨会话下的高低权限进程通信的实现

  此处的解决方案是通过在系统服务进程中创建一个命名管道穿透会话的隔离,并创建一个事件内核对象保证管道通信的同步,这样就可以完成在 Windows 7 系统上的跨会话进程通信。不过,在创建事件内核对象时需要注意两点:第一,事件内核对象需要声明在全局的命名空间,即需要 Global 的一个命名限制;第二,由于系统服务创建的全局内核对象具有很高的访问权限,需要在创建内核对象时在其控制访问列表中添加一个能让普通应用程序所属用户访问的授权,在 Windows 安全对象管理中,一个属于 everyone 组里的对象是每一个用户都可以访问的,所以如果创建的内核对象访问控制列表中添加一个所属为 everyone 的分组,那么应用进程就可以访问服务创建的这一内核对象了。

?
以下是通过测试的服务进程关键设计代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
voidABC()
{
    BYTEaclBuffer[1024], sidBuffer[100];
    PACL pacl = (PACL)&aclBuffer;               //声明一个ACL,长度是1024
    PSID psid = (PSID)&sidBuffer;               //声明一个SID,长度是100
 
    SID_NAME_USE snu;
    DWORDsidBufferSize = 100, domainBufferSize = 80;
    TCHARdomainBuffer[80];
 
    SECURITY_DESCRIPTOR sd;                     //声明一个SD
    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
    InitializeAcl(pacl, 1024, ACL_REVISION);
    LookupAccountName(0, _T("everyone"), psid, &sidBufferSize, domainBuffer, &domainBufferSize, &snu);
    AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid);
    SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE);
 
    SECURITY_ATTRIBUTES sa;                     //声明一个SA
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = &sd;              //把SD设置到SA中
    sa.bInheritHandle = FALSE;
 
    HANDLEhShareEvent = CreateEvent(&sa, FALSE, FALSE, _T("Global\\ShareEvent")); //创建事件内核对象保持服务与应用进程的同步
    TCHARbuffer[MAX_PATH] = { 0 };
    DWORDcbBytesRead = 0;
    HANDLEhPipe = CreateNamedPipe(_T("\\\\.\\pipe\\SharePipe"),
                                   PIPE_ACCESS_DUPLEX,
                                   PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                                   PIPE_UNLIMITED_INSTANCES,
                                   MAX_PATH, MAX_PATH,
                                   NMPWAIT_USE_DEFAULT_WAIT, &sa);
 
    while(TRUE)
    {
        ConnectNamedPipe(hPipe, NULL);
        ZeroMemory(buffer, MAX_PATH);
        ReadFile(hPipe, buffer, MAX_PATH, &cbBytesRead, NULL);      //读取管道数据
        Process();                                                  //利用从管道的数据进行需要进行的处理
        WriteFile(hPipe, &bRet, sizeof(bRet), &cbBytesRead, NULL);  //结果返回管道
        SetEvent(hShareEvent);
        DisconnectNamedPipe(hPipe);
    }
}
?
以下是通过测试的应用进程中的关键设计代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
voidCDE()
{
    CHARbuffer[8] = { 0 };
    DWORDcbWritten = 0;
    HANDLEhPipe = NULL, hShareEvent = NULL;
 
    WaitNamedPipe(_T("\\\\.\\pipe\\SharePipe"), NMPWAIT_USE_DEFAULT_WAIT);
 
    hPipe = CreateFile(_T("\\\\.\\pipe\\SharePipe"),
                       GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
                       CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
 
    if(hPipe != INVALID_HANDLE_VALUE)
    {
        WriteFile(hPipe, buffer, 8, &cbWritten, NULL);  //往管道中写数据
 
        hShareEvent = OpenEvent(EVENT_ALL_ACCESS, NULL, _T("Global\\ShareEvent"));
 
        if(hShareEvent != NULL)    //与服务保持同步
        {
            DWORDdwErr = WaitForSingleObject(hShareEvent, 1000 * 60);
 
            if(dwErr == WAIT_OBJECT_0) {
                ReadFile(hPipe, &bResult, sizeof(bResult), &bReaded, NULL); //读取管道数道
            }
 
            CloseHandle(hShareEvent);
        }
 
        CloseHandle(hPipe);
    }
}

关于Win7系统服务的Session 0隔离,可参考:

  • VS与Win7共舞:系统服务的Session 0隔离

结论

  本文给出了在 Windows 7 操作系统上高低权限进程间通信的方案。通过测试表明,在同一会话下两个高低权限窗口进程通信时可以借助 Windows 7 提供的消息过滤函数并加上用户自定义的消息完成从低权限进程到高权限进程的通信;在跨会话下,可以通过命名管道并加上全局命名的内核对象来完成系统服务与应用进程之间的通信。

  总的来讲,以上两种方式达到了 Windows 7 高低权限进程通信的目的。

0 0
原创粉丝点击