Показать сообщение отдельно

  #12  
Старый 30.04.2007, 20:01
_Great_
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
С нами: 10721066

Репутация: 4360


По умолчанию

Перенос программы в другое адресное пространство.

Был замечательный метод по инжекту кода в другую программу - вся наша программа постранично копировалась в чужое АП (адресное пространство) по тем же адресам со всеми заголовками, секциями и прочим.

Все было бы хорошо, пока там память свободна. Если там память занята, метод не предусматривал решения в этом случае.

Предлагаю модификацию: поиск наилучшего достаточного места в другом АП, копирование программы, коррекция фиксапов:

Код:
// Get VA
#define RVATOVA( base, offset )(((DWORD)(base) + (DWORD)(offset))) 

// Move program's memory
void __CopyMemoryAcrossProcesses( HANDLE hProcess, char* pMemLocal, char* pMemRemote )
{
	DWORD dwOldProt, dwNumBytes, i;
	MEMORY_BASIC_INFORMATION mbi;
	 
	VirtualQueryEx(hProcess, pMemRemote, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
	while (mbi.Protect!=PAGE_NOACCESS && mbi.RegionSize!=0)
	{
		if (!(mbi.Protect & PAGE_GUARD))
		{
			for (i = 0; i < mbi.RegionSize; i += 0x1000)
			{
				VirtualProtectEx(hProcess, pMemRemote + i, 0x1000,PAGE_EXECUTE_READWRITE, &dwOldProt);
				WriteProcessMemory(hProcess, pMemRemote + i, pMemLocal + i, 0x1000, &dwNumBytes);
			}
		}
		pMemLocal += mbi.RegionSize;
		pMemRemote += mbi.RegionSize;
		VirtualQueryEx(hProcess, pMemRemote, &mbi, sizeof(MEMORY_BASIC_INFORMATION));	
	}
}

bool TransferProgram(HANDLE hProcess)
{
	HMODULE g_module = GetModuleHandle(0);
	VirtualFreeEx(hProcess, g_module, 0, MEM_RELEASE);
	
	DWORD dwSize = ((PIMAGE_OPTIONAL_HEADER)((LPVOID)((BYTE *)(g_module) + ((PIMAGE_DOS_HEADER)(g_module))->e_lfanew + 
		sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER))))->SizeOfImage;

	char *pMem = (char *)VirtualAllocEx(hProcess, g_module, dwSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if(pMem == NULL) return FALSE;

	__CopyMemoryAcrossProcesses( hProcess, (char*) g_module, pMem );

	return true;
}

DWORD TransferProgramEx(HANDLE hProcess)
/*
 Return value: image base delta, -1 on error
*/
{
	HMODULE hmodule = GetModuleHandle(0);
	DWORD dwSize = ((PIMAGE_OPTIONAL_HEADER)((LPVOID)((BYTE *)(hmodule) + ((PIMAGE_DOS_HEADER)(hmodule))->e_lfanew + 
		sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER))))->SizeOfImage;

	MEMORY_BASIC_INFORMATION mbi = {0};
	VirtualQueryEx( hProcess, hmodule, &mbi, sizeof(mbi) );

	LPVOID Allocated;

	// Memory isn't free, relocate
	if( mbi.Protect!=PAGE_NOACCESS && mbi.RegionSize!=0 )
	{
__try_relocate:
		LPVOID DesiredAddress = hmodule;
		*(DWORD*)&DesiredAddress += mbi.RegionSize;

		for(;;)
		{
			Allocated = VirtualAllocEx( hProcess, DesiredAddress, dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
			if( Allocated )
				break;
			*(DWORD*)&DesiredAddress += dwSize;
		}
	}
	else
	{
		Allocated = VirtualAllocEx( hProcess, hmodule, dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
		if( !Allocated )
			goto __try_relocate;
	}

	// move memory
	__CopyMemoryAcrossProcesses( hProcess, (char*) hmodule, (char*) Allocated );

	DWORD ImageBaseDelta = (DWORD)Allocated - (DWORD)hmodule;

	// Nonzero imagebase delta
	if( ImageBaseDelta )
	{
		// Apply fixups
		typedef struct 
		{
			WORD	Offset:12;
			WORD	Type:4;
		} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;

		PIMAGE_OPTIONAL_HEADER poh = 
			(PIMAGE_OPTIONAL_HEADER)(
				(DWORD)hmodule
				+ ((PIMAGE_DOS_HEADER)hmodule)->e_lfanew
				+ sizeof(IMAGE_NT_SIGNATURE)
				+ sizeof(IMAGE_FILE_HEADER)
			);

		// No fixups?
		if( !poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress )
		{
			VirtualFreeEx( hProcess, Allocated, dwSize, MEM_DECOMMIT );
			VirtualFreeEx( hProcess, Allocated, dwSize, MEM_RELEASE  );
			return -1;
		}

		PIMAGE_BASE_RELOCATION Reloc = (PIMAGE_BASE_RELOCATION) RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, hmodule);
		int i = 0;

		// Process fixups
		for( PIMAGE_FIXUP_ENTRY Fixup = (PIMAGE_FIXUP_ENTRY)( (DWORD)Reloc + sizeof(IMAGE_BASE_RELOCATION) );
		     (DWORD)Fixup < (DWORD)Reloc + Reloc->SizeOfBlock -2;
			 Fixup ++, i ++
				 )
		{
			if( Fixup->Type == IMAGE_REL_BASED_HIGHLOW )
			{
				DWORD* Patch = (DWORD*)RVATOVA( Reloc->VirtualAddress + Fixup->Offset, Allocated );
				
				DWORD t, r;
				BOOL b = 1;

				// correct fixup
				b &= ReadProcessMemory( hProcess, Patch, &t, 4, &r );
				t += ImageBaseDelta;
				b &= WriteProcessMemory( hProcess, Patch, &t, 4, &r );

				if( !b ) 
				{
					// smth wrong
					VirtualFreeEx( hProcess, Allocated, dwSize, MEM_DECOMMIT );
					VirtualFreeEx( hProcess, Allocated, dwSize, MEM_RELEASE  );
					return -1;
				}
			}
			else 
			{
				// unsupported fixup type
				VirtualFreeEx( hProcess, Allocated, dwSize, MEM_DECOMMIT );
				VirtualFreeEx( hProcess, Allocated, dwSize, MEM_RELEASE  );
				return -1;
			}
		}
	}

	return ImageBaseDelta;
}
TransferProgram - старый вариант
TransferProgramEx - моя модификация

Использовать примерно так:

Код:
	DWORD ImageBaseDelta = TransferProgramEx( hProcess );

	switch(ImageBaseDelta)
	{
	case -1:
		return printf("Cannot copy body\n"), 0;

	case 0:
		printf("Program copied at the same addresses\n");
		break;

	default:
		printf("Program relocated (delta = 0x%08x)\n", ImageBaseDelta);
		break;
	}

	DWORD thID;
	HANDLE hTh;

	hTh = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE)((char*)RemoteThread+ImageBaseDelta), 0, 0, &thID);
	WaitForSingleObject( hTh, INFINITE );
 
Ответить с цитированием