+ PIMAGE_DATA_DIRECTORY RelocationDDir;
+ PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
+ ULONG Count, ProtectSize, OldProtect, OldProtect2;
+ PVOID Page, ProtectPage, ProtectPage2;
+ PUSHORT TypeOffset;
+ ULONG_PTR Delta;
+ NTSTATUS Status;
+
+ if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ RelocationDDir =
+ &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+ if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ ProtectSize = PAGE_SIZE;
+ Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
+ RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
+ RelocationDDir->VirtualAddress);
+ RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
+ RelocationDDir->VirtualAddress + RelocationDDir->Size);
+
+ while (RelocationDir < RelocationEnd &&
+ RelocationDir->SizeOfBlock > 0)
+ {
+ Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
+ sizeof(USHORT);
+ Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
+ TypeOffset = (PUSHORT)(RelocationDir + 1);
+
+ /* Unprotect the page(s) we're about to relocate. */
+ ProtectPage = Page;
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &ProtectPage,
+ &ProtectSize,
+ PAGE_READWRITE,
+ &OldProtect);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to unprotect relocation target.\n");
+ return Status;
+ }
+
+ if (RelocationDir->VirtualAddress + PAGE_SIZE <
+ NTHeaders->OptionalHeader.SizeOfImage)
+ {
+ ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &ProtectPage2,
+ &ProtectSize,
+ PAGE_READWRITE,
+ &OldProtect2);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to unprotect relocation target (2).\n");
+ NtProtectVirtualMemory(NtCurrentProcess(),
+ &ProtectPage,
+ &ProtectSize,
+ OldProtect,
+ &OldProtect);
+ return Status;
+ }
+ }
+ else
+ {
+ ProtectPage2 = NULL;
+ }
+
+ RelocationDir = LdrProcessRelocationBlock(Page,
+ Count,
+ TypeOffset,
+ Delta);
+ if (RelocationDir == NULL)
+ return STATUS_UNSUCCESSFUL;
+
+ /* Restore old page protection. */
+ NtProtectVirtualMemory(NtCurrentProcess(),
+ &ProtectPage,
+ &ProtectSize,
+ OldProtect,
+ &OldProtect);
+
+ if (ProtectPage2 != NULL)
+ {
+ NtProtectVirtualMemory(NtCurrentProcess(),
+ &ProtectPage2,
+ &ProtectSize,
+ OldProtect2,
+ &OldProtect2);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+LdrpGetOrLoadModule(PWCHAR SerachPath,
+ PCHAR Name,
+ PLDR_DATA_TABLE_ENTRY* Module,
+ BOOLEAN Load)
+{
+ UNICODE_STRING DllName;
+ NTSTATUS Status;
+
+ DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
+
+ RtlCreateUnicodeStringFromAsciiz (&DllName, Name);
+
+ Status = LdrFindEntryForName (&DllName, Module, Load);
+ if (Load && !NT_SUCCESS(Status))
+ {
+ Status = LdrpLoadModule(SerachPath,
+ NtCurrentPeb()->Ldr->Initialized ? 0 : LDRP_PROCESS_CREATION_TIME,
+ &DllName,
+ Module,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ Status = LdrFindEntryForName (&DllName, Module, FALSE);
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("failed to load %wZ\n", &DllName);
+ }
+ }
+ RtlFreeUnicodeString (&DllName);
+ return Status;
+}
+
+static NTSTATUS
+LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
+ PLDR_DATA_TABLE_ENTRY ImportedModule,
+ PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
+{
+ NTSTATUS Status;
+ PVOID* ImportAddressList;
+ PULONG FunctionNameList;
+ PVOID IATBase;
+ ULONG OldProtect;
+ ULONG Ordinal;
+ ULONG IATSize;
+
+ if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Get the import address list. */
+ ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+
+ /* Get the list of functions to import. */
+ if (ImportModuleDirectory->OriginalFirstThunk != 0)
+ {
+ FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
+ }
+ else
+ {
+ FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+ }
+
+ /* Get the size of IAT. */
+ IATSize = 0;
+ while (FunctionNameList[IATSize] != 0L)
+ {
+ IATSize++;
+ }
+
+ /* Unprotect the region we are about to write into. */
+ IATBase = (PVOID)ImportAddressList;
+ IATSize *= sizeof(PVOID*);
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &IATBase,
+ &IATSize,
+ PAGE_READWRITE,
+ &OldProtect);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to unprotect IAT.\n");
+ return(Status);
+ }
+
+ /* Walk through function list and fixup addresses. */
+ while (*FunctionNameList != 0L)
+ {
+ if ((*FunctionNameList) & 0x80000000)
+ {
+ Ordinal = (*FunctionNameList) & 0x7fffffff;
+ *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
+ if ((*ImportAddressList) == NULL)
+ {
+ DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ else
+ {
+ IMAGE_IMPORT_BY_NAME *pe_name;
+ pe_name = RVA(Module->DllBase, *FunctionNameList);
+ *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
+ if ((*ImportAddressList) == NULL)
+ {
+ DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ ImportAddressList++;
+ FunctionNameList++;
+ }
+
+ /* Protect the region we are about to write into. */
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &IATBase,
+ &IATSize,
+ OldProtect,
+ &OldProtect);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to protect IAT.\n");
+ return(Status);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+LdrpProcessImportDirectory(
+ PLDR_DATA_TABLE_ENTRY Module,
+ PLDR_DATA_TABLE_ENTRY ImportedModule,
+ PCHAR ImportedName)
+{
+ NTSTATUS Status;
+ PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+ PCHAR Name;
+ ULONG Size;
+
+ DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
+ Module, &Module->BaseDllName, ImportedName);
+
+
+ ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+ RtlImageDirectoryEntryToData(Module->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &Size);
+ if (ImportModuleDirectory == NULL)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ while (ImportModuleDirectory->Name)
+ {
+ Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
+ if (0 == _stricmp(Name, ImportedName))
+ {
+ Status = LdrpProcessImportDirectoryEntry(Module,
+ ImportedModule,
+ ImportModuleDirectory);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
+ ImportModuleDirectory++;
+ }
+
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
+ PLDR_DATA_TABLE_ENTRY ImportedModule,
+ PCHAR ImportedName)
+{
+ PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+ NTSTATUS Status;
+ PVOID* ImportAddressList;
+ PVOID Start;
+ PVOID End;
+ PULONG FunctionNameList;
+ PVOID IATBase;
+ ULONG OldProtect;
+ ULONG Offset;
+ ULONG IATSize;
+ PIMAGE_NT_HEADERS NTHeaders;
+ PCHAR Name;
+ ULONG Size;
+
+ DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
+ Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
+
+ ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+ RtlImageDirectoryEntryToData(Module->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &Size);
+ if (ImportModuleDirectory == NULL)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ while (ImportModuleDirectory->Name)
+ {
+ Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
+ if (0 == _stricmp(Name, (PCHAR)ImportedName))
+ {
+
+ /* Get the import address list. */
+ ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+
+ /* Get the list of functions to import. */
+ if (ImportModuleDirectory->OriginalFirstThunk != 0)
+ {
+ FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
+ }
+ else
+ {
+ FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+ }
+
+ /* Get the size of IAT. */
+ IATSize = 0;
+ while (FunctionNameList[IATSize] != 0L)
+ {
+ IATSize++;
+ }
+
+ /* Unprotect the region we are about to write into. */
+ IATBase = (PVOID)ImportAddressList;
+ IATSize *= sizeof(PVOID*);
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &IATBase,
+ &IATSize,
+ PAGE_READWRITE,
+ &OldProtect);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to unprotect IAT.\n");
+ return(Status);
+ }
+
+ NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
+ Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
+ End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
+ Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
+
+ /* Walk through function list and fixup addresses. */
+ while (*FunctionNameList != 0L)
+ {
+ if (*ImportAddressList >= Start && *ImportAddressList < End)
+ {
+ (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
+ }
+ ImportAddressList++;
+ FunctionNameList++;
+ }
+
+ /* Protect the region we are about to write into. */
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &IATBase,
+ &IATSize,
+ OldProtect,
+ &OldProtect);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to protect IAT.\n");
+ return(Status);
+ }
+ }
+ ImportModuleDirectory++;
+ }