我正在使用DLL注入(inject)来启动文件管道的客户端,该管道与记录消息的服务器通信。问题在于服务器仅接收一个填充有问号('?')字符的缓冲区。

客户端/可注入(inject)DLL:

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

#define BUFSIZE 1024*1024

HANDLE hPipe;
BOOL   fSuccess = FALSE;
DWORD  cbToWrite, cbWritten, dwMode;
const wchar_t* lpszPipename = TEXT("\\\\.\\pipe\\listen");
char write_buffer[BUFSIZE];

void init()
{
    hPipe = CreateFile(
        lpszPipename,   // pipe name
        GENERIC_READ |  // read and write access
        GENERIC_WRITE,
        0,              // no sharing
        NULL,           // default security attributes
        OPEN_EXISTING,  // opens existing pipe
        0,              // default attributes
        NULL);          // no template file

// The pipe connected; change to message-read mode.

    dwMode = PIPE_READMODE_MESSAGE;
    fSuccess = SetNamedPipeHandleState(
        hPipe,    // pipe handle
        &dwMode,  // new pipe mode
        NULL,     // don't set maximum bytes
        NULL);    // don't set maximum time
}
#pragma warning(disable:4996)
void report(const char* frmt, ...)
{
    va_list args;
    va_start(args, frmt);
    vsnprintf(write_buffer, BUFSIZE, frmt, args);
    va_end(args);

    // Send a message to the pipe server.

    fSuccess = WriteFile(
        hPipe,                  // pipe handle
        write_buffer,             // message
        strlen(write_buffer),              // message length
        &cbWritten,             // bytes written
        NULL);                  // not overlapped

    return;
}

服务器:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>

#define BUFSIZE 1024*1024

BOOL   fConnected = FALSE;
DWORD  dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
const wchar_t* lpszPipename = TEXT("\\\\.\\pipe\\listen");

// The main loop creates an instance of the named pipe and
// then waits for a client to connect to it. When the client
// connects, a thread is created to handle communications
// with that client, and this loop is free to wait for the
// next client connect request. It is an infinite loop.

for (;;)
{
    _tprintf(TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);
    hPipe = CreateNamedPipe(
        lpszPipename,             // pipe name
        PIPE_ACCESS_DUPLEX,       // read/write access
        PIPE_TYPE_MESSAGE |       // message type pipe
        PIPE_READMODE_MESSAGE |   // message-read mode
        PIPE_WAIT,                // blocking mode
        PIPE_UNLIMITED_INSTANCES, // max. instances
        BUFSIZE,                  // output buffer size
        BUFSIZE,                  // input buffer size
        0,                        // client time-out
        NULL);                    // default security attribute

    if (hPipe == INVALID_HANDLE_VALUE)
    {
        _tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
        return -1;
    }

    // Wait for the client to connect; if it succeeds,
    // the function returns a nonzero value. If the function
    // returns zero, GetLastError returns ERROR_PIPE_CONNECTED.

    fConnected = ConnectNamedPipe(hPipe, NULL) ?
        TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

    if (fConnected)
    {
        printf("Client connected, creating a processing thread.\n");

        // Create a thread for this client.
        hThread = CreateThread(
            NULL,              // no security attribute
            0,                 // default stack size
            InstanceThread,    // thread proc
            (LPVOID)hPipe,    // thread parameter
            0,                 // not suspended
            &dwThreadId);      // returns thread ID

        if (hThread == NULL)
        {
            _tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());
            return -1;
        }
        else CloseHandle(hThread);
    }
    else
        // The client could not connect, so close the pipe.
        CloseHandle(hPipe);
}

DWORD WINAPI InstanceThread(LPVOID lpvParam)
// This routine is a thread processing function to read from and reply to a client
// via the open pipe connection passed from the main loop. Note this allows
// the main loop to continue executing, potentially creating more threads of
// of this procedure to run concurrently, depending on the number of incoming
// client connections.
{
    HANDLE hHeap = GetProcessHeap();
    TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(TCHAR));
    TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(TCHAR));

    DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
    BOOL fSuccess = FALSE;
    HANDLE hPipe = NULL;

    // Print verbose messages. In production code, this should be for debugging only.
    printf("InstanceThread created, receiving and processing messages.\n");

    // The thread's parameter is a handle to a pipe object instance.

    hPipe = (HANDLE)lpvParam;

    // Loop until done reading
    while (1)
    {
        // Read client requests from the pipe. This simplistic code only allows messages
        // up to BUFSIZE characters in length.
        fSuccess = ReadFile(
            hPipe,        // handle to pipe
            pchRequest,    // buffer to receive data
            BUFSIZE,    // size of buffer
            &cbBytesRead, // number of bytes read
            NULL);        // not overlapped I/O

        // Process the incoming message.
        _tprintf(TEXT("Client Request String:\"%s\"\n"), pchRequest);
    }

    FlushFileBuffers(hPipe);
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);

    HeapFree(hHeap, 0, pchRequest);
    HeapFree(hHeap, 0, pchReply);

    printf("InstanceThread exitting.\n");
    return 1;
}

附言如果有可能将调试器与可注入(inject)DLL一起使用,请告诉我!

最佳答案

这段代码有一些问题,我将在最后讨论。首先,一些有效的代码。请注意,我通过将它们全部集成到一个应用程序中(以便我可以轻松对其进行测试)并通过摆脱线程来对事情进行了一些简化,但这与您的问题无关。

#define _CRT_SECURE_NO_WARNINGS

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

#define BUFSIZE     1024*1024

const TCHAR* lpszPipename = TEXT("\\\\.\\pipe\\listen");
char write_buffer [BUFSIZE];

HANDLE init()
{
    HANDLE hPipe = CreateFile(
        lpszPipename,   // pipe name
        GENERIC_READ |  // read and write access
        GENERIC_WRITE,
        0,              // no sharing
        NULL,           // default security attributes
        OPEN_EXISTING,  // opens existing pipe
        0,              // default attributes
        NULL);          // no template file

    if (hPipe == INVALID_HANDLE_VALUE)
    {
        printf ("CreateFile returned error %d\n", GetLastError ());
        return INVALID_HANDLE_VALUE;
    }

// The pipe connected; change to message-read mode.

    DWORD dwMode = PIPE_READMODE_MESSAGE;
    BOOL fSuccess = SetNamedPipeHandleState(
        hPipe,    // pipe handle
        &dwMode,  // new pipe mode
        NULL,     // don't set maximum bytes
        NULL);    // don't set maximum time

    if (!fSuccess)
    {
        printf ("SetNamedPipeHandleState returned error %d\n", GetLastError ());
        CloseHandle (hPipe);
        return INVALID_HANDLE_VALUE;
    }

   return hPipe;
}

void report(HANDLE hPipe, const char *frmt, ...)
{
    va_list args;
    va_start(args, frmt);
    _vsnprintf(write_buffer, BUFSIZE, frmt, args);
    va_end(args);

    // Send a message to the pipe server.

    DWORD cbWritten;
    BOOL fSuccess = WriteFile(
        hPipe,                              // pipe handle
        write_buffer,                       // message
        (DWORD) strlen (write_buffer) + 1,  // message length, including EOS
        &cbWritten,                         // bytes written
        NULL);                              // not overlapped

    if (!fSuccess)
        printf ("WriteFile returned error %d\n", GetLastError ());
}

int _tmain (int argc, TCHAR **argv)
{
    if (argc > 1 && _tcscmp (argv [1], __T ("send")) == 0)
    {
        // send
        HANDLE hPipe = init ();
        if (hPipe != INVALID_HANDLE_VALUE)
        {
            report (hPipe, "A message to you, Rudi");
            CloseHandle (hPipe);
        }
        return 0;
    }

    // receive
    for (;;)
    {
        _tprintf(TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);
        HANDLE hPipe = CreateNamedPipe(
            lpszPipename,             // pipe name
            PIPE_ACCESS_DUPLEX,       // read/write access
            PIPE_TYPE_MESSAGE |       // message type pipe
            PIPE_READMODE_MESSAGE |   // message-read mode
            PIPE_WAIT,                // blocking mode
            PIPE_UNLIMITED_INSTANCES, // max. instances
            BUFSIZE,                  // output buffer size
            BUFSIZE,                  // input buffer size
            0,                        // client time-out
            NULL);                    // default security attribute

        if (hPipe == INVALID_HANDLE_VALUE)
        {
            printf ("CreateNamedPipe failed, GLE=%d.\n", GetLastError());
            return -1;
        }

        // Wait for the client to connect; if it succeeds,
        // the function returns a nonzero value. If the function
        // returns zero, GetLastError returns ERROR_PIPE_CONNECTED.

        BOOL fConnected = ConnectNamedPipe(hPipe, NULL) ?
            TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

        if (!fConnected)
        {
             printf ("Error %d connecting named pipe\n", GetLastError());
             return 255;
        }

        printf ("Client connected\n");
        HANDLE hHeap = GetProcessHeap();
        char* pchRequest = (char*) HeapAlloc(hHeap, 0, BUFSIZE);

        // Loop until done reading
        while (1)
        {
            // Read client requests from the pipe. This simplistic code only allows messages
            // up to BUFSIZE characters in length.
            DWORD cbBytesRead = 0;
            BOOL fSuccess = ReadFile(
                hPipe,        // handle to pipe
                pchRequest,    // buffer to receive data
                BUFSIZE,    // size of buffer
                &cbBytesRead, // number of bytes read
                NULL);        // not overlapped I/O

            if (!fSuccess)
                break;

            // Process the incoming message.
            printf("Client Request String:\"%s\"\n", pchRequest);
        }

        FlushFileBuffers(hPipe);
        DisconnectNamedPipe(hPipe);
        CloseHandle(hPipe);
        HeapFree(hHeap, 0, pchRequest);
    }

    return 0;
}

要在“发送”模式下运行此命令,请在命令行上指定send。否则,它将作为服务器运行。我的服务器永远运行。用Ctrl + C杀死它。

那么您的代码出了什么问题?好吧,大多数情况下,这有点像是ANSI和UNICODE字符串的混搭。在这种情况下,您需要更加小心,并且还需要适当地计算缓冲区大小。上面的代码已修复了所有问题,这就是我发布它的原因。此外,就良好的编程习惯而言:
  • 您应该更彻底地检查错误。
  • 如所写,服务器假定发送给它的字符串是NUL终止的,但是客户端不以这种方式发送它(所以我固定了客户端)。
  • 当发送者关闭管道末端时,服务器需要打破其接收循环。
  • 在本地声明局部变量! (并在适当时将它们作为参数传递。)不要使用不必要的全局变量。
  • 使用#define _CRT_SECURE_NO_WARNINGS优于显式禁用如果没有得到的警告。

  • 我的代码解决了所有这些问题。 HTH。

    关于c++ - Microsoft VC++,vsnprintf和管道(IO)错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51220926/

    10-14 16:46
    查看更多