命名管道客户端返回 ACCESS DENIED 但仅在初始成功连接后

问题描述

我有一个管理员身份运行并充当命名管道服务器的 VB.NET 进程(非服务)。 DLL 被注入到某些进程中,并且 DLL 尝试连接到服务器进程。这一切都在同一台主机上。

我收到来自客户端的 ACCESS_DENIED (5) 错误,但仅在前两个客户端成功连接到服务器后才会发生。因此,至少有两个可以成功连接,然后所有其他尝试都被拒绝。

在我的测试 VM 中,至少创建了 4 个管道服务器实例,因此它似乎不是管道繁忙的简单情况(无论如何我假设返回 STATUS_PIPE_BUSY 而不是 ACCESS_DENIED)。我还添加了最宽松的管道安全性 (WorldSid/FullControl),但它仍然失败。

这是服务器管道代码

tidyr::separate

在 DLLMain() 期间,使用以下调用进行连接尝试,这是连接失败并显示 ACCESS_DENIED 的地方。

Private Sub PipeSetup() 
    For x = 1 To Environment.ProcessorCount  '4 in my test VM 
        t = New Thread(AddressOf PipeSetupProc)
        t.IsBackground = True
        t.Start()
    Next
End Sub

Private Sub PipeSetupProc() 
    Dim s As NamedPipeServerStream = nothing
    Dim x As PipeSecurity = nothing

    While True
        Try
            'I've made the access rule the most permissive possible
            'and I'm still getting ACCESS_DENIED from the client.

            x = New PipeSecurity()
            x.AddAccessRule(New PipeAccessRule(New SecurityIdentifier(WellKNownSidType.WorldSid,nothing),PipeAccessRights.FullControl,Security.AccessControl.AccessControlType.Allow))

            s = New NamedPipeServerStream(MY_PIPE_NAME,PipeDirection.InOut,NamedPipeServerStream.MaxAllowedServerInstances,PipeTransmissionMode.Message,PipeOptions.Asynchronous,4096,x)
            s.WaitForConnection()

            'Do stuff here...

            s.Close()
            s = nothing
        Catch ex As Exception
           'logerror()
        End Try
    End While
End Sub

解决方法

检查两边的 MY_PIPE_NAME。对于 C++,它应该类似于“\\.\pipe\MY_PIPE”,而在 vb 方面,它只是“MY_PIPE”。

如果数据总是从 vb 到 dll,你可以在 c++ 中声明一个函数从 vb 调用(在'extern "c"' 内)。

_stdcall int Send2Cpp(char * msg,int length){ /*...*/}

我习惯于在 module.def 中定义我的导出。如果没有,请添加 nessasary dll 导出条款。否则,将文件 module.def 添加到您的 vs c++ 项目中,内容

LIBRARY
    EXPORTS
        Send2Cpp

然后从vb中,添加

Public Declare Function Send2Cpp Lib "mydll.dll" (byval S as byte,byval L as integer) as integer

您也可以从 vb 提供回调。

Public Delegate Function GetCppString(ByVal str As IntPtr)
Function LogC(ByVal LI As IntPtr,ByVal lc As Int64) As Int64
        Dim F(lc) As Byte
        Marshal.Copy(LI,F,lc)
        Debug.Print(System.Text.Encoding.ASCII.GetString(F))
End Function
'make sure these vars persist untill dll is done with pointer
'or you will get errors when they are GC'd
dim CBD as GetCppString=AddressOf(GetCppString)
dim CB_PTR as IntPtr = Marshal.GetFunctionPointerForDelegate(CBD)

然后你将 CB_PTR 传递给一个 dll 函数,在那里你可以从他们那里调用这个函数。在 C++ 中

typedef int(*send2vb)(char *,int);
void RegCB(send2vb f){ /*do something with function pointer*/}

在这种情况下,将 RegCB 添加到您的 module.def 并在 vb 中为其声明。 然后你有 dll 和 vb 之间的双向通信。 (当然,您必须将它们全部连接在一起。在您的 dllmain 中,只需在发送数据之前等待函数指针为非空即可。 附注我只是提到了这一点,因为事实证明它比管道或类似的东西更有效,特别是如果您使用与您的用例相匹配的函数(在我的情况下,它是从 c++ dll 到 vb 和返回的视频)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...