-/*
+/* $Id: utils.c,v 1.47 2001/09/01 19:36:30 rex Exp $
+ *
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: lib/ntdll/ldr/startup.c
* Rex Jolliff (rex@lvcablemodem.com)
*/
+/*
+ * TODO:
+ * - Fix calling of entry points
+ * - Handle loading flags correctly
+ * - any more ??
+ */
+
/* INCLUDES *****************************************************************/
-#define WIN32_NO_PEHDR
-#include <windows.h>
+#include <reactos/config.h>
#include <ddk/ntddk.h>
-#include <pe.h>
+#include <windows.h>
#include <string.h>
-#include <internal/string.h>
#include <wchar.h>
#include <ntdll/ldr.h>
+#include <ntos/minmax.h>
+#include <napi/shared_data.h>
+
+#ifdef DBG_NTDLL_LDR_UTILS
#define NDEBUG
+#endif
#include <ntdll/ntdll.h>
+/* PROTOTYPES ****************************************************************/
+
+
+/* Type for a DLL's entry point */
+typedef
+WINBOOL
+STDCALL
+(* PDLLMAIN_FUNC) (
+ HANDLE hInst,
+ ULONG ul_reason_for_call,
+ LPVOID lpReserved
+ );
+
+static NTSTATUS LdrFindDll(PLDR_MODULE *Dll,PUNICODE_STRING Name);
+static PVOID LdrFixupForward(PCHAR ForwardName);
+static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
+
+
/* FUNCTIONS *****************************************************************/
-typedef WINBOOL STDCALL (*PDLLMAIN_FUNC)(HANDLE hInst,
- ULONG ul_reason_for_call,
- LPVOID lpReserved);
+#ifdef KDBG
-static NTSTATUS LdrLoadDll(PDLL* Dll, PCHAR Name)
+VOID LdrLoadModuleSymbols(PLDR_MODULE ModuleObject)
{
- char fqname[255] = "\\??\\C:\\reactos\\system\\";
- ANSI_STRING AnsiString;
- UNICODE_STRING UnicodeString;
- OBJECT_ATTRIBUTES FileObjectAttributes;
- char BlockBuffer[1024];
- PIMAGE_DOS_HEADER DosHeader;
- NTSTATUS Status;
- PIMAGE_NT_HEADERS NTHeaders;
- PEPFUNC DllStartupAddr;
- ULONG ImageSize, InitialViewSize;
- PVOID ImageBase;
- HANDLE FileHandle, SectionHandle;
- PDLLMAIN_FUNC Entrypoint;
-
- DPRINT("LdrLoadDll(Base %x, Name %s)\n",Dll,Name);
-
- strcat(fqname, Name);
-
- DPRINT("fqname %s\n",fqname);
-
- RtlInitAnsiString(&AnsiString,fqname);
- RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
-
- InitializeObjectAttributes(&FileObjectAttributes,
- &UnicodeString,
- 0,
- NULL,
- NULL);
- DPRINT("Opening dll\n");
- Status = ZwOpenFile(&FileHandle, FILE_ALL_ACCESS, &FileObjectAttributes,
- NULL, 0, 0);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Dll open failed ");
- return Status;
- }
- Status = ZwReadFile(FileHandle, 0, 0, 0, 0, BlockBuffer, 1024, 0, 0);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Dll header read failed ");
- ZwClose(FileHandle);
- return Status;
- }
-
- DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
- if (DosHeader->e_magic != IMAGE_DOS_MAGIC ||
- DosHeader->e_lfanew == 0L ||
- *(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
+ NtSystemDebugControl(
+ 0xffffffff,
+ (PVOID)ModuleObject,
+ 0,
+ NULL,
+ 0,
+ NULL);
+}
+
+#endif /* KDBG */
+
+
+/***************************************************************************
+ * NAME LOCAL
+ * LdrAdjustDllName
+ *
+ * DESCRIPTION
+ * Adjusts the name of a dll to a fully qualified name.
+ *
+ * ARGUMENTS
+ * FullDllName: Pointer to caller supplied storage for the fully
+ * qualified dll name.
+ * DllName: Pointer to the dll name.
+ * BaseName: TRUE: Only the file name is passed to FullDllName
+ * FALSE: The full path is preserved in FullDllName
+ *
+ * RETURN VALUE
+ * None
+ *
+ * REVISIONS
+ *
+ * NOTE
+ * A given path is not affected by the adjustment, but the file
+ * name only:
+ * ntdll --> ntdll.dll
+ * ntdll. --> ntdll
+ * ntdll.xyz --> ntdll.xyz
+ */
+
+static VOID
+LdrAdjustDllName (PUNICODE_STRING FullDllName,
+ PUNICODE_STRING DllName,
+ BOOLEAN BaseName)
+{
+ WCHAR Buffer[MAX_PATH];
+ ULONG Length;
+ PWCHAR Extension;
+ PWCHAR Pointer;
+
+ Length = DllName->Length / sizeof(WCHAR);
+
+ if (BaseName == TRUE)
{
- DPRINT("NTDLL format invalid\n");
- ZwClose(FileHandle);
-
- return STATUS_UNSUCCESSFUL;
- }
- NTHeaders = (PIMAGE_NT_HEADERS)(BlockBuffer + DosHeader->e_lfanew);
- ImageBase = (PVOID)NTHeaders->OptionalHeader.ImageBase;
- ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
+ /* get the base dll name */
+ Pointer = DllName->Buffer + Length;
+ Extension = Pointer;
- DPRINT("ImageBase %x\n",ImageBase);
- DllStartupAddr = (PEPFUNC)(ImageBase +
- NTHeaders->OptionalHeader.AddressOfEntryPoint);
-
- /* Create a section for NTDLL */
- Status = ZwCreateSection(&SectionHandle,
- SECTION_ALL_ACCESS,
- NULL,
- NULL,
- PAGE_READWRITE,
- MEM_COMMIT,
- FileHandle);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NTDLL create section failed ");
- ZwClose(FileHandle);
- return Status;
+ do
+ {
+ --Pointer;
+ }
+ while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
+
+ Pointer++;
+ Length = Extension - Pointer;
+ memmove (Buffer, Pointer, Length * sizeof(WCHAR));
}
-
- /* Map the NTDLL into the process */
- InitialViewSize = DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)
- + sizeof(IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
- Status = ZwMapViewOfSection(SectionHandle,
- NtCurrentProcess(),
- (PVOID *)&ImageBase,
- 0,
- InitialViewSize,
- NULL,
- &InitialViewSize,
- 0,
- MEM_COMMIT,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NTDLL map view of secion failed ");
- ZwClose(FileHandle);
-
- return Status;
+ else
+ {
+ /* get the full dll name */
+ memmove (Buffer, DllName->Buffer, DllName->Length);
}
- ZwClose(FileHandle);
-
- (*Dll) = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DLL));
- (*Dll)->Headers = NTHeaders;
- (*Dll)->BaseAddress = (PVOID)ImageBase;
- (*Dll)->Next = LdrDllListHead.Next;
- (*Dll)->Prev = &LdrDllListHead;
- LdrDllListHead.Next->Prev = (*Dll);
- LdrDllListHead.Next = (*Dll);
-
- Entrypoint = (PDLLMAIN_FUNC)LdrPEStartup(ImageBase, SectionHandle);
- if (Entrypoint != NULL)
+
+ /* Build the DLL's absolute name */
+ Extension = wcsrchr (Buffer, L'.');
+ if ((Extension != NULL) && (*Extension == L'.'))
{
- DPRINT("Calling entry point at %x\n",Entrypoint);
- Entrypoint(ImageBase, DLL_PROCESS_ATTACH, NULL);
- DPRINT("Successful called entrypoint\n");
+ /* with extension - remove dot if it's the last character */
+ if (Buffer[Length - 1] == L'.')
+ Length--;
+ Buffer[Length] = 0;
}
-
- return(STATUS_SUCCESS);
+ else
+ {
+ /* name without extension - assume that it is .dll */
+ memmove (Buffer + Length, L".dll", 10);
+ }
+
+ RtlCreateUnicodeString (FullDllName,
+ Buffer);
+}
+
+
+/***************************************************************************
+ * NAME EXPORTED
+ * LdrLoadDll
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+
+NTSTATUS STDCALL
+LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
+ IN ULONG LoadFlags,
+ IN PUNICODE_STRING Name,
+ OUT PVOID *BaseAddress OPTIONAL)
+{
+ WCHAR SearchPathBuffer[MAX_PATH];
+ WCHAR FullDosName[MAX_PATH];
+ UNICODE_STRING AdjustedName;
+ UNICODE_STRING FullNtFileName;
+ OBJECT_ATTRIBUTES FileObjectAttributes;
+ char BlockBuffer [1024];
+ PIMAGE_DOS_HEADER DosHeader;
+ NTSTATUS Status;
+ PIMAGE_NT_HEADERS NTHeaders;
+ ULONG ImageSize;
+ ULONG InitialViewSize;
+ PVOID ImageBase;
+ HANDLE FileHandle;
+ HANDLE SectionHandle;
+ PDLLMAIN_FUNC Entrypoint = NULL;
+ PLDR_MODULE Module;
+
+ if (Name == NULL)
+ {
+ *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+ return STATUS_SUCCESS;
+ }
+
+ *BaseAddress = NULL;
+
+ DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
+ Name, BaseAddress);
+
+ /* adjust the full dll name */
+ LdrAdjustDllName (&AdjustedName,
+ Name,
+ FALSE);
+ DPRINT("AdjustedName: %wZ\n", &AdjustedName);
+
+ /*
+ * Test if dll is already loaded.
+ */
+ if (LdrFindDll(&Module, &AdjustedName) == STATUS_SUCCESS)
+ {
+ DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
+ if (Module->LoadCount != -1)
+ Module->LoadCount++;
+ *BaseAddress = Module->BaseAddress;
+ return STATUS_SUCCESS;
+ }
+ DPRINT("Loading \"%wZ\"\n", Name);
+
+ if (SearchPath == NULL)
+ {
+ PKUSER_SHARED_DATA SharedUserData =
+ (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
+
+ SearchPath = SearchPathBuffer;
+ wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
+ wcscat (SearchPathBuffer, L"\\system32;");
+ wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
+ wcscat (SearchPathBuffer, L";.");
+ }
+
+ DPRINT("SearchPath %S\n", SearchPath);
+
+ if (RtlDosSearchPath_U (SearchPath,
+ AdjustedName.Buffer,
+ NULL,
+ MAX_PATH,
+ FullDosName,
+ NULL) == 0)
+ return STATUS_DLL_NOT_FOUND;
+
+ DPRINT("FullDosName %S\n", FullDosName);
+
+ RtlFreeUnicodeString (&AdjustedName);
+
+ if (!RtlDosPathNameToNtPathName_U (FullDosName,
+ &FullNtFileName,
+ NULL,
+ NULL))
+ return STATUS_DLL_NOT_FOUND;
+
+ DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
+
+ InitializeObjectAttributes(&FileObjectAttributes,
+ &FullNtFileName,
+ 0,
+ NULL,
+ NULL);
+
+ DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
+
+ Status = ZwOpenFile(&FileHandle,
+ FILE_ALL_ACCESS,
+ &FileObjectAttributes,
+ NULL,
+ 0,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
+ &FullNtFileName, Status);
+ RtlFreeUnicodeString (&FullNtFileName);
+ return Status;
+ }
+ RtlFreeUnicodeString (&FullNtFileName);
+
+ Status = ZwReadFile(FileHandle,
+ 0,
+ 0,
+ 0,
+ 0,
+ BlockBuffer,
+ sizeof(BlockBuffer),
+ 0,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
+ ZwClose(FileHandle);
+ return Status;
+ }
+ /*
+ * Overlay DOS and NT headers structures to the
+ * buffer with DLL's header raw data.
+ */
+ DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
+ NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
+ /*
+ * Check it is a PE image file.
+ */
+ if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
+ || (DosHeader->e_lfanew == 0L)
+ || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
+ {
+ DPRINT("NTDLL format invalid\n");
+ ZwClose(FileHandle);
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
+ ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
+
+ DPRINT("ImageBase 0x%08x\n", ImageBase);
+
+ /*
+ * Create a section for dll.
+ */
+ Status = ZwCreateSection(&SectionHandle,
+ SECTION_ALL_ACCESS,
+ NULL,
+ NULL,
+ PAGE_READWRITE,
+ SEC_COMMIT | SEC_IMAGE,
+ FileHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
+ ZwClose(FileHandle);
+ return Status;
+ }
+
+ /*
+ * Map the dll into the process.
+ */
+ InitialViewSize = 0;
+ ImageBase = 0;
+ Status = ZwMapViewOfSection(SectionHandle,
+ NtCurrentProcess(),
+ &ImageBase,
+ 0,
+ InitialViewSize,
+ NULL,
+ &InitialViewSize,
+ 0,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
+ Status);
+ ZwClose(FileHandle);
+ return(Status);
+ }
+ ZwClose(FileHandle);
+
+ /* relocate dll and fixup import table */
+ if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
+ IMAGE_FILE_DLL)
+ {
+ Entrypoint =
+ (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle);
+ }
+
+ /* build module entry */
+ Module = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ sizeof (LDR_MODULE));
+ Module->BaseAddress = (PVOID)ImageBase;
+ Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
+ if (Module->EntryPoint != 0)
+ Module->EntryPoint += (ULONG)Module->BaseAddress;
+ Module->SizeOfImage = ImageSize;
+ if (NtCurrentPeb()->Ldr->Initialized == TRUE)
+ {
+ /* loading while app is running */
+ Module->LoadCount = 1;
+ }
+ else
+ {
+ /*
+ * loading while app is initializing
+ * dll must not be unloaded
+ */
+ Module->LoadCount = -1;
+ }
+
+ Module->TlsIndex = 0;
+ Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
+ Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
+
+ RtlCreateUnicodeString (&Module->FullDllName,
+ FullDosName);
+ RtlCreateUnicodeString (&Module->BaseDllName,
+ wcsrchr(FullDosName, L'\\') + 1);
+ DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
+
+ /* FIXME: aquire loader lock */
+ InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
+ &Module->InLoadOrderModuleList);
+ InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
+ &Module->InInitializationOrderModuleList);
+ /* FIXME: release loader lock */
+
+#ifdef KDBG
+ LdrLoadModuleSymbols(Module);
+#endif /* KDBG */
+
+ /* initialize dll */
+ if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
+ IMAGE_FILE_DLL)
+ {
+ if (Module->EntryPoint != 0)
+ {
+ Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+
+ DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+ if (FALSE == Entrypoint(Module->BaseAddress,
+ DLL_PROCESS_ATTACH,
+ NULL))
+ {
+ DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
+ &Module->BaseDllName);
+ /* FIXME: should clean up and fail */
+ }
+ else
+ {
+ DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
+ &Module->BaseDllName);
+ }
+ }
+ else
+ {
+ DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
+ &Module->BaseDllName);
+ }
+ }
+
+ *BaseAddress = Module->BaseAddress;
+ return STATUS_SUCCESS;
}
-static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
+
+/***************************************************************************
+ * NAME LOCAL
+ * LdrFindDll
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static NTSTATUS LdrFindDll(PLDR_MODULE *Dll, PUNICODE_STRING Name)
{
- PIMAGE_EXPORT_DIRECTORY ExportDir;
- DLL* current;
- PIMAGE_OPTIONAL_HEADER OptionalHeader;
-
- DPRINT("LdrFindDll(Name %s)\n",Name);
-
- current = &LdrDllListHead;
- do
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+
+ DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name);
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+ Entry = ModuleListHead->Flink;
+
+ // NULL is the current process
+ if ( Name == NULL )
{
- OptionalHeader = ¤t->Headers->OptionalHeader;
- ExportDir = (PIMAGE_EXPORT_DIRECTORY)OptionalHeader->DataDirectory[
- IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
- ExportDir = (PIMAGE_EXPORT_DIRECTORY)
- ((ULONG)ExportDir + (ULONG)current->BaseAddress);
-
- DPRINT("Scanning %x %x %x\n", ExportDir->Name,
- current->BaseAddress, ExportDir->Name + current->BaseAddress);
- DPRINT("Scanning %s\n", ExportDir->Name + current->BaseAddress);
- if (strcmp(ExportDir->Name + current->BaseAddress, Name) == 0)
+ *Dll = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+ return STATUS_SUCCESS;
+ }
+
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+ DPRINT("Scanning %wZ %wZ\n", &Module->BaseDllName, Name);
+
+ if (RtlCompareUnicodeString(&Module->BaseDllName, Name, TRUE) == 0)
{
- *Dll = current;
- return(STATUS_SUCCESS);
+ *Dll = Module;
+ return STATUS_SUCCESS;
}
-
- current = current->Next;
- } while (current != &LdrDllListHead);
-
- dprintf("Failed to find dll %s\n",Name);
-
- return(LdrLoadDll(Dll, Name));
+
+ Entry = Entry->Flink;
+ }
+
+ DPRINT("Failed to find dll %wZ\n", Name);
+
+ return STATUS_UNSUCCESSFUL;
}
-NTSTATUS LdrMapSections(HANDLE ProcessHandle,
- PVOID ImageBase,
- HANDLE SectionHandle,
- PIMAGE_NT_HEADERS NTHeaders)
+/**********************************************************************
+ * NAME LOCAL
+ * LdrFixupForward
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static PVOID
+LdrFixupForward(PCHAR ForwardName)
{
- ULONG i;
+ CHAR NameBuffer[128];
+ UNICODE_STRING DllName;
+ UNICODE_STRING FunctionName;
NTSTATUS Status;
-
- for (i=0; i<NTHeaders->FileHeader.NumberOfSections; i++)
+ PCHAR p;
+ PVOID BaseAddress;
+
+ strcpy(NameBuffer, ForwardName);
+ p = strchr(NameBuffer, '.');
+ if (p != NULL)
{
- PIMAGE_SECTION_HEADER Sections;
- LARGE_INTEGER Offset;
- ULONG Base;
-
- Sections = (PIMAGE_SECTION_HEADER)SECHDROFFSET(ImageBase);
- Base = (ULONG)(Sections[i].VirtualAddress + ImageBase);
- Offset.u.LowPart = Sections[i].PointerToRawData;
- Offset.u.HighPart = 0;
- Status = ZwMapViewOfSection(SectionHandle,
- ProcessHandle,
- (PVOID *)&Base,
- 0,
- Sections[i].Misc.VirtualSize,
- &Offset,
- (PULONG)&Sections[i].Misc.VirtualSize,
- 0,
- MEM_COMMIT,
- PAGE_READWRITE);
+ *p = 0;
+
+ DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
+ RtlCreateUnicodeStringFromAsciiz (&DllName,
+ NameBuffer);
+
+ Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
if (!NT_SUCCESS(Status))
{
- return Status;
+ Status = LdrLoadDll(NULL,
+ 0,
+ &DllName,
+ &BaseAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
+ RtlFreeUnicodeString (&DllName);
+ return NULL;
+ }
}
+
+ RtlFreeUnicodeString (&DllName);
+ DPRINT("BaseAddress: %p\n", BaseAddress);
+
+ return LdrGetExportByName(BaseAddress, p+1, -1);
}
- return(STATUS_SUCCESS);
+
+ return NULL;
}
-static PVOID LdrGetExportByOrdinal(PDLL Module, ULONG Ordinal)
+
+/**********************************************************************
+ * NAME LOCAL
+ * LdrGetExportByOrdinal
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static PVOID
+LdrGetExportByOrdinal (
+ PVOID BaseAddress,
+ ULONG Ordinal
+ )
{
- PIMAGE_EXPORT_DIRECTORY ExportDir;
- PDWORD* ExFunctions;
- USHORT* ExOrdinals;
+ PIMAGE_EXPORT_DIRECTORY ExportDir;
+ PDWORD * ExFunctions;
+ USHORT * ExOrdinals;
- ExportDir = (Module->BaseAddress +
- (Module->Headers->OptionalHeader.
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
-
- ExOrdinals = (USHORT*)RVA(Module->BaseAddress,
- ExportDir->AddressOfNameOrdinals);
- ExFunctions = (PDWORD*)RVA(Module->BaseAddress,
- ExportDir->AddressOfFunctions);
- dprintf("LdrGetExportByOrdinal(Ordinal %d) = %x\n",
- Ordinal,ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
- return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
+ ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+ RtlImageDirectoryEntryToData (BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ NULL);
+
+
+ ExOrdinals = (USHORT *)
+ RVA(
+ BaseAddress,
+ ExportDir->AddressOfNameOrdinals
+ );
+ ExFunctions = (PDWORD *)
+ RVA(
+ BaseAddress,
+ ExportDir->AddressOfFunctions
+ );
+ DbgPrint(
+ "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
+ Ordinal,
+ ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
+ );
+ return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
}
-static PVOID LdrGetExportByName(PDLL Module, PUCHAR SymbolName)
+
+/**********************************************************************
+ * NAME LOCAL
+ * LdrGetExportByName
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static PVOID
+LdrGetExportByName(PVOID BaseAddress,
+ PUCHAR SymbolName,
+ WORD Hint)
{
- PIMAGE_EXPORT_DIRECTORY ExportDir;
- PDWORD* ExFunctions;
- PDWORD* ExNames;
- USHORT* ExOrdinals;
- ULONG i;
- PVOID ExName;
- ULONG Ordinal;
+ PIMAGE_EXPORT_DIRECTORY ExportDir;
+ PDWORD * ExFunctions;
+ PDWORD * ExNames;
+ USHORT * ExOrdinals;
+ ULONG i;
+ PVOID ExName;
+ ULONG Ordinal;
+ PVOID Function;
+ ULONG minn, maxn;
+ ULONG ExportDirSize;
- DPRINT("LdrFindExport(Module %x, SymbolName %s)\n",
- Module, SymbolName);
+ DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
- ExportDir = (Module->BaseAddress +
- (Module->Headers->OptionalHeader.
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
+ ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+ RtlImageDirectoryEntryToData(BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportDirSize);
+ if (ExportDir == NULL)
+ {
+ DbgPrint("LdrGetExportByName(): no export directory!\n");
+ return NULL;
+ }
- /* Get header pointers */
- ExNames = (PDWORD*)RVA(Module->BaseAddress, ExportDir->AddressOfNames);
- ExOrdinals = (USHORT*)RVA(Module->BaseAddress,
- ExportDir->AddressOfNameOrdinals);
- ExFunctions = (PDWORD*)RVA(Module->BaseAddress,
- ExportDir->AddressOfFunctions);
- for (i=0; i<ExportDir->NumberOfFunctions; i++)
- {
- ExName = RVA(Module->BaseAddress, ExNames[i]);
- DPRINT("Comparing '%s' '%s'\n",ExName,SymbolName);
- if (strcmp(ExName,SymbolName) == 0)
+ /*
+ * Get header pointers
+ */
+ ExNames = (PDWORD *)RVA(BaseAddress,
+ ExportDir->AddressOfNames);
+ ExOrdinals = (USHORT *)RVA(BaseAddress,
+ ExportDir->AddressOfNameOrdinals);
+ ExFunctions = (PDWORD *)RVA(BaseAddress,
+ ExportDir->AddressOfFunctions);
+
+ /*
+ * Check the hint first
+ */
+ if (Hint < ExportDir->NumberOfFunctions)
+ {
+ ExName = RVA(BaseAddress, ExNames[Hint]);
+ if (strcmp(ExName, SymbolName) == 0)
{
- Ordinal = ExOrdinals[i];
- return(RVA(Module->BaseAddress, ExFunctions[Ordinal]));
+ Ordinal = ExOrdinals[Hint];
+ Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+ if (((ULONG)Function >= (ULONG)ExportDir) &&
+ ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+ {
+ DPRINT("Forward: %s\n", (PCHAR)Function);
+ Function = LdrFixupForward((PCHAR)Function);
+ }
+ if (Function != NULL)
+ return Function;
}
}
- dprintf("LdrGetExportByName() = failed to find %s\n",SymbolName);
- return(NULL);
-}
+
+ /*
+ * Try a binary search first
+ */
+ minn = 0;
+ maxn = ExportDir->NumberOfFunctions;
+ while (minn <= maxn)
+ {
+ ULONG mid;
+ LONG res;
-static NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
- PVOID ImageBase)
-{
- USHORT NumberOfEntries;
- PUSHORT pValue16;
- ULONG RelocationRVA;
- ULONG Delta32, Offset;
- PULONG pValue32;
- PRELOCATION_DIRECTORY RelocationDir;
- PRELOCATION_ENTRY RelocationBlock;
- int i;
+ mid = (minn + maxn) / 2;
+
+ ExName = RVA(BaseAddress, ExNames[mid]);
+ res = strcmp(ExName, SymbolName);
+ if (res == 0)
+ {
+ Ordinal = ExOrdinals[mid];
+ Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+ if (((ULONG)Function >= (ULONG)ExportDir) &&
+ ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+ {
+ DPRINT("Forward: %s\n", (PCHAR)Function);
+ Function = LdrFixupForward((PCHAR)Function);
+ }
+ if (Function != NULL)
+ return Function;
+ }
+ else if (minn == maxn)
+ {
+ DPRINT("LdrGetExportByName(): binary search failed\n");
+ break;
+ }
+ else if (res > 0)
+ {
+ maxn = mid - 1;
+ }
+ else
+ {
+ minn = mid + 1;
+ }
+ }
- RelocationRVA = NTHeaders->OptionalHeader.DataDirectory[
- IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
- if (RelocationRVA)
+ /*
+ * Fall back on a linear search
+ */
+ DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
+ for (i = 0; i < ExportDir->NumberOfFunctions; i++)
{
- RelocationDir = (PRELOCATION_DIRECTORY)((PCHAR)ImageBase +
- RelocationRVA);
- while (RelocationDir->SizeOfBlock)
+ ExName = RVA(BaseAddress, ExNames[i]);
+ if (strcmp(ExName,SymbolName) == 0)
{
- Delta32 = (unsigned long)(ImageBase -
- NTHeaders->OptionalHeader.ImageBase);
- RelocationBlock = (PRELOCATION_ENTRY)
- (RelocationRVA + ImageBase + sizeof(RELOCATION_DIRECTORY));
- NumberOfEntries =
- (RelocationDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) /
- sizeof(RELOCATION_ENTRY);
- for (i = 0; i < NumberOfEntries; i++)
+ Ordinal = ExOrdinals[i];
+ Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+ DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
+ if (((ULONG)Function >= (ULONG)ExportDir) &&
+ ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
{
- Offset = (RelocationBlock[i].TypeOffset & 0xfff) +
- RelocationDir->VirtualAddress;
- switch (RelocationBlock[i].TypeOffset >> 12)
- {
- case TYPE_RELOC_ABSOLUTE:
- break;
-
- case TYPE_RELOC_HIGH:
- pValue16 = (PUSHORT) (ImageBase + Offset);
- *pValue16 += Delta32 >> 16;
- break;
-
- case TYPE_RELOC_LOW:
- pValue16 = (PUSHORT)(ImageBase + Offset);
- *pValue16 += Delta32 & 0xffff;
- break;
-
- case TYPE_RELOC_HIGHLOW:
- pValue32 = (PULONG) (ImageBase + Offset);
- *pValue32 += Delta32;
- break;
-
- case TYPE_RELOC_HIGHADJ:
- /* FIXME: do the highadjust fixup */
- DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented"
- ", sorry\n");
- return(STATUS_UNSUCCESSFUL);
-
- default:
- DPRINT("unexpected fixup type\n");
- return(STATUS_UNSUCCESSFUL);
- }
+ DPRINT("Forward: %s\n", (PCHAR)Function);
+ Function = LdrFixupForward((PCHAR)Function);
}
- RelocationRVA += RelocationDir->SizeOfBlock;
- RelocationDir = (PRELOCATION_DIRECTORY)(ImageBase +
- RelocationRVA);
+ return Function;
}
}
- return(STATUS_SUCCESS);
+ DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
+ return NULL;
+}
+
+
+/**********************************************************************
+ * NAME LOCAL
+ * LdrPerformRelocations
+ *
+ * DESCRIPTION
+ * Relocate a DLL's memory image.
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
+ PVOID ImageBase)
+{
+ USHORT NumberOfEntries;
+ PUSHORT pValue16;
+ ULONG RelocationRVA;
+ ULONG Delta32;
+ ULONG Offset;
+ PULONG pValue32;
+ PRELOCATION_DIRECTORY RelocationDir;
+ PRELOCATION_ENTRY RelocationBlock;
+ int i;
+
+
+ RelocationRVA = NTHeaders->OptionalHeader
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
+ .VirtualAddress;
+
+ if (RelocationRVA)
+ {
+ RelocationDir = (PRELOCATION_DIRECTORY)
+ ((PCHAR)ImageBase + RelocationRVA);
+
+ while (RelocationDir->SizeOfBlock)
+ {
+ Delta32 = (ULONG)(ImageBase -
+ NTHeaders->OptionalHeader.ImageBase);
+ RelocationBlock = (PRELOCATION_ENTRY) (
+ RelocationRVA
+ + ImageBase
+ + sizeof (RELOCATION_DIRECTORY)
+ );
+ NumberOfEntries = (
+ RelocationDir->SizeOfBlock
+ - sizeof (RELOCATION_DIRECTORY)
+ )
+ / sizeof (RELOCATION_ENTRY);
+
+ for ( i = 0;
+ (i < NumberOfEntries);
+ i++
+ )
+ {
+ Offset = (
+ RelocationBlock[i].TypeOffset
+ & 0xfff
+ )
+ + RelocationDir->VirtualAddress;
+ /*
+ * What kind of relocations should we perform
+ * for the current entry?
+ */
+ switch (RelocationBlock[i].TypeOffset >> 12)
+ {
+ case TYPE_RELOC_ABSOLUTE:
+ break;
+
+ case TYPE_RELOC_HIGH:
+ pValue16 = (PUSHORT) (ImageBase + Offset);
+ *pValue16 += Delta32 >> 16;
+ break;
+
+ case TYPE_RELOC_LOW:
+ pValue16 = (PUSHORT)(ImageBase + Offset);
+ *pValue16 += Delta32 & 0xffff;
+ break;
+
+ case TYPE_RELOC_HIGHLOW:
+ pValue32 = (PULONG) (ImageBase + Offset);
+ *pValue32 += Delta32;
+ break;
+
+ case TYPE_RELOC_HIGHADJ:
+ /* FIXME: do the highadjust fixup */
+ DPRINT(
+ "TYPE_RELOC_HIGHADJ fixup not implemented"
+ ", sorry\n"
+ );
+ return(STATUS_UNSUCCESSFUL);
+
+ default:
+ DPRINT("unexpected fixup type\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ RelocationRVA += RelocationDir->SizeOfBlock;
+ RelocationDir = (PRELOCATION_DIRECTORY) (
+ ImageBase
+ + RelocationRVA
+ );
+ }
+ }
+ return STATUS_SUCCESS;
}
-static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
- PVOID ImageBase)
+
+/**********************************************************************
+ * NAME LOCAL
+ * LdrFixupImports
+ *
+ * DESCRIPTION
+ * Compute the entry point for every symbol the DLL imports
+ * from other modules.
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
+ PVOID ImageBase)
{
PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
ULONG Ordinal;
- PDLL Module;
+ PVOID BaseAddress;
NTSTATUS Status;
- /* Process each import module */
- ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
- (ImageBase + NTHeaders->OptionalHeader.
- DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+ DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
+ ImageBase);
+
+ /*
+ * Process each import module.
+ */
+ ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
+ ImageBase + NTHeaders->OptionalHeader
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
+ .VirtualAddress);
+ DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
+
while (ImportModuleDirectory->dwRVAModuleName)
{
- PVOID *ImportAddressList;
- PULONG FunctionNameList;
- DWORD pName;
- PWORD pHint;
-
- Status = LdrFindDll(&Module,
- (PCHAR)(ImageBase +
- ImportModuleDirectory->dwRVAModuleName));
+ PVOID * ImportAddressList;
+ PULONG FunctionNameList;
+ UNICODE_STRING DllName;
+ DWORD pName;
+ WORD pHint;
+
+ DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
+ (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
+
+ RtlCreateUnicodeStringFromAsciiz (&DllName,
+ (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
+
+ Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
if (!NT_SUCCESS(Status))
{
- return(Status);
- }
-
- /* Get the import address list */
- ImportAddressList = (PVOID *)
- (NTHeaders->OptionalHeader.ImageBase +
- ImportModuleDirectory->dwRVAFunctionAddressList);
+ Status = LdrLoadDll(NULL,
+ 0,
+ &DllName,
+ &BaseAddress);
+ RtlFreeUnicodeString (&DllName);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("LdrFixupImports:failed to load %s\n"
+ ,(PCHAR)(ImageBase
+ + ImportModuleDirectory->dwRVAModuleName));
+
+ return Status;
+ }
+ }
+
+ /*
+ * Get the import address list.
+ */
+ ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
+ + ImportModuleDirectory->dwRVAFunctionAddressList);
- /* Get the list of functions to import */
+ /*
+ * Get the list of functions to import.
+ */
if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
{
- FunctionNameList = (PULONG) (ImageBase +
- ImportModuleDirectory->dwRVAFunctionNameList);
+ FunctionNameList = (PULONG) (
+ ImageBase
+ + ImportModuleDirectory->dwRVAFunctionNameList
+ );
}
else
{
- FunctionNameList = (PULONG) (ImageBase +
- ImportModuleDirectory->dwRVAFunctionAddressList);
+ FunctionNameList =
+ (PULONG)(ImageBase
+ + ImportModuleDirectory->dwRVAFunctionAddressList);
}
-
- /* Walk through function list and fixup addresses */
- while(*FunctionNameList != 0L)
+ /*
+ * Walk through function list and fixup addresses.
+ */
+ while (*FunctionNameList != 0L)
{
if ((*FunctionNameList) & 0x80000000)
{
Ordinal = (*FunctionNameList) & 0x7fffffff;
- *ImportAddressList = LdrGetExportByOrdinal(Module, Ordinal);
+ *ImportAddressList =
+ LdrGetExportByOrdinal(BaseAddress,
+ Ordinal);
}
- else
+ else
{
- pName = (DWORD)(ImageBase + *FunctionNameList + 2);
- pHint = (PWORD)(ImageBase + *FunctionNameList);
-
- *ImportAddressList = LdrGetExportByName(Module,
- (PUCHAR)pName);
+ pName = (DWORD) (ImageBase + *FunctionNameList + 2);
+ pHint = *(PWORD)(ImageBase + *FunctionNameList);
+
+ *ImportAddressList =
+ LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
if ((*ImportAddressList) == NULL)
{
- return(STATUS_UNSUCCESSFUL);
+ DbgPrint("Failed to import %s\n", pName);
+ return STATUS_UNSUCCESSFUL;
}
}
-
ImportAddressList++;
FunctionNameList++;
}
ImportModuleDirectory++;
}
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
-PEPFUNC LdrPEStartup(PVOID ImageBase, HANDLE SectionHandle)
+
+/**********************************************************************
+ * NAME
+ * LdrPEStartup
+ *
+ * DESCRIPTION
+ * 1. Map the DLL's sections into memory.
+ * 2. Relocate, if needed the DLL.
+ * 3. Fixup any imported symbol.
+ * 4. Compute the DLL's entry point.
+ *
+ * ARGUMENTS
+ * ImageBase
+ * Address at which the DLL's image
+ * is loaded.
+ *
+ * SectionHandle
+ * Handle of the section that contains
+ * the DLL's image.
+ *
+ * RETURN VALUE
+ * NULL on error; otherwise the entry point
+ * to call for initializing the DLL.
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+PEPFUNC LdrPEStartup (PVOID ImageBase,
+ HANDLE SectionHandle)
{
- NTSTATUS Status;
- PEPFUNC EntryPoint;
- PIMAGE_DOS_HEADER DosHeader;
- PIMAGE_NT_HEADERS NTHeaders;
-
+ NTSTATUS Status;
+ PEPFUNC EntryPoint = NULL;
+ PIMAGE_DOS_HEADER DosHeader;
+ PIMAGE_NT_HEADERS NTHeaders;
+
+ DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
+ ImageBase, (ULONG)SectionHandle);
+
+ /*
+ * Overlay DOS and WNT headers structures
+ * to the DLL's image.
+ */
DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
- NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + DosHeader->e_lfanew);
-
- /* Initialize Image sections */
- LdrMapSections(NtCurrentProcess(), ImageBase, SectionHandle, NTHeaders);
-
- if (ImageBase != (PVOID)NTHeaders->OptionalHeader.ImageBase)
+ NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
+
+ /*
+ * If the base address is different from the
+ * one the DLL is actually loaded, perform any
+ * relocation.
+ */
+ if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
+ {
+ DbgPrint("LDR: Performing relocations\n");
+ Status = LdrPerformRelocations(NTHeaders, ImageBase);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("LdrPerformRelocations() failed\n");
+ return NULL;
+ }
+ }
+
+ /*
+ * If the DLL's imports symbols from other
+ * modules, fixup the imported calls entry points.
+ */
+ if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
+ .VirtualAddress != 0)
{
- Status = LdrPerformRelocations(NTHeaders, ImageBase);
+ DPRINT("About to fixup imports\n");
+ Status = LdrFixupImports(NTHeaders, ImageBase);
if (!NT_SUCCESS(Status))
{
- dprintf("LdrPerformRelocations() failed\n");
- return(NULL);
+ DbgPrint("LdrFixupImports() failed\n");
+ return NULL;
}
+ DPRINT("Fixup done\n");
}
-
- if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].
- VirtualAddress != 0)
+
+ /*
+ * Compute the DLL's entry point's address.
+ */
+ DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
+ DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
+ if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
{
- Status = LdrFixupImports(NTHeaders, ImageBase);
- if (!NT_SUCCESS(Status))
+ EntryPoint = (PEPFUNC) (ImageBase
+ + NTHeaders->OptionalHeader.AddressOfEntryPoint);
+ }
+ DPRINT("LdrPEStartup() = %x\n",EntryPoint);
+ return EntryPoint;
+}
+
+
+NTSTATUS STDCALL
+LdrUnloadDll (IN PVOID BaseAddress)
+{
+ PIMAGE_NT_HEADERS NtHeaders;
+ PDLLMAIN_FUNC Entrypoint;
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+ NTSTATUS Status;
+
+ if (BaseAddress == NULL)
+ return STATUS_SUCCESS;
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+ Entry = ModuleListHead->Flink;
+
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+ if (Module->BaseAddress == BaseAddress)
{
- dprintf("LdrFixupImports() failed\n");
- return(NULL);
+ if (Module->LoadCount == -1)
+ {
+ /* never unload this dll */
+ return STATUS_SUCCESS;
+ }
+ else if (Module->LoadCount > 1)
+ {
+ Module->LoadCount--;
+ return STATUS_SUCCESS;
+ }
+
+ NtHeaders = RtlImageNtHeader (Module->BaseAddress);
+ if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
+ {
+ if (Module->EntryPoint != 0)
+ {
+ Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+ DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+ Entrypoint(Module->BaseAddress,
+ DLL_PROCESS_DETACH,
+ NULL);
+ }
+ else
+ {
+ DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
+ }
+ }
+ Status = ZwUnmapViewOfSection (NtCurrentProcess (),
+ Module->BaseAddress);
+ ZwClose (Module->SectionHandle);
+
+ /* remove the module entry from the list */
+ RtlFreeUnicodeString (&Module->FullDllName);
+ RtlFreeUnicodeString (&Module->BaseDllName);
+ RemoveEntryList (Entry);
+ RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
+
+ return Status;
}
+
+ Entry = Entry->Flink;
}
-
- EntryPoint = (PEPFUNC)(ImageBase +
- NTHeaders->OptionalHeader.AddressOfEntryPoint);
- dprintf("LdrPEStartup() = %x\n",EntryPoint);
- return(EntryPoint);
+
+ DPRINT("NTDLL.LDR: Dll not found\n")
+
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+NTSTATUS STDCALL
+LdrFindResource_U(PVOID BaseAddress,
+ PLDR_RESOURCE_INFO ResourceInfo,
+ ULONG Level,
+ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
+{
+ PIMAGE_RESOURCE_DIRECTORY ResDir;
+ PIMAGE_RESOURCE_DIRECTORY ResBase;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG EntryCount;
+ PWCHAR ws;
+ ULONG i;
+ ULONG Id;
+
+ DPRINT ("LdrFindResource_U()\n");
+
+ /* Get the pointer to the resource directory */
+ ResDir = (PIMAGE_RESOURCE_DIRECTORY)
+ RtlImageDirectoryEntryToData (BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &i);
+ if (ResDir == NULL)
+ {
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ }
+
+ DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
+
+ ResBase = ResDir;
+
+ /* Let's go into resource tree */
+ for (i = 0; i < Level; i++)
+ {
+ DPRINT("ResDir: %x\n", (ULONG)ResDir);
+ Id = ((PULONG)ResourceInfo)[i];
+ EntryCount = ResDir->NumberOfNamedEntries;
+ ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
+ DPRINT("ResEntry %x\n", (ULONG)ResEntry);
+ if (Id & 0xFFFF0000)
+ {
+ /* Resource name is a unicode string */
+ for (; EntryCount--; ResEntry++)
+ {
+ /* Scan entries for equal name */
+ if (ResEntry->Name & 0x80000000)
+ {
+ ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
+ if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
+ wcslen((PWCHAR)Id) == (int)*ws )
+ {
+ goto found;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* We use ID number instead of string */
+ ResEntry += EntryCount;
+ EntryCount = ResDir->NumberOfIdEntries;
+ for (; EntryCount--; ResEntry++)
+ {
+ /* Scan entries for equal name */
+ if (ResEntry->Name == Id)
+ {
+ DPRINT("ID entry found %x\n", Id);
+ goto found;
+ }
+ }
+ }
+ DPRINT("Error %lu\n", i);
+
+ switch (i)
+ {
+ case 0:
+ return STATUS_RESOURCE_TYPE_NOT_FOUND;
+
+ case 1:
+ return STATUS_RESOURCE_NAME_NOT_FOUND;
+
+ case 2:
+ if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
+ {
+ /* Use the first available language */
+ ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
+ break;
+ }
+ return STATUS_RESOURCE_LANG_NOT_FOUND;
+
+ case 3:
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+found:;
+ ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
+ (ResEntry->OffsetToData & 0x7FFFFFFF));
+ }
+ DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
+
+ if (ResourceDataEntry)
+ {
+ *ResourceDataEntry = (PVOID)ResDir;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS STDCALL
+LdrAccessResource(IN PVOID BaseAddress,
+ IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
+ OUT PVOID *Resource OPTIONAL,
+ OUT PULONG Size OPTIONAL)
+{
+ PIMAGE_SECTION_HEADER Section;
+ PIMAGE_NT_HEADERS NtHeader;
+ ULONG SectionRva;
+ ULONG SectionVa;
+ ULONG DataSize;
+ ULONG Offset = 0;
+ ULONG Data;
+
+ Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &DataSize);
+ if (Data == 0)
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+
+ if ((ULONG)BaseAddress & 1)
+ {
+ /* loaded as ordinary file */
+ NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
+ Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+ Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
+ if (Section == NULL)
+ {
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ }
+
+ if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
+ {
+ SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
+ SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
+ Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
+ }
+ }
+
+ if (Resource)
+ {
+ *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
+ }
+
+ if (Size)
+ {
+ *Size = ResourceDataEntry->Size;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS STDCALL
+LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress)
+{
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+ NTSTATUS Status;
+
+ DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
+ BaseAddress);
+
+ Status = STATUS_DLL_NOT_FOUND;
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+ Entry = ModuleListHead->Flink;
+
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+ DPRINT("BaseDllName %wZ BaseAddress %x\n",
+ &Module->BaseDllName,
+ Module->BaseAddress);
+
+ if (Module->BaseAddress == BaseAddress)
+ {
+ if (Module->TlsIndex == 0)
+ {
+ Module->Flags |= 0x00040000;
+ Status = STATUS_SUCCESS;
+ }
+ return Status;
+ }
+
+ Entry = Entry->Flink;
+ }
+
+ return Status;
}
+NTSTATUS STDCALL
+LdrFindResourceDirectory_U (IN PVOID BaseAddress,
+ WCHAR **name,
+ DWORD level,
+ OUT PVOID *addr)
+{
+ PIMAGE_RESOURCE_DIRECTORY ResDir;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
+ ULONG EntryCount;
+ ULONG i;
+ NTSTATUS Status = STATUS_SUCCESS;
+ WCHAR *ws;
+
+ /* Get the pointer to the resource directory */
+ ResDir = (PIMAGE_RESOURCE_DIRECTORY)
+ RtlImageDirectoryEntryToData (BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &i);
+ if (ResDir == NULL)
+ {
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ }
+
+ /* Let's go into resource tree */
+ for (i = 0; i < level; i++, name++)
+ {
+ EntryCount = ResDir->NumberOfNamedEntries;
+ ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
+ if ((ULONG)(*name) & 0xFFFF0000)
+ {
+ /* Resource name is a unicode string */
+ for (; EntryCount--; ResEntry++)
+ {
+ /* Scan entries for equal name */
+ if (ResEntry->Name & 0x80000000)
+ {
+ ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
+ if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
+ {
+ goto found;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* We use ID number instead of string */
+ ResEntry += EntryCount;
+ EntryCount = ResDir->NumberOfIdEntries;
+ for (; EntryCount--; ResEntry++)
+ {
+ /* Scan entries for equal name */
+ if (ResEntry->Name == (ULONG)(*name))
+ goto found;
+ }
+ }
+
+ switch (i)
+ {
+ case 0:
+ return STATUS_RESOURCE_TYPE_NOT_FOUND;
+
+ case 1:
+ return STATUS_RESOURCE_NAME_NOT_FOUND;
+
+ case 2:
+ Status = STATUS_RESOURCE_LANG_NOT_FOUND;
+ /* Just use first language entry */
+ if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
+ {
+ ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
+ break;
+ }
+ return Status;
+
+ case 3:
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+found:;
+ ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
+ }
+
+ if (addr)
+ {
+ *addr = (PVOID)ResDir;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS STDCALL
+LdrGetDllHandle (IN ULONG Unknown1,
+ IN ULONG Unknown2,
+ IN PUNICODE_STRING DllName,
+ OUT PVOID *BaseAddress)
+{
+ UNICODE_STRING FullDllName;
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+
+ DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
+ Unknown1, Unknown2, DllName, BaseAddress);
+
+ /* NULL is the current executable */
+ if ( DllName == NULL )
+ {
+ *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+ DPRINT("BaseAddress %x\n", *BaseAddress);
+ return STATUS_SUCCESS;
+ }
+
+ LdrAdjustDllName (&FullDllName,
+ DllName,
+ TRUE);
+
+ DPRINT("FullDllName %wZ\n",
+ &FullDllName);
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+ Entry = ModuleListHead->Flink;
+
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+ DPRINT("EntryPoint %x\n", Module->EntryPoint);
+ DPRINT("Comparing %wZ and %wZ\n",
+ &Module->BaseDllName,
+ &FullDllName);
+
+ if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE))
+ {
+ RtlFreeUnicodeString (&FullDllName);
+ *BaseAddress = Module->BaseAddress;
+ DPRINT("BaseAddress %x\n", *BaseAddress);
+ return STATUS_SUCCESS;
+ }
+
+ Entry = Entry->Flink;
+ }
+
+ DPRINT("Failed to find dll %wZ\n", &FullDllName);
+ RtlFreeUnicodeString (&FullDllName);
+ *BaseAddress = NULL;
+ return STATUS_DLL_NOT_FOUND;
+}
+
+
+NTSTATUS STDCALL
+LdrGetProcedureAddress (IN PVOID BaseAddress,
+ IN PANSI_STRING Name,
+ IN ULONG Ordinal,
+ OUT PVOID *ProcedureAddress)
+{
+ PIMAGE_EXPORT_DIRECTORY ExportDir;
+ PUSHORT OrdinalPtr;
+ PULONG NamePtr;
+ PULONG AddressPtr;
+ ULONG i = 0;
+
+ DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
+ BaseAddress, Name, Ordinal, ProcedureAddress);
+
+ /* Get the pointer to the export directory */
+ ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+ RtlImageDirectoryEntryToData (BaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &i);
+
+ DPRINT("ExportDir %x i %lu\n", ExportDir, i);
+
+ if (!ExportDir || !i || !ProcedureAddress)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
+ if (Name && Name->Length)
+ {
+ /* by name */
+ OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
+ NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
+ for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
+ {
+ if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
+ {
+ *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
+ return STATUS_SUCCESS;
+ }
+ }
+ DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
+ }
+ else
+ {
+ /* by ordinal */
+ Ordinal &= 0x0000FFFF;
+ if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
+ {
+ *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
+ return STATUS_SUCCESS;
+ }
+ DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
+ }
+
+ return STATUS_PROCEDURE_NOT_FOUND;
+}
+
+
+NTSTATUS STDCALL
+LdrShutdownProcess (VOID)
+{
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+
+ DPRINT("LdrShutdownProcess() called\n");
+
+ RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+ Entry = ModuleListHead->Blink;
+
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+
+ DPRINT(" Unloading %S\n",
+ &Module->BaseDllName);
+ // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
+ // they loaded dynamically, and when the last reference is gone, that lib will
+ // be detached.
+ if (Module->EntryPoint != 0 && Module->LoadCount == -1)
+ {
+ PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+
+ DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+ Entrypoint (Module->BaseAddress,
+ DLL_PROCESS_DETACH,
+ NULL);
+ }
+
+ Entry = Entry->Blink;
+ }
+
+ RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+
+ DPRINT("LdrShutdownProcess() done\n");
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS STDCALL
+LdrShutdownThread (VOID)
+{
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_MODULE Module;
+
+ DPRINT("LdrShutdownThread() called\n");
+
+ RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+
+ ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+ Entry = ModuleListHead->Blink;
+
+ while (Entry != ModuleListHead)
+ {
+ Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+
+ DPRINT(" Unloading %wZ\n",
+ &Module->BaseDllName);
+
+ if (Module->EntryPoint != 0)
+ {
+ PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+
+ DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+ Entrypoint (Module->BaseAddress,
+ DLL_THREAD_DETACH,
+ NULL);
+ }
+
+ Entry = Entry->Blink;
+ }
+
+ RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+
+ DPRINT("LdrShutdownThread() done\n");
+
+ return STATUS_SUCCESS;
+}
+/* EOF */