如何让应用不受 Windows UIPI 机制影响
前言
关于 UIPI (User Interface Privilege Isolation) ,官方文档 已经给出了详细的描述,该机制阻止某些行为来防止较低权限的进程访问较高权限的进程,以下是官方文档中列出的被阻止的行为
A lower privilege process cannot:
- Perform a window handle validation of higher process privilege.
- SendMessage or PostMessage to higher privilege application windows. These Application Programming Interfaces (APIs) return success but silently drop the window message.
- Use thread hooks to attach to a higher privilege process.
- Use Journal hooks to monitor a higher privilege process.
- Perform DLL injection to a higher privilege process.
解决方案
那我们该如何允许被阻止的行为?
方式一 : UIAccess
做法 : 在应用程序清单文件 app.manifest 中,将 uiAccess 设置为 true (默认值是 false)。同时你还需要给应用程序进行数字签名。
<requestedExecutionLevel level="asInvoker" uiAccess="true" />
影响 :
- 如果你设置了 UIAccess 的应用程序可能会被其它应用启动,那么需要注意其它应用启动该应用时,请明确设置
UseShellExecute = true
, 不然将因为权限问题导致启动失败。
using (Process process = Process.Start(new ProcessStartInfo()
{
UseShellExecute = true,
Arguments = string.Empty,
FileName = "D:\\test.exe",
}))
- 如果你的应用的窗口已经设置了
Topmost = true
,那么 UIAccess 的加入将会使你的窗口层级更高。
方式二 : 更改注册表,Windows 重启后生效(慎重)
在 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
下增加 EnableUIPI
以达到禁用 UIPI 机制的效果,需要注意,一旦这样设置,意味着 Windows UIPI 的约束将不再起作用。
方式三 : 提高进程的完整性级别
从官方文档中,可以看到 Windows 定义了四种完整性级别:low, medium, high, system。那么可以尽量提高进程的完整性级别。(比如,以管理员的方式启动应用)
方式四 : ChangeWindowMessageFilterEx
该 API 能修改指定窗口的 UIPI 消息过滤。比如在如下示例中,进程 A 采用管理员方式启动,考虑到对接的应用完整性级别参差不齐,那么就可以通过 ChangeWindowMessageFilterEx 指定消息过滤,让低完整性级别的进程也能发送消息给到高完整性级别的进程。
public partial class MainWindow : Window //进程 A 代码示例
{
private const int WM_APP = 0x8000;
private const int WM_CUSTOM_MESSAGE = WM_APP + 1;
[DllImport("user32.dll", SetLastError = true)]
static extern bool ChangeWindowMessageFilterEx(IntPtr hwnd, uint msg, uint action, IntPtr pChangeFilterStruct);
private enum MessageFilterAction
{
MSGFLT_ALLOW = 1,
MSGFLT_DISALLOW = 2,
MSGFLT_RESET = 0
}
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
hwndSource.AddHook(WndProc);
ChangeWindowMessageFilterEx(hwndSource.Handle, WM_CUSTOM_MESSAGE, (uint)MessageFilterAction.MSGFLT_ALLOW, IntPtr.Zero);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_CUSTOM_MESSAGE)
{
MessageBox.Show($"Message received.");
handled = true;
}
return IntPtr.Zero;
}
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步