命名管道客户端无法将数据发送到服务器:"Stream was not writable"

Named pipe client failed to send data to server: "Stream was not writable"

我在 C++ 中创建了一个类似 \.\pipe\mypipe 的命名管道服务器,我正在尝试使用 PowerShell 连接它。
我成功连接,但我想向它发送一些数据,这就是它在 PowerShell 中引发错误的地方:

PS > $pipe = New-Object System.IO.Pipes.NamedPipeClientStream '.','mypipe','In'
PS > $pipe.Connect()
PS > $sw = New-Object System.IO.StreamWriter $pipe
New-Object : Exception calling ".ctor" with "1" argument(s): "Stream was not writable."
At line:1 char:7
+ $sw = New-Object System.IO.StreamWriter $pipe
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

“流不可写”是什么意思?我将服务器上的权限设置为所有人,所以我认为这不应该是权限问题。

我的命名管道服务器:

    DWORD dwRes, dwDisposition;
    PSID pEveryoneSID = NULL, pAdminSID = NULL;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea[2];
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
        SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    SECURITY_ATTRIBUTES sa;
    LONG lRes;
    HKEY hkSub = NULL;
 
    // Create a well-known SID for the Everyone group.
    if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
        SECURITY_WORLD_RID,
        0, 0, 0, 0, 0, 0, 0,
        &pEveryoneSID))
    {
        ..
    }
 
    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow Everyone read access to the key.
    ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
    //ea[0].grfAccessPermissions = KEY_READ;
    ea[0].grfAccessPermissions = GENERIC_READ | FILE_WRITE_DATA;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
 
    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes)
    {
        ...
    }
 
    // Initialize a security descriptor.  
    pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
        SECURITY_DESCRIPTOR_MIN_LENGTH);
    if (NULL == pSD)
    {
        ...
    }
 
    if (!InitializeSecurityDescriptor(pSD,
        SECURITY_DESCRIPTOR_REVISION))
    {
 
        ...
    }
 
 
    // Add the ACL to the security descriptor. 
    if (!SetSecurityDescriptorDacl(pSD,
        TRUE,     // bDaclPresent flag   
        pACL,
        //NULL,
        FALSE))   // not a default DACL 
    {
 
        ...
    }
 
    SECURITY_ATTRIBUTES SecurityAttrs = {
        sizeof(SECURITY_ATTRIBUTES),
        NULL,                               // assigned access token of calling process
        FALSE
    };
 
    DWORD openMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_OWNER;
    DWORD pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
 
    std::cout << "[+] Creating pipe server\n";
    for (;;) {
        // create the named pipe
        HANDLE pipe = NULL;
 
        DWORD msgSize = 1024;
        pipe = CreateNamedPipeA(
            "\\.\pipe\mypipe",
            openMode,
            pipeMode,
            2,              // max instances
            msgSize,        // out buffer size
            msgSize,        // in buffer size
            0,              // timeout. 0 ~= 50ms
            &SecurityAttrs);
 
        if (pipe == INVALID_HANDLE_VALUE) {
            DWORD err = GetLastError();
            std::cout << "[!] Pipe creation failed! " << err << std::endl;
            return err;
        }
 
        // wait for docker to connect to the client
        std::cout << "[+] Waiting for docker to connect\n";
        bool connected = ConnectNamedPipe(pipe, NULL) ? true : (
            GetLastError() == ERROR_PIPE_CONNECTED);
        if (!connected)
            continue;
        std::cout << "[+] Client connected\n";
 
        // read byte from pipe
        char buf[1024];
        DWORD bytesread = 0;
        bool status = ReadFile(
            pipe,
            &buf,
            msgSize,
            &bytesread,
            NULL);
 ...

您的方向是反的 - In 表示“仅接收”(或 只读)。

对于双向管道(这是 PIPE_ACCESS_DUPLEX 在服务器端指定的),使用 InOut:

$pipe = [System.IO.Pipes.NamedPipeClientStream]::new('.', 'mypipe', 'InOut')

生成的流对象现在应该是可读可写的