在 Windows 中枚举命名管道

发布于 2024-07-12 08:58:51 字数 607 浏览 5 评论 0原文

我在连接到命名管道时遇到问题(在本例中是快速 cgi 命名管道) 根据 MSDN,我应该使用 CreateFile() 或 CallNamedPipe() (扁平 C API,同步 - 无重叠 I/O) http://msdn.microsoft.com/en-us/ library/aa363858(VS.85).aspx

但我收到 INVALID_HANDLE_VALUE ,当我 GetLastError() 时它为零!?

我还想知道是否可以使用某种 . 调用枚举所有命名管道,然后解析出我正在寻找的管道: “\.\pipe\FastCGI\”

并且有人有这些评论的经验吗: http://blade.nagaokaut.ac.jp /cgi-bin/scat.rb/ruby/ruby-talk/225878

I am having trouble connecting to a Named Pipe (in this case a fast cgi named pipe)
According to MSDN, I should be using CreateFile() or CallNamedPipe()
(flat C API, synchronous - no overlapped I/O)
http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx

Yet I am getting INVALID_HANDLE_VALUE and when I GetLastError() it is zero!?

I am also wondering if I can just enumerate all the named pipes with a . call of some sort and then parse out the one I am looking for:
"\.\pipe\FastCGI\"

and does anyone have experience with these comments:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/225878

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

蹲墙角沉默 2024-07-19 08:58:51

问题出在这里:


    TmpInfo = DirInfo;   
    while(1)   
    {   
       if(TmpInfo->NextEntryOffset==0)   
         break;   

       TmpInfo->FileDirectoryInformationClass.FileName[TmpInfo->FileNameLength/sizeof(WCHAR)] = NULL;   

       wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,   
                                TmpInfo->EndOfFile.LowPart,   
                                TmpInfo->AllocationSize.LowPart );   

       TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);   
    }   

在“while(1)”之后,您检查 NextEntryOffset == 0
这意味着最后一个条目永远不会被报告,请移动“if(...)break;” 在“wprintf(...)”调用之后,您应该能够枚举所有管道。

编辑

对于那些想要完整源代码(不需要 DDK)的人来说,这里就是。 请注意,这不是我的代码,是在 此处。 此代码与原始代码之间的唯一变化是修复了上述错误。

编辑 v2.0
在下面的代码中发现了另一个错误。 当它打印有关正在迭代的当前项目的信息时,它会在名称末尾放置一个空字符。 这个空字符实际上覆盖了下一个条目的前 2 个字节,这恰好覆盖了该条目中“NextEntryOffset”变量的 2 个最低有效字节(通常导致它等于 0),因此只有前 2 个项目是每个从每个“NtQueryDirectoryFile”调用中枚举。

我在下面的代码中添加了一个修复程序,应该可以解决这个问题(存储被清除的 WCHAR,然后在打印后恢复它。有点黑客,但这只是一些示例代码,为了正确实现,要么避免使用 wprintf打印名称,或将其复制到另一个缓冲区,您可以安全地将其末尾设为 NULL)。



// pipelist.cpp (Windows NT/2000)   
//   
// This example will show how you can enumerate all named pipes   
// active on a system.   
//   
// (c)2000 Ashot Oganesyan K, SmartLine, Inc   
// mailto:[email protected], http://www.protect-me.com, http://www.codepile.com   

#include <windows.h>   
#include <stdio.h>  

#define FileDirectoryInformation 1   
#define STATUS_NO_MORE_FILES 0x80000006L   

typedef struct   
{   
    USHORT Length;   
    USHORT MaximumLength;   
    PWSTR  Buffer;   
} UNICODE_STRING, *PUNICODE_STRING;   

typedef struct   
{   
    LONG Status;   
    ULONG Information;   
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;   

typedef struct {   
    ULONG NextEntryOffset;   
    ULONG FileIndex;   
    LARGE_INTEGER CreationTime;   
    LARGE_INTEGER LastAccessTime;   
    LARGE_INTEGER LastWriteTime;   
    LARGE_INTEGER ChangeTime;   
    LARGE_INTEGER EndOfFile;   
    LARGE_INTEGER AllocationSize;   
    ULONG FileAttributes;   
    ULONG FileNameLength;   
    union {   
        struct {   
            WCHAR FileName[1];   
        } FileDirectoryInformationClass;   

        struct {   
            DWORD dwUknown1;   
            WCHAR FileName[1];   
        } FileFullDirectoryInformationClass;   

        struct {   
            DWORD dwUknown2;   
            USHORT AltFileNameLen;   
            WCHAR AltFileName[12];   
            WCHAR FileName[1];   
    } FileBothDirectoryInformationClass;   
    };   
} FILE_QUERY_DIRECTORY, *PFILE_QUERY_DIRECTORY;   


// ntdll!NtQueryDirectoryFile (NT specific!)   
//   
// The function searches a directory for a file whose name and attributes   
// match those specified in the function call.   
//   
// NTSYSAPI   
// NTSTATUS   
// NTAPI   
// NtQueryDirectoryFile(   
//    IN HANDLE FileHandle,                      // handle to the file   
//    IN HANDLE EventHandle OPTIONAL,   
//    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,   
//    IN PVOID ApcContext OPTIONAL,   
//    OUT PIO_STATUS_BLOCK IoStatusBlock,   
//    OUT PVOID Buffer,                          // pointer to the buffer to receive the result   
//    IN ULONG BufferLength,                     // length of Buffer   
//    IN FILE_INFORMATION_CLASS InformationClass,// information type   
//    IN BOOLEAN ReturnByOne,                    // each call returns info for only one file   
//    IN PUNICODE_STRING FileTemplate OPTIONAL,  // template for search   
//    IN BOOLEAN Reset                           // restart search   
// );   
typedef LONG (WINAPI *PROCNTQDF)( HANDLE,HANDLE,PVOID,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,   
                                  UINT,BOOL,PUNICODE_STRING,BOOL );   

PROCNTQDF NtQueryDirectoryFile;   

void main(void)   
{   
    LONG ntStatus;   
    IO_STATUS_BLOCK IoStatus;   
    HANDLE hPipe;   
    BOOL bReset = TRUE;   
    PFILE_QUERY_DIRECTORY DirInfo,   
                          TmpInfo;   


    NtQueryDirectoryFile = (PROCNTQDF)GetProcAddress(   
                                      GetModuleHandle("ntdll"),   
                                      "NtQueryDirectoryFile"   
                                      );   

    if (!NtQueryDirectoryFile)   
       return;   

    hPipe = CreateFile("\\\\.\\Pipe\\",GENERIC_READ,   
                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,   
                       NULL,OPEN_EXISTING,0,NULL);   

   if(hPipe == INVALID_HANDLE_VALUE)   
     return;   

   DirInfo = (PFILE_QUERY_DIRECTORY) new BYTE[1024];   

   printf("Pipe name (Number of instances, Maximum instances)\n\n");   
   while(1)   
   {   
       ntStatus = NtQueryDirectoryFile(hPipe,NULL,NULL,NULL,&IoStatus,DirInfo,1024,   
                                       FileDirectoryInformation,FALSE,NULL,bReset);   

       if (ntStatus!=NO_ERROR)   
       {   
          if (ntStatus == STATUS_NO_MORE_FILES)   
             break;   

          return;   
       }   

       TmpInfo = DirInfo;   
       while(1)   
       {
          // Store old values before we mangle the buffer
          const int endStringAt = TmpInfo->FileNameLength/sizeof(WCHAR);
          const WCHAR oldValue = TmpInfo->FileDirectoryInformationClass.FileName[endStringAt];

          // Place a null character at the end of the string so wprintf doesn't read past the end
          TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = NULL;   

          wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,   
                                   TmpInfo->EndOfFile.LowPart,   
                                   TmpInfo->AllocationSize.LowPart );   

          // Restore the buffer to its correct state
          TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = oldValue;

          if(TmpInfo->NextEntryOffset==0)   
            break;   

          TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);   
       }   

       bReset = FALSE;   
   }   

   delete DirInfo;   
   CloseHandle(hPipe);   
}   

problem lies in here:


    TmpInfo = DirInfo;   
    while(1)   
    {   
       if(TmpInfo->NextEntryOffset==0)   
         break;   

       TmpInfo->FileDirectoryInformationClass.FileName[TmpInfo->FileNameLength/sizeof(WCHAR)] = NULL;   

       wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,   
                                TmpInfo->EndOfFile.LowPart,   
                                TmpInfo->AllocationSize.LowPart );   

       TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);   
    }   

just after the "while(1)" you check if the NextEntryOffset == 0
this means that the last entry never gets reported, move the "if(...) break;" to after the "wprintf(...)" call and you should be able to enumerate all of the pipes.



EDIT

For those of you who would like the full source code (without requiring the DDK) here it is. Please not that this is not my code and was found here. The only change between this code and the original is the bug fix as detailed above.



EDIT v2.0

Found another bug in the code below. As it goes to print information about the current item it is iterating through, it places a null character at the end of the name. This null character actually overwrites the first 2 bytes of the next entry, which just happens to overwrite the 2 least significant bytes of the 'NextEntryOffset' variable in that entry (usually resulting making it equal 0), hence only the first 2 items are every enumerated from each 'NtQueryDirectoryFile' call.



I have added a fix to the code below that should resolve this issue (store the WCHAR being cleared and then restoring it after printing. Bit of a hack, but this is just some example code, for a proper implementation, either avoid using wprintf to print the name, or copy it to another buffer that you can safely NULL the end of).



// pipelist.cpp (Windows NT/2000)   
//   
// This example will show how you can enumerate all named pipes   
// active on a system.   
//   
// (c)2000 Ashot Oganesyan K, SmartLine, Inc   
// mailto:[email protected], http://www.protect-me.com, http://www.codepile.com   

#include <windows.h>   
#include <stdio.h>  

#define FileDirectoryInformation 1   
#define STATUS_NO_MORE_FILES 0x80000006L   

typedef struct   
{   
    USHORT Length;   
    USHORT MaximumLength;   
    PWSTR  Buffer;   
} UNICODE_STRING, *PUNICODE_STRING;   

typedef struct   
{   
    LONG Status;   
    ULONG Information;   
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;   

typedef struct {   
    ULONG NextEntryOffset;   
    ULONG FileIndex;   
    LARGE_INTEGER CreationTime;   
    LARGE_INTEGER LastAccessTime;   
    LARGE_INTEGER LastWriteTime;   
    LARGE_INTEGER ChangeTime;   
    LARGE_INTEGER EndOfFile;   
    LARGE_INTEGER AllocationSize;   
    ULONG FileAttributes;   
    ULONG FileNameLength;   
    union {   
        struct {   
            WCHAR FileName[1];   
        } FileDirectoryInformationClass;   

        struct {   
            DWORD dwUknown1;   
            WCHAR FileName[1];   
        } FileFullDirectoryInformationClass;   

        struct {   
            DWORD dwUknown2;   
            USHORT AltFileNameLen;   
            WCHAR AltFileName[12];   
            WCHAR FileName[1];   
    } FileBothDirectoryInformationClass;   
    };   
} FILE_QUERY_DIRECTORY, *PFILE_QUERY_DIRECTORY;   


// ntdll!NtQueryDirectoryFile (NT specific!)   
//   
// The function searches a directory for a file whose name and attributes   
// match those specified in the function call.   
//   
// NTSYSAPI   
// NTSTATUS   
// NTAPI   
// NtQueryDirectoryFile(   
//    IN HANDLE FileHandle,                      // handle to the file   
//    IN HANDLE EventHandle OPTIONAL,   
//    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,   
//    IN PVOID ApcContext OPTIONAL,   
//    OUT PIO_STATUS_BLOCK IoStatusBlock,   
//    OUT PVOID Buffer,                          // pointer to the buffer to receive the result   
//    IN ULONG BufferLength,                     // length of Buffer   
//    IN FILE_INFORMATION_CLASS InformationClass,// information type   
//    IN BOOLEAN ReturnByOne,                    // each call returns info for only one file   
//    IN PUNICODE_STRING FileTemplate OPTIONAL,  // template for search   
//    IN BOOLEAN Reset                           // restart search   
// );   
typedef LONG (WINAPI *PROCNTQDF)( HANDLE,HANDLE,PVOID,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,   
                                  UINT,BOOL,PUNICODE_STRING,BOOL );   

PROCNTQDF NtQueryDirectoryFile;   

void main(void)   
{   
    LONG ntStatus;   
    IO_STATUS_BLOCK IoStatus;   
    HANDLE hPipe;   
    BOOL bReset = TRUE;   
    PFILE_QUERY_DIRECTORY DirInfo,   
                          TmpInfo;   


    NtQueryDirectoryFile = (PROCNTQDF)GetProcAddress(   
                                      GetModuleHandle("ntdll"),   
                                      "NtQueryDirectoryFile"   
                                      );   

    if (!NtQueryDirectoryFile)   
       return;   

    hPipe = CreateFile("\\\\.\\Pipe\\",GENERIC_READ,   
                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,   
                       NULL,OPEN_EXISTING,0,NULL);   

   if(hPipe == INVALID_HANDLE_VALUE)   
     return;   

   DirInfo = (PFILE_QUERY_DIRECTORY) new BYTE[1024];   

   printf("Pipe name (Number of instances, Maximum instances)\n\n");   
   while(1)   
   {   
       ntStatus = NtQueryDirectoryFile(hPipe,NULL,NULL,NULL,&IoStatus,DirInfo,1024,   
                                       FileDirectoryInformation,FALSE,NULL,bReset);   

       if (ntStatus!=NO_ERROR)   
       {   
          if (ntStatus == STATUS_NO_MORE_FILES)   
             break;   

          return;   
       }   

       TmpInfo = DirInfo;   
       while(1)   
       {
          // Store old values before we mangle the buffer
          const int endStringAt = TmpInfo->FileNameLength/sizeof(WCHAR);
          const WCHAR oldValue = TmpInfo->FileDirectoryInformationClass.FileName[endStringAt];

          // Place a null character at the end of the string so wprintf doesn't read past the end
          TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = NULL;   

          wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,   
                                   TmpInfo->EndOfFile.LowPart,   
                                   TmpInfo->AllocationSize.LowPart );   

          // Restore the buffer to its correct state
          TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = oldValue;

          if(TmpInfo->NextEntryOffset==0)   
            break;   

          TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);   
       }   

       bReset = FALSE;   
   }   

   delete DirInfo;   
   CloseHandle(hPipe);   
}   

彼岸花似海 2024-07-19 08:58:51

如果您想要一个可以为您完成此操作的编译工具,请查看 SysInternals(Microsoft 所有)的“PipeList”。

在此处下载

If you want a compiled tool that can do this for you, have a look at "PipeList" from SysInternals (owned by Microsoft).

Download Here

×眷恋的温暖 2024-07-19 08:58:51

您是否正确转义了管道名称? 它应该看起来像: \\\\.\\pipe\\FastCGI

请参阅 命名管道客户端演示了解更多信息。

Are you escaping the pipe name properly? It should look like: \\\\.\\pipe\\FastCGI

See the Named Pipe Client Demo for more information.

浅唱々樱花落 2024-07-19 08:58:51

使用未记录的函数:

// NtQueryDirectoryFile(
// IN HANDLE FileHandle, // 文件句柄
// IN HANDLE EventHandle 可选,
// 在 PIO_APC_ROUTINE 中 ApcRoutine 可选,
// 在 PVOID ApcContext 中可选,
// 输出 PIO_STATUS_BLOCK IoStatusBlock,
// OUT PVOID Buffer, // 指向接收结果的缓冲区的指针
// IN ULONG BufferLength, // Buffer 的长度
// IN FILE_INFORMATION_CLASS InformationClass,// 信息类型
// IN BOOLEAN ReturnByOne, // 每次调用仅返回一个文件的信息
// IN PUNICODE_STRING FileTemplate OPTIONAL, // 搜索模板
// IN BOOLEAN 重置 // 重新开始搜索
// );

Using the undocumented function:

// NtQueryDirectoryFile(
// IN HANDLE FileHandle, // handle to the file
// IN HANDLE EventHandle OPTIONAL,
// IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
// IN PVOID ApcContext OPTIONAL,
// OUT PIO_STATUS_BLOCK IoStatusBlock,
// OUT PVOID Buffer, // pointer to the buffer to receive the result
// IN ULONG BufferLength, // length of Buffer
// IN FILE_INFORMATION_CLASS InformationClass,// information type
// IN BOOLEAN ReturnByOne, // each call returns info for only one file
// IN PUNICODE_STRING FileTemplate OPTIONAL, // template for search
// IN BOOLEAN Reset // restart search
// );

你与清晨阳光 2024-07-19 08:58:51

管道名称的第一个反斜杠被论坛软件截断。 管道名称是:(

\\.\pipe\test

不需要用我用于测试的语言进行转义)

我编写了两个应用程序,一个是管道服务器,一个是管道客户端来测试阻塞等
他们工作完美。

我使用以下命令创建管道:

Pipe_Name      = "\\.\pipe\test"
MaxInstances   = 1
OutBufferSize  = 1024
InBufferSize   = 1024

hPipe = CreateNamedPipe(_
Pipe_Name, _                                     ' Name of the Pipe
PIPE_ACCESS_DUPLEX, _                            ' Specifies the pipe access/overlapped/write-through/security access modes 
PIPE_TYPE_MESSAGE OR PIPE_READMODE_MESSAGE, _    ' Specifies the type, read, and wait modes of the pipe handle
MaxInstances, _                                  ' Specifies the maximum number of instances that can be created for this pipe
OutBufferSize, _                                 ' Specifies the number of bytes to reserve for the output buffer
InBufferSize, _                                  ' Specifies the number of bytes to reserve for the input buffer
0, _                                             ' Specifies the default time-out value, in milliseconds
Security_Declaration)                            ' Pointer to a SECURITY_ATTRIBUTES structure 

它不会返回 INVALID_HANDLE_VALUE,而是返回一个有效的句柄,我随后使用该句柄并完美运行
他们按预期阻止并且沟通良好。

The first backslash of the pipe name was cut off by the forum software. The pipe name is:

\\.\pipe\test

(It does not need to be escaped in the language I am using for testing)

I wrote two applications, one a pipe server, one a pipe client to test blocking etc
They work perfectly.

I create the pipe with:

Pipe_Name      = "\\.\pipe\test"
MaxInstances   = 1
OutBufferSize  = 1024
InBufferSize   = 1024

hPipe = CreateNamedPipe(_
Pipe_Name, _                                     ' Name of the Pipe
PIPE_ACCESS_DUPLEX, _                            ' Specifies the pipe access/overlapped/write-through/security access modes 
PIPE_TYPE_MESSAGE OR PIPE_READMODE_MESSAGE, _    ' Specifies the type, read, and wait modes of the pipe handle
MaxInstances, _                                  ' Specifies the maximum number of instances that can be created for this pipe
OutBufferSize, _                                 ' Specifies the number of bytes to reserve for the output buffer
InBufferSize, _                                  ' Specifies the number of bytes to reserve for the input buffer
0, _                                             ' Specifies the default time-out value, in milliseconds
Security_Declaration)                            ' Pointer to a SECURITY_ATTRIBUTES structure 

It does not return INVALID_HANDLE_VALUE, but a valid handle which I use subsequently and works perfectly
They block as expected and communicate fine.

难得心□动 2024-07-19 08:58:51

好的,我在用于生成管道列表的代码中发现了另一个错误(有关第一个错误的帖子中的详细信息)。

至于“有人对这些评论有经验吗”下面的链接中的信息,我明白他们在说什么,您能否更具体地说明您不理解或好奇的内容(关于的部分)顺便说一句,不能进行非阻塞操作有点谎言,尽管它不是以 UNIX 系统的“传统”方式完成的。

Ok, I found another bug in the code being used to generate the pipe list (details in the the post about the first bug).

As far as the information in the link following "and does anyone have experience with these comments", I understand what they are talking about, could you be a little more specific about what you don't understand or are curious about (the part about not being able to do non-blocking operations is a bit of a lie btw, though its not done in the "traditional" way of unix systems).

德意的啸 2024-07-19 08:58:51

谢谢你抓住了这一点。 我将此代码转换为另一种类似 C 的语言并使用:
文件名称信息
因为我只是查找名称,

然后我使用另一个应用程序创建了一个命名管道:

 \\.\pipe\test

Thank you for catching that. I converted this code to another C like language and used:
FILE_NAMES_INFORMATION
as I am only looking for the names

I then created a named pipe with another application:

 \\.\pipe\test
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文