Alexandre Julliard : ntdll: Relocate the PE ntdll if necessary.
Alexandre Julliard
julliard at winehq.org
Thu Feb 25 16:45:37 CST 2021
Module: wine
Branch: master
Commit: 06b729f7773243a76fb2df3c1bfe53b39819da5f
URL: https://source.winehq.org/git/wine.git/?a=commit;h=06b729f7773243a76fb2df3c1bfe53b39819da5f
Author: Alexandre Julliard <julliard at winehq.org>
Date: Thu Feb 25 12:37:37 2021 +0100
ntdll: Relocate the PE ntdll if necessary.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/loader.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 97 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index c4f897f3d0d..d03034f35fc 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -891,6 +891,98 @@ static void load_ntdll_functions( HMODULE module )
#undef SET_PTR
}
+/* reimplementation of LdrProcessRelocationBlock */
+static IMAGE_BASE_RELOCATION *process_relocation_block( void *module, IMAGE_BASE_RELOCATION *rel,
+ INT_PTR delta )
+{
+ char *page = get_rva( module, rel->VirtualAddress );
+ UINT count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT);
+ USHORT *relocs = (USHORT *)(rel + 1);
+
+ while (count--)
+ {
+ USHORT offset = *relocs & 0xfff;
+ switch (*relocs >> 12)
+ {
+ 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;
+ break;
+#ifdef _WIN64
+ case IMAGE_REL_BASED_DIR64:
+ *(INT_PTR *)(page + offset) += delta;
+ break;
+#elif defined(__arm__)
+ case IMAGE_REL_BASED_THUMB_MOV32:
+ {
+ DWORD *inst = (DWORD *)(page + offset);
+ WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
+ ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
+ WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
+ ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
+ DWORD imm = MAKELONG( lo, hi ) + delta;
+
+ lo = LOWORD( imm );
+ hi = HIWORD( imm );
+ inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
+ ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
+ inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
+ ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
+ break;
+ }
+#endif
+ default:
+ FIXME("Unknown/unsupported relocation %x\n", *relocs);
+ return NULL;
+ }
+ relocs++;
+ }
+ return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
+}
+
+static void relocate_ntdll( void *module )
+{
+ IMAGE_DOS_HEADER *dos = module;
+ IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
+ IMAGE_DATA_DIRECTORY *relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ IMAGE_BASE_RELOCATION *rel, *end;
+ IMAGE_SECTION_HEADER *sec;
+ ULONG protect_old[96], i;
+ INT_PTR delta;
+
+ ERR( "ntdll could not be mapped at preferred address (%p/%p), expect trouble\n",
+ module, (void *)nt->OptionalHeader.ImageBase );
+
+ if (!relocs->Size || !relocs->VirtualAddress) return;
+
+ sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
+ for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+ {
+ void *addr = get_rva( module, sec[i].VirtualAddress );
+ SIZE_T size = sec[i].SizeOfRawData;
+ NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &protect_old[i] );
+ }
+
+ rel = get_rva( module, relocs->VirtualAddress );
+ end = get_rva( module, relocs->VirtualAddress + relocs->Size );
+ delta = (char *)module - (char *)nt->OptionalHeader.ImageBase;
+ while (rel && rel < end - 1 && rel->SizeOfBlock) rel = process_relocation_block( module, rel, delta );
+
+ for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
+ {
+ void *addr = get_rva( module, sec[i].VirtualAddress );
+ SIZE_T size = sec[i].SizeOfRawData;
+ NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, protect_old[i], &protect_old[i] );
+ }
+}
+
static void *callback_module;
@@ -1534,8 +1626,11 @@ static void load_ntdll(void)
status = open_builtin_file( name, &attr, &mapping, &module, &info, &st, FALSE );
if (!status && !module)
{
- status = map_builtin_module( mapping, &module, &st );
- NtClose( mapping );
+ SIZE_T len = 0;
+ status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
+ ViewShare, 0, PAGE_EXECUTE_READ );
+ if (status == STATUS_IMAGE_NOT_AT_BASE) relocate_ntdll( module );
+ status = add_builtin_module( module, NULL, &st );
}
if (status) fatal_error( "failed to load %s error %x\n", name, status );
free( name );
More information about the wine-cvs
mailing list