All pastes #2122599 Raw Edit

2ci-

public cpp v1 · immutable
#2122599 ·published 2012-02-29 03:00 UTC
rendered paste body
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *														 ** Class Name: cModuleLoader								 ** Written by: 2ci-										 ** http://www.cod2hacks.com								 **														 ** This is a class implementation based on ManualMap		 ** written by Darawk. Full credits go to him.			 ** This version has an extra feature which i needed.		 ** * * * * * * * * * * * * * * * * * * * * * * * * * * * *///				ManualMap - by Darawk////	v1.1//	- Fixed a bug that would cause it not to load modules//	  that were in folders in the PATH environment variable//	- Fixed a bug that made it so that when ManualMap loaded//	  a dependency of the main module it was loading, it//	  wouldn't keep track of them, so GetRemoteModuleHandle()//	  wouldn't be able to find it them.  This would have//	  made it impossible for the main module to import//	  functions from some of it's dependencies.//	- Also new is that I wrote my own implementation of//	  GetProcAddress.  Available here://	  http://www.darawk.com/Code/GetProcAddress2.cpp//	  This allows you to dynamically locate functions//	  exported by ManualMap'd modules.  ////	The purpose of ManualMap is to "manually map" a dll//	module into a remote process's address space.  This//	means that instead of just manipulating the remote//	process into calling the LoadLibrary function, we//	have our own emulation of what LoadLibrary does//	without all those annoying detectability issues ^^.//	The advantage of this method over using something //	like my CloakDll function, is that this method never //	has to call a function like LoadLibrary inside the //	remote process.  Since LoadLibrary can be hooked, //	the dll	could still be caught at the injection stage. //	Or possibly also through the weakness I discussed in //	the comment header of that file, which is not present//	when using this technique.#include <windows.h>#include <tlhelp32.h>#include <shlwapi.h>#include <vector>#include "cModuleLoader.h"//	Pietrek's macro////	MakePtr is a macro that allows you to easily add to values (including//	pointers) together without dealing with C's pointer arithmetic.  It//	essentially treats the last two parameters as DWORDs.  The first//	parameter is used to typecast the result to the appropriate pointer type.#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))//	This one is mine (Darawk), but obviously..."adapted" from matt's original idea =p#define MakeDelta(cast, x, y) (cast) ( (DWORD_PTR)(x) - (DWORD_PTR)(y))//	Stub that calls the Dll from within the remote process.//	This is necessary because a DllMain function takes 3//	arguments, and CreateRemoteThread can pass only 1.#define DLL_BASEADDR_OFFSET 9// This wont work in debug mode!__declspec( naked )void DllCall_stub( HMODULE hMod ){	_asm	{//		int 3;		push 0		push 1		push [esp+0Ch]		//	Pointer to the hMod argument        mov eax, 0xDEADBEEF	//	Patch this in with the real value at run-time		call eax			//	MSVC++ doesn't like direct absolute calls, so we have to be							//	clever about it.		ret					//	Don't have to clean up the stack because the calling function							//	is just going to call ExitThread() immediately after this							//	function returns.	}}//unsigned char *DllCall_stub = (unsigned char * )"\x6A\x00\x6A\x01\xFF\x74\x24\x0C\xB8\xEF\xBE\xAD\xDE\xFF\xD0\xC3";//	Marker for the end of the DllCall_stub function__declspec(naked) void DC_stubend(void) { }	std::vector<MODULE*>	cModuleLoader::mappedMods;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////cModuleLoader::cModuleLoader( unsigned long processId, char *pszmoduleName ){	m_ModuleBase	= NULL;	m_ProcessId		= processId;	strncpy( m_szModuleName, pszmoduleName, sizeof(m_szModuleName) );	InitFileMapping( pszmoduleName );}cModuleLoader::cModuleLoader( unsigned long processId, unsigned char *pbModule ){	m_ModuleBase	= NULL;	m_ProcessId		= processId;	strncpy( m_szModuleName, "(NULL)", sizeof(m_szModuleName) );	InitMemoryMapping( pbModule );}cModuleLoader::~cModuleLoader(){}HMODULE cModuleLoader::GetModuleHandle(){	int somecrap = 123;	somecrap+=123;	DWORD moduleBase = PtrToUlong( m_ModuleBase );	return( (HMODULE)m_ModuleBase );}char * cModuleLoader::GetModuleName(){	return( m_szModuleName );}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void cModuleLoader::InitFileMapping( char *pszmoduleName ){	HANDLE			hFile		= OpenModule( pszmoduleName );	unsigned int	fileSize	= 0;	unsigned long	nBytesRead	= 0;	if( hFile == INVALID_HANDLE_VALUE ) {		return;	}		fileSize	= GetModuleSize( hFile, pszmoduleName );	if( fileSize == INVALID_FILE_SIZE ) {		return;	}	m_pbRawDll = new unsigned char[ fileSize ];	ReadFile( hFile, m_pbRawDll, fileSize, &nBytesRead, FALSE );	CloseHandle( hFile );}void cModuleLoader::InitMemoryMapping( unsigned char *pbModule ){	m_pbRawDll = pbModule;}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////HMODULE cModuleLoader::LoadDll(){	PIMAGE_DOS_HEADER	pDOSHeader	= NULL;	PIMAGE_NT_HEADERS	pNTHeader	= NULL;	DWORD				dwCallStubSize	= 0;	DWORD				dwPageAddress	= 0;	// Enough to be safe #if defined( _DEBUG )	dwCallStubSize = 0x20;#else	dwCallStubSize = 0x20;//	dwCallStubSize = MakeDelta(SIZE_T, DC_stubend, DllCall_stub);#endif	if( !GetPEHeaders( (DWORD*)m_pbRawDll, pDOSHeader, pNTHeader ) ) {		delete[]m_pbRawDll;		return( NULL );	}	dwPageAddress = pNTHeader->OptionalHeader.ImageBase;	HANDLE	hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, m_ProcessId );	if( hProcess == NULL ) {		delete[]m_pbRawDll;		return( NULL );	}		m_ModuleBase	= VirtualAllocEx( hProcess,		(LPVOID)dwPageAddress,		pNTHeader->OptionalHeader.SizeOfImage,		MEM_COMMIT | MEM_RESERVE,		PAGE_EXECUTE_READWRITE );	if( m_ModuleBase == NULL ) {		return( NULL );	}	m_StubBase		= VirtualAllocEx( hProcess,		NULL,		dwCallStubSize, // THIS WILL BREAK IN DEBUG MODE!!		MEM_COMMIT | MEM_RESERVE,		PAGE_EXECUTE_READWRITE );	//////////////////////////////////////////////////////////////////////////	//	Fix up the import table of the new module	//////////////////////////////////////////////////////////////////////////	PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA(		(DWORD)( pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ),		pNTHeader,		m_pbRawDll );		if( pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size ) {		FixImports( (unsigned char *)m_pbRawDll, pNTHeader, pImportDesc );	}	//	Fix "base relocations" of the new module.  Base relocations are places	//	in the module that use absolute addresses to reference data.  Since	//	the base address of the module can be different at different times,	//	the base relocation data is necessary to make the module loadable	//	at any address.	PIMAGE_BASE_RELOCATION	pReloc = ( PIMAGE_BASE_RELOCATION )GetPtrFromRVA(		(DWORD)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),		pNTHeader, 		m_pbRawDll );	if( pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size ) {		FixRelocs( m_pbRawDll, m_ModuleBase, pNTHeader, pReloc,			pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);	}	DWORD			dwNumberOfBytes = 0;	//	Write the PE header into the remote process's memory space	WriteProcessMemory( hProcess, m_ModuleBase, m_pbRawDll,		pNTHeader->FileHeader.SizeOfOptionalHeader + sizeof(pNTHeader->FileHeader) + sizeof(pNTHeader->Signature),		&dwNumberOfBytes );	//	Map the sections into the remote process(they need to be aligned	//	along their virtual addresses)	MapSections( hProcess, m_ModuleBase, m_pbRawDll, pNTHeader );	//	Change the page protection on the DllCall_stub function from PAGE_EXECUTE_READ	//	to PAGE_EXECUTE_READWRITE, so we can patch it.	VirtualProtect( (LPVOID)DllCall_stub, 		dwCallStubSize, 		PAGE_EXECUTE_READWRITE,		&dwNumberOfBytes);	//	Patch the stub so it calls the correct address	*MakePtr(unsigned long *, DllCall_stub, DLL_BASEADDR_OFFSET) = 		MakePtr(unsigned long, m_ModuleBase, pNTHeader->OptionalHeader.AddressOfEntryPoint);	//	Write the stub into the remote process	WriteProcessMemory( hProcess, m_StubBase, (LPVOID)DllCall_stub, 		dwCallStubSize,		&dwNumberOfBytes );	//	Execute our stub in the remote process	CreateRemoteThread(hProcess, 		NULL, 		0, 		(LPTHREAD_START_ROUTINE)m_StubBase,		m_ModuleBase,	//	Pass the base address of the module as the argument to the stub.		//	All a module handle is, is the base address of the module(except		//	in windows CE), so we're really passing a handle to the module		//	so that it can refer to itself, create dialogs, etc..		0, 		NULL);	//	Cleanup after ourselves	VirtualFreeEx( hProcess, m_StubBase, dwCallStubSize, MEM_DECOMMIT | MEM_RELEASE );	CloseHandle( hProcess );	delete[] m_pbRawDll;	return (HMODULE)m_ModuleBase;}HMODULE cModuleLoader::LoadLibraryDll( char *pszmoduleName ){	PTHREAD_START_ROUTINE	pfnThread;	HANDLE					hThread;	LPSTR					pszRemotePath	= NULL;		HANDLE	hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, m_ProcessId );	// Allocate some memory for the string	pszRemotePath = ( LPSTR )VirtualAllocEx( hProcess, NULL, 255, MEM_COMMIT, PAGE_EXECUTE_READWRITE );	// Write the file path into the memory	WriteProcessMemory( hProcess, pszRemotePath, pszmoduleName, lstrlen( pszmoduleName ), 0 );	// GetProcAddress of LoadLibrary	pfnThread = ( PTHREAD_START_ROUTINE )GetProcAddress( LoadLibrary( "kernel32.dll"), "LoadLibraryA" );	// push LoadLibary as the func to call with "path.to.dll" as the params.	hThread = CreateRemoteThread( hProcess, NULL, 0, pfnThread, pszRemotePath, 0, NULL );	// Wait for exit	WaitForSingleObject( hThread, INFINITE );		DWORD		dwLibBase = 0;	if (!GetExitCodeThread( hThread, &dwLibBase ) ) {		VirtualFreeEx( hProcess, pszRemotePath, 255, MEM_DECOMMIT );		return( NULL );	}	CloseHandle( hThread );	VirtualFreeEx( hProcess, pszRemotePath, 255, MEM_DECOMMIT );	return( GetRemoteModuleHandle( m_ProcessId, pszmoduleName) );}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////HANDLE cModuleLoader::OpenModule( char *pszModuleName ){#define MAX_ENV_LEN 32767	char pathVar[MAX_ENV_LEN], *p, *p2;	char modPath[MAX_PATH] = {0};	char c;	HANDLE hFile;		//	If it's an absolute path that was passed to us(i.e. C:\xxx or D:\xxx) then we don't need	//	do scan the PATH folders.	if(!strchr(pszModuleName, ':'))	{		GetEnvironmentVariable("PATH", pathVar, MAX_ENV_LEN);		p = pathVar;		while(p2 = strchr(p, ';'))		{			memset(modPath, 0, sizeof(modPath));			c = *p2;			*p2 = '\0';			strncpy(modPath, p, MAX_PATH);			strcat(modPath, "\\");			strcat(modPath, pszModuleName);				p = ++p2;			hFile = CreateFile(modPath, 				GENERIC_READ, 				FILE_SHARE_READ | FILE_SHARE_WRITE, 				NULL, 				OPEN_EXISTING, 				FILE_ATTRIBUTE_NORMAL, 				NULL);						if(hFile && hFile != INVALID_HANDLE_VALUE)				return hFile;		}		}	hFile = CreateFile(pszModuleName, 		GENERIC_READ, 		FILE_SHARE_READ | FILE_SHARE_WRITE, 		NULL, 		OPEN_EXISTING, 		FILE_ATTRIBUTE_NORMAL, 		NULL);    return hFile;}unsigned int cModuleLoader::GetModuleSize( HANDLE hFile, char *pszModuleName ){	unsigned int fSize = 0;//	if( GetFileAttributes(pszModuleName) & FILE_ATTRIBUTE_COMPRESSED ) {//		fSize = GetCompressedFileSize( pszModuleName, NULL );//	} else {		fSize = GetFileSize( hFile, NULL );//	}	return( fSize );}bool cModuleLoader::GetPEHeaders( DWORD * dllBase, PIMAGE_DOS_HEADER & pDOSHeader, PIMAGE_NT_HEADERS & pNTHeader ){	//  Grab the Dos Header	pDOSHeader = MakePtr( PIMAGE_DOS_HEADER, dllBase, 0 );	if( pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE )	{		return( false );	}	//  Grab the NT Header	pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dllBase, pDOSHeader->e_lfanew );	if( pNTHeader->Signature != IMAGE_NT_SIGNATURE )	{		return( false );	}	return( true );}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////FARPROC cModuleLoader::GetRemoteProcAddress( unsigned long pId, char *module, char *func ){	HMODULE remoteMod	= GetRemoteModuleHandle( pId, module );	HMODULE localMod	= ::GetModuleHandle( module );	//	Account for potential differences in base address	//	of modules in different processes.	unsigned long delta = MakeDelta( unsigned long, remoteMod, localMod );	return MakePtr( FARPROC, GetProcAddress( localMod, func ), delta );}HMODULE cModuleLoader::GetRemoteModuleHandle( unsigned long pId, char *module ){	MODULEENTRY32	modEntry;	HANDLE			tlh = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pId);	modEntry.dwSize = sizeof(MODULEENTRY32);	Module32First( tlh, &modEntry );		do {		if( !stricmp( modEntry.szModule, module ) ) {			return( modEntry.hModule );		}		modEntry.dwSize = sizeof(MODULEENTRY32);	}	while( Module32Next(tlh, &modEntry) );	//	If we didn't find it in the real list, check to see if it was one	//	of the dependencies that we just loaded.	for( unsigned int i = 0; i < mappedMods.size(); i++ ) {		if( !stricmp( mappedMods[i]->name, module ) ) {			return mappedMods[i]->handle;		}	}		return( NULL );}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool cModuleLoader::MapSections( HANDLE hProcess, void *moduleBase, void *dllBin, PIMAGE_NT_HEADERS pNTHeader ){	PIMAGE_SECTION_HEADER header = IMAGE_FIRST_SECTION(pNTHeader);	unsigned int nBytes			= 0;	unsigned int virtualSize	= 0;	unsigned int n				= 0;	//	Loop through the list of sections	for( unsigned int i = 0; pNTHeader->FileHeader.NumberOfSections; i++ ) {		//	Once we've reached the SizeOfImage, the rest of the sections		//	don't need to be mapped, if there are any.		if( nBytes >= pNTHeader->OptionalHeader.SizeOfImage ) {			break;		}		WriteProcessMemory (hProcess,			MakePtr(LPVOID, moduleBase, header->VirtualAddress),			MakePtr(LPCVOID, dllBin, header->PointerToRawData),			header->SizeOfRawData,			(LPDWORD)&n );				virtualSize = header->VirtualAddress;		header++;		virtualSize = header->VirtualAddress - virtualSize;		nBytes += virtualSize;		//	Set the proper page protections for this section.		//	This really could be skipped, but it's not that		//	hard to implement and it makes it more like a		//	real loader.		VirtualProtectEx( hProcess,			MakePtr(LPVOID, moduleBase, header->VirtualAddress),			virtualSize,			header->Characteristics & 0x00FFFFFF,			NULL );	}		return( true );}bool cModuleLoader::FixImports( void *base, PIMAGE_NT_HEADERS pNTHeader, PIMAGE_IMPORT_DESCRIPTOR pImportDesc ){	char *module;	//	Loop through all the required modules	while( ( module = (char *)GetPtrFromRVA( (DWORD)(pImportDesc->Name), pNTHeader, (PBYTE)base)))	{		//	If the library is already loaded(like kernel32.dll or ntdll.dll) LoadLibrary will		//	just return the handle to that module.		HMODULE localMod = LoadLibrary(module);		//	If the module isn't loaded in the remote process, we recursively call the		//	module mapping code.  This has the added benefit of ensuring that any of		//	the current module's dependencies will be just as invisible as this one.		if( !(GetRemoteModuleHandle(m_ProcessId, module) ) ) {						if( strstr( module, "ntdll") || strstr( module, "kernel32") ) {				LoadLibraryDll( module );			} else {				cModuleLoader *	pModule		= new cModuleLoader( m_ProcessId, module );				MODULE *		mod			= new MODULE;				memset( mod, 0, sizeof(MODULE) );				mod->handle	= pModule->LoadDll();				strncpy( mod->name, module, sizeof( mod->name ) );	//			mod->handle = pModule->GetModuleHandle();				if( mod->handle == 0 ) {					MessageBox( 0, mod->name, "handle == 0", MB_OK );				}				mappedMods.push_back( mod );			}		}		//	Lookup the first import thunk for this module		//	NOTE: It is possible this module could forward functions...which is something		//	that I really should handle.  Maybe i'll add support for forwarded functions		//	a little bit later.		PIMAGE_THUNK_DATA itd = (PIMAGE_THUNK_DATA)GetPtrFromRVA((DWORD)(pImportDesc->FirstThunk), pNTHeader, (PBYTE)base);		while( itd->u1.AddressOfData ) {			PIMAGE_IMPORT_BY_NAME iibn = NULL;			iibn = ( PIMAGE_IMPORT_BY_NAME )GetPtrFromRVA((DWORD)(itd->u1.AddressOfData), pNTHeader, (PBYTE)base);//			unsigned long delta = MakeDelta(unsigned long, remoteMod, localMod);//			itd->u1.Function = MakePtr( DWORD, GetProcAddress( localMod, ( char * )iibn->Name ), delta );			itd->u1.Function = MakePtr(DWORD, GetRemoteProcAddress(m_ProcessId, module, (char *)iibn->Name), 0 );			itd++;		}		pImportDesc++;	}	return( true );}bool cModuleLoader::FixRelocs(void *base, void *rBase, PIMAGE_NT_HEADERS pNTHeader, PIMAGE_BASE_RELOCATION pReloc, unsigned int size ){	unsigned long ImageBase	= pNTHeader->OptionalHeader.ImageBase;	unsigned int nBytes		= 0;	unsigned long delta = MakeDelta( unsigned long, rBase, ImageBase );	while( 1 ) {		unsigned long *locBase =  (unsigned long *)GetPtrFromRVA( 			(DWORD)(pReloc->VirtualAddress), pNTHeader, (PBYTE)base );		unsigned int numRelocs = ( pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof(WORD);		if( nBytes >= size ) {			break;		}		unsigned short *locData = MakePtr( unsigned short *, pReloc, sizeof(IMAGE_BASE_RELOCATION) );				for( unsigned int i = 0; i < numRelocs; i++ ) {			if( ( (*locData >> 12) & IMAGE_REL_BASED_HIGHLOW ) ) {				*MakePtr( unsigned long *, locBase, (*locData & 0x0FFF) ) += delta;			}			locData++;		}				nBytes += pReloc->SizeOfBlock;		pReloc = (PIMAGE_BASE_RELOCATION)locData;	}	return( true );}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////PIMAGE_SECTION_HEADER cModuleLoader::GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader ){	PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);	unsigned int i;	for ( i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )	{		// This 3 line idiocy is because Watcom's linker actually sets the		// Misc.VirtualSize field to 0.  (!!! - Retards....!!!)		DWORD size = section->Misc.VirtualSize;		if ( 0 == size )			size = section->SizeOfRawData;		// Is the RVA within this section?		if ( (rva >= section->VirtualAddress) && 			(rva < (section->VirtualAddress + size)))			return section;	}	return 0;}LPVOID cModuleLoader::GetPtrFromRVA( DWORD rva, PIMAGE_NT_HEADERS pNTHeader, PBYTE imageBase ){	PIMAGE_SECTION_HEADER	pSectionHeader = NULL;	INT delta;	pSectionHeader = GetEnclosingSectionHeader( rva, pNTHeader );	if( pSectionHeader == NULL ) {		return( NULL );	}	delta = (INT)( pSectionHeader->VirtualAddress-pSectionHeader->PointerToRawData );	return( imageBase + rva - delta );}