现在,我们可以调用ShellExecute,以不同的特权等级运行这个应用程序,他们虽然处于不同的特权等级,但是由于我们使用ChangeWindowMessageFilter将自定义的消息添加进了白名单,他们都可以处理这个自定义的消息了。
// 应用程序名称
LPCTSTR exeName = _T("UIPIDemo.exe");
// 以不同的特权等级运行同一个应用程序
// 更高权限
HINSTANCE h1 = ShellExecute(NULL, _T("runas"), exeName, NULL, NULL, SW_SHOWDEFAULT);
// 中等权限
HINSTANCE h2 = ShellExecute(NULL, _T("open"), exeName, NULL, NULL, SW_SHOWDEFAULT);
LPCTSTR exeName = _T("UIPIDemo.exe");
// 以不同的特权等级运行同一个应用程序
// 更高权限
HINSTANCE h1 = ShellExecute(NULL, _T("runas"), exeName, NULL, NULL, SW_SHOWDEFAULT);
// 中等权限
HINSTANCE h2 = ShellExecute(NULL, _T("open"), exeName, NULL, NULL, SW_SHOWDEFAULT);
在Windows 7中,为了更加灵活地控制消息的传入,它引入了一个新的函数ChangeWindowMessageFilterEx,这个新的扩展函数可以为某个特定的窗口制定消息白名单,而不是像ChangeWindowMessageFilter一样为整个进程制定白名单。
// Windows 7新引入的函数
BOOL ChangeWindowMessageFilterEx(
HWND hWnd, UINT message, DWORD action,
PCHANGEFILTERSTRUCT pChangeFilterStruct
);
BOOL ChangeWindowMessageFilterEx(
HWND hWnd, UINT message, DWORD action,
PCHANGEFILTERSTRUCT pChangeFilterStruct
);
在这个函数中,参数action表示这个函数的动作,它可以是MSGFLT_ALLOW (类似于 MSGFLT_ADD),MSGFLT_DISALLOW (类似于 MSGFLT_REMOVE), 和 MSGFLT_RESET,表示将窗口设置为它的默认过滤器。
托管代码中绕过UIPI
以上的例子演示了在非托管代码中调用ChangeWindowMessageFilter实现消息过滤白名单,允许消息通过用户界面特权隔离的过程。在托管代码中,我们还是使用这个API函数。为了便于使用,我们对这个API函数做一些包装。在托管代码中,我们用一个类来封装所有我们所需要的API函数:
// 用类封装对API函数的调用
internal static class NativeWrappers {
[DllImport("user32")]
public static extern uint RegisterWindowMessage(string msg);
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hWnd,
uint msg, IntPtr wParam, IntPtr lParam);
public enum ChangeWindowMessageFilterFlags : uint {
Add = 1, Remove = 2
};
[DllImport("user32")]
public static extern bool ChangeWindowMessageFilter(uint msg,
ChangeWindowMessageFilterFlags flags);
}
internal static class NativeWrappers {
[DllImport("user32")]
public static extern uint RegisterWindowMessage(string msg);
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hWnd,
uint msg, IntPtr wParam, IntPtr lParam);
public enum ChangeWindowMessageFilterFlags : uint {
Add = 1, Remove = 2
};
[DllImport("user32")]
public static extern bool ChangeWindowMessageFilter(uint msg,
ChangeWindowMessageFilterFlags flags);
}
完成API的封装后,我们就可以在主程序中直接使用这个类,完成进程消息过滤器白名单的设置。
public PingPongForm() {
InitializeComponent();
// 注册消息
_message = NativeWrappers.RegisterWindowMessage("BALL");
if(_message == 0)
Close();
else {
// 添加可以通过的消息
NativeWrappers.ChangeWindowMessageFilter(_message,
NativeWrappers.ChangeWindowMessageFilterFlags.Add);
// 发送消息
NativeWrappers.PostMessage(Program.hOtherForm,
_message, Handle, IntPtr.Zero);
}
}
InitializeComponent();
// 注册消息
_message = NativeWrappers.RegisterWindowMessage("BALL");
if(_message == 0)
Close();
else {
// 添加可以通过的消息
NativeWrappers.ChangeWindowMessageFilter(_message,
NativeWrappers.ChangeWindowMessageFilterFlags.Add);
// 发送消息
NativeWrappers.PostMessage(Program.hOtherForm,
_message, Handle, IntPtr.Zero);
}
}
用户特权等级隔离,就像进程窗口的门神,把不受欢迎的Windows消息隔离在外,把列在客人名单上的Windows消息请进来。门神守候,家宅无忧!
图3 门神守候,家宅无忧
系列文章索引: