Windows进程间消息通信

Windows改进的安全机制

操作系统服务通过系统的Session 0隔离,Windows 实现了各个Session之间的独立,和更加安全的互访,使得操作系统的安全性,有了较大的提高。从操作系统服务的Session 0隔离,尝到了甜头后,微软的程序员们爱上了“隔离”。现在,他们又将隔离引入了同一个Session中的各个进程之间,带来全新的:用户界面特权隔离UIPI。

用户界面特权隔离

在早期的Windows操作系统中,在同一用户下,运行的所有进程,有着相同的安全等级,拥有相同的权限。例如,一个进程可以自由地,发送一个Windows消息到另一个进程的窗口。而从Windows Vista,Windows 7开始,对于某些Windows消息,这一方式再也行不通了。进程开始拥有一个新的属性——特权等级(Privilege Level)。一个特权等级较低的进程,不可以向一个特权等级较高的进程发送消息,虽然他们在相同的用户权限下运行。这就是所谓的用户界面特权隔离(User Interface Privilege Isolation ,UIPI)。

UIPI的引入,最大的目的是防止恶意代码发送消息,给那些拥有较高权限的窗口,以对其进行攻击,从而获取较高的权限等等。这就像一个国家,原本人人平等,大家可以互相交流问候,但是后来坏人多了,为了防止坏人,就人为地给每个人划分等级,等级低的不可以跟等级高的说话交流。在人类社会,这是一种令人讨厌的等级制度,但是在计算机系统中,这却是一种维护系统安全的合适方式。
 

UIPI的运行机制

UIPI的等级划分为低等级(low),普通(normal),高等级(high),系统(system)。

在Windows 7中,当UAC(User Account Control)启用的时候,UIPI的运行可以得到最明显的体现。在UAC中,当一个管理员用户登录系统后,操作系统会创建两个令牌对象(Token Object):第一个是管理员令牌,拥有大多数特权(类似于Windows Vista之前的System用户),而第二个是一个过滤后的简化版本令牌,只拥有普通用户的权限。

默认情况下,以普通用户权限启动的进程,拥有普通等级特权。以管理员权限运行的进程,例如,用户右键单击选择“以管理员身份运行”或者是通过添加“runas”参数调用ShellExecute运行的进程,这样的进程就拥有一个较高(high)的特权等级。

从技术上讲在同一用户下,系统可以运行两种不同特权等级的进程。我们可以使用Windows Sysinternals工具集中的进程浏览器(Process Explorer)查看各个进程的特权等级。 

UIPI所带来的限制

当你发现你的进程之间Windows消息通信发生问题时,不妨使用进程浏览器查看一下两个进程之间是否有合适的特权等级。

等级的划分,是为了防止以下犯上。

有了用户界面特权隔离,一个运行在较低特权等级的应用程序,它的行为就受到了诸多限制,它不可以:

  • 验证由较高特权等级进程创建的窗口句柄
  • 通过调用SendMessage和PostMessage向由较高特权等级进程创建的窗口发送Windows消息
  • 使用线程钩子处理较高特权等级进程
  • 使用普通钩子(SetWindowsHookEx)监视较高特权等级进程
  • 向一个较高特权等级进程执行DLL注入

但是,一些特殊Windows消息是容许的。因为这些消息对进程的安全性没有太大影响。这些Windows消息包括:

  0x000 - WM_NULL
  0x003 - WM_MOVE
  0x005 - WM_SIZE
  0x00D - WM_GETTEXT
  0x00E - WM_GETTEXTLENGTH
  0x033 - WM_GETHOTKEY
  0x07F - WM_GETICON
  0x305 - WM_RENDERFORMAT
  0x308 - WM_DRAWCLIPBOARD
  0x30D - WM_CHANGECBCHAIN
  0x31A - WM_THEMECHANGED
  0x313, 0x31B (WM_???)

修复UIPI问题

因为UIPI机制,这种消息传递被阻断了。
希望Windows消息能够在进程之间自由的传递,Windows引入了一个新的API函数ChangeWindowMessageFilter。

用这个函数,我们可以添加或者删除特权等级隔离的Windows消息。高特权等级的进程设置了一个过滤器,允许通过的Windows消息都被添加到这个过滤器的白名单,只有在这个白名单上的消息才允许传递进来。如果我们想容许一个消息可以发送给较高特权等级的进程,我们可以在较高特权等级的进程中调用ChangeWindowMessageFilter函数,以MSGFLT_ADD作为参数,将消息添加进消息过滤器的白名单。同样的,我们也可以以MSGFLT_REMOVE作为参数,将这个消息从白名单中删除。

消息的发送包括:系统消息的发送和用户自定义消息的发送。

ChangeWindowMessageFilterEx 函数

ChangeWindowMessageFilterEx 函数,指定窗口修改用户界面特权隔离 (UIPI) 消息过滤器。

函数原型:

BOOL WINAPI ChangeWindowMessageFilterEx(
  __in HWND hWnd,
  __in UINT message,
  __in DWORD action,
  __inout_opt PCHANGEFILTERSTRUCT pChangeFilterStruct
  );


【参数】
hWnd
要修改其 UIPI 消息过滤器的窗口句柄。
message
要允许或阻止通过消息过滤器的消息。
action
要执行的操作,可以采取下列值之一:
MSGFLT_ALLOW :允许消息通过过滤器。允许窗口接收该消息,不管源消息是什么,甚至它来自一个低特权的进程。
MSGFLT_DISALLOW :如果消息来自低特权的进程,阻止它转递给窗口。
MSGFLT_RESET :为窗口重置消息过滤器为默认,任何全局允许消息或进程范围内的将通过。但不包含这两个类别,其中其中来自低特权的进程将被阻塞。
pChangeFilterStruct
指向CHANGEFILTERSTRUCT结构指针的可选项。


【返回值】
如果函数成功,则返回值为非零值。
如果该函数失败,则返回值为零。要获取扩展的错误的信息,请调用GetLastError 。

对于系统消息的处理,非常简单,接受消息的进程需要将该消息加入到白名单中,可以通过下面的代码实现:
需要在高权限程序开始的地方加入以下代码,指定什么消息可以接受


eg:
//设置高权限程序的消息过滤白名单
BOOL bRes = ChangeWindowMessageFilterEx(m_hWnd, WM_COPYDATA, MSGFLT_ALLOW, NULL);


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

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

猜你喜欢

转载自blog.csdn.net/panjunnn/article/details/110656759