Click here to Skip to main content
15,898,731 members
Articles / Desktop Programming / MFC

Task Manager Extension 2.0

Rate me:
Please Sign up or sign in to vote.
4.92/5 (149 votes)
22 Jan 2007CDDL11 min read 598.8K   18.7K   263  
Task Manager Extension. This is a Windows Task Manager (NT/2000/XP/2003) plug-in. It adds lots of useful features to the standard Task Manager. It can show process modules, memory map, used handles, open files, file properties and a lot of other info!
// Modified by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
// For companies(Austin,TX): If you would like to get my resume, send an email.
//
//******************************************************************************
//
// Original version made by Felix Kasza, http://www.mvps.org/win32/
//
// demonstrates getting the command line of another process
// requires PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION,
// PROCESS_VM_WRITE, PROCESS_VM_READ to the target, or the
// SeDebugPrivilege

// *** You *must* remove "/GZ" from the debug build settings ***
// (If you use my (felixk's) project file, this has already happened)

#include "stdafx.h"
//#include "TaskManagerExDll.h"
#include "LoadDll.h"
#include "../TaskManagerExDll/TaskManagerExDllExport.h" // for TASKMANAGEREXDLL_DEBUG_API macro

#include "WindowsCore.h"

const DWORD MAXINJECTSIZE = 4096;


DWORD IsWindowsNT()
{
   OSVERSIONINFOEX osvi;
   BOOL bOsVersionInfoEx;
   
   // Try calling GetVersionEx using the OSVERSIONINFOEX structure,
   // which is supported on Windows 2000.
   //
   // If that fails, try using the OSVERSIONINFO structure.

   my_memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

   bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi);

   if( bOsVersionInfoEx == 0 )
   {
      // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.

      osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
      if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) 
         return FALSE;
   }

   return ( osvi.dwPlatformId == VER_PLATFORM_WIN32_NT ? osvi.dwMajorVersion : 0 );
}

PVOID GetFuncAddress(PVOID addr)
{
#ifdef _DEBUG
	//check if instruction is relative jump (E9)
	if (0xE9 != *((UCHAR*)addr))
	return addr;

	// calculate base of relative jump
	ULONG base = (ULONG)((UCHAR*)addr + 5);

	// calculate offset 
	ULONG *offset = (ULONG*)((UCHAR*)addr + 1);

	return (PVOID)(base + *offset);
#else
	// in release, don't have to mess with jumps
	return addr;
#endif
}


DWORD LoadDllForRemoteThread(
		DWORD	processID,
		RemoteExecute::eLoad	bLoad,
		RemoteExecute::eFree	bFree,
		RemoteExecute::eSpecialMode SpecialMode,
		LPCTSTR	lpModuleName,
		LPCSTR	lpFunctionName,
		DWORD*	pReturnCodeForFunction,
		DWORD*	pReturnCodeForFunctionSpecial,
		LONG*	pLastError,
		DWORD*	pErrorLoad,
		DWORD*	pErrorFunction,
		DWORD*	pErrorFree,
		DWORD	dwArgumentCount,
		DWORD*	pdwArguments
		)
{
	DWORD rc = (DWORD)-2;

	//Enable debug privilege
	EnableDebugPriv();

	// open the process
	HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
			PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, processID );

	if ( hProcess != NULL )
	{
		// let's work
		rc = ExecuteRemoteThread( hProcess, bLoad, bFree, SpecialMode, lpModuleName, lpFunctionName,
					pReturnCodeForFunction, pReturnCodeForFunctionSpecial, pLastError,
					pErrorLoad, pErrorFunction, pErrorFree,
					dwArgumentCount, pdwArguments );

		CloseHandle( hProcess );
	}

	return rc;
}

void EnableDebugPriv( void )
{
	HANDLE hToken;
	LUID sedebugnameValue;
	TOKEN_PRIVILEGES tkp;

	// enable the SeDebugPrivilege
	if ( ! OpenProcessToken( GetCurrentProcess(),
		TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
		return;

	if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )
	{
		CloseHandle( hToken );
		return;
	}

	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Luid = sedebugnameValue;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL );
		
	CloseHandle( hToken );
}

DWORD ExecuteRemoteThread(
		HANDLE	hProcess,
		RemoteExecute::eLoad	bLoad,
		RemoteExecute::eFree	bFree,
		RemoteExecute::eSpecialMode SpecialMode,
		LPCTSTR	lpModuleName,
		LPCSTR	lpFunctionName,
		DWORD*	pReturnCodeForFunction,
		DWORD*	pReturnCodeForFunctionSpecial,
		LONG*	pLastError,
		DWORD*	pErrorLoad,
		DWORD*	pErrorFunction,
		DWORD*	pErrorFree,
		DWORD	dwArgumentCount,
		DWORD*	pdwArguments
		)
{
	HANDLE ht = 0;
	void *p = 0;
	RemoteDllThreadBlock *c = 0;
	DWORD rc = (DWORD)-1;
	HMODULE hKernel32 = 0;
	RemoteDllThreadBlock localCopy;
	DWORD i;
	DWORD ThreadId = 0;
	DWORD dwReadBytes = 0;
	DWORD WaitObjectRes = 0;
	BYTE* pSpecialBuffer = NULL;

	// clear the parameter block
	//my_memset( &localCopy, 0, sizeof(localCopy) );
	my_memset( &localCopy, 0xAA, sizeof(localCopy) ); // debug purposes

	// allocate memory for injected code
	p = VirtualAllocEx( hProcess, 0, MAXINJECTSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
	if ( p == 0 )
		goto cleanup;

	// allocate memory for parameter block
	c = (RemoteDllThreadBlock*) VirtualAllocEx( hProcess, 0, sizeof(RemoteDllThreadBlock), MEM_COMMIT, PAGE_READWRITE );
	if ( c == 0 )
		goto cleanup;

	// copy function there, we will execute this piece of code
	if ( ! WriteProcessMemory( hProcess, p, GetFuncAddress(RemoteDllThread), MAXINJECTSIZE, 0 ) )
		goto cleanup;
	
	// copy dll path to parameter block
	lstrcpyn( localCopy.lpModulePath, lpModuleName, SIZEOF_ARRAY(localCopy.lpModulePath) );
//#ifdef _UNICODE
//	lstrcpyW( localCopy.lpModulePath, lpModuleName );
//#else
//	wsprintfW( localCopy.lpModulePath, L"%hs", lpModuleName );
//#endif

	if ( lpFunctionName == NULL )
		localCopy.lpFunctionName[0] = '\0';
	else
		lstrcpynA( localCopy.lpFunctionName, lpFunctionName, SIZEOF_ARRAY(localCopy.lpFunctionName) );
	
	localCopy.bLoadLibrary = bLoad;
	localCopy.bFreeLibrary = bFree;
	localCopy.SpecialMode = SpecialMode;
	localCopy.MarkerBegin = MARKER_BEGIN;
	localCopy.MarkerEnd = MARKER_END;

	// kernel32.dll
	hKernel32 = GetModuleHandle( _T("kernel32.dll") );

	if ( hKernel32 == NULL )
		goto cleanup;
	
	// get the addresses for the functions, what we will use in the remote thread

	localCopy.fnLoadLibrary = (PLoadLibrary)GetProcAddress( hKernel32, "LoadLibrary" FUNC_SUFFIX );
	localCopy.fnGetModuleHandle = (PGetModuleHandle)GetProcAddress( hKernel32, "GetModuleHandle" FUNC_SUFFIX );
	localCopy.fnFreeLibrary = (PFreeLibrary)GetProcAddress( hKernel32, "FreeLibrary" );
	localCopy.fnGetProcAddress = (PGetProcAddress)GetProcAddress( hKernel32, "GetProcAddress" );
	localCopy.fnGetLastError = (PGetLastError)GetProcAddress( hKernel32, "GetLastError" );
	localCopy.fnSetLastError = (PSetLastError)GetProcAddress( hKernel32, "SetLastError" );

	if (localCopy.fnLoadLibrary == NULL ||
		localCopy.fnGetModuleHandle == NULL ||
		localCopy.fnFreeLibrary == NULL ||
		localCopy.fnGetProcAddress == NULL)
		goto cleanup;

	if( dwArgumentCount > REMOTE_MAX_ARGUMENTS )
	{
		goto cleanup;
	}

	if( pdwArguments == NULL && dwArgumentCount != 0 )
	{
		goto cleanup;
	}

	localCopy.dwArgumentCount = dwArgumentCount;
	for( i=0; i<dwArgumentCount; i++ )
	{
		localCopy.Arguments[i] = pdwArguments[i];
	}

	// copy the parameterblock to the other process adress space
	if ( ! WriteProcessMemory( hProcess, c, &localCopy, sizeof localCopy, 0 ) )
		goto cleanup;

	// CreateRemoteThread()
	ht = CreateRemoteThread( hProcess, 0, 0, (DWORD (__stdcall *)( void *)) p, c, 0, &ThreadId );
	if ( ht == NULL )
		goto cleanup;

	WaitObjectRes = WaitForSingleObject( ht, INFINITE );
	switch ( WaitObjectRes )
	{
	case WAIT_TIMEOUT:
		goto cleanup;

	case WAIT_FAILED:
		goto cleanup;

	case WAIT_OBJECT_0:
		// this might just have worked, pick up the result!
		// rad back the prameter block, it has the error code

		// clear the parameter block
		my_memset( &localCopy, 0, sizeof(localCopy) );

		if ( ! ReadProcessMemory( hProcess, c, &localCopy, sizeof(localCopy), &dwReadBytes ) )
		{
			rc = 0x100;
			goto cleanup;
		}

		if( dwReadBytes != sizeof(localCopy) )
		{
			rc = 0x200;
			goto cleanup;
		}

		if( localCopy.MarkerBegin != MARKER_BEGIN )
		{
			rc = 0x300;
			goto cleanup;
		}

		if( localCopy.MarkerEnd != MARKER_END )
		{
			rc = 0x400;
			goto cleanup;
		}

      rc = 0;

      if ( pReturnCodeForFunction != NULL )
         *pReturnCodeForFunction = localCopy.ReturnCodeForFunction;

	  if( pLastError != NULL )
		 *pLastError = localCopy.LastError;

      if ( pErrorLoad != NULL )
         *pErrorLoad = localCopy.ErrorLoad;

      if ( pErrorFunction != NULL )
         *pErrorFunction = localCopy.ErrorFunction;

      if ( pErrorFree != NULL )
         *pErrorFree = localCopy.ErrorFree;


		if( SpecialMode != RemoteExecute::NO_SPECIAL_MODE )
		{
			if ( pReturnCodeForFunction != NULL )
				*pReturnCodeForFunction = 0;

			if ( pReturnCodeForFunctionSpecial != NULL )
				*pReturnCodeForFunctionSpecial = 0;

			if( pReturnCodeForFunction != NULL
				&& pReturnCodeForFunctionSpecial != NULL )
			{
				LPCVOID pRemoteBuffer = (LPCVOID) localCopy.ReturnCodeForFunction;
				if( pRemoteBuffer != NULL )
				{
					DWORD n = localCopy.ReturnCodeForFunctionSpecial;
					pSpecialBuffer = (PBYTE) LocalAlloc( LMEM_FIXED, n );
					if( pSpecialBuffer != NULL )
					{
						my_memset( pSpecialBuffer, 0, n );
						if ( ! ReadProcessMemory( hProcess, pRemoteBuffer, pSpecialBuffer, n, &dwReadBytes ) )
						{
							rc = 0x500;
							goto cleanup;
						}

						if( dwReadBytes != n )
						{
							rc = 0x600;
							goto cleanup;
						}

						*pReturnCodeForFunction = (DWORD) pSpecialBuffer;
						*pReturnCodeForFunctionSpecial = n;
						pSpecialBuffer = NULL;
					}
				}
			}
		}

      if ( localCopy.ErrorLoad )
         rc |= 1;

      if ( localCopy.ErrorFunction == 1 )
         rc |= 2;

      if ( localCopy.ErrorFree )
         rc |= 4;

      if ( localCopy.ErrorFunction == 2 )
         rc |= 8;

		break;
	
	default:
		goto cleanup;
	}

cleanup:
	if( ht != NULL )
	{
		CloseHandle( ht );
	}

	if( pSpecialBuffer != NULL )
	{
		LocalFree( pSpecialBuffer );
	}

	// Let's clean
	if ( p != 0 )
		VirtualFreeEx( hProcess, p, 0, MEM_RELEASE );
	if ( c != 0 )
		VirtualFreeEx( hProcess, c, 0, MEM_RELEASE );
	
	return rc;
}

void FreeSpecialBuffer( DWORD pReturnCodeForFunction )
{
	if( pReturnCodeForFunction )
	{
		PBYTE p = (PBYTE)pReturnCodeForFunction;
		LocalFree( p );
	}
}


/*
DWORD RemoteGetCurrentDirectory( DWORD pID, LPWSTR lpPath, DWORD size, DWORD* pRetCode )
{
	HANDLE ht = 0;
	void *p = 0;
	RemoteGetCurrentDirectoryThreadBlock *c = 0;
	DWORD rc = (DWORD)-1;
	RemoteGetCurrentDirectoryThreadBlock localCopy;

	HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
			PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pID );

	if ( hProcess == NULL )
	   return 0;

	// clear the parameter block
	my_memset( &localCopy, 0, sizeof(localCopy) );

	// allocate memory for injected code
	p = VirtualAllocEx( hProcess, 0, MAXINJECTSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
	if ( p == 0 )
		goto cleanup;

	// allocate memory for parameter block
	c = (RemoteGetCurrentDirectoryThreadBlock*) VirtualAllocEx( 
	         hProcess, 0, sizeof(RemoteGetCurrentDirectoryThreadBlock), MEM_COMMIT, PAGE_READWRITE );

	if ( c == 0 )
		goto cleanup;

	// copy function there, we will execute this piece of code
	if ( ! WriteProcessMemory( hProcess, p, GetFuncAddress(RemoteGetCurrentDirectoryThread), MAXINJECTSIZE, 0 ) )
		goto cleanup;
	
	localCopy.fnGetCurrentDirectoryW = (PGetCurrentDirectoryW)GetProcAddress( 
	      GetModuleHandle( _T("kernel32.dll") ), "GetCurrentDirectoryW" );

	if (localCopy.fnGetCurrentDirectoryW == NULL)
		goto cleanup;
		
	// copy the parameterblock to the other process adress space
	if ( ! WriteProcessMemory( hProcess, c, &localCopy, sizeof localCopy, 0 ) )
		goto cleanup;

   // CreateRemoteThread()
	ht = CreateRemoteThread( hProcess, 0, 0, (DWORD (__stdcall *)( void *)) p, c, 0, &rc );
	if ( ht == NULL )
		goto cleanup;
	
	rc = WaitForSingleObject( ht, INFINITE );
	switch ( rc )
	{
	case WAIT_TIMEOUT:
		goto cleanup;

	case WAIT_FAILED:
		goto cleanup;

	case WAIT_OBJECT_0:
		// this might just have worked, pick up the result!
		// rad back the prameter block, it has the error code
		if ( ! ReadProcessMemory( hProcess, c, &localCopy, sizeof localCopy, 0 ) )
			goto cleanup;

      if ( pRetCode != NULL )
         *pRetCode = localCopy.dwReturnCode;

      if ( localCopy.dwReturnCode != 0 )
	  {
         lstrcpynW( lpPath, localCopy.lpDirectory, size );
	  }

      break;
	
	default:
		break;
	}

cleanup:
 	// Let's clean
   if ( ht != NULL )
	   CloseHandle( ht );
	if ( p != 0 )
		VirtualFreeEx( hProcess, p, 0, MEM_RELEASE );
	if ( c != 0 )
		VirtualFreeEx( hProcess, c, 0, MEM_RELEASE );
	if ( hProcess != NULL)
		CloseHandle( hProcess );

	return rc;
}
*/

BOOL RemoteSimpleFunction( DWORD processId, DWORD dwArgument, char* lpszFunction, DWORD* lpdwFuncRetVal )
{
	HANDLE hRemoteThread = NULL;
	BOOL rc = FALSE;
	HMODULE hKernel32 = NULL;
	FARPROC pfnProc = NULL;
	DWORD ThreadId = 0;
	DWORD dwWaitRes;

	//Enable debug privilege
	EnableDebugPriv();

	// open the process
	HANDLE hProcess = OpenProcess(
		PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
		FALSE, processId );

	if ( hProcess == NULL )
		goto cleanup;

	hKernel32 = GetModuleHandle(_T("kernel32.dll"));

	if ( hKernel32 == NULL )
		goto cleanup;

	pfnProc = GetProcAddress( hKernel32, lpszFunction );

	if ( pfnProc == NULL )
		goto cleanup;

	hRemoteThread = CreateRemoteThread( hProcess, 0, 0, 
		(LPTHREAD_START_ROUTINE)pfnProc, (LPVOID)dwArgument, 0, (DWORD*)&ThreadId );

	if( lpdwFuncRetVal != NULL )
	{
		dwWaitRes = WaitForSingleObject( hRemoteThread, INFINITE );
		switch ( rc )
		{
		case WAIT_OBJECT_0:
			GetExitCodeThread( hRemoteThread, lpdwFuncRetVal );
			break;

		case WAIT_FAILED:
		case WAIT_TIMEOUT:
		default:
			goto cleanup;
		}
	}

	rc = TRUE;

cleanup:

	if( hProcess != NULL )
	{
		CloseHandle( hProcess );
	}

	if( hRemoteThread != NULL )
	{
		CloseHandle( hRemoteThread );
	}

	return rc;
}

// The whole shebang makes a number of assumptions:
// -- target process is a Win32 process
// -- kernel32.dll loaded at same address in each process (safe)
// -- bem() shorter than MAXINJECTSIZE
// -- bem() does not rely on the C/C++ runtime
// -- /GZ is _not_ used. (If it is, the compiler generates calls
//    to functions which are not injected into the target. Oops!
// -- Target function uses WINAPI (pascal) call convention.
DWORD __stdcall RemoteDllThread( RemoteDllThreadBlock* execBlock )
{
	// and this is the code we are injecting

	typedef DWORD (WINAPI *PFN)();
	typedef DWORD (WINAPI *PFN1)(DWORD);
	typedef DWORD (WINAPI *PFN2)(DWORD,DWORD);
	typedef DWORD (WINAPI *PFN3)(DWORD,DWORD,DWORD);
	typedef DWORD (WINAPI *PFN4)(DWORD,DWORD,DWORD,DWORD);
	typedef DWORD (WINAPI *PFN5)(DWORD,DWORD,DWORD,DWORD,DWORD);
	typedef DWORD (WINAPI *PFN6)(DWORD,DWORD,DWORD,DWORD,DWORD,DWORD);
	typedef DWORD (WINAPI *PFN7)(DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD);
	typedef DWORD (WINAPI *PFN8)(DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD);

	HMODULE hModule = NULL;

	// clear the error codes
	execBlock->ErrorLoad = 0;
	execBlock->ErrorFunction = 0;
	execBlock->ErrorFree = 0;

	// load the requested dll
	if ( execBlock->bLoadLibrary )
	{
		execBlock->hModule = (HMODULE)(*execBlock->fnLoadLibrary)( execBlock->lpModulePath );

		hModule = execBlock->hModule;

		execBlock->ErrorLoad = execBlock->hModule != NULL ? 0 : 1;
	}

	// if we didn't load the library, try to query the module handle
	if ( hModule == NULL )
		hModule = (*execBlock->fnGetModuleHandle)( execBlock->lpModulePath );

	// call function
	if ( execBlock->lpFunctionName[0] != 0 )
	{
		//execute a function if we have a function name
		PFN pfn = (PFN)
			(*execBlock->fnGetProcAddress)( hModule, execBlock->lpFunctionName );

		// execute the function, and get the result
		if ( pfn != NULL )
		{
			DWORD ret = 0;
			DWORD* p = execBlock->Arguments;
			execBlock->ErrorFunction = 0;

			execBlock->LastError = 0;
			execBlock->fnSetLastError( execBlock->LastError );

			// !!!! Switch is a bad idea: compiler does something with it and
			// function don't copy correctly into the remote process
/*
#define S_BEGIN \
			switch( execBlock->dwArgumentCount ) \
			{ \

#define S_CASE(x)	case x:
#define S_ENDCASE	break;
// this condition must be checked and prevented in ExecuteRemoteThread()!
#define S_END \
				default: \
					execBlock->ErrorFunction = 1; \
			}
*/

#define S_BEGIN		DWORD cnt = execBlock->dwArgumentCount; if( cnt != execBlock->dwArgumentCount ) { }
#define S_CASE(x)	else if( cnt == (x) ) {
#define S_ENDCASE	}
#define S_END		else { execBlock->ErrorFunction = 2; }

			S_BEGIN
				S_CASE(0)		ret = (*(PFN) pfn)();  S_ENDCASE
				S_CASE(1)		ret = (*(PFN1)pfn)(p[0]);  S_ENDCASE
				S_CASE(2)		ret = (*(PFN2)pfn)(p[0],p[1]);  S_ENDCASE
				S_CASE(3)		ret = (*(PFN3)pfn)(p[0],p[1],p[2]);  S_ENDCASE
				S_CASE(4)		ret = (*(PFN4)pfn)(p[0],p[1],p[2],p[3]);  S_ENDCASE
				S_CASE(5)		ret = (*(PFN5)pfn)(p[0],p[1],p[2],p[3],p[4]);  S_ENDCASE
				S_CASE(6)		ret = (*(PFN6)pfn)(p[0],p[1],p[2],p[3],p[4],p[5]);  S_ENDCASE
				S_CASE(7)		ret = (*(PFN7)pfn)(p[0],p[1],p[2],p[3],p[4],p[5],p[6]);  S_ENDCASE
				S_CASE(8)		ret = (*(PFN8)pfn)(p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);  S_ENDCASE
			S_END

			execBlock->LastError = execBlock->fnGetLastError();
			execBlock->ReturnCodeForFunction = ret;

			if( execBlock->SpecialMode != RemoteExecute::NO_SPECIAL_MODE )
			{
				execBlock->ReturnCodeForFunctionSpecial = 0;
			}

			if( execBlock->SpecialMode == RemoteExecute::GET_COMMAND_LINE )
			{
				TCHAR* p = (TCHAR*)ret;
				if( p != NULL )
				{
					int n = 0;
					while( *p )
					{
						n++;
						p++;
					}
					execBlock->ReturnCodeForFunctionSpecial = (n + 1 ) * sizeof(TCHAR);
				}
			}
			else if( execBlock->SpecialMode == RemoteExecute::GET_ENVIRONMENT )
			{
				TCHAR* p = (TCHAR*)ret;
				if( p != NULL )
				{
					int n = 0;
					while( *p )
					{
						while( *p )
						{
							n++;
							p++;
						}
						n++;
						p++;
					}
					execBlock->ReturnCodeForFunctionSpecial = (n + 1 ) * sizeof(TCHAR);
				}

			}
		}
		else
			execBlock->ErrorFunction = 1;
	}

	// free library
	if ( execBlock->bFreeLibrary )
	{
		execBlock->ErrorFree = execBlock->fnFreeLibrary( hModule ) ? 0 : 1;
	}

	execBlock->hModule = hModule;
	
	return 0;
}

/*
// and this is the code we are injecting
DWORD __stdcall RemoteGetCurrentDirectoryThread( RemoteGetCurrentDirectoryThreadBlock* pParam )
{
	pParam->dwReturnCode = (*pParam->fnGetCurrentDirectoryW )( pParam->lpDirectory, SIZEOF_ARRAY(pParam->lpDirectory) );

	return 0;
}
*/

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 Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior)
Belarus Belarus
He is a young and forward-looking software developer. He also has lots of interesting hobbies like snowboarding, bicycle riding, carting racing and of course talking about himself in a third person. Smile | :)

github.com/kolomenkin

Curriculum Vitae

Comments and Discussions