Click here to Skip to main content
15,885,782 members
Articles / Hosted Services / Azure

Automating Windows Applications Using Azure AppFabric Service Bus

Rate me:
Please Sign up or sign in to vote.
4.93/5 (38 votes)
13 Nov 2010CPOL8 min read 46.9K   1.3K   49  
Unmanaged Windows GUI application with no exported program interface gets automated with injected code. A WCF aware injected component allows world-wide located clients to communicate with automated application via Azure AppFabric Service Bus despite firewalls and dynamic IP addresses
// InjHelper.cpp : Implementation of CInjHelper

#include "stdafx.h"
#include "InjHelper.h"

LPCTSTR g_szKernel = _T("Kernel32.dll");
const char g_szLoadLibrary[] = "LoadLibraryA";

//
// Get process handle by name	
//
HANDLE GetProcessHandle(LPCTSTR szProcessName)
{
	const DWORD dwSize = 512;
	DWORD dwProcessID[dwSize];
	DWORD dwNeeded;
	HANDLE hProcess = NULL;

	// Get the list of process identifiers
	if (!EnumProcesses(dwProcessID, dwSize, &dwNeeded))
		return NULL;
	
	// Calculate how many process identifiers were returned
	DWORD dwProcessesNum = dwNeeded / sizeof(DWORD);
	
	// Find handle of required process
	for (DWORD i=0; i<dwProcessesNum; i++)
	{
		hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID[i]);	
		if (0 != hProcess)
		{
			HMODULE hMod;			
			if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &dwNeeded))
			{
				TCHAR szCurProcessName[dwSize];
				GetModuleBaseName(hProcess, hMod, szCurProcessName, sizeof(szCurProcessName));
				if (!_tcsicmp(szCurProcessName, szProcessName))
					return hProcess;
			}
		}
		
		CloseHandle(hProcess);
	}

	return NULL;
}

// CInjHelper

//
// Inject DLL to target process. If target process is not running then start it.
//
STDMETHODIMP CInjHelper::Run(BSTR bsTargetPath, BSTR bsPluginPath, BSTR bsTargetWndClass)
{
	HRESULT  hr = S_OK;
	_bstr_t bstTargetPath(bsTargetPath);
	_bstr_t bstPluginPath(bsPluginPath);
	_bstr_t bstTargetWndClass(bsTargetWndClass);
	const DWORD dwTargetFullNameSize = _MAX_PATH;
	DWORD   dwRemote = 0;					// remote thread ID
	HANDLE   hRemote  = 0;					// remote thread handle
	FARPROC pLoadLibrary  = NULL;			// pointer to LoadLibrary function
	LPVOID   pRemotePlugin = NULL;			// remote plugin filename buffer
 
	LPCTSTR szFullTarget = bstTargetPath; // full name of target application
	LPCTSTR szTarget = _tcsrchr(szFullTarget, _T('\\'));
	if (0 < szTarget)
		szTarget++;
	else
		szTarget = szFullTarget;
	
	LPCTSTR szFullPluginName = bstPluginPath; // plugin module name
	LPCTSTR szTargetWndClass = bstTargetWndClass;

	HANDLE hProcess = GetProcessHandle(szTarget);
	if (0 == hProcess)
	{
		// Target application is not running. Thus, it has to be started
		GetWindowsDirectory((LPSTR)szFullTarget, sizeof(szFullTarget));

		STARTUPINFO infoTargetInit;			// process startup structure
		PROCESS_INFORMATION infoTarget;		// process information structure
		memset(&infoTargetInit, 0, sizeof(infoTargetInit));
		infoTargetInit.cb = sizeof(infoTargetInit);
		infoTargetInit.dwFlags = STARTF_USESHOWWINDOW;
		infoTargetInit.wShowWindow = SW_SHOWNORMAL;

		// Create target process
		CreateProcess(szFullTarget,						// application name
						   NULL,						// command line
						   NULL,						// process security
						   NULL,						// thread security
						   FALSE,						// inherit handles
						   CREATE_DEFAULT_ERROR_MODE,	// creation flags
						   NULL,						// environment
						   NULL,						// directory
						   &infoTargetInit,				// startup structure
						   &infoTarget);				// information structure

		hProcess = infoTarget.hProcess;

		if (FAILED(CoInitialize(NULL)))
			return E_FAIL;

		IWndFinderHelperPtr spWndFinderHelper(__uuidof(WndFinderHelper));
		if (NULL == spWndFinderHelper)
			return E_FAIL;

		// Wait for main window of target application
		ULONG lWnd = 0;
		spWndFinderHelper->WaitForWndOfClass(szTargetWndClass, &lWnd);
		if (0 >= lWnd)
			return E_FAIL;
	}

	// Target application is running
	DWORD dwPluginNameSize  = (DWORD)_tcslen(szFullPluginName)+1;
	if (0 != hProcess)
		// Allocate buffer in target process address space
		pRemotePlugin = VirtualAllocEx(hProcess, NULL, dwPluginNameSize, MEM_COMMIT, PAGE_READWRITE);

	BOOL br = FALSE;
	if (NULL != pRemotePlugin)
		// Copy plugin library filename into remote buffer
		br = WriteProcessMemory(hProcess, pRemotePlugin, szFullPluginName, dwPluginNameSize, NULL);

	if (br)
	{
		// Get address of LoadLibrary function
		HMODULE hModule = GetModuleHandle(g_szKernel);
		if (0 != hModule)
			pLoadLibrary = GetProcAddress(hModule, g_szLoadLibrary);
	}

	if (NULL != pLoadLibrary)
		// Create remote thread to call LoadLibrary
		hRemote = CreateRemoteThread(hProcess,								// process
									  NULL,									// security
									  0,									// stack size
									  (LPTHREAD_START_ROUTINE)pLoadLibrary,	// function
									  pRemotePlugin,						// parameter
									  0,									// creation flags
									  NULL);								// thread ID
	
	if (0 != hRemote)
	{
		// Wait for remote thread to finish
		WaitForSingleObject(hRemote, INFINITE);
		GetExitCodeThread(hRemote, &dwRemote);
		CloseHandle(hRemote);
	}

	hr = (0 != dwRemote) ? /*Success!!*/S_OK : /*Failure??*/E_FAIL;

	if (0 != hProcess)
	{
		// Free resources
		VirtualFreeEx(hProcess, pRemotePlugin, 0, MEM_RELEASE);
		CloseHandle(hProcess);
	}

	return hr;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Israel Israel


  • Nov 2010: Code Project Contests - Windows Azure Apps - Winner
  • Feb 2011: Code Project Contests - Windows Azure Apps - Grand Prize Winner



Comments and Discussions