原文链接:https://www.x86matthew.com/view_post?id=eventpipe
这篇文章展示了我为隐蔽的进程间通信提出的一个想法。
当系统上的两个进程需要相互通信时,它们通常会使用命名管道或共享内存等常用方法。然而,这些都相当容易检测和监控——我决定想出一种使用 Windows 事件对象的新方法。
事件句柄只有两种状态——开和关。它们通常用于一般的多线程同步,通常不需要任何进一步的调查。
我的基本理论如下: 1. 使用CreateEvent
在接收程序中创建 256 个事件对象。2.在接收程序中对上述所有事件句柄 调用WaitForMultipleObjects 。
3. 发送方程序使用OpenEvent打开接收方程序创建的所有 256 个事件对象。
4、在发送方程序中调用SetEvent,触发每个字节发送的对应事件(0-255)。
上面的理论有几个问题。正如大多数 Windows 开发人员已经知道的那样,WaitForMultipleObjects函数最多只允许 64 个句柄。另一个问题是同步——我们需要知道最初触发事件的确切顺序。
要解决上述问题,需要进行以下更改:
1. 我们不使用 256 个事件对象(每个字节一个),而是将每个字节分成两个事件——我们将在 base-16 中称其为“高”和“低”。例如,当发送 0x95 时,我们会触发 0x9“高”事件和 0x5“低”事件。这意味着我们只需要在任何时候使用WaitForMultipleObjects等待 16 个事件句柄,而不是全部 256 个。作为副作用,这也意味着事件对象的总数减少到 32 个(16 高 + 16 低) .
2. 为了解决同步问题,我们将创建一个称为“确认”标志的额外事件句柄。处理完每个字节后,将在接收程序中触发此事件。发送方程序只会在确认标志设置后发送下一个字节。
我创建了一个函数库来演示这个概念:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
#include <stdio.h> #include <windows.h> #define EVENT_DATA_HIGH_COUNT 16 #define EVENT_DATA_LOW_COUNT 16 struct EventPipeObjectStruct { HANDLE hEventDataHigh[EVENT_DATA_HIGH_COUNT]; HANDLE hEventDataLow[EVENT_DATA_LOW_COUNT]; HANDLE hEventAck; }; DWORD EventPipe_GetHandles(char *pName, DWORD dwCreate, EventPipeObjectStruct *pEventPipeObject) { char szEventName[512]; EventPipeObjectStruct EventPipeObject; // create "high" data event handles for(DWORD i = 0; i < EVENT_DATA_HIGH_COUNT; i++) { // set current event name memset(szEventName, 0, sizeof(szEventName)); _snprintf(szEventName, sizeof(szEventName) - 1, "EventPipe_%s_H%u", pName, i); if(dwCreate == 0) { // open existing object EventPipeObject.hEventDataHigh[i] = OpenEvent(EVENT_ALL_ACCESS, 0, szEventName); } else { // create new object EventPipeObject.hEventDataHigh[i] = CreateEvent(NULL, 0, 0, szEventName); } // check for errors if(EventPipeObject.hEventDataHigh[i] == NULL) { return 1; } } // create "low" data event handles for(i = 0; i < EVENT_DATA_LOW_COUNT; i++) { // set current event name memset(szEventName, 0, sizeof(szEventName)); _snprintf(szEventName, sizeof(szEventName) - 1, "EventPipe_%s_L%u", pName, i); if(dwCreate == 0) { // open existing object EventPipeObject.hEventDataLow[i] = OpenEvent(EVENT_ALL_ACCESS, 0, szEventName); } else { // create new object EventPipeObject.hEventDataLow[i] = CreateEvent(NULL, 0, 0, szEventName); } // check for errors if(EventPipeObject.hEventDataLow[i] == NULL) { return 1; } } // create acknowledgement event memset(szEventName, 0, sizeof(szEventName)); _snprintf(szEventName, sizeof(szEventName) - 1, "EventPipe_%s_A", pName); if(dwCreate == 0) { // open existing object EventPipeObject.hEventAck = OpenEvent(EVENT_ALL_ACCESS, 0, szEventName); } else { // create new object EventPipeObject.hEventAck = CreateEvent(NULL, 0, 0, szEventName); } if(EventPipeObject.hEventAck == NULL) { return 1; } // store data memcpy((void*)pEventPipeObject, (void*)&EventPipeObject, sizeof(EventPipeObject)); return 0; } DWORD EventPipe_CreateReceiver(char *pName, EventPipeObjectStruct *pEventPipeObject) { // create event handles if(EventPipe_GetHandles(pName, 1, pEventPipeObject) != 0) { return 1; } return 0; } DWORD EventPipe_Open(char *pName, EventPipeObjectStruct *pEventPipeObject) { // open event handles if(EventPipe_GetHandles(pName, 0, pEventPipeObject) != 0) { return 1; } return 0; } DWORD EventPipe_RecvRawByte(EventPipeObjectStruct *pEventPipeObject, BYTE *pByte) { DWORD dwEventDataHighValue = 0; DWORD dwEventDataLowValue = 0; BYTE bByte = 0; // wait for "high" data value dwEventDataHighValue = WaitForMultipleObjects(EVENT_DATA_HIGH_COUNT, pEventPipeObject->hEventDataHigh, 0, INFINITE); if(dwEventDataHighValue >= EVENT_DATA_HIGH_COUNT) { return 1; } // wait for "low" data value dwEventDataLowValue = WaitForMultipleObjects(EVENT_DATA_LOW_COUNT, pEventPipeObject->hEventDataLow, 0, INFINITE); if(dwEventDataLowValue >= EVENT_DATA_LOW_COUNT) { return 1; } // calculate byte value from high/low value bByte = (BYTE)((dwEventDataHighValue * EVENT_DATA_LOW_COUNT) + dwEventDataLowValue); // set acknowledgement event if(SetEvent(pEventPipeObject->hEventAck) == 0) { return 1; } // store byte value *pByte = bByte; return 0; } DWORD EventPipe_RecvRawData(EventPipeObjectStruct *pEventPipeObject, BYTE *pData, DWORD dwLength) { BYTE *pCurrPtr = NULL; // receive all requested bytes pCurrPtr = pData; for(DWORD i = 0; i < dwLength; i++) { // get current byte if(EventPipe_RecvRawByte(pEventPipeObject, pCurrPtr) != 0) { return 1; } // increase ptr pCurrPtr++; } return 0; } DWORD EventPipe_RecvDataBlock(EventPipeObjectStruct *pEventPipeObject, BYTE *pData, DWORD dwMaxLength, DWORD *pdwDataLength) { DWORD dwBlockLength = 0; // get block length if(EventPipe_RecvRawData(pEventPipeObject, (BYTE*)&dwBlockLength, sizeof(DWORD)) != 0) { return 1; } // validate length if(dwBlockLength > dwMaxLength) { return 1; } // get block data if(EventPipe_RecvRawData(pEventPipeObject, pData, dwBlockLength) != 0) { return 1; } if(pdwDataLength != NULL) { // store block length *pdwDataLength = dwBlockLength; } return 0; } DWORD EventPipe_SendRawByte(EventPipeObjectStruct *pEventPipeObject, BYTE bByte) { // set "high" data event if(SetEvent(pEventPipeObject->hEventDataHigh[bByte / EVENT_DATA_LOW_COUNT]) == 0) { return 1; } // set "low" data event if(SetEvent(pEventPipeObject->hEventDataLow[bByte % EVENT_DATA_LOW_COUNT]) == 0) { return 1; } // wait for acknowledgement if(WaitForSingleObject(pEventPipeObject->hEventAck, INFINITE) != 0) { return 1; } return 0; } DWORD EventPipe_SendRawData(EventPipeObjectStruct *pEventPipeObject, BYTE *pData, DWORD dwLength) { BYTE *pCurrPtr = NULL; // send all requested bytes pCurrPtr = pData; for(DWORD i = 0; i < dwLength; i++) { // send current byte if(EventPipe_SendRawByte(pEventPipeObject, *pCurrPtr) != 0) { return 1; } // increase ptr pCurrPtr++; } return 0; } DWORD EventPipe_SendDataBlock(EventPipeObjectStruct *pEventPipeObject, BYTE *pData, DWORD dwLength) { // send block length if(EventPipe_SendRawData(pEventPipeObject, (BYTE*)&dwLength, sizeof(DWORD)) != 0) { return 1; } // send block data if(EventPipe_SendRawData(pEventPipeObject, pData, dwLength) != 0) { return 1; } return 0; } |
接收程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
int main() { EventPipeObjectStruct EventPipeObject; char szRecvString[512]; DWORD dwDataLength = 0; memset((void*)&EventPipeObject, 0, sizeof(EventPipeObject)); if(EventPipe_CreateReceiver("x86matthew", &EventPipeObject) != 0) { return 1; } for(;;) { memset(szRecvString, 0, sizeof(szRecvString)); if(EventPipe_RecvDataBlock(&EventPipeObject, (BYTE*)szRecvString, sizeof(szRecvString) - 1, &dwDataLength) != 0) { return 1; } printf("Received %u bytes: '%s'\n", dwDataLength, szRecvString); } return 0; } |
发件人程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
int main(int argc, char *argv[]) { EventPipeObjectStruct EventPipeObject; if(argc != 2) { return 1; } memset((void*)&EventPipeObject, 0, sizeof(EventPipeObject)); if(EventPipe_Open("x86matthew", &EventPipeObject) != 0) { return 1; } if(EventPipe_SendDataBlock(&EventPipeObject, (BYTE*)argv[1], strlen(argv[1])) != 0) { return 1; } return 0; } |
潜在的未来改进:
– 目前只有单向通信 – 添加双工支持。
– 事件对象的命名允许我们在远程进程中打开句柄 – 使它们“匿名”并将句柄复制到远程进程中。