NamedPipeClientStream 无法在没有 UAC 的情况下连接

问题描述 投票:0回答:1

我正在编写一个可执行文件,通过

NamedPipe
将数据发送到开放进程(Unity 游戏),以使用自定义 URI 方案“模拟”来自浏览器的深层链接。这意味着管道客户端和管道服务器都只能在 IPC 的本地用户上运行。

游戏开始

NamedPipeServerStream
并等待,直到客户端连接并发送数据:

var pipeSecurity = new PipeSecurity();
SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
pipeSecurity.AddAccessRule(new PipeAccessRule(everyone, PipeAccessRights.Read, AccessControlType.Allow));
                
pipe = new NamedPipeServerStream(PIPE_NAME, PipeDirection.InOut, 1, 
            PipeTransmissionMode.Message, PipeOptions.Asynchronous, 
            8192, 8192, pipeSecurity);

try
{
    await pipe.WaitForConnectionAsync(cancellationTokenSource.Token);
}

我的

Deeplink.exe
(使用 Rider 构建的
WinExe
)在打开并尝试连接时会创建
NamedPipeClientStream

using NamedPipeClientStream pipeClient = new(".", PIPE_NAME, 
            PipeDirection.InOut, PipeOptions.Asynchronous);
try
{
    pipeClient.Connect(PIPE_TIMEOUT);
}

仅当 Deeplink.exe 以管理员身份运行时才能正常工作。 如果不是,pipeClient.Connect

 会抛出 
UnauthorizedAccessException: Access to the path is denied
。
我不能让我的应用程序在每次使用深层链接时都请求 UAC!从 
public mono repo 来看,这似乎与 UnauthorizedAccess_IODenied_NoPathName
 字符串匹配,但我检查过,
PIPE_NAMEs
 是正确的。

起初我以为这是由于

Deeplink.exe

 被放置在 
C:/Program Files
 文件夹下,靠近 Unity 程序的位置,但事实并非如此,即使尝试从桌面运行它,问题仍然存在。我尝试过使用 
PipeAccessRights.FullAccess
 来代替,但也没有运气。

鉴于 UAC 是它工作与不工作之间的唯一区别,我必须假设问题与权限相关(尽管我期望

WorldSid

 允许任何人和任何东西访问管道)。

有什么是我忽略的吗?没有管理员权限真的没有办法连接到管道吗?


更新

为了了解一些上下文,游戏可执行文件首先从

Game Launcher 程序(我也在 Unity 中开发)运行,该程序简单地调用:

Process process = new(); process.StartInfo.FileName = "/path/to/game.exe"; process.StartInfo.UseShellExecute = true; process.StartInfo.CreateNoWindow = false; process.Start();
我发现:

    直接打开
  • Game.exe
    ,然后运行
    Deeplink.exe
    按预期工作
    
  • 打开
  • Launcher.exe
    ,然后启动
    Game.exe
    进程,然后运行
    Deeplink.exe
    不起作用。在此过程中的任何步骤中,UAC 都应该不是 是必需的。
    
对此我还是一脸茫然。我开始假设我的

NamedPipeClientStream

 有问题,但也许以这些特定的 
Game.exe
 属性开始 
StartInfo
 是阻止正确创建 
NamedPipeServerStream
 的原因?


更新2

谜团越来越浓:我尝试用

game.exe

开始
UseShellExecute = false
,现在管道可以正确通信......但只是
有时!它似乎在 75% 的时间内有效。我真的不知道是什么偶尔拒绝我的客户端管道访问,服务器总是根据我的日志启动。

c# .net windows-services named-pipes access-rules
1个回答
0
投票
回答我自己的问题,因为我想我已经找到了为什么会发生这种情况以及如何解决它。

问题似乎是,如果我的启动器以提升的权限打开,那么它运行的任何进程也会继承它们。这意味着我的

NamedPipeServerStream

 有时会在 
提升的权限下运行,但我的 NamedPipeClientStream 始终会在
 没有 
的情况下运行。无论我在创建过程中设置什么访问规则,我的管道客户端总是拒绝连接到它。 由于我不需要

game.exe

来获得提升的访问权限,因此我研究了如何取消提升由提升的子流程启动的子流程,并最终按照

这篇博文
中的建议通过
explorer.exe
. // If the Launcher has UAC, use the explorer to launch the game if (FileUtility.HasElevatedPermissions()) { ProcessStartInfo processInfo = new() { FileName = "explorer.exe", UseShellExecute = true, Arguments = $"\"{exePath}\"" }; Process.Start(processInfo); } // If the Launcher doesn't have UAC, open the game normally else { ProcessStartInfo processInfo = new() { FileName = exePath, UseShellExecute = true, Verb = "open" }; Process.Start(processInfo); }

这似乎可以解决问题,
game.exe

总是在没有权限的情况下打开,并且

deeplinker.exe
管道可以毫无问题地进行通信。 感谢
@Sinatr
@BenVoigt 的建议。

如果有人对
HasElevatedPermissions()

感兴趣,我尝试在

C:/Program Files
下创建一个目录并返回无论成功与否。
public static bool HasElevatedPermissions(string _path = null)
{
    if (string.IsNullOrEmpty(_path))
        _path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
        
    float random = UnityEngine.Random.Range(0f, 1f);
    var path = @$"{_path}\temp{random}"; // Random to prevent user interference
    try
    {
        Directory.CreateDirectory(path);
    }
    catch (UnauthorizedAccessException)
    {
        return false;
    }
    Directory.Delete(path);
    return true;
}

我承认这不是最好的方法,但我找不到任何可以通过 Unity 程序轻松运行的方法。

© www.soinside.com 2019 - 2024. All rights reserved.