asmfan с импортом нестандартных библиотек, конечно, придется повозиться) вот улучшенный код. Функция DWORD TransferProgramEx(HANDLE hProcess) переносит код программы в чужое адресное пространство. Если там адреса заняты, выбирается первый свободный участок достаточного размера и туда переносится программа с применением фиксапов (собирать, конечно, нужно с ними). Возвращает дельту в базах, 0 - если загружено по тому же адресу, -1 если загрузка не удалась. Код (Text): // 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)); } } 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; }
А не достаточно ли проверять State - MEM_FREE и RegionSize >= требуемый размер, а не атрибуты защиты страниц?
для удобства =) если не нравится, копируй только код поточной функции + данные + импорт, и корректируй фиксапы для потока asmfan имхо без ощутимой разницы)
еще стоит при инжекте всего образа с фиксапами после корректировки фиксапов делоть корректировку импорта и подгрузку нужных либ. так как может оказаться что какаято либа будет загружена не по тому же адресу(я не про кернел), либо быть вообще не загруженной. и вся обработка может быть засунута в инжектируемый код, что позволит лишний раз не юзать write/readprocmem
Great Самих Reloc блоков может присутствовать столько, что каждый покрывает 4К пространство, поэтому не только fixup'ы надо считать, но и к-во IMAGE_BASE_RELOCATION.
Код (Text): PIMAGE_BASE_RELOCATION Reloc = (PIMAGE_BASE_RELOCATION) RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, hmodule); И далее считаешь к-во fixup'ов в данном блоке. Блоков может быть много, т.к. 12битовое смещение каждого фиксапа в данном блоке (Fixup->Offset) адресует 4К памяти.
В таблице директорий общий размер всех блоков и смещений, блоки распологаются последовательно, т.е. каждый следующий блок распологается после смещений предыдущего. [added] Как пример этого всего, посмотри под Hiew екзешку (f8->f10->fixups).
asmfan просто мне один раз надо было большую прогу перенести, фиксапнул только первый блок (про другие не знал) и удивлялся, почему не все адреса поменялись )
Не выход абсолютно, релоки не обязаны находиться в отдельной секции, а как следствие нет выравнивания нулями. (пример директива DATA FIXUPS в фасме - в любом месте может быть прописана)
Great Чёто нигде не видел пофиксеный вариант твоего кодеса. Выкладываю: Код (Text): PIMAGE_BASE_RELOCATION Reloc = (PIMAGE_BASE_RELOCATION) RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, hmodule); // Process fixups for (; Reloc->VirtualAddress > 0; ) { PIMAGE_FIXUP_ENTRY Fixup = (PIMAGE_FIXUP_ENTRY)( (DWORD)Reloc + sizeof(IMAGE_BASE_RELOCATION) ); for (DWORD i=0; i<((Reloc->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION)) / 2); i++, Fixup++) { 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; } } Reloc = (PIMAGE_BASE_RELOCATION)(((DWORD)Reloc) + Reloc->SizeOfBlock); }