From fc2053838f14412d0f31d94bb7650b140d98a13a Mon Sep 17 00:00:00 2001 From: Peter Oberndorfer Date: Fri, 4 Jan 2008 11:46:06 +0100 Subject: [PATCH] ntdll: move relocations from mapping into loader while writing test for some mem mapping functions i found that the relocation should happen in the loader and not in NtMapViewOfSection http://www.codeguru.com/forum/archive/index.php/t-376151.html describes this a bit still quite hackish it changes protections of each section in the image without checking if it is even needed need to check if "oep points into data section check" is supposed to happen inside NtMapViewOfSection or later in the loader --- dlls/ntdll/loader.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++-- dlls/ntdll/tests/file.c | 12 ++--- dlls/ntdll/virtual.c | 117 ++++------------------------------------------ 3 files changed, 134 insertions(+), 117 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index df10de4e3a4..2c079fa2de7 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1381,6 +1381,75 @@ static void load_builtin_callback( void *module, const char *filename ) } +/*********************************************************************** + * do_relocations + * + * Apply the relocations to a mapped PE image + */ +static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir, + int delta, SIZE_T total_size ) +{ + IMAGE_BASE_RELOCATION *rel; + + TRACE_(module)( "relocating from %p-%p to %p-%p\n", + base - delta, base - delta + total_size, base, base + total_size ); + + for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress); + ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock; + rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) ) + { + char *page = base + rel->VirtualAddress; + WORD *TypeOffset = (WORD *)(rel + 1); + int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset); + + if (!count) continue; + + /* sanity checks */ + if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size) + { + ERR_(module)("invalid relocation %p,%x,%d at %p,%x,%x\n", + rel, rel->VirtualAddress, rel->SizeOfBlock, + base, dir->VirtualAddress, dir->Size ); + return 0; + } + + if (page > base + total_size) + { + WARN_(module)("skipping %d relocations for page %p beyond module %p-%p\n", + count, page, base, base + total_size ); + continue; + } + + TRACE_(module)("%d relocations for page %x\n", count, rel->VirtualAddress); + + /* patching in reverse order */ + for (i = 0 ; i < count; i++) + { + int offset = TypeOffset[i] & 0xFFF; + int type = TypeOffset[i] >> 12; + switch(type) + { + case IMAGE_REL_BASED_ABSOLUTE: + break; + case IMAGE_REL_BASED_HIGH: + *(short*)(page+offset) += HIWORD(delta); + break; + case IMAGE_REL_BASED_LOW: + *(short*)(page+offset) += LOWORD(delta); + break; + case IMAGE_REL_BASED_HIGHLOW: + *(int*)(page+offset) += delta; + /* FIXME: if this is an exported address, fire up enhanced logic */ + break; + default: + FIXME_(module)("Unknown/unsupported fixup type %d.\n", type); + break; + } + } + } + return 1; +} + /****************************************************************************** * load_native_dll (internal) */ @@ -1408,7 +1477,9 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY ); NtClose( mapping ); - if (status != STATUS_SUCCESS) return status; + + if (status != STATUS_SUCCESS && status != STATUS_IMAGE_NOT_AT_BASE) + return status; filename = strrchrW(name, '\\'); if(filename) @@ -1429,6 +1500,53 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, } } + nt = RtlImageNtHeader( module ); + + if(status == STATUS_IMAGE_NOT_AT_BASE) + { + /* image was not loaded at preferred address -> need to relocate it */ + char *ptr = (char*) module; + const IMAGE_DATA_DIRECTORY *relocs; + char* base; + IMAGE_SECTION_HEADER *sec; + ULONG old_protections[255];//FIXME + int i; + PVOID address; + SIZE_T size; + ULONG old_prot; + + nt = RtlImageNtHeader( module ); + base = (char*)nt->OptionalHeader.ImageBase; + relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + + sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) + { + if(i>=255) break; + address = ptr + sec->VirtualAddress;//FIXME: virtual.c does some rounding/sanity checks on the parameters + size = sec->Misc.VirtualSize; +// FIXME("unprotecting %x, %p, %x\n", sec->Misc.VirtualSize, address, size); + status = NtProtectVirtualMemory(NtCurrentProcess(), &address, &size, PAGE_READWRITE, &old_prot); + old_protections[i] = old_prot; + if(status) + FIXME("NtProtectVirtualMemory failed with %x\n", status); + } + +// FIXME("relocating DLL %s %p, %p %x\n", debugstr_w(name), ptr, base, ptr-base); +// FIXME("len: %lx, size:%x%08x\n", len, size.u.HighPart, size.u.LowPart); + do_relocations(ptr, relocs, ptr - base, len); + + sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) + { + if(i>=255) break; + address = ptr + sec->VirtualAddress;//FIXME: virtual.c does some rounding/sanity checks on the parameters + size = sec->Misc.VirtualSize; + status = NtProtectVirtualMemory(NtCurrentProcess(), &address, &size, old_protections[i], &old_prot); + if(status) + FIXME("NtProtectVirtualMemory failed with %x\n", status); + } + } if (is_fake_dll( module )) { @@ -1464,8 +1582,6 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, /* send DLL load event */ - nt = RtlImageNtHeader( module ); - SERVER_START_REQ( load_dll ) { req->handle = file; diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index f7dd3cafef4..41ce81dbc79 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1139,7 +1139,7 @@ static void NtMapViewOfSection_test(void) status = pNtMapViewOfSection(NULL, NtCurrentProcess(), &mapping_address, 0, 0, &offset, &mapping_size, ViewShare, 0, PAGE_READWRITE); ok( status == STATUS_INVALID_HANDLE, "NtMapViewOfSection failed with %x\n", status ); - + trace("mapping_size: %lx\n", mapping_size); mapping_address = NULL; offset.QuadPart = 0; mapping_size = 0; @@ -1320,7 +1320,7 @@ static void NtAreMappedFilesTheSame_test(void) /* second mapping */ status = pNtMapViewOfSection(section, NtCurrentProcess(), &address2, 0, 0, &offset, &mapping_size, ViewShare, 0, PAGE_READWRITE); - todo_wine ok( status == STATUS_IMAGE_NOT_AT_BASE, "NtMapViewOfSection failed with %x\n", status); + ok( status == STATUS_IMAGE_NOT_AT_BASE, "NtMapViewOfSection failed with %x\n", status); ok( address2 != NULL, "Mapping address is 0\n"); address3 = NULL; @@ -1330,7 +1330,7 @@ static void NtAreMappedFilesTheSame_test(void) /* third mapping */ status = pNtMapViewOfSection(section2, NtCurrentProcess(), &address3, 0, 0, &offset, &mapping_size, ViewShare, 0, PAGE_READWRITE); - todo_wine ok( status == STATUS_IMAGE_NOT_AT_BASE, "NtMapViewOfSection failed with %x\n", status); + ok( status == STATUS_IMAGE_NOT_AT_BASE, "NtMapViewOfSection failed with %x\n", status); ok( address3 != NULL, "Mapping address is 0\n"); address4 = NULL; @@ -1605,7 +1605,7 @@ static void NtMapViewOfSection_relocation_test() /* relocation is not done by NtMapViewOfSection but later */ status = pNtMapViewOfSection(section, NtCurrentProcess(), &address2, 0, 0, &offset, &mapping_size, ViewShare, 0, PAGE_READWRITE); - todo_wine ok( status == STATUS_IMAGE_NOT_AT_BASE, "NtMapViewOfSection failed with %x\n", status ); + ok( status == STATUS_IMAGE_NOT_AT_BASE, "NtMapViewOfSection failed with %x\n", status ); ok( address2 != NULL, "Mapping address is 0\n" ); trace("second mapping at: %p\n", address2); @@ -1661,8 +1661,8 @@ static void NtMapViewOfSection_relocation_test() dump_mem_basic(&mem_basic_info); trace("relocated var1: %x var2: %x\n", section_text->address, section_text2->address); - todo_wine ok( section_text->address == section_text2->address, "second dlls should not be relocated yet %x/%x\n", section_text->address, section_text2->address ); - todo_wine ok( section_text2->address == BASEADDRESS + DATA_RVA, "address wrong %x/%x\n", section_text->address, BASEADDRESS + DATA_RVA ); + ok( section_text->address == section_text2->address, "second dlls should not be relocated yet %x/%x\n", section_text->address, section_text2->address ); + ok( section_text2->address == BASEADDRESS + DATA_RVA, "address wrong %x/%x\n", section_text->address, BASEADDRESS + DATA_RVA ); status = pNtUnmapViewOfSection(NtCurrentProcess(), address); ok( status == STATUS_SUCCESS, "NtUnmapViewOfSection failed with %x\n", status ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 644d5cf4b71..7888a6cc389 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -864,76 +864,6 @@ static NTSTATUS decommit_pages( struct file_view *view, size_t start, size_t siz /*********************************************************************** - * do_relocations - * - * Apply the relocations to a mapped PE image - */ -static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir, - int delta, SIZE_T total_size ) -{ - IMAGE_BASE_RELOCATION *rel; - - TRACE_(module)( "relocating from %p-%p to %p-%p\n", - base - delta, base - delta + total_size, base, base + total_size ); - - for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress); - ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock; - rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) ) - { - char *page = base + rel->VirtualAddress; - WORD *TypeOffset = (WORD *)(rel + 1); - int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset); - - if (!count) continue; - - /* sanity checks */ - if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size) - { - ERR_(module)("invalid relocation %p,%x,%d at %p,%x,%x\n", - rel, rel->VirtualAddress, rel->SizeOfBlock, - base, dir->VirtualAddress, dir->Size ); - return 0; - } - - if (page > base + total_size) - { - WARN_(module)("skipping %d relocations for page %p beyond module %p-%p\n", - count, page, base, base + total_size ); - continue; - } - - TRACE_(module)("%d relocations for page %x\n", count, rel->VirtualAddress); - - /* patching in reverse order */ - for (i = 0 ; i < count; i++) - { - int offset = TypeOffset[i] & 0xFFF; - int type = TypeOffset[i] >> 12; - switch(type) - { - case IMAGE_REL_BASED_ABSOLUTE: - break; - case IMAGE_REL_BASED_HIGH: - *(short*)(page+offset) += HIWORD(delta); - break; - case IMAGE_REL_BASED_LOW: - *(short*)(page+offset) += LOWORD(delta); - break; - case IMAGE_REL_BASED_HIGHLOW: - *(int*)(page+offset) += delta; - /* FIXME: if this is an exported address, fire up enhanced logic */ - break; - default: - FIXME_(module)("Unknown/unsupported fixup type %d.\n", type); - break; - } - } - } - return 1; -} - - -/*********************************************************************** * map_image * * Map an executable (PE format) image into memory. @@ -1041,13 +971,6 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz /* perform relocations if necessary */ /* FIXME: not 100% compatible, Windows doesn't do this for non page-aligned binaries */ - if (ptr != base) - { - const IMAGE_DATA_DIRECTORY *relocs; - relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - if (relocs->VirtualAddress && relocs->Size) - do_relocations( ptr, relocs, ptr - base, total_size ); - } goto done; } @@ -1144,35 +1067,6 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz } } - - /* perform base relocation, if necessary */ - - if (ptr != base) - { - const IMAGE_DATA_DIRECTORY *relocs; - - relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) - { - WARN( "Need to relocate module from addr %lx, but there are no relocation records\n", - (ULONG_PTR)nt->OptionalHeader.ImageBase ); - status = STATUS_CONFLICTING_ADDRESSES; - goto error; - } - - /* FIXME: If we need to relocate a system DLL (base > 2GB) we should - * really make sure that the *new* base address is also > 2GB. - * Some DLLs really check the MSB of the module handle :-/ - */ - if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((ULONG_PTR)base & 0x80000000)) - ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" ); - - if (!do_relocations( ptr, relocs, ptr - base, total_size )) - { - goto error; - } - } - /* set the image protections */ VIRTUAL_SetProt( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ ); @@ -1995,7 +1889,8 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p res = NTDLL_queue_process_apc( process, &call, &result ); if (res != STATUS_SUCCESS) return res; - if (result.map_view.status == STATUS_SUCCESS) + if (result.map_view.status == STATUS_SUCCESS || result.map_view.status == STATUS_IMAGE_NOT_AT_BASE) + //FIXME maybe use NT_SUCCESS macro which ignores information status values(0x4xxxxxxx) { *addr_ptr = result.map_view.addr; *size_ptr = result.map_view.size; @@ -2043,7 +1938,13 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p -1, dup_mapping, addr_ptr ); } if (needs_close) close( unix_handle ); - if (!res) *size_ptr = size; + if (!res) + { + *size_ptr = size; +// FIXME("addr_ptr: %p, base: %p\n", *addr_ptr, base); + if(*addr_ptr != base) + return STATUS_IMAGE_NOT_AT_BASE; + } return res; } -- 2.11.4.GIT