/* * PipeSpy * Copyright (c) 2004, Skywing (skywing@valhallalegends.com) * Released under the GNU GPL for the ReactOS project * * This program can be used to spy on a named pipe in Windows NT(+) * or ReactOS. It is particularly intended to be used for * understanding the remote kernel debugging protocol used * by windows kd. * * USE: * * PipeSpy \\.\pipe\debug_server \\.\pipe\debug_client > PipeSpy.log * * VMware: act as client, connect to \\.\pipe\debug_server, pipe is connected * to application * * WinDbg -k com:pipe,port=\\.\pipe\debug_client,resets=0 * * NOTE: * * This program hasn't really been tested against ReactOS, and has only * been built with Visual Studio .NET 2003. */ #include #include #include HANDLE g_DebugServerPipe, g_DebugClientPipe; CRITICAL_SECTION g_OutputLock; void dumphex(const char *buf, int len, int pos) { int i, j; for(j = 0; j < len; j += 16) { for(i = 0; i < 16; i++) { if(i + j < len) printf("%02x%c", (unsigned char)buf[i + j], j + i + 1 == pos ? '*' : ' '); else printf(" "); } for(i = 0; i < 16; i++) { if(i + j < len) printf("%c", buf[i + j] >= ' ' ? buf[i + j] : '.'); else printf(" "); } printf("\n"); } } enum { PIPEBUF_INITIAL_SIZE = 4096, PIPEBUF_MAX_SIZE = 16384 }; typedef struct _READ_OVERLAPPED { OVERLAPPED ReadOverlapped; char* Buffer; HANDLE Pipe, OtherPipe; bool Server; bool Connected; } READ_OVERLAPPED; VOID WINAPI WritePipeCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped) { if(dwErrorCode) { EnterCriticalSection(&g_OutputLock); printf(lpOverlapped->hEvent ? "Server> Error %u writing to client pipe\n" : "Client> Error %u writing to server pipe\n", dwErrorCode); LeaveCriticalSection(&g_OutputLock); } free((void*)lpOverlapped); } VOID WINAPI ReadPipeCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped) { READ_OVERLAPPED* ReadOverlapped = (READ_OVERLAPPED*)lpOverlapped; LPOVERLAPPED WriteOverlapped; EnterCriticalSection(&g_OutputLock); if(dwErrorCode) { printf(ReadOverlapped->Server ? "Server> Error %u reading from pipe\n" : "Client> Error %u reading from pipe\n", dwErrorCode); ReadOverlapped->Connected = false; } else { SYSTEMTIME SystemTime; GetLocalTime(&SystemTime); printf(ReadOverlapped->Server ? "Server> [%02u:%02u:%02u.%03u] Received %u byte message:\n" : "Client> [%02u:%02u:%02u.%03u] Received %u byte message:\n", SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, dwNumberOfBytesTransferred); dumphex(ReadOverlapped->Buffer, (int)dwNumberOfBytesTransferred, -1); printf("\n"); } LeaveCriticalSection(&g_OutputLock); WriteOverlapped = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED)+dwNumberOfBytesTransferred); if(!WriteOverlapped) printf(ReadOverlapped->Server ? "Server> Out of memory\n" : "Client> Out of memory\n"); else { ZeroMemory(WriteOverlapped, sizeof(OVERLAPPED)); WriteOverlapped->hEvent = (HANDLE)ReadOverlapped->Server; memcpy(((char*)WriteOverlapped)+sizeof(OVERLAPPED), ReadOverlapped->Buffer, dwNumberOfBytesTransferred); WriteFileEx(ReadOverlapped->OtherPipe, ((char*)WriteOverlapped)+sizeof(OVERLAPPED), dwNumberOfBytesTransferred, WriteOverlapped, WritePipeCompletion); } if(!dwErrorCode) { ZeroMemory(ReadOverlapped, sizeof(OVERLAPPED)); ReadFileEx(ReadOverlapped->Pipe, ReadOverlapped->Buffer, PIPEBUF_INITIAL_SIZE, &ReadOverlapped->ReadOverlapped, ReadPipeCompletion); } } void __cdecl pipeserver(void* param) { READ_OVERLAPPED ReadOverlapped; ReadOverlapped.Pipe = (HANDLE)param, ReadOverlapped.OtherPipe = ReadOverlapped.Pipe == g_DebugServerPipe ? g_DebugClientPipe : g_DebugServerPipe; ReadOverlapped.Server = ReadOverlapped.Pipe == g_DebugServerPipe; ReadOverlapped.Buffer = (char*)malloc(PIPEBUF_INITIAL_SIZE); for(;;) { if(!ConnectNamedPipe(ReadOverlapped.Pipe, 0) && GetLastError() != ERROR_PIPE_CONNECTED) { printf(ReadOverlapped.Server ? "Server> Error %u accepting pipe connection\n" : "Client> Error %u accepting pipe connection\n", GetLastError()); break; } ReadOverlapped.Connected = true; printf(ReadOverlapped.Server ? "Server> Connected\n" : "Client> Connected\n"); ZeroMemory(&ReadOverlapped.ReadOverlapped, sizeof(OVERLAPPED)); ReadFileEx(ReadOverlapped.Pipe, ReadOverlapped.Buffer, PIPEBUF_INITIAL_SIZE, &ReadOverlapped.ReadOverlapped, ReadPipeCompletion); do { SleepEx(INFINITE, TRUE); } while(ReadOverlapped.Connected) ; DisconnectNamedPipe(ReadOverlapped.Pipe); printf(ReadOverlapped.Server ? "Server> Disconnected\n" : "Client> Disconnected\n"); } printf(ReadOverlapped.Server ? "Server> Shutting down\n" : "Client> Shutting down\n"); free(ReadOverlapped.Buffer); CloseHandle(ReadOverlapped.Pipe); SleepEx(0, TRUE); } int main(int ac, char **av) { if(ac != 3) { printf("syntax: pipespy serverpipe clientpipe\n"); return 0; } g_DebugServerPipe = CreateNamedPipe(av[1], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 4096, 4096, NMPWAIT_WAIT_FOREVER, 0); if(g_DebugServerPipe == INVALID_HANDLE_VALUE) { printf("Error %u creating server pipe\n", GetLastError()); return 0; } g_DebugClientPipe = CreateNamedPipe(av[2], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 4096, 4096, NMPWAIT_WAIT_FOREVER, 0); if(g_DebugClientPipe == INVALID_HANDLE_VALUE) { printf("Error %u creating client pipe\n", GetLastError()); CloseHandle(g_DebugServerPipe); return 0; } InitializeCriticalSection(&g_OutputLock); _beginthread(pipeserver, 0, (void*)g_DebugServerPipe); pipeserver((void*)g_DebugClientPipe); DeleteCriticalSection(&g_OutputLock); return 0; } /* while(!Error) { SleepEx(0, TRUE); BufferPos = 0; if(BufferSize > PIPEBUF_MAX_SIZE) { char* NewBuf = (char*)realloc(Buffer, PIPEBUF_MAX_SIZE); if(NewBuf) { Buffer = NewBuf; BufferSize = PIPEBUF_MAX_SIZE; } } for(;;) { char* NewBuf; if(ReadFile(Pipe, Buffer+BufferPos, BufferSize-BufferPos, &Read, 0)) { BufferPos += Read; Error = 0; break; } Error = GetLastError(); printf("Error=%u read=%u\n", Error, Read); if(Error != ERROR_MORE_DATA) { printf(Server ? "Server> Error %u reading from pipe\n" : "Client> Error %u reading from pipe\n", GetLastError()); break; } NewBuf = (char*)realloc(Buffer, BufferSize << 1); if(!NewBuf) { printf(Server ? "Server> Out of memory\n" : "Client> Out of memory\n"); break; } BufferSize <<= 1; BufferPos += Read; Error = 0; } if(Error) break; WriteOverlapped = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED)+BufferPos); if(!WriteOverlapped) printf(Server ? "Server> Out of memory\n" : "Client> Out of memory\n"); else { ZeroMemory(WriteOverlapped, sizeof(OVERLAPPED)); memcpy(((char*)WriteOverlapped)+sizeof(OVERLAPPED), Buffer, BufferPos); WriteFileEx(OtherPipe, ((char*)WriteOverlapped)+sizeof(OVERLAPPED), BufferPos, WriteOverlapped, WritePipeCompletion); } EnterCriticalSection(&g_OutputLock); printf(Server ? "Server> Received %u byte message:\n" : "Client> Received %u byte message:\n", BufferPos); dumphex(Buffer, (int)BufferPos, -1); printf("\n"); LeaveCriticalSection(&g_OutputLock); } DisconnectNamedPipe(Pipe); printf(Server ? "Server> Disconnected\n" : "Client> Disconnected\n"); */