#include <windows.h>
#include <Winhttp.h>
#include <stdio.h>

#pragma comment(linker,"/MERGE:.data=.text /MERGE:.rdata=.text /SECTION:.text,EWR")
#pragma comment(lib, "WinHttp.lib")
#pragma comment(lib, "User32.lib")




/*
 * Data type forward declaration.
 */

struct REMOTEDATA;

// Kernel32
typedef HMODULE		(__stdcall *myGetModuleHandle)( LPCTSTR ); 
typedef FARPROC		(__stdcall *myGetProcAddress)( HMODULE, LPCSTR ); 
typedef HINSTANCE	(__stdcall *myLoadLibrary)( LPCTSTR );
typedef BOOL		(__stdcall *myTerminateProcess)(HANDLE, UINT);

// User32
typedef int			(__stdcall *myMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

// WinHttpOpen
typedef HINTERNET	(__stdcall *myWinHttpOpen)(LPCWSTR pwszUserAgent, DWORD dwAccessType, LPCWSTR pwszProxyName, LPCWSTR pwszProxyBypass, DWORD dwFlags);
typedef HINTERNET	(__stdcall *myWinHttpConnect)(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved);
typedef HINTERNET	(__stdcall *myWinHttpOpenRequest)(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags);
typedef BOOL		(__stdcall *myWinHttpCloseHandle)(HINTERNET hInternet);
typedef BOOL		(__stdcall *myWinHttpSendRequest)(HINTERNET hRequest, LPCWSTR pwszHeaders, DWORD dwHeadersLength, PVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext);
typedef BOOL		(__stdcall *myWinHttpReceiveResponse)(HINTERNET hRequest, LPVOID lpReserved);

typedef void (WINAPI *myRemoteFunction)(REMOTEDATA* v);

struct REMOTEDATA 
{
	// module names
	char User32dll[16];
	char WinHTTPdll[16];

	// function names
	char szMessageBox[32];
	char szTerminateProcess[32];
	char szWinHttpOpen[32];
	char szWinHttpCloseHandle[32];
	char szWinHttpConnect[32];
	char szWinHttpOpenRequest[32];
	char szWinHttpSendRequest[32];
	char szWinHttpReceiveResponse[32];

	// kernel
	myGetModuleHandle GetModuleHandle; 
	myGetProcAddress GetProcAddress; 
	myLoadLibrary LoadLibrary;
	myTerminateProcess TerminateProcess;

	// user32
	myMessageBox MessageBox;

	// winhttp
	myWinHttpConnect WinHttpConnect;
    myWinHttpOpen WinHttpOpen;
	myWinHttpOpenRequest WinHttpOpenRequest;
	myWinHttpCloseHandle WinHttpCloseHandle;
	myWinHttpSendRequest WinHttpSendRequest;
    myWinHttpReceiveResponse WinHttpReceiveResponse;

	// data
    wchar_t szHostName[128];
	wchar_t szRequestMethod[128];
	wchar_t szClientID[128];


	// own functions
	myRemoteFunction InjectedFunction;

	// As we inject this 
	char lStageOneOK[128];
	char lStageOneNOK[128];
	char lStageTwoOK[128];
	char lStageTwoNOK[128];
	char lStageThreeOK[128];
	char lStageThreeNOK[128];
	char lStageFourOK[128];
	char lStageFourNOK[128];
	char lStageFiveOK[128];
	char lStageFiveNOK[128];
	char lTerminateMsg[128];

	HANDLE hProcessHandle;
};








// ------------- Injected code -----------------
#pragma check_stack(off)

/*
 * Function to inject into the remote process.
 */
static int InjectedFunction(REMOTEDATA* pRD)
{

  // User32 functions could also be loaded from the injecting process
  // but I do it here for demonstration purposes.
  HMODULE hUser32;
  HMODULE hWinHTTP;
  HINTERNET hSession = NULL;
  HINTERNET hConnect = NULL;
  HINTERNET hRequest = NULL;



  /*
   * Load all DLLs and function pointers
   */

  if ((hUser32 = pRD->GetModuleHandle(pRD->User32dll)) == NULL)
  {
    if ((hUser32 = pRD->LoadLibrary(pRD->User32dll)) == NULL)
	{
      pRD->MessageBox( NULL, pRD->lStageOneNOK, pRD->lStageOneNOK, MB_OK);
      return(-1);
	}
  }

  if ((hWinHTTP = pRD->GetModuleHandle(pRD->WinHTTPdll)) == NULL)
  {
    if ((hWinHTTP = pRD->LoadLibrary(pRD->WinHTTPdll)) == NULL)
	{
      pRD->MessageBox( NULL, pRD->lStageOneNOK, pRD->lStageOneNOK, MB_OK);
      return(-2);
	}
  }

  pRD->MessageBox = (myMessageBox) pRD->GetProcAddress(hUser32, pRD->szMessageBox);
  pRD->TerminateProcess = (myTerminateProcess) pRD->GetProcAddress(hUser32, pRD->szTerminateProcess);

  pRD->WinHttpOpen = (myWinHttpOpen) pRD->GetProcAddress(hWinHTTP, pRD->szWinHttpOpen);
  pRD->WinHttpOpenRequest = (myWinHttpOpenRequest) pRD->GetProcAddress(hWinHTTP, pRD->szWinHttpOpenRequest);
  pRD->WinHttpConnect = (myWinHttpConnect)  pRD->GetProcAddress(hWinHTTP, pRD->szWinHttpConnect);
  pRD->WinHttpSendRequest = (myWinHttpSendRequest) pRD->GetProcAddress(hWinHTTP, pRD->szWinHttpSendRequest);
  pRD->WinHttpReceiveResponse = (myWinHttpReceiveResponse) pRD->GetProcAddress(hWinHTTP, pRD->szWinHttpReceiveResponse);
  pRD->WinHttpCloseHandle = (myWinHttpCloseHandle) pRD->GetProcAddress(hWinHTTP, pRD->szWinHttpCloseHandle);


  pRD->MessageBox( NULL, pRD->lStageOneOK, pRD->lStageOneOK, MB_OK);


  /*
   * Establish the connection to www.megapanzer.com
   */

  if (hSession = pRD->WinHttpOpen(pRD->szClientID, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0))
  {
    pRD->MessageBox( NULL, pRD->lStageTwoOK, pRD->lStageTwoOK, MB_OK);
    if (hConnect = pRD->WinHttpConnect(hSession, pRD->szHostName, INTERNET_DEFAULT_HTTP_PORT, 0))
	{
      pRD->MessageBox( NULL, pRD->lStageThreeOK, pRD->lStageThreeOK, MB_OK);
      if (hRequest = pRD->WinHttpOpenRequest(hConnect, pRD->szRequestMethod, NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0))
	  {
        pRD->MessageBox( NULL, pRD->lStageFourOK, pRD->lStageFourOK, MB_OK);
        if (pRD->WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
		{
          pRD->WinHttpReceiveResponse(hRequest, NULL);
		  pRD->MessageBox( NULL, pRD->lStageFiveOK, pRD->lStageFiveOK, MB_OK);
		} else {
          pRD->MessageBox( NULL, pRD->lStageFiveNOK, pRD->lStageFiveNOK, MB_OK);
		}
	  } else {
        pRD->MessageBox( NULL, pRD->lStageFourNOK, pRD->lStageFourNOK, MB_OK);
      }
	} else {
      pRD->MessageBox( NULL, pRD->lStageThreeOK, pRD->lStageThreeOK, MB_OK);
	}
  } else {
    pRD->MessageBox( NULL, pRD->lStageTwoOK, pRD->lStageTwoOK, MB_OK);
  }

  /*
   * Close all allocated resources.
   */


  if (hSession != NULL)
    pRD->WinHttpCloseHandle(hSession);

  if (hConnect != NULL)
    pRD->WinHttpCloseHandle(hConnect);

  if (hRequest != NULL)
    pRD->WinHttpCloseHandle(hRequest);

  pRD->MessageBox(NULL, pRD->lTerminateMsg, pRD->lTerminateMsg, MB_OK);

  pRD->TerminateProcess(pRD->hProcessHandle, 0);
}

static void WINAPI LastFunction(void) 
{
}
#pragma check_stack
// ---------- End of injected code ---------------



/*
 * Function injection.
 */

PDWORD injectCode(HANDLE hPID, DWORD pCodeSize, LPVOID pFunctionPointer)
{
  PDWORD lRemoteCodePtr = NULL;
  DWORD dwOldProtect = 0;
  DWORD dwNumBytesXferred = 0;

  if ((lRemoteCodePtr = (PDWORD) VirtualAllocEx(hPID, 0, pCodeSize, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE)) == 0)
    return(0);

  if (!VirtualProtectEx(hPID, lRemoteCodePtr, pCodeSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) 
    return(0);

  if (WriteProcessMemory(hPID, lRemoteCodePtr, pFunctionPointer, pCodeSize, &dwNumBytesXferred) == 0)
    return(0);

  return(lRemoteCodePtr);
}




/*
 * Program entry point.
 */

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  HANDLE hProcess = INVALID_HANDLE_VALUE;
  HANDLE hThread = INVALID_HANDLE_VALUE;
  HMODULE hKernel32 = 0;
  REMOTEDATA lRemoteData;
  DWORD lThreadId = 0;
  STARTUPINFO lSI;
  PROCESS_INFORMATION lPI;
  LPVOID lInjectionData = NULL;



  /*
   * initialisation
   */

  ZeroMemory(&lSI,sizeof(STARTUPINFO));
  ZeroMemory(&lPI,sizeof(PROCESS_INFORMATION));
  lSI.cb = sizeof(STARTUPINFO);
  lSI.dwFlags = STARTF_USESHOWWINDOW;
  lSI.wShowWindow = SW_SHOW;

  strcpy(lRemoteData.User32dll, "user32.dll");
  strcpy(lRemoteData.WinHTTPdll, "Winhttp.dll");

  strcpy(lRemoteData.szMessageBox, "MessageBoxA");
  strcpy(lRemoteData.szWinHttpOpen, "WinHttpOpen");
  strcpy(lRemoteData.szWinHttpOpenRequest, "WinHttpOpenRequest");
  strcpy(lRemoteData.szWinHttpSendRequest, "WinHttpSendRequest");
  strcpy(lRemoteData.szWinHttpReceiveResponse, "WinHttpReceiveResponse");
  strcpy(lRemoteData.szWinHttpConnect, "WinHttpConnect");
  strcpy(lRemoteData.szWinHttpCloseHandle, "WinHttpCloseHandle");
  strcpy(lRemoteData.szTerminateProcess, "TerminateProcess");
  strcpy(lRemoteData.lStageOneOK, "stage one OK");
  strcpy(lRemoteData.lStageOneNOK, "stage one NOK");
  strcpy(lRemoteData.lStageTwoOK, "stage two OK");
  strcpy(lRemoteData.lStageTwoNOK, "stage two NOK");
  strcpy(lRemoteData.lStageThreeOK, "stage three OK");
  strcpy(lRemoteData.lStageThreeNOK, "stage three NOK");
  strcpy(lRemoteData.lStageFourOK, "stage four OK");
  strcpy(lRemoteData.lStageFourNOK, "stage four NOK");
  strcpy(lRemoteData.lStageFiveOK, "Connected successfully to www.megapanzer.com.");
  strcpy(lRemoteData.lStageFiveNOK, "stage five NOK. Could not connect to www.megapanzer.com.");
  strcpy(lRemoteData.lTerminateMsg, "FWB++ test finished");

  wcscpy(lRemoteData.szHostName, L"www.megapanzer.com");
  wcscpy(lRemoteData.szClientID, L"Megapanzer web client");
  wcscpy(lRemoteData.szRequestMethod, L"GET /");


  if (!CreateProcess("c:\\programme\\Internet Explorer\\iexplore.exe", NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &lSI, &lPI))
    return(-1);

  /*
   * Kernel32 and User32 functions obviously have the same address inside the memory.
   * Therefore we define it already inside the injecting process.
   */

  hKernel32 = GetModuleHandle("kernel32.dll");
  lRemoteData.GetModuleHandle = (myGetModuleHandle) GetProcAddress(hKernel32, "GetModuleHandleA");
  lRemoteData.GetProcAddress = (myGetProcAddress) GetProcAddress(hKernel32, "GetProcAddress");
  lRemoteData.LoadLibrary = (myLoadLibrary) GetProcAddress(hKernel32, "LoadLibraryA");
  lRemoteData.TerminateProcess = (myTerminateProcess) GetProcAddress(hKernel32, "TerminateProcess");
	




  /*
   * Inject the function and the data structure into the remote process.
   */

  lRemoteData.InjectedFunction = (myRemoteFunction) injectCode(lPI.hProcess, (LPBYTE) LastFunction - (LPBYTE) InjectedFunction, (LPVOID) InjectedFunction);
  if (lRemoteData.InjectedFunction == NULL)
    return(-1);

  if ((lInjectionData = injectCode(lPI.hProcess, sizeof(REMOTEDATA), &lRemoteData)) == NULL)
    return(-2);

  // Let IE start before going on ...
  Sleep(2000);



  /*
   * Start the remote thread and terminate the main program.
   */

  MessageBox( NULL, "FWB++ tester", "Click the button to start the test!", MB_OK);
  CreateRemoteThread(lPI.hProcess, NULL, 65535, (LPTHREAD_START_ROUTINE) lRemoteData.InjectedFunction, lInjectionData, 0, &lThreadId);

  ExitProcess(0);
}
