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
dumphex(const char * buf,int len,int pos)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
WritePipeCompletion(DWORD dwErrorCode,DWORD dwNumberOfBytesTransferred,LPOVERLAPPED lpOverlapped)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
ReadPipeCompletion(DWORD dwErrorCode,DWORD dwNumberOfBytesTransferred,LPOVERLAPPED lpOverlapped)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
pipeserver(void * param)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
main(int ac,char ** av)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