1 /* 2 * PipeSpy 3 * Copyright (c) 2004, Skywing (skywing@valhallalegends.com) 4 * Released under the GNU GPL for the ReactOS project 5 * 6 * This program can be used to spy on a named pipe in Windows NT(+) 7 * or ReactOS. It is particularly intended to be used for 8 * understanding the remote kernel debugging protocol used 9 * by windows kd. 10 * 11 * USE: 12 * 13 * PipeSpy \\.\pipe\debug_server \\.\pipe\debug_client > PipeSpy.log 14 * 15 * VMware: act as client, connect to \\.\pipe\debug_server, pipe is connected 16 * to application 17 * 18 * WinDbg -k com:pipe,port=\\.\pipe\debug_client,resets=0 19 * 20 * NOTE: 21 * 22 * This program hasn't really been tested against ReactOS, and has only 23 * been built with Visual Studio .NET 2003. 24 */ 25 #include <process.h> 26 #include <windows.h> 27 #include <stdio.h> 28 29 HANDLE g_DebugServerPipe, g_DebugClientPipe; 30 CRITICAL_SECTION g_OutputLock; 31 32 void dumphex(const char *buf, int len, int pos) 33 { 34 int i, j; 35 for(j = 0; j < len; j += 16) { 36 for(i = 0; i < 16; i++) { 37 if(i + j < len) 38 printf("%02x%c", (unsigned char)buf[i + j], j + i + 1 == pos ? '*' : ' '); 39 else 40 printf(" "); 41 } 42 for(i = 0; i < 16; i++) { 43 if(i + j < len) 44 printf("%c", buf[i + j] >= ' ' ? buf[i + j] : '.'); 45 else 46 printf(" "); 47 } 48 printf("\n"); 49 } 50 } 51 52 enum { 53 PIPEBUF_INITIAL_SIZE = 4096, 54 PIPEBUF_MAX_SIZE = 16384 55 }; 56 57 typedef struct _READ_OVERLAPPED { 58 OVERLAPPED ReadOverlapped; 59 char* Buffer; 60 HANDLE Pipe, OtherPipe; 61 bool Server; 62 bool Connected; 63 } READ_OVERLAPPED; 64 65 VOID WINAPI WritePipeCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped) 66 { 67 if(dwErrorCode) { 68 EnterCriticalSection(&g_OutputLock); 69 printf(lpOverlapped->hEvent ? "Server> Error %u writing to client pipe\n" : "Client> Error %u writing to server pipe\n", dwErrorCode); 70 LeaveCriticalSection(&g_OutputLock); 71 } 72 73 free((void*)lpOverlapped); 74 } 75 76 VOID WINAPI ReadPipeCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped) 77 { 78 READ_OVERLAPPED* ReadOverlapped = (READ_OVERLAPPED*)lpOverlapped; 79 LPOVERLAPPED WriteOverlapped; 80 81 EnterCriticalSection(&g_OutputLock); 82 83 if(dwErrorCode) { 84 printf(ReadOverlapped->Server ? "Server> Error %u reading from pipe\n" : "Client> Error %u reading from pipe\n", dwErrorCode); 85 ReadOverlapped->Connected = false; 86 } else { 87 SYSTEMTIME SystemTime; 88 89 GetLocalTime(&SystemTime); 90 printf(ReadOverlapped->Server ? "Server> [%02u:%02u:%02u.%03u] Received %u byte message:\n" : "Client> [%02u:%02u:%02u.%03u] Received %u byte message:\n", 91 SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, dwNumberOfBytesTransferred); 92 dumphex(ReadOverlapped->Buffer, (int)dwNumberOfBytesTransferred, -1); 93 printf("\n"); 94 } 95 96 LeaveCriticalSection(&g_OutputLock); 97 98 WriteOverlapped = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED)+dwNumberOfBytesTransferred); 99 100 if(!WriteOverlapped) 101 printf(ReadOverlapped->Server ? "Server> Out of memory\n" : "Client> Out of memory\n"); 102 else { 103 ZeroMemory(WriteOverlapped, sizeof(OVERLAPPED)); 104 WriteOverlapped->hEvent = (HANDLE)ReadOverlapped->Server; 105 memcpy(((char*)WriteOverlapped)+sizeof(OVERLAPPED), ReadOverlapped->Buffer, dwNumberOfBytesTransferred); 106 WriteFileEx(ReadOverlapped->OtherPipe, ((char*)WriteOverlapped)+sizeof(OVERLAPPED), dwNumberOfBytesTransferred, WriteOverlapped, 107 WritePipeCompletion); 108 } 109 110 if(!dwErrorCode) { 111 ZeroMemory(ReadOverlapped, sizeof(OVERLAPPED)); 112 ReadFileEx(ReadOverlapped->Pipe, ReadOverlapped->Buffer, PIPEBUF_INITIAL_SIZE, &ReadOverlapped->ReadOverlapped, ReadPipeCompletion); 113 } 114 } 115 116 void __cdecl pipeserver(void* param) 117 { 118 READ_OVERLAPPED ReadOverlapped; 119 120 ReadOverlapped.Pipe = (HANDLE)param, ReadOverlapped.OtherPipe = ReadOverlapped.Pipe == g_DebugServerPipe ? g_DebugClientPipe : g_DebugServerPipe; 121 ReadOverlapped.Server = ReadOverlapped.Pipe == g_DebugServerPipe; 122 ReadOverlapped.Buffer = (char*)malloc(PIPEBUF_INITIAL_SIZE); 123 124 for(;;) { 125 if(!ConnectNamedPipe(ReadOverlapped.Pipe, 0) && GetLastError() != ERROR_PIPE_CONNECTED) { 126 printf(ReadOverlapped.Server ? "Server> Error %u accepting pipe connection\n" : "Client> Error %u accepting pipe connection\n", 127 GetLastError()); 128 break; 129 } 130 131 ReadOverlapped.Connected = true; 132 printf(ReadOverlapped.Server ? "Server> Connected\n" : "Client> Connected\n"); 133 134 ZeroMemory(&ReadOverlapped.ReadOverlapped, sizeof(OVERLAPPED)); 135 ReadFileEx(ReadOverlapped.Pipe, ReadOverlapped.Buffer, PIPEBUF_INITIAL_SIZE, &ReadOverlapped.ReadOverlapped, ReadPipeCompletion); 136 137 do { 138 SleepEx(INFINITE, TRUE); 139 } while(ReadOverlapped.Connected) ; 140 141 DisconnectNamedPipe(ReadOverlapped.Pipe); 142 printf(ReadOverlapped.Server ? "Server> Disconnected\n" : "Client> Disconnected\n"); 143 } 144 145 printf(ReadOverlapped.Server ? "Server> Shutting down\n" : "Client> Shutting down\n"); 146 147 free(ReadOverlapped.Buffer); 148 CloseHandle(ReadOverlapped.Pipe); 149 SleepEx(0, TRUE); 150 } 151 152 int main(int ac, char **av) 153 { 154 if(ac != 3) { 155 printf("syntax: pipespy serverpipe clientpipe\n"); 156 return 0; 157 } 158 159 g_DebugServerPipe = CreateNamedPipe(av[1], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 160 1, 4096, 4096, NMPWAIT_WAIT_FOREVER, 0); 161 162 if(g_DebugServerPipe == INVALID_HANDLE_VALUE) { 163 printf("Error %u creating server pipe\n", GetLastError()); 164 return 0; 165 } 166 167 g_DebugClientPipe = CreateNamedPipe(av[2], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 168 1, 4096, 4096, NMPWAIT_WAIT_FOREVER, 0); 169 170 if(g_DebugClientPipe == INVALID_HANDLE_VALUE) { 171 printf("Error %u creating client pipe\n", GetLastError()); 172 CloseHandle(g_DebugServerPipe); 173 return 0; 174 } 175 176 InitializeCriticalSection(&g_OutputLock); 177 _beginthread(pipeserver, 0, (void*)g_DebugServerPipe); 178 pipeserver((void*)g_DebugClientPipe); 179 DeleteCriticalSection(&g_OutputLock); 180 return 0; 181 } 182 183 184 /* 185 while(!Error) { 186 SleepEx(0, TRUE); 187 BufferPos = 0; 188 189 if(BufferSize > PIPEBUF_MAX_SIZE) { 190 char* NewBuf = (char*)realloc(Buffer, PIPEBUF_MAX_SIZE); 191 192 if(NewBuf) { 193 Buffer = NewBuf; 194 BufferSize = PIPEBUF_MAX_SIZE; 195 } 196 } 197 198 for(;;) { 199 char* NewBuf; 200 201 if(ReadFile(Pipe, Buffer+BufferPos, BufferSize-BufferPos, &Read, 0)) { 202 BufferPos += Read; 203 Error = 0; 204 break; 205 } 206 207 Error = GetLastError(); 208 209 printf("Error=%u read=%u\n", Error, Read); 210 211 if(Error != ERROR_MORE_DATA) { 212 printf(Server ? "Server> Error %u reading from pipe\n" : "Client> Error %u reading from pipe\n", GetLastError()); 213 break; 214 } 215 216 NewBuf = (char*)realloc(Buffer, BufferSize << 1); 217 218 if(!NewBuf) { 219 printf(Server ? "Server> Out of memory\n" : "Client> Out of memory\n"); 220 break; 221 } 222 223 BufferSize <<= 1; 224 BufferPos += Read; 225 Error = 0; 226 } 227 228 if(Error) 229 break; 230 231 WriteOverlapped = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED)+BufferPos); 232 233 if(!WriteOverlapped) 234 printf(Server ? "Server> Out of memory\n" : "Client> Out of memory\n"); 235 else { 236 ZeroMemory(WriteOverlapped, sizeof(OVERLAPPED)); 237 memcpy(((char*)WriteOverlapped)+sizeof(OVERLAPPED), Buffer, BufferPos); 238 WriteFileEx(OtherPipe, ((char*)WriteOverlapped)+sizeof(OVERLAPPED), BufferPos, WriteOverlapped, WritePipeCompletion); 239 } 240 241 EnterCriticalSection(&g_OutputLock); 242 printf(Server ? "Server> Received %u byte message:\n" : "Client> Received %u byte message:\n", BufferPos); 243 dumphex(Buffer, (int)BufferPos, -1); 244 printf("\n"); 245 LeaveCriticalSection(&g_OutputLock); 246 } 247 248 DisconnectNamedPipe(Pipe); 249 printf(Server ? "Server> Disconnected\n" : "Client> Disconnected\n"); 250 251 */ 252