You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何WebView2控件在UAC提权应用中支持拖放?能否复刻该行为?

WebView2的UIPI拖放绕过机制及普通控件的复刻方案

一、WebView2如何绕过UIPI限制实现拖放

WebView2的核心突破点在于其多进程架构设计:

  • 当宿主应用以管理员权限(高完整性级别)运行时,WebView2的渲染进程仍保持在中等完整性级别(与普通权限应用处于同一级别)。
  • 拖放操作依赖OLE消息交互,由于普通应用与WebView2渲染进程的完整性级别一致,UIPI不会拦截它们之间的拖放消息。
  • 渲染进程接收到拖放数据后,通过WebView2内置的受控跨进程通信(IPC)通道将数据传递给高权限宿主进程,这一交互不受UIPI限制,属于系统允许的进程间合法通信。

二、为普通控件(如TextBox)复刻该行为

要让高权限窗口中的普通控件接受普通权限应用的拖放,需模拟WebView2的多进程思路,核心步骤如下:

1. 创建中等完整性级别的辅助进程

该进程负责直接接收拖放操作(与普通应用同级别,UIPI不限制),再将数据传递给高权限主进程。

辅助进程代码(WinForms示例)

using System;
using System.Windows.Forms;
using System.IO.Pipes;
using System.Text;

namespace DragDropHelper
{
    public partial class HelperForm : Form
    {
        private NamedPipeClientStream _pipeClient;

        public HelperForm()
        {
            InitializeComponent();
            AllowDrop = true;
            DragEnter += HelperForm_DragEnter;
            DragDrop += HelperForm_DragDrop;

            // 连接到主进程的命名管道
            _pipeClient = new NamedPipeClientStream(".", "ElevatedDragDropPipe", PipeDirection.Out);
            _pipeClient.Connect();
        }

        private void HelperForm_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
        }

        private void HelperForm_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                string data = string.Join("|", files);
                
                // 通过管道发送数据到主进程
                byte[] buffer = Encoding.UTF8.GetBytes(data);
                _pipeClient.Write(buffer, 0, buffer.Length);
            }
        }
    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.Run(new HelperForm());
        }
    }
}

2. 高权限主进程实现

主进程需创建命名管道监听辅助进程的消息,并将接收到的拖放数据同步到目标控件(如TextBox),同时确保辅助进程以中等完整性级别启动。

主进程代码(WinForms示例)

using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO.Pipes;
using System.Text;
using System.Security.AccessControl;
using System.Security.Principal;

namespace ElevatedDragDropDemo
{
    public partial class MainForm : Form
    {
        private NamedPipeServerStream _pipeServer;
        private Process _helperProcess;

        public MainForm()
        {
            InitializeComponent();
            StartHelperProcess();
            StartPipeListener();
        }

        private void StartHelperProcess()
        {
            // 启动辅助进程,强制以中等完整性级别运行
            ProcessStartInfo psi = new ProcessStartInfo(@"DragDropHelper.exe");
            psi.Verb = "open"; // 避免继承主进程的管理员权限
            psi.UseShellExecute = true;
            _helperProcess = Process.Start(psi);
        }

        private void StartPipeListener()
        {
            // 配置管道权限,允许中等完整性进程访问
            PipeSecurity pipeSecurity = new PipeSecurity();
            pipeSecurity.AddAccessRule(new PipeAccessRule(
                new SecurityIdentifier(WellKnownSidType.AuthenticatedUsersSid, null),
                PipeAccessRights.ReadWrite,
                AccessControlType.Allow
            ));
            
            _pipeServer = new NamedPipeServerStream(
                "ElevatedDragDropPipe", 
                PipeDirection.In, 
                1, 
                PipeTransmissionMode.Byte, 
                PipeOptions.Asynchronous, 
                4096, 
                4096, 
                pipeSecurity
            );
            _pipeServer.BeginWaitForConnection(OnPipeConnected, null);
        }

        private void OnPipeConnected(IAsyncResult ar)
        {
            try
            {
                _pipeServer.EndWaitForConnection(ar);
                
                // 读取辅助进程发送的拖放数据
                byte[] buffer = new byte[4096];
                int bytesRead = _pipeServer.Read(buffer, 0, buffer.Length);
                string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                string[] files = data.Split('|');
                
                // 跨线程更新TextBox内容
                Invoke(new Action(() =>
                {
                    textBox1.Text = string.Join(Environment.NewLine, files);
                }));
                
                // 重置管道监听状态
                _pipeServer.Disconnect();
                _pipeServer.BeginWaitForConnection(OnPipeConnected, null);
            }
            catch (Exception)
            {
                // 处理辅助进程退出等异常情况
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            _helperProcess?.Kill();
            _pipeServer?.Dispose();
            base.OnFormClosing(e);
        }
    }
}

3. 关键注意事项

  • 完整性级别控制:辅助进程必须运行在中等完整性级别,通过设置UseShellExecute = true和Verb = "open"可避免继承主进程的高权限。
  • 管道权限配置:必须为命名管道添加允许Authenticated Users访问的规则,否则辅助进程无法建立连接。
  • UI线程安全:主进程从管道读取数据后,需通过Invoke方法跨线程更新UI控件,避免线程异常。

内容的提问来源于stack exchange,提问作者FaniX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 06:04:54