From 2d89dd3da30f759a08ed92f342425c3ab68dcb8a Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Fri, 24 Jun 2011 21:30:09 +0000 Subject: [PATCH] [NTDLL/LDR] - The long awaited LDR rewrite, a commit for testing the new implementation. In case of serious problems it may be reverted (revert should be approved by me). - Its features include: * A proper ...everything. Process, thread initialization codes, DLL loading (including compatible path lookup, and compatible/proper loading order of the dependent DLLs, including their initialization) and mapping and section creation, reference counting, relocations, good and understandable PE code for walking import descriptor, snapping, etc etc. Hacks--; GoodCode++; * Activation contexts operations are now being performed compatible to how Windows performs them (though the actual actctx implementation is still Wine's, it was modified to be compatible). Previously, actctx stuff was added to the ldr code like a pepper is added to the soup: in different places until it starts to work. * Partial DLL redirection implementation. * Possibility to support Shim engine and app compat stuff in future. * More cool stuff, just browse the code. - I fixed all regressions I could find but one (hang during shutdown of the 3rd stage). The purpose of this commit is to seek and destroy the regressions I couldn't find (if there are any). - Some of the old rarely called ldr code still remains in startup.c and utils.c. They are subject to be rewritten/removed soon, and every remaining old function is marked with a respective DPRINT1 to see when it's being called. svn path=/trunk/; revision=52446 --- reactos/dll/ntdll/include/ntdllp.h | 32 +- reactos/dll/ntdll/ldr/ldrapi.c | 494 +++++- reactos/dll/ntdll/ldr/ldrinit.c | 514 +++++- reactos/dll/ntdll/ldr/ldrpe.c | 85 +- reactos/dll/ntdll/ldr/ldrutils.c | 1777 ++++++++++++++++++++- reactos/dll/ntdll/ldr/startup.c | 279 +--- reactos/dll/ntdll/ldr/utils.c | 2077 +------------------------ reactos/dll/win32/kernel32/misc/ldr.c | 19 +- reactos/lib/rtl/actctx.c | 19 +- 9 files changed, 2853 insertions(+), 2443 deletions(-) diff --git a/reactos/dll/ntdll/include/ntdllp.h b/reactos/dll/ntdll/include/ntdllp.h index a01a960cef2..dc4bf7593ba 100644 --- a/reactos/dll/ntdll/include/ntdllp.h +++ b/reactos/dll/ntdll/include/ntdllp.h @@ -10,6 +10,11 @@ #define LDR_HASH_TABLE_ENTRIES 32 +/* LdrpUpdateLoadCount2 flags */ +#define LDRP_UPDATE_REFCOUNT 0x01 +#define LDRP_UPDATE_DEREFCOUNT 0x02 +#define LDRP_UPDATE_PIN 0x03 + typedef struct _LDRP_TLS_DATA { LIST_ENTRY TlsLinks; @@ -27,10 +32,21 @@ extern BOOLEAN LdrpInLdrInit; extern LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES]; extern BOOLEAN ShowSnaps; extern UNICODE_STRING LdrpDefaultPath; +extern HANDLE LdrpKnownDllObjectDirectory; +extern ULONG LdrpNumberOfProcessors; +extern ULONG LdrpFatalHardErrorCount; +extern PUNICODE_STRING LdrpTopLevelDllBeingLoaded; +extern PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer; +extern UNICODE_STRING LdrApiDefaultExtension; +extern BOOLEAN LdrpLdrDatabaseIsSetup; +extern ULONG LdrpActiveUnloadCount; +extern BOOLEAN LdrpShutdownInProgress; +extern UNICODE_STRING LdrpKnownDllPath; +extern PLDR_DATA_TABLE_ENTRY LdrpGetModuleHandleCache; /* ldrinit.c */ NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL); -NTSTATUS NTAPI LdrpInitializeThread(IN PCONTEXT Context); +VOID NTAPI LdrpInitializeThread(IN PCONTEXT Context); NTSTATUS NTAPI LdrpInitializeTls(VOID); NTSTATUS NTAPI LdrpAllocateTls(VOID); VOID NTAPI LdrpFreeTls(VOID); @@ -38,7 +54,7 @@ VOID NTAPI LdrpTlsCallback(PVOID BaseAddress, ULONG Reason); BOOLEAN NTAPI LdrpCallDllEntry(PDLLMAIN_FUNC EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context); NTSTATUS NTAPI LdrpInitializeProcess(PCONTEXT Context, PVOID SystemArgument1); VOID NTAPI LdrpInitFailure(NTSTATUS Status); - +VOID NTAPI LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry); /* ldrpe.c */ NTSTATUS @@ -79,6 +95,10 @@ LdrpLoadDll(IN BOOLEAN Redirected, OUT PVOID *BaseAddress, IN BOOLEAN CallInit); +VOID NTAPI +LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN ULONG Flags); + ULONG NTAPI LdrpClearLoadInProgress(); @@ -101,6 +121,9 @@ LdrpMapDll(IN PWSTR SearchPath OPTIONAL, PVOID NTAPI LdrpFetchAddressOfEntryPoint(PVOID ImageBase); +BOOLEAN NTAPI +LdrpFreeUnicodeString(PUNICODE_STRING String); + /* FIXME: Cleanup this mess */ typedef NTSTATUS (NTAPI *PEPFUNC)(PPEB); @@ -110,13 +133,8 @@ NTSTATUS LdrMapSections(HANDLE ProcessHandle, PIMAGE_NT_HEADERS NTHeaders); NTSTATUS LdrMapNTDllForProcess(HANDLE ProcessHandle, PHANDLE NTDllSectionHandle); -BOOLEAN LdrMappedAsDataFile(PVOID *BaseAddress); ULONG LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders); -PEPFUNC LdrPEStartup (PVOID ImageBase, - HANDLE SectionHandle, - PLDR_DATA_TABLE_ENTRY* Module, - PWSTR FullDosName); extern HANDLE WindowsApiPort; diff --git a/reactos/dll/ntdll/ldr/ldrapi.c b/reactos/dll/ntdll/ldr/ldrapi.c index e08f4ca5ec8..cf9b5d2d6d1 100644 --- a/reactos/dll/ntdll/ldr/ldrapi.c +++ b/reactos/dll/ntdll/ldr/ldrapi.c @@ -16,6 +16,8 @@ /* GLOBALS *******************************************************************/ LONG LdrpLoaderLockAcquisitonCount; +BOOLEAN LdrpShowRecursiveLoads; +UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL"); /* FUNCTIONS *****************************************************************/ @@ -242,6 +244,483 @@ Quickie: return Status; } +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrLoadDll(IN PWSTR SearchPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *BaseAddress) +{ + WCHAR StringBuffer[MAX_PATH]; + UNICODE_STRING DllString1, DllString2; + BOOLEAN RedirectedDll = FALSE; + NTSTATUS Status; + ULONG Cookie; + PUNICODE_STRING OldTldDll; + PTEB Teb = NtCurrentTeb(); + + /* Initialize the strings */ + RtlInitUnicodeString(&DllString2, NULL); + DllString1.Buffer = StringBuffer; + DllString1.Length = 0; + DllString1.MaximumLength = sizeof(StringBuffer); + + /* Check if the SxS Assemblies specify another file */ + Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, + DllName, + &LdrApiDefaultExtension, + &DllString1, + &DllString2, + &DllName, + NULL, + NULL, + NULL); + + /* Check success */ + if (NT_SUCCESS(Status)) + { + /* Let Ldrp know */ + RedirectedDll = TRUE; + } + else if (Status != STATUS_SXS_KEY_NOT_FOUND) + { + /* Unrecoverable SxS failure; did we get a string? */ + if (DllString2.Buffer) + { + /* Free the string */ + RtlFreeUnicodeString(&DllString2); + return Status; + } + } + + /* Lock the loader lock */ + LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie); + + /* Check if there's a TLD DLL being loaded */ + if ((OldTldDll = LdrpTopLevelDllBeingLoaded)) + { + /* This is a recursive load, do something about it? */ + if (ShowSnaps || LdrpShowRecursiveLoads) + { + /* Print out debug messages */ + DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n", + Teb->RealClientId.UniqueProcess, + Teb->RealClientId.UniqueThread); + DPRINT1("[%lx, %lx] Previous DLL being loaded \"%wZ\"\n", + Teb->RealClientId.UniqueProcess, + Teb->RealClientId.UniqueThread, + OldTldDll); + DPRINT1("[%lx, %lx] DLL being requested \"%wZ\"\n", + Teb->RealClientId.UniqueProcess, + Teb->RealClientId.UniqueThread, + DllName); + + /* Was it initializing too? */ + if (!LdrpCurrentDllInitializer) + { + DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n", + Teb->RealClientId.UniqueProcess, + Teb->RealClientId.UniqueThread); + } + else + { + DPRINT1("[%lx, %lx] DLL whose initializer was currently running \"%wZ\"\n", + Teb->ClientId.UniqueProcess, + Teb->ClientId.UniqueThread, + &LdrpCurrentDllInitializer->BaseDllName); + } + } + } + + /* Set this one as the TLD DLL being loaded*/ + LdrpTopLevelDllBeingLoaded = DllName; + + /* Load the DLL */ + Status = LdrpLoadDll(RedirectedDll, + SearchPath, + DllCharacteristics, + DllName, + BaseAddress, + TRUE); + + /* Set it to success just to be sure */ + Status = STATUS_SUCCESS; + + /* Restore the old TLD DLL */ + LdrpTopLevelDllBeingLoaded = OldTldDll; + + /* Release the lock */ + LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); + + /* Do we have a redirect string? */ + if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2); + + /* Return */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrFindEntryForAddress(PVOID Address, + PLDR_DATA_TABLE_ENTRY *Module) +{ + PLIST_ENTRY ListHead, NextEntry; + PLDR_DATA_TABLE_ENTRY LdrEntry; + PIMAGE_NT_HEADERS NtHeader; + PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr; + ULONG_PTR DllBase, DllEnd; + + DPRINT("LdrFindEntryForAddress(Address %p)\n", Address); + + /* Nothing to do */ + if (!Ldr) return STATUS_NO_MORE_ENTRIES; + + /* Loop the module list */ + ListHead = &Ldr->InMemoryOrderModuleList; + NextEntry = ListHead->Flink; + while (NextEntry != ListHead) + { + /* Get the entry and NT Headers */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList); + if ((NtHeader = RtlImageNtHeader(LdrEntry->DllBase))) + { + /* Get the Image Base */ + DllBase = (ULONG_PTR)LdrEntry->DllBase; + DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage; + + /* Check if they match */ + if (((ULONG_PTR)Address >= DllBase) && + ((ULONG_PTR)Address < DllEnd)) + { + /* Return it */ + *Module = LdrEntry; + return STATUS_SUCCESS; + } + + /* Next Entry */ + NextEntry = NextEntry->Flink; + } + } + + /* Nothing found */ + return STATUS_NO_MORE_ENTRIES; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrGetDllHandleEx(IN ULONG Flags, + IN PWSTR DllPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *DllHandle OPTIONAL) +{ + NTSTATUS Status = STATUS_DLL_NOT_FOUND; + PLDR_DATA_TABLE_ENTRY LdrEntry; + UNICODE_STRING RedirectName, DllString1; + UNICODE_STRING RawDllName; + PUNICODE_STRING pRedirectName = &RedirectName; + PUNICODE_STRING CompareName; + PWCHAR p1, p2, p3; + BOOLEAN Locked = FALSE; + BOOLEAN RedirectedDll = FALSE; + ULONG Cookie; + ULONG LoadFlag; + + /* Initialize the strings */ + RtlInitUnicodeString(&DllString1, NULL); + RtlInitUnicodeString(&RawDllName, NULL); + RedirectName = *DllName; + + /* Clear the handle */ + if (DllHandle) *DllHandle = NULL; + + /* Check for a valid flag */ + if ((Flags & ~3) || (!DllHandle && !(Flags & 2))) + { + DPRINT1("Flags are invalid or no DllHandle given\n"); + return STATUS_INVALID_PARAMETER; + } + + /* If not initializing */ + if (!LdrpInLdrInit) + { + /* Acquire the lock */ + Status = LdrLockLoaderLock(0, NULL, &Cookie); + Locked = TRUE; + } + + /* Check if the SxS Assemblies specify another file */ + Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, + pRedirectName, + &LdrApiDefaultExtension, + NULL, + &DllString1, + &pRedirectName, + NULL, + NULL, + NULL); + + /* Check success */ + if (NT_SUCCESS(Status)) + { + /* Let Ldrp know */ + RedirectedDll = TRUE; + } + else if (Status != STATUS_SXS_KEY_NOT_FOUND) + { + /* Unrecoverable SxS failure; */ + goto Quickie; + } + + /* Use the cache if we can */ + if (LdrpGetModuleHandleCache) + { + /* Check if we were redirected */ + if (RedirectedDll) + { + /* Check the flag */ + if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED) + { + /* Use the right name */ + CompareName = &LdrpGetModuleHandleCache->FullDllName; + } + else + { + goto DontCompare; + } + } + else + { + /* Check the flag */ + if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)) + { + /* Use the right name */ + CompareName = &LdrpGetModuleHandleCache->BaseDllName; + } + else + { + goto DontCompare; + } + } + + /* Check if the name matches */ + if (RtlEqualUnicodeString(pRedirectName, + CompareName, + TRUE)) + { + /* Skip the rest */ + LdrEntry = LdrpGetModuleHandleCache; + + /* Return success */ + Status = STATUS_SUCCESS; + + goto FoundEntry; + } + } + +DontCompare: + /* Find the name without the extension */ + p1 = pRedirectName->Buffer; + p3 = &p1[pRedirectName->Length / sizeof(WCHAR)]; +StartLoop: + p2 = NULL; + while (p1 != p3) + { + if (*p1++ == L'.') + { + p2 = p1; + } + else if (*p1 == L'\\') + { + goto StartLoop; + } + } + + /* Check if no extension was found or if we got a slash */ + if (!p2 || *p2 == L'\\' || *p2 == L'/') + { + /* Check that we have space to add one */ + if (pRedirectName->Length + LdrApiDefaultExtension.Length >= MAXLONG) + { + /* No space to add the extension */ + return STATUS_NAME_TOO_LONG; + } + + /* Setup the string */ + RawDllName.MaximumLength = pRedirectName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL); + RawDllName.Length = RawDllName.MaximumLength - sizeof(UNICODE_NULL); + RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + RawDllName.MaximumLength); + + /* Copy the buffer */ + RtlMoveMemory(RawDllName.Buffer, + pRedirectName->Buffer, + pRedirectName->Length); + + /* Add extension */ + RtlMoveMemory((PVOID)((ULONG_PTR)RawDllName.Buffer + pRedirectName->Length), + LdrApiDefaultExtension.Buffer, + LdrApiDefaultExtension.Length); + + /* Null terminate */ + RawDllName.Buffer[RawDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; + } + else + { + /* Check if there's something in the name */ + if (pRedirectName->Length) + { + /* Check and remove trailing period */ + if (pRedirectName->Buffer[(pRedirectName->Length - 2) / + sizeof(WCHAR)] == '.') + { + /* Decrease the size */ + pRedirectName->Length -= sizeof(WCHAR); + } + } + + /* Setup the string */ + RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR); + RawDllName.Length = pRedirectName->Length; + RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + RawDllName.MaximumLength); + + /* Copy the buffer */ + RtlMoveMemory(RawDllName.Buffer, + pRedirectName->Buffer, + pRedirectName->Length); + + /* Null terminate */ + RawDllName.Buffer[RawDllName.Length / sizeof(WCHAR)] = UNICODE_NULL; + } + + /* Display debug string */ + if (ShowSnaps) + { + DPRINT1("LDR: LdrGetDllHandle, searching for %wZ from %ws\n", + &RawDllName, + DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L""); + } + + /* Do the lookup */ + if (LdrpCheckForLoadedDll(DllPath, + &RawDllName, + ((ULONG_PTR)DllPath == 1) ? TRUE : FALSE, + RedirectedDll, + &LdrEntry)) + { + /* Update cached entry */ + LdrpGetModuleHandleCache = LdrEntry; + + /* Return success */ + Status = STATUS_SUCCESS; + } + else + { + /* Make sure to NULL this */ + LdrEntry = NULL; + } +FoundEntry: + DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL); + + /* Check if we got an entry */ + if (LdrEntry) + { + /* Check for success */ + if (NT_SUCCESS(Status)) + { + /* Check if the DLL is locked */ + if (LdrEntry->LoadCount != -1) + { + /* Check what flag we got */ + if (!(Flags & 1)) + { + /* Check what to do with the load count */ + if (Flags & 2) + { + /* Pin it */ + LdrEntry->LoadCount = -1; + LoadFlag = LDRP_UPDATE_PIN; + } + else + { + /* Increase the load count */ + LdrEntry->LoadCount++; + LoadFlag = LDRP_UPDATE_REFCOUNT; + } + + /* Update the load count now */ + LdrpUpdateLoadCount2(LdrEntry, LoadFlag); + LdrpClearLoadInProgress(); + } + } + + /* Check if the caller is requesting the handle */ + if (DllHandle) *DllHandle = LdrEntry->DllBase; + } + } +Quickie: + /* Free string if needed */ + if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1); + + /* Free the raw DLL Name if needed */ + if (RawDllName.Buffer) + { + /* Free the heap-allocated buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer); + RawDllName.Buffer = NULL; + } + + /* Release lock */ + if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); + + /* Return */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrGetDllHandle(IN PWSTR DllPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *DllHandle) +{ + /* Call the newer API */ + return LdrGetDllHandleEx(TRUE, + DllPath, + DllCharacteristics, + DllName, + DllHandle); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrGetProcedureAddress(IN PVOID BaseAddress, + IN PANSI_STRING Name, + IN ULONG Ordinal, + OUT PVOID *ProcedureAddress) +{ + /* Call the internal routine and tell it to execute DllInit */ + return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE); +} + /* * @implemented */ @@ -374,21 +853,6 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle, return !Result ? STATUS_IMAGE_CHECKSUM_MISMATCH : Status; } -/* - * @implemented - */ -NTSTATUS -NTAPI -LdrGetProcedureAddress_(IN PVOID BaseAddress, - IN PANSI_STRING Name, - IN ULONG Ordinal, - OUT PVOID *ProcedureAddress) -{ - /* Call the internal routine and tell it to execute DllInit */ - return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE); -} - - NTSTATUS NTAPI LdrQueryProcessModuleInformationEx(IN ULONG ProcessId, diff --git a/reactos/dll/ntdll/ldr/ldrinit.c b/reactos/dll/ntdll/ldr/ldrinit.c index 6b08bed65dd..fd0aa391f11 100644 --- a/reactos/dll/ntdll/ldr/ldrinit.c +++ b/reactos/dll/ntdll/ldr/ldrinit.c @@ -10,9 +10,12 @@ /* INCLUDES *****************************************************************/ #include +#include + #define NDEBUG #include + /* GLOBALS *******************************************************************/ HKEY ImageExecOptionsKey; @@ -25,11 +28,14 @@ BOOLEAN LdrpInLdrInit; LONG LdrpProcessInitialized; BOOLEAN LdrpLoaderLockInit; BOOLEAN LdrpLdrDatabaseIsSetup; +BOOLEAN LdrpShutdownInProgress; +HANDLE LdrpShutdownThreadId; BOOLEAN LdrpDllValidation; PLDR_DATA_TABLE_ENTRY LdrpImageEntry; PUNICODE_STRING LdrpTopLevelDllBeingLoaded; +WCHAR StringBuffer[156]; extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c! PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer; PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry; @@ -68,6 +74,7 @@ RTL_CRITICAL_SECTION FastPebLock; BOOLEAN ShowSnaps; ULONG LdrpFatalHardErrorCount; +ULONG LdrpActiveUnloadCount; //extern LIST_ENTRY RtlCriticalSectionList; @@ -78,10 +85,12 @@ extern BOOLEAN RtlpPageHeapEnabled; extern ULONG RtlpDphGlobalFlags; NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase); -NTSTATUS NTAPI -LdrpInitializeProcess_(PCONTEXT Context, - PVOID SystemArgument1); +#ifdef _WIN64 +#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll +#else +#define DEFAULT_SECURITY_COOKIE 0xBB40E64E +#endif /* FUNCTIONS *****************************************************************/ @@ -414,8 +423,7 @@ LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage) Cookie = (PVOID)ConfigDir->SecurityCookie; /* Check this cookie */ - if (Cookie == NULL || - (PCHAR)Cookie <= (PCHAR)BaseAddress || + if ((PCHAR)Cookie <= (PCHAR)BaseAddress || (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage) { Cookie = NULL; @@ -429,20 +437,178 @@ PVOID NTAPI LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry) { - PVOID Cookie; + PULONG_PTR Cookie; + LARGE_INTEGER Counter; + //ULONG NewCookie; /* Fetch address of the cookie */ Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage); if (Cookie) { - UNIMPLEMENTED; - Cookie = NULL; + /* Check if it's a default one */ + if (*Cookie == DEFAULT_SECURITY_COOKIE || + *Cookie == 0xBB40) + { + /* We need to initialize it */ + + NtQueryPerformanceCounter(&Counter, NULL); +#if 0 + GetSystemTimeAsFileTime (&systime.ft_struct); +#ifdef _WIN64 + cookie = systime.ft_scalar; +#else + cookie = systime.ft_struct.dwLowDateTime; + cookie ^= systime.ft_struct.dwHighDateTime; +#endif + + cookie ^= GetCurrentProcessId (); + cookie ^= GetCurrentThreadId (); + cookie ^= GetTickCount (); + + QueryPerformanceCounter (&perfctr); +#ifdef _WIN64 + cookie ^= perfctr.QuadPart; +#else + cookie ^= perfctr.LowPart; + cookie ^= perfctr.HighPart; +#endif + +#ifdef _WIN64 + cookie &= 0x0000ffffffffffffll; +#endif +#endif + *Cookie = Counter.LowPart; + + //Cookie = NULL; + } } return Cookie; } +VOID +NTAPI +LdrpInitializeThread(IN PCONTEXT Context) +{ + PPEB Peb = NtCurrentPeb(); + PLDR_DATA_TABLE_ENTRY LdrEntry; + PLIST_ENTRY NextEntry, ListHead; + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; + NTSTATUS Status; + PVOID EntryPoint; + + DPRINT("LdrpInitializeThread() called for %wZ\n", + &LdrpImageEntry->BaseDllName); + + /* Allocate an Activation Context Stack */ + /* FIXME: This is a hack for Wine's actctx stuff */ + DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer); + if (!(NtCurrentTeb()->ActivationContextStackPointer)) + { + Status = RtlAllocateActivationContextStack((PVOID*)&NtCurrentTeb()->ActivationContextStackPointer); + if (NT_SUCCESS(Status)) + { + DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer); + DPRINT("ActiveFrame %p\n", ((PACTIVATION_CONTEXT_STACK)NtCurrentTeb()->ActivationContextStackPointer)->ActiveFrame); + NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL; + } + else + DPRINT1("Warning: Unable to allocate ActivationContextStack\n"); + } + + /* Make sure we are not shutting down */ + if (LdrpShutdownInProgress) return; + + /* Allocate TLS */ + LdrpAllocateTls(); + + /* Start at the beginning */ + ListHead = &Peb->Ldr->InMemoryOrderModuleList; + NextEntry = ListHead->Flink; + while (NextEntry != ListHead) + { + /* Get the current entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList); + + /* Make sure it's not ourselves */ + if (Peb->ImageBaseAddress != LdrEntry->DllBase) + { + /* Check if we should call */ + if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS)) + { + /* Get the entrypoint */ + EntryPoint = LdrEntry->EntryPoint; + + /* Check if we are ready to call it */ + if ((EntryPoint) && + (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) && + (LdrEntry->Flags & LDRP_IMAGE_DLL)) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Check if it has TLS */ + if (LdrEntry->TlsIndex) + { + /* Make sure we're not shutting down */ + if (!LdrpShutdownInProgress) + { + /* Call TLS */ + LdrpTlsCallback(LdrEntry->DllBase, DLL_THREAD_ATTACH); + } + } + + /* Make sure we're not shutting down */ + if (!LdrpShutdownInProgress) + { + /* Call the Entrypoint */ + DPRINT("%wZ - Calling entry point at %x for thread attaching\n", + &LdrEntry->BaseDllName, LdrEntry->EntryPoint); + LdrpCallDllEntry(LdrEntry->EntryPoint, + LdrEntry->DllBase, + DLL_THREAD_ATTACH, + NULL); + } + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + } + } + + /* Next entry */ + NextEntry = NextEntry->Flink; + } + + /* Check for TLS */ + if (LdrpImageHasTls && !LdrpShutdownInProgress) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrpImageEntry->EntryPointActivationContext); + + /* Do TLS callbacks */ + LdrpTlsCallback(Peb->ImageBaseAddress, DLL_THREAD_ATTACH); + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + + DPRINT("LdrpInitializeThread() done\n"); +} + NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL) @@ -715,6 +881,267 @@ Quickie: return Status; } +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrShutdownProcess(VOID) +{ + PPEB Peb = NtCurrentPeb(); + PLDR_DATA_TABLE_ENTRY LdrEntry; + PLIST_ENTRY NextEntry, ListHead; + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; + PVOID EntryPoint; + + DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName); + if (LdrpShutdownInProgress) return STATUS_SUCCESS; + + /* Tell the Shim Engine */ + //if (ShimsEnabled) + //{ + /* FIXME */ + //} + + /* Tell the world */ + if (ShowSnaps) + { + DPRINT1("\n"); + } + + /* Set the shutdown variables */ + LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread; + LdrpShutdownInProgress = TRUE; + + /* Enter the Loader Lock */ + RtlEnterCriticalSection(&LdrpLoaderLock); + + /* Cleanup trace logging data (Etw) */ + if (SharedUserData->TraceLogging) + { + /* FIXME */ + DPRINT1("We don't support Etw yet.\n"); + } + + /* Start at the end */ + ListHead = &Peb->Ldr->InInitializationOrderModuleList; + NextEntry = ListHead->Blink; + while (NextEntry != ListHead) + { + /* Get the current entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); + NextEntry = NextEntry->Blink; + + /* Make sure it's not ourselves */ + if (Peb->ImageBaseAddress != LdrEntry->DllBase) + { + /* Get the entrypoint */ + EntryPoint = LdrEntry->EntryPoint; + + /* Check if we are ready to call it */ + if (EntryPoint && + (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) && + LdrEntry->Flags) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Check if it has TLS */ + if (LdrEntry->TlsIndex) + { + /* Call TLS */ + LdrpTlsCallback(LdrEntry->DllBase, DLL_PROCESS_DETACH); + } + + /* Call the Entrypoint */ + DPRINT("%wZ - Calling entry point at %x for thread detaching\n", + &LdrEntry->BaseDllName, LdrEntry->EntryPoint); + LdrpCallDllEntry(EntryPoint, + LdrEntry->DllBase, + DLL_PROCESS_DETACH, + (PVOID)1); + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + } + } + + /* Check for TLS */ + if (LdrpImageHasTls) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrpImageEntry->EntryPointActivationContext); + + /* Do TLS callbacks */ + LdrpTlsCallback(Peb->ImageBaseAddress, DLL_PROCESS_DETACH); + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + + /* FIXME: Do Heap detection and Etw final shutdown */ + + /* Release the lock */ + RtlLeaveCriticalSection(&LdrpLoaderLock); + DPRINT("LdrpShutdownProcess() done\n"); + + return STATUS_SUCCESS; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrShutdownThread(VOID) +{ + PPEB Peb = NtCurrentPeb(); + PTEB Teb = NtCurrentTeb(); + PLDR_DATA_TABLE_ENTRY LdrEntry; + PLIST_ENTRY NextEntry, ListHead; + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; + PVOID EntryPoint; + + DPRINT("LdrShutdownThread() called for %wZ\n", + &LdrpImageEntry->BaseDllName); + + /* Cleanup trace logging data (Etw) */ + if (SharedUserData->TraceLogging) + { + /* FIXME */ + DPRINT1("We don't support Etw yet.\n"); + } + + /* Get the Ldr Lock */ + RtlEnterCriticalSection(&LdrpLoaderLock); + + /* Start at the end */ + ListHead = &Peb->Ldr->InInitializationOrderModuleList; + NextEntry = ListHead->Blink; + while (NextEntry != ListHead) + { + /* Get the current entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); + NextEntry = NextEntry->Blink; + + /* Make sure it's not ourselves */ + if (Peb->ImageBaseAddress != LdrEntry->DllBase) + { + /* Check if we should call */ + if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) && + (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) && + (LdrEntry->Flags & LDRP_IMAGE_DLL)) + { + /* Get the entrypoint */ + EntryPoint = LdrEntry->EntryPoint; + + /* Check if we are ready to call it */ + if (EntryPoint) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Check if it has TLS */ + if (LdrEntry->TlsIndex) + { + /* Make sure we're not shutting down */ + if (!LdrpShutdownInProgress) + { + /* Call TLS */ + LdrpTlsCallback(LdrEntry->DllBase, DLL_THREAD_DETACH); + } + } + + /* Make sure we're not shutting down */ + if (!LdrpShutdownInProgress) + { + /* Call the Entrypoint */ + DPRINT("%wZ - Calling entry point at %x for thread detaching\n", + &LdrEntry->BaseDllName, LdrEntry->EntryPoint); + LdrpCallDllEntry(EntryPoint, + LdrEntry->DllBase, + DLL_THREAD_DETACH, + NULL); + } + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + } + } + } + + /* Check for TLS */ + if (LdrpImageHasTls) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrpImageEntry->EntryPointActivationContext); + + /* Do TLS callbacks */ + LdrpTlsCallback(Peb->ImageBaseAddress, DLL_THREAD_DETACH); + + /* Deactivate the ActCtx */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + + /* Free TLS */ + LdrpFreeTls(); + RtlLeaveCriticalSection(&LdrpLoaderLock); + + /* Check for expansion slots */ + if (Teb->TlsExpansionSlots) + { + /* Free expansion slots */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots); + } + + /* Check for FLS Data */ + if (Teb->FlsData) + { + /* FIXME */ + DPRINT1("We don't support FLS Data yet\n"); + } + + /* Check for Fiber data */ + if (Teb->HasFiberData) + { + /* Free Fiber data*/ + RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData); + Teb->NtTib.FiberData = NULL; + } + + /* Free the activation context stack */ + RtlFreeThreadActivationContextStack(); + DPRINT("LdrShutdownThread() done\n"); + + return STATUS_SUCCESS; +} + NTSTATUS NTAPI LdrpInitializeTls(VOID) @@ -879,10 +1306,10 @@ LdrpFreeTls(VOID) NTSTATUS NTAPI -LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PULONG Options) +LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHKEY OptionsKey) { UNIMPLEMENTED; - *Options = 0; + *OptionsKey = NULL; return STATUS_SUCCESS; } @@ -915,7 +1342,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, //LPWSTR ImagePathBuffer; ULONG ConfigSize; UNICODE_STRING CurrentDirectory; - ULONG ExecuteOptions; + HKEY OptionsKey; ULONG HeapFlags; PIMAGE_NT_HEADERS NtHeader; LPWSTR NtDllName = NULL; @@ -928,9 +1355,9 @@ LdrpInitializeProcess(IN PCONTEXT Context, ULONG i; PWSTR ImagePath; ULONG DebugProcessHeapOnly = 0; - WCHAR FullNtDllPath[MAX_PATH]; PLDR_DATA_TABLE_ENTRY NtLdrEntry; PWCHAR Current; + ULONG ExecuteOptions = 0; /* Set a NULL SEH Filter */ RtlSetUnhandledExceptionFilter(NULL); @@ -954,7 +1381,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress); /* Get the execution options */ - Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &ExecuteOptions); + Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey); /* Check if this is a .NET executable */ if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, @@ -1040,7 +1467,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, } /* Check if verbose debugging (ShowSnaps) was requested */ - ShowSnaps = TRUE;//Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS; + ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS; /* Start verbose debugging messages right now if they were requested */ if (ShowSnaps) @@ -1091,9 +1518,11 @@ LdrpInitializeProcess(IN PCONTEXT Context, } /* Initialize the Loader Lock */ + // FIXME: What's the point of initing it manually, if two lines lower + // a call to RtlInitializeCriticalSection() is being made anyway? //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList); //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock; - UNIMPLEMENTED; + RtlInitializeCriticalSection(&LdrpLoaderLock); LdrpLoaderLockInit = TRUE; /* Check if User Stack Trace Database support was requested */ @@ -1134,19 +1563,30 @@ LdrpInitializeProcess(IN PCONTEXT Context, return STATUS_NO_MEMORY; } + // FIXME: Is it located properly? + /* Initialize table of callbacks for the kernel. */ + Peb->KernelCallbackTable = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(PVOID) * + (USER32_CALLBACK_MAXIMUM + 1)); + if (!Peb->KernelCallbackTable) + { + DPRINT1("Failed to create callback table\n"); + ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES); + } + /* Allocate an Activation Context Stack */ Status = RtlAllocateActivationContextStack((PVOID *)&Teb->ActivationContextStackPointer); if (!NT_SUCCESS(Status)) return Status; // FIXME: Loader private heap is missing - DPRINT1("Loader private heap is missing\n"); + //DPRINT1("Loader private heap is missing\n"); /* Check for Debug Heap */ - DPRINT1("Check for a debug heap is missing\n"); - if (FALSE) + if (OptionsKey) { /* Query the setting */ - Status = LdrQueryImageFileKeyOption(NULL,//hKey + Status = LdrQueryImageFileKeyOption(OptionsKey, L"DebugProcessHeapOnly", REG_DWORD, &DebugProcessHeapOnly, @@ -1165,9 +1605,9 @@ LdrpInitializeProcess(IN PCONTEXT Context, } /* Build the NTDLL Path */ - FullPath.Buffer = FullNtDllPath; + FullPath.Buffer = StringBuffer; FullPath.Length = 0; - FullPath.MaximumLength = sizeof(FullNtDllPath); + FullPath.MaximumLength = sizeof(StringBuffer); RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot); RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot); RtlAppendUnicodeToString(&FullPath, L"\\System32\\"); @@ -1188,7 +1628,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, { /* It doesn't, so assume System32 */ LdrpKnownDllObjectDirectory = NULL; - RtlInitUnicodeString(&LdrpKnownDllPath, FullPath.Buffer); + RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer); LdrpKnownDllPath.Length -= sizeof(WCHAR); } else @@ -1230,6 +1670,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, else { /* We need a valid path */ + DPRINT1("No valid DllPath was given!\n"); LdrpInitFailure(STATUS_INVALID_PARAMETER); } @@ -1246,6 +1687,11 @@ LdrpInitializeProcess(IN PCONTEXT Context, 0, 3 * sizeof(WCHAR) + sizeof(UNICODE_NULL)); + if (!CurrentDirectory.Buffer) + { + DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n"); + // FIXME: And what? + } /* Copy the drive of the system root */ RtlMoveMemory(CurrentDirectory.Buffer, @@ -1256,12 +1702,12 @@ LdrpInitializeProcess(IN PCONTEXT Context, CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR); FreeCurDir = TRUE; + DPRINT("Using dynamically allocd curdir\n"); } else { /* Use the local buffer */ - CurrentDirectory.Length = NtSystemRoot.Length; - CurrentDirectory.Buffer = NtSystemRoot.Buffer; + DPRINT("Using local system root\n"); } } @@ -1280,8 +1726,8 @@ LdrpInitializeProcess(IN PCONTEXT Context, NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase); NtLdrEntry->LoadCount = -1; NtLdrEntry->EntryPointActivationContext = 0; - NtLdrEntry->FullDllName.Length = ImageFileName.Length; - NtLdrEntry->FullDllName.Buffer = ImageFileName.Buffer; + NtLdrEntry->FullDllName = ImageFileName; + if (IsDotNetImage) NtLdrEntry->Flags = LDRP_COR_IMAGE; else @@ -1291,7 +1737,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, if (!ImageFileName.Buffer[0]) { /* Use the same Base name */ - NtLdrEntry->BaseDllName = NtLdrEntry->BaseDllName; + NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName; } else { @@ -1332,14 +1778,16 @@ LdrpInitializeProcess(IN PCONTEXT Context, NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase); NtLdrEntry->LoadCount = -1; NtLdrEntry->EntryPointActivationContext = 0; - //NtLdrEntry->BaseDllName.Length = NtSystemRoot.Length; - //RtlAppendUnicodeStringToString(&NtSystemRoot, &NtDllString); + + NtLdrEntry->FullDllName.Length = FullPath.Length; + NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength; + NtLdrEntry->FullDllName.Buffer = StringBuffer; + RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString); + NtLdrEntry->BaseDllName.Length = NtDllString.Length; NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength; NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer; - // FIXME: Full DLL name?! - /* Processing done, insert it */ LdrpNtDllDataTableEntry = NtLdrEntry; LdrpInsertMemoryTableEntry(NtLdrEntry); @@ -1510,7 +1958,7 @@ LdrpInitializeProcess(IN PCONTEXT Context, ///* Close the key if we have one opened */ //if (hKey) NtClose(hKey); -DbgBreakPoint(); + /* Return status */ return Status; } @@ -1596,7 +2044,7 @@ LdrpInit(PCONTEXT Context, _SEH2_TRY { /* Initialize the Process */ - LoaderStatus = LdrpInitializeProcess_(Context, + LoaderStatus = LdrpInitializeProcess(Context, SystemArgument1); /* Check for success and if MinimumStackCommit was requested */ diff --git a/reactos/dll/ntdll/ldr/ldrpe.c b/reactos/dll/ntdll/ldr/ldrpe.c index 12e24fe547d..41694d37e96 100644 --- a/reactos/dll/ntdll/ldr/ldrpe.c +++ b/reactos/dll/ntdll/ldr/ldrpe.c @@ -100,9 +100,7 @@ LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry, /* Deal with Watcom and other retarded compilers */ if (!IatSize) - { IatSize = SectionHeader->SizeOfRawData; - } /* Found it, get out */ break; @@ -255,7 +253,7 @@ NTSTATUS NTAPI LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, IN PLDR_DATA_TABLE_ENTRY LdrEntry, - IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry, + IN PIMAGE_BOUND_IMPORT_DESCRIPTOR *BoundEntryPtr, IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry) { LPSTR ImportName = NULL, BoundImportName, ForwarderName; @@ -264,11 +262,15 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, PIMAGE_IMPORT_DESCRIPTOR ImportEntry; PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry; PIMAGE_BOUND_FORWARDER_REF ForwarderEntry; + PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry; PPEB Peb = NtCurrentPeb(); ULONG i, IatSize; + /* Get the pointer to the bound entry */ + BoundEntry = *BoundEntryPtr; + /* Get the name's VA */ - BoundImportName = (LPSTR)(BoundEntry + BoundEntry->OffsetModuleName); + BoundImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName; /* Show debug mesage */ if (ShowSnaps) @@ -311,7 +313,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, if (ShowSnaps) { DPRINT1("LDR: %wZ has stale binding to %s\n", - &DllLdrEntry->BaseDllName, + &LdrEntry->BaseDllName, BoundImportName); } @@ -324,7 +326,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, if (ShowSnaps) { DPRINT1("LDR: %wZ has correct binding to %s\n", - &DllLdrEntry->BaseDllName, + &LdrEntry->BaseDllName, BoundImportName); } @@ -339,7 +341,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++) { /* Get the name */ - ForwarderName = (LPSTR)(FirstEntry + ForwarderEntry->OffsetModuleName); + ForwarderName = (LPSTR)FirstEntry + ForwarderEntry->OffsetModuleName; /* Show debug message */ if (ShowSnaps) @@ -376,7 +378,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, if (ShowSnaps) { DPRINT1("LDR: %wZ has stale binding to %s\n", - &ForwarderLdrEntry->BaseDllName, + &LdrEntry->BaseDllName, ForwarderName); } @@ -389,7 +391,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, if (ShowSnaps) { DPRINT1("LDR: %wZ has correct binding to %s\n", - &ForwarderLdrEntry->BaseDllName, + &LdrEntry->BaseDllName, ForwarderName); } @@ -423,7 +425,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, if (!_stricmp(ImportName, BoundImportName)) break; /* Move to next entry */ - ImportEntry += 1; + ImportEntry++; } /* If we didn't find a name, fail */ @@ -477,7 +479,7 @@ LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL, Quickie: /* Write where we are now and return */ - *BoundEntry = *FirstEntry; + *BoundEntryPtr = FirstEntry; return Status; } @@ -496,7 +498,7 @@ LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL, /* Parse this descriptor */ Status = LdrpHandleOneNewFormatImportDescriptor(DllPath, LdrEntry, - BoundEntry, + &BoundEntry, FirstEntry); if (!NT_SUCCESS(Status)) return Status; } @@ -642,8 +644,35 @@ LdrpNameToOrdinal(LPSTR ImportName, PULONG NameTable, PUSHORT OrdinalTable) { - UNIMPLEMENTED; - return 0; + ULONG Start, End, Next; + LONG CmpResult; + + /* Use classical binary search to find the ordinal */ + Start = 0; + End = NumberOfNames - 1; + while (End >= Start) + { + /* Next will be exactly between Start and End */ + Next = (Start + End) >> 1; + + /* Compare this name with the one we need to find */ + CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next])); + + /* We found our entry if result is 0 */ + if (!CmpResult) break; + + /* We didn't find, update our range then */ + if (CmpResult < 0) + End = Next - 1; + else if (CmpResult > 0) + Start = Next + 1; + } + + /* If end is before start, then the search failed */ + if (End < Start) return -1; + + /* Return found name */ + return OrdinalTable[Next]; } NTSTATUS @@ -657,10 +686,12 @@ LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL, PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL; PIMAGE_IMPORT_DESCRIPTOR ImportEntry; ULONG BoundSize, IatSize; -DPRINT1("LdrpWalkImportDescriptor('%S' %x)\n", DllPath, LdrEntry); + + DPRINT("LdrpWalkImportDescriptor('%S' %x)\n", DllPath, LdrEntry); + /* Set up the Act Ctx */ ActCtx.Size = sizeof(ActCtx); - ActCtx.Frame.Flags = 1; + ActCtx.Format = 1; RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); /* Check if we have a manifest prober routine */ @@ -680,7 +711,7 @@ DPRINT1("LdrpWalkImportDescriptor('%S' %x)\n", DllPath, LdrEntry); RtlActivateActivationContextUnsafeFast(&ActCtx, LdrEntry->EntryPointActivationContext); - /* Check if we were directed */ + /* Check if we were redirected */ if (!(LdrEntry->Flags & LDRP_REDIRECTED)) { /* Get the Bound IAT */ @@ -764,7 +795,9 @@ LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL, NTSTATUS Status; PPEB Peb = RtlGetCurrentPeb(); PTEB Teb = NtCurrentTeb(); -DPRINT1("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath, ImportName, DllBase, DataTableEntry, Existing); + + DPRINT("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath, ImportName, DllBase, DataTableEntry, Existing); + /* Convert import descriptor name to unicode string */ ImpDescName = &Teb->StaticUnicodeString; RtlInitAnsiString(&AnsiString, ImportName); @@ -788,8 +821,8 @@ DPRINT1("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath, ImportName, DllBa /* Map it */ Status = LdrpMapDll(DllPath, - ImpDescName->Buffer, NULL, + ImpDescName->Buffer, NULL, TRUE, FALSE, @@ -893,6 +926,12 @@ FailurePath: /* Is this a static snap? */ if (Static) { + /* Inform the debug log */ + if (IsOrdinal) + DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal); + else + DPRINT1("Failed to snap %s\n", ImportName); + /* These are critical errors. Setup a string for the DLL name */ RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown"); RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE); @@ -944,6 +983,14 @@ FailurePath: /* Return ordinal error */ RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND); } + else + { + /* Inform the debug log */ + if (IsOrdinal) + DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal); + else + DPRINT("Non-fatal: Failed to snap %s\n", ImportName); + } /* Set this as a bad DLL */ Thunk->u1.Function = (ULONG_PTR)0xffbadd11; diff --git a/reactos/dll/ntdll/ldr/ldrutils.c b/reactos/dll/ntdll/ldr/ldrutils.c index 8c2783755ae..9ad33ee6fbf 100644 --- a/reactos/dll/ntdll/ldr/ldrutils.c +++ b/reactos/dll/ntdll/ldr/ldrutils.c @@ -14,8 +14,11 @@ #include /* GLOBALS *******************************************************************/ +#define IMAGE_DLLCHARACTERISTICS_WX86_DLL 0x1000 +LIST_ENTRY LdrpUnloadHead; PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache; +PLDR_DATA_TABLE_ENTRY LdrpGetModuleHandleCache; #define LDR_GET_HASH_ENTRY(x) (RtlUpcaseUnicodeChar((x)) & (LDR_HASH_TABLE_ENTRIES - 1)) @@ -32,6 +35,241 @@ LdrpCallDllEntry(PDLLMAIN_FUNC EntryPoint, return EntryPoint(BaseAddress, Reason, Context); } +VOID +NTAPI +LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN ULONG Flags, + OUT PUNICODE_STRING UpdateString) +{ + PIMAGE_BOUND_FORWARDER_REF NewImportForwarder; + + + PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry; + PIMAGE_IMPORT_DESCRIPTOR ImportEntry; + PIMAGE_THUNK_DATA FirstThunk; + PLDR_DATA_TABLE_ENTRY Entry; + PUNICODE_STRING ImportNameUnic; + ANSI_STRING ImportNameAnsi; + LPSTR ImportName; + ULONG ImportSize; + NTSTATUS Status; + ULONG i; + + /* Check the action we need to perform */ + if (Flags == LDRP_UPDATE_REFCOUNT) + { + /* Make sure entry is not being loaded already */ + if (LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS) + return; + + LdrEntry->Flags |= LDRP_LOAD_IN_PROGRESS; + } + else if (Flags == LDRP_UPDATE_DEREFCOUNT) + { + /* Make sure the entry is not being unloaded already */ + if (LdrEntry->Flags & LDRP_UNLOAD_IN_PROGRESS) + return; + + LdrEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS; + } + + /* Go through all bound DLLs and dereference them */ + ImportNameUnic = &NtCurrentTeb()->StaticUnicodeString; + + /* Try to get the new import entry */ + BoundEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, + &ImportSize); + + if (BoundEntry) + { + /* Set entry flags if refing/derefing */ + if (Flags == LDRP_UPDATE_REFCOUNT) + LdrEntry->Flags |= LDRP_LOAD_IN_PROGRESS; + else if (Flags == LDRP_UPDATE_DEREFCOUNT) + LdrEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS; + + while (BoundEntry->OffsetModuleName) + { + /* Get pointer to the current import name */ + ImportName = (PCHAR)BoundEntry + BoundEntry->OffsetModuleName; + + RtlInitAnsiString(&ImportNameAnsi, ImportName); + Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE); + + if (NT_SUCCESS(Status)) + { + if (LdrpCheckForLoadedDll(NULL, + ImportNameUnic, + TRUE, + FALSE, + &Entry)) + { + if (Entry->LoadCount != -1) + { + /* Perform the required action */ + switch (Flags) + { + case LDRP_UPDATE_REFCOUNT: + Entry->LoadCount++; + break; + case LDRP_UPDATE_DEREFCOUNT: + Entry->LoadCount--; + break; + case LDRP_UPDATE_PIN: + Entry->LoadCount == -1; + break; + } + + /* Show snaps */ + if (ShowSnaps) + { + DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount); + } + } + + /* Recurse into this entry */ + LdrpUpdateLoadCount3(Entry, Flags, UpdateString); + } + } + + /* Go through forwarders */ + NewImportForwarder = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1); + for (i=0; iNumberOfModuleForwarderRefs; i++) + { + ImportName = (PCHAR)BoundEntry + NewImportForwarder->OffsetModuleName; + + RtlInitAnsiString(&ImportNameAnsi, ImportName); + Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE); + if (NT_SUCCESS(Status)) + { + if (LdrpCheckForLoadedDll(NULL, + ImportNameUnic, + TRUE, + FALSE, + &Entry)) + { + if (Entry->LoadCount != -1) + { + /* Perform the required action */ + switch (Flags) + { + case LDRP_UPDATE_REFCOUNT: + Entry->LoadCount++; + break; + case LDRP_UPDATE_DEREFCOUNT: + Entry->LoadCount--; + break; + case LDRP_UPDATE_PIN: + Entry->LoadCount == -1; + break; + } + + /* Show snaps */ + if (ShowSnaps) + { + DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount); + } + } + + /* Recurse into this entry */ + LdrpUpdateLoadCount3(Entry, Flags, UpdateString); + } + } + + NewImportForwarder++; + } + + BoundEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewImportForwarder; + } + + /* We're done */ + return; + } + + /* Check oldstyle import descriptor */ + ImportEntry = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &ImportSize); + if (ImportEntry) + { + /* There is old one, so go through its entries */ + while (ImportEntry->Name && ImportEntry->FirstThunk) + { + FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->FirstThunk); + + /* Skip this entry if needed */ + if (!FirstThunk->u1.Function) + { + ImportEntry++; + continue; + } + + ImportName = (PSZ)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name); + + RtlInitAnsiString(&ImportNameAnsi, ImportName); + Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE); + if (NT_SUCCESS(Status)) + { + if (LdrpCheckForLoadedDll(NULL, + ImportNameUnic, + TRUE, + FALSE, + &Entry)) + { + if (Entry->LoadCount != -1) + { + /* Perform the required action */ + switch (Flags) + { + case LDRP_UPDATE_REFCOUNT: + Entry->LoadCount++; + break; + case LDRP_UPDATE_DEREFCOUNT: + Entry->LoadCount--; + break; + case LDRP_UPDATE_PIN: + Entry->LoadCount == -1; + break; + } + + /* Show snaps */ + if (ShowSnaps) + { + DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount); + } + } + + /* Recurse */ + LdrpUpdateLoadCount3(Entry, Flags, UpdateString); + } + } + + /* Go to the next entry */ + ImportEntry++; + } + } +} + +VOID +NTAPI +LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry, + IN ULONG Flags) +{ + WCHAR Buffer[MAX_PATH]; + UNICODE_STRING UpdateString; + + /* Setup the string */ + UpdateString.Buffer = Buffer; + UpdateString.Length = 0; + UpdateString.MaximumLength = sizeof(Buffer); + + /* Call the extended API */ + LdrpUpdateLoadCount3(LdrEntry, Flags, &UpdateString); +} + VOID NTAPI LdrpTlsCallback(PVOID BaseAddress, ULONG Reason) @@ -84,6 +322,259 @@ LdrpTlsCallback(PVOID BaseAddress, ULONG Reason) _SEH2_END; } +NTSTATUS +NTAPI +LdrpCodeAuthzCheckDllAllowed(PUNICODE_STRING FullName, + HANDLE DllHandle) +{ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +LdrpCreateDllSection(IN PUNICODE_STRING FullName, + IN HANDLE DllHandle, + IN PULONG DllCharacteristics OPTIONAL, + OUT PHANDLE SectionHandle) +{ + HANDLE FileHandle; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + ULONG_PTR HardErrorParameters[1]; + ULONG Response; + SECTION_IMAGE_INFORMATION SectionImageInfo; + + /* Check if we don't already have a handle */ + if (!DllHandle) + { + /* Create the object attributes */ + InitializeObjectAttributes(&ObjectAttributes, + FullName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Open the DLL */ + Status = NtOpenFile(&FileHandle, + SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + + /* Check if we failed */ + if (!NT_SUCCESS(Status)) + { + /* Attempt to open for execute only */ + Status = NtOpenFile(&FileHandle, + SYNCHRONIZE | FILE_EXECUTE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + + /* Check if this failed too */ + if (!NT_SUCCESS(Status)) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n", + Status); + } + + /* Make sure to return an expected status code */ + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + { + /* Callers expect this instead */ + Status = STATUS_DLL_NOT_FOUND; + } + + /* Return an empty section handle */ + *SectionHandle = NULL; + return Status; + } + } + } + else + { + /* Use the handle we already have */ + FileHandle = DllHandle; + } + + /* Create a section for the DLL */ + Status = NtCreateSection(SectionHandle, + SECTION_MAP_READ | SECTION_MAP_EXECUTE | + SECTION_MAP_WRITE | SECTION_QUERY, + NULL, + NULL, + PAGE_EXECUTE, + SEC_IMAGE, + FileHandle); + + /* If mapping failed, raise a hard error */ + if (!NT_SUCCESS(Status)) + { + /* Forget the handle */ + *SectionHandle = NULL; + + /* Give the DLL name */ + HardErrorParameters[0] = (ULONG_PTR)FullName; + + /* Raise the error */ + ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT, + 1, + 1, + HardErrorParameters, + OptionOk, + &Response); + + /* Increment the error count */ + if (LdrpInLdrInit) LdrpFatalHardErrorCount++; + } + + /* Check for Safer restrictions */ + if (DllCharacteristics && + !(*DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WX86_DLL)) + { + /* Make sure it's executable */ + Status = ZwQuerySection(*SectionHandle, + SectionImageInformation, + &SectionImageInfo, + sizeof(SECTION_IMAGE_INFORMATION), + NULL); + if (NT_SUCCESS(Status)) + { + /* Check if it's executable */ + if (SectionImageInfo.ImageContainsCode) + { + /* It is, check safer */ + Status = LdrpCodeAuthzCheckDllAllowed(FullName, DllHandle); + if (!NT_SUCCESS(Status) && (Status != STATUS_NOT_FOUND)) + { + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n", + &FullName); + } + } + else + { + /* We're fine, return normally */ + goto Quickie; + } + } + } + + /* Failure case, close section handle */ + NtClose(*SectionHandle); + *SectionHandle = NULL; + } + +Quickie: + /* Close the file handle, we don't need it */ + NtClose(FileHandle); + + /* Return status */ + return Status; +} + +BOOLEAN +NTAPI +LdrpResolveDllName(PWSTR DllPath, + PWSTR DllName, + PUNICODE_STRING FullDllName, + PUNICODE_STRING BaseDllName) +{ + PWCHAR NameBuffer, p1, p2 = 0; + ULONG Length; + ULONG BufSize = 500; + + /* Allocate space for full DLL name */ + FullDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize + sizeof(UNICODE_NULL)); + if (!FullDllName->Buffer) return FALSE; + + Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer, + DllName, + NULL, + BufSize, + FullDllName->Buffer, + &BaseDllName->Buffer); + + if (!Length || Length > BufSize) + { + if (ShowSnaps) + { + DPRINT1("LDR: LdrResolveDllName - Unable to find "); + DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer); + } + + RtlFreeUnicodeString(FullDllName); + return FALSE; + } + + /* Construct full DLL name */ + FullDllName->Length = Length; + FullDllName->MaximumLength = FullDllName->Length + sizeof(UNICODE_NULL); + + /* Allocate a new buffer */ + NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName->MaximumLength); + if (!NameBuffer) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName->Buffer); + return FALSE; + } + + /* Copy over the contents from the previous one and free it */ + RtlCopyMemory(NameBuffer, FullDllName->Buffer, FullDllName->MaximumLength); + RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName->Buffer); + FullDllName->Buffer = NameBuffer; + + /* Find last backslash */ + p1 = FullDllName->Buffer; + while (*p1) + { + if (*p1++ == L'\\') + { + p2 = p1; + } + } + + /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */ + if (p2) + p1 = p2; + else + p1 = DllName; + + p2 = p1; + + /* Calculate remaining length */ + while (*p1) ++p1; + + /* Construct base DLL name */ + BaseDllName->Length = (ULONG_PTR)p1 - (ULONG_PTR)p2; + BaseDllName->MaximumLength = BaseDllName->Length + sizeof(UNICODE_NULL); + BaseDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BaseDllName->MaximumLength); + + if (!BaseDllName->Buffer) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); + return FALSE; + } + + /* Copy base dll name to the new buffer */ + RtlMoveMemory(BaseDllName->Buffer, + p2, + BaseDllName->Length); + + /* Null-terminate the string */ + BaseDllName->Buffer[BaseDllName->Length / sizeof(WCHAR)] = 0; + + return TRUE; +} + PVOID NTAPI LdrpFetchAddressOfEntryPoint(PVOID ImageBase) @@ -105,6 +596,170 @@ LdrpFetchAddressOfEntryPoint(PVOID ImageBase) return (PVOID)EntryPoint; } +HANDLE +NTAPI +LdrpCheckForKnownDll(PWSTR DllName, + PUNICODE_STRING FullDllName, + PUNICODE_STRING BaseDllName) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Section = NULL; + UNICODE_STRING DllNameUnic; + NTSTATUS Status; + PCHAR p1; + PWCHAR p2; + + /* Upgrade DllName to a unicode string */ + RtlInitUnicodeString(&DllNameUnic, DllName); + + /* Get the activation context */ + Status = RtlFindActivationContextSectionString(0, + NULL, + ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, + &DllNameUnic, + NULL); + + /* Check if it's a SxS or not */ + if (Status == STATUS_SXS_SECTION_NOT_FOUND || + Status == STATUS_SXS_KEY_NOT_FOUND) + { + /* Set up BaseDllName */ + BaseDllName->Length = DllNameUnic.Length; + BaseDllName->MaximumLength = DllNameUnic.MaximumLength; + BaseDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + DllNameUnic.MaximumLength); + if (!BaseDllName->Buffer) return NULL; + + /* Copy the contents there */ + RtlMoveMemory(BaseDllName->Buffer, DllNameUnic.Buffer, DllNameUnic.MaximumLength); + + /* Set up FullDllName */ + FullDllName->Length = LdrpKnownDllPath.Length + BaseDllName->Length + sizeof(WCHAR); + FullDllName->MaximumLength = FullDllName->Length + sizeof(UNICODE_NULL); + FullDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName->MaximumLength); + if (!FullDllName->Buffer) + { + /* Free base name and fail */ + RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName->Buffer); + return NULL; + } + + RtlMoveMemory(FullDllName->Buffer, LdrpKnownDllPath.Buffer, LdrpKnownDllPath.Length); + + /* Put a slash there */ + p1 = (PCHAR)FullDllName->Buffer + LdrpKnownDllPath.Length; + p2 = (PWCHAR)p1; + *p2++ = (WCHAR)'\\'; + p1 = (PCHAR)p2; + + /* Set up DllNameUnic for a relative path */ + DllNameUnic.Buffer = (PWSTR)p1; + DllNameUnic.Length = BaseDllName->Length; + DllNameUnic.MaximumLength = DllNameUnic.Length + sizeof(UNICODE_NULL); + + /* Copy the contents */ + RtlMoveMemory(p1, BaseDllName->Buffer, BaseDllName->MaximumLength); + + /* There are all names, init attributes and open the section */ + InitializeObjectAttributes(&ObjectAttributes, + &DllNameUnic, + OBJ_CASE_INSENSITIVE, + LdrpKnownDllObjectDirectory, + NULL); + + Status = NtOpenSection(&Section, + SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* Opening failed, free resources */ + Section = NULL; + RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName->Buffer); + RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName->Buffer); + } + } + else + { + if (!NT_SUCCESS(Status)) Section = NULL; + } + + /* Return section handle */ + return Section; +} + +NTSTATUS +NTAPI +LdrpSetProtection(PVOID ViewBase, + BOOLEAN Restore) +{ + PIMAGE_NT_HEADERS NtHeaders; + PIMAGE_SECTION_HEADER Section; + NTSTATUS Status; + PVOID SectionBase; + SIZE_T SectionSize; + ULONG NewProtection, OldProtection, i; + + /* Get the NT headers */ + NtHeaders = RtlImageNtHeader(ViewBase); + + /* Compute address of the first section header */ + Section = (PIMAGE_SECTION_HEADER)( + (ULONG_PTR)NtHeaders + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) + + NtHeaders->FileHeader.SizeOfOptionalHeader); + + /* Go through all sections */ + for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++) + { + if (Section->SizeOfRawData && + !(Section->Characteristics & IMAGE_SCN_MEM_WRITE)) + { + /* This section is not writable and has some size, so we need to change + its protection */ + if (Restore) + { + /* Set it to either EXECUTE or READONLY */ + if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) + NewProtection = PAGE_EXECUTE; + else + NewProtection = PAGE_READONLY; + + /* Add PAGE_NOCACHE if needed */ + if (Section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) + NewProtection |= PAGE_NOCACHE; + } + else + { + /* Enable write access */ + NewProtection = PAGE_READWRITE; + } + + SectionBase = (PVOID)((ULONG_PTR)ViewBase + Section->VirtualAddress); + SectionSize = Section->SizeOfRawData; + + if (SectionSize) + { + /* Set protection */ + Status = ZwProtectVirtualMemory(NtCurrentProcess(), + &SectionBase, + &SectionSize, + NewProtection, + &OldProtection); + + if (!NT_SUCCESS(Status)) return Status; + } + } + + /* Move to the next section */ + Section++; + } + + /* Flush instruction cache if necessary */ + if (Restore) ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); + + return STATUS_SUCCESS; +} + NTSTATUS NTAPI LdrpMapDll(IN PWSTR SearchPath OPTIONAL, @@ -115,8 +770,504 @@ LdrpMapDll(IN PWSTR SearchPath OPTIONAL, IN BOOLEAN Redirect, OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry) { - UNIMPLEMENTED; - return STATUS_SUCCESS; + PTEB Teb = NtCurrentTeb(); + PPEB Peb = NtCurrentPeb(); + PWCHAR p1 = DllName; + WCHAR TempChar; + BOOLEAN KnownDll = FALSE; + UNICODE_STRING FullDllName, BaseDllName; + HANDLE SectionHandle = NULL, DllHandle = 0; + UNICODE_STRING NtPathDllName; + ULONG_PTR HardErrorParameters[2]; + UNICODE_STRING HardErrorDllName, HardErrorDllPath; + ULONG Response; + SIZE_T ViewSize = 0; + PVOID ViewBase = NULL; + PVOID ArbitraryUserPointer; + PIMAGE_NT_HEADERS NtHeaders; + NTSTATUS HardErrorStatus, Status; + BOOLEAN OverlapDllFound = FALSE; + ULONG_PTR ImageBase, ImageEnd; + PLIST_ENTRY ListHead, NextEntry; + PLDR_DATA_TABLE_ENTRY CandidateEntry, LdrEntry; + ULONG_PTR CandidateBase, CandidateEnd; + UNICODE_STRING OverlapDll; + BOOLEAN RelocatableDll = TRUE; + UNICODE_STRING IllegalDll; + PVOID RelocData; + ULONG RelocDataSize = 0; + + // FIXME: AppCompat stuff is missing + + if (ShowSnaps) + { + DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n", + DllName, + SearchPath ? SearchPath : L""); + } + + /* Check if we have a known dll directory */ + if (LdrpKnownDllObjectDirectory) + { + /* Check if the path is full */ + while (*p1) + { + TempChar = *p1++; + if (TempChar == '\\' || TempChar == '/' ) + { + /* Complete path, don't do Known Dll lookup */ + goto SkipCheck; + } + } + + /* Try to find a Known DLL */ + SectionHandle = LdrpCheckForKnownDll(DllName, + &FullDllName, + &BaseDllName); + } + +SkipCheck: + + /* Check if the Known DLL Check returned something */ + if (!SectionHandle) + { + /* It didn't, so try to resolve the name now */ + if (LdrpResolveDllName(SearchPath, + DllName, + &FullDllName, + &BaseDllName)) + { + /* Got a name, display a message */ + if (ShowSnaps) + { + DPRINT1("LDR: Loading (%s) %wZ\n", + Static ? "STATIC" : "DYNAMIC", + &FullDllName); + } + + /* Convert to NT Name */ + if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer, + &NtPathDllName, + NULL, + NULL)) + { + /* Path was invalid */ + return STATUS_OBJECT_PATH_SYNTAX_BAD; + } + + /* Create a section for this dLL */ + Status = LdrpCreateDllSection(&NtPathDllName, + DllHandle, + DllCharacteristics, + &SectionHandle); + + /* Free the NT Name */ + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName.Buffer); + + /* If we failed */ + if (!NT_SUCCESS(Status)) + { + /* Free the name strings and return */ + RtlFreeUnicodeString(&FullDllName); + RtlFreeUnicodeString(&BaseDllName); + return Status; + } + } + else + { + /* We couldn't resolve the name, is this a static load? */ + if (Static) + { + /* + * This is BAD! Static loads are CRITICAL. Bugcheck! + * Initialize the strings for the error + */ + RtlInitUnicodeString(&HardErrorDllName, DllName); + RtlInitUnicodeString(&HardErrorDllPath, + DllPath2 ? DllPath2 : LdrpDefaultPath.Buffer); + + /* Set them as error parameters */ + HardErrorParameters[0] = (ULONG_PTR)&HardErrorDllName; + HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllPath; + + /* Raise the hard error */ + NtRaiseHardError(STATUS_DLL_NOT_FOUND, + 2, + 0x00000003, + HardErrorParameters, + OptionOk, + &Response); + + /* We're back, where we initializing? */ + if (LdrpInLdrInit) LdrpFatalHardErrorCount++; + } + + /* Return failure */ + return STATUS_DLL_NOT_FOUND; + } + } + else + { + /* We have a section handle, so this is a known dll */ + KnownDll = TRUE; + } + + /* Stuff the image name in the TIB, for the debugger */ + ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; + Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; + + /* Map the DLL */ + ViewBase = NULL; + ViewSize = 0; + Status = NtMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &ViewBase, + 0, + 0, + NULL, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + + /* Restore */ + Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; + + /* Fail if we couldn't map it */ + if (!NT_SUCCESS(Status)) + { + /* Close and return */ + NtClose(SectionHandle); + return Status; + } + + /* Get the NT Header */ + if (!(NtHeaders = RtlImageNtHeader(ViewBase))) + { + /* Invalid image, unmap, close handle and fail */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + NtClose(SectionHandle); + return STATUS_INVALID_IMAGE_FORMAT; + } + + // FIXME: .NET support is missing + + /* Allocate an entry */ + if (!(LdrEntry = LdrpAllocateDataTableEntry(ViewBase))) + { + /* Invalid image, unmap, close handle and fail */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + NtClose(SectionHandle); + return STATUS_NO_MEMORY; + } + + /* Setup the entry */ + LdrEntry->Flags = Static ? LDRP_STATIC_LINK : 0; + if (Redirect) LdrEntry->Flags |= LDRP_REDIRECTED; + LdrEntry->LoadCount = 0; + LdrEntry->FullDllName = FullDllName; + LdrEntry->BaseDllName = BaseDllName; + LdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrEntry->DllBase); + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n", + &FullDllName, + &BaseDllName); + } + + /* Insert this entry */ + LdrpInsertMemoryTableEntry(LdrEntry); + + // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE) + + /* Check for invalid CPU Image */ + if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) + { + /* Load our header */ + PIMAGE_NT_HEADERS ImageNtHeader = RtlImageNtHeader(Peb->ImageBaseAddress); + + /* Assume defaults if we don't have to run the Hard Error path */ + HardErrorStatus = STATUS_SUCCESS; + Response = ResponseCancel; + + /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */ + if (ImageNtHeader->OptionalHeader.MajorSubsystemVersion <= 3) + { + /* Reset the entrypoint, save our Dll Name */ + LdrEntry->EntryPoint = 0; + HardErrorParameters[0] = (ULONG_PTR)&FullDllName; + + /* Raise the error */ + HardErrorStatus = ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH, + 1, + 1, + HardErrorParameters, + OptionOkCancel, + &Response); + } + + /* Check if the user pressed cancel */ + if (NT_SUCCESS(HardErrorStatus) && Response == ResponseCancel) + { + /* Remove the DLL from the lists */ + RemoveEntryList(&LdrEntry->InLoadOrderLinks); + RemoveEntryList(&LdrEntry->InMemoryOrderModuleList); + RemoveEntryList(&LdrEntry->HashLinks); + + /* Remove the LDR Entry */ + RtlFreeHeap(RtlGetProcessHeap(), 0, LdrEntry ); + + /* Unmap and close section */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + NtClose(SectionHandle); + + /* Did we do a hard error? */ + if (ImageNtHeader->OptionalHeader.MajorSubsystemVersion <= 3) + { + /* Yup, so increase fatal error count if we are initializing */ + if (LdrpInLdrInit) LdrpFatalHardErrorCount++; + } + + /* Return failure */ + return STATUS_INVALID_IMAGE_FORMAT; + } + } + else + { + /* The image was valid. Is it a DLL? */ + if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) + { + /* Set the DLL Flag */ + LdrEntry->Flags |= LDRP_IMAGE_DLL; + } + + /* If we're not a DLL, clear the entrypoint */ + if (!(LdrEntry->Flags & LDRP_IMAGE_DLL)) + { + LdrEntry->EntryPoint = 0; + } + } + + /* Return it for the caller */ + *DataTableEntry = LdrEntry; + + /* Check if we loaded somewhere else */ + if (Status == STATUS_IMAGE_NOT_AT_BASE) + { + /* Write the flag */ + LdrEntry->Flags |= LDRP_IMAGE_NOT_AT_BASE; + + /* Find our region */ + ImageBase = (ULONG_PTR)NtHeaders->OptionalHeader.ImageBase; + ImageEnd = ImageBase + ViewSize; + + DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p -> %p)\n", DllName, ImageBase, ViewBase); + + /* Scan all the modules */ + ListHead = &Peb->Ldr->InLoadOrderModuleList; + NextEntry = ListHead->Flink; + while (NextEntry != ListHead) + { + /* Get the entry */ + CandidateEntry = CONTAINING_RECORD(NextEntry, + LDR_DATA_TABLE_ENTRY, + InLoadOrderLinks); + NextEntry = NextEntry->Flink; + + /* Get the entry's bounds */ + CandidateBase = (ULONG_PTR)CandidateEntry->DllBase; + CandidateEnd = CandidateBase + CandidateEntry->SizeOfImage; + + /* Make sure this entry isn't unloading */ + if (!CandidateEntry->InMemoryOrderModuleList.Flink) continue; + + /* Check if our regions are colliding */ + if ((ImageBase >= CandidateBase && ImageBase <= CandidateEnd) || + (ImageEnd >= CandidateBase && ImageEnd <= CandidateEnd) || + (CandidateBase >= ImageBase && CandidateBase <= ImageEnd)) + { + /* Found who is overlapping */ + OverlapDllFound = TRUE; + OverlapDll = CandidateEntry->FullDllName; + break; + } + } + + /* Check if we found the DLL overlapping with us */ + if (!OverlapDllFound) + { + /* It's not another DLL, it's memory already here */ + RtlInitUnicodeString(&OverlapDll, L"Dynamically Allocated Memory"); + } + + DPRINT1("Overlapping DLL: %wZ\n", &OverlapDll); + + /* Are we dealing with a DLL? */ + if (LdrEntry->Flags & LDRP_IMAGE_DLL) + { + /* Check if relocs were stripped */ + if (!(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)) + { + /* Get the relocation data */ + RelocData = RtlImageDirectoryEntryToData(ViewBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_BASERELOC, + &RelocDataSize); + + /* Does the DLL not have any? */ + if (!RelocData && !RelocDataSize) + { + /* We'll allow this and simply continue */ + goto NoRelocNeeded; + } + } + + /* See if this is an Illegal DLL - IE: user32 and kernel32 */ + RtlInitUnicodeString(&IllegalDll,L"user32.dll"); + if (RtlEqualUnicodeString(&BaseDllName, &IllegalDll, TRUE)) + { + /* Can't relocate user32 */ + RelocatableDll = FALSE; + } + else + { + RtlInitUnicodeString(&IllegalDll, L"kernel32.dll"); + if (RtlEqualUnicodeString(&BaseDllName, &IllegalDll, TRUE)) + { + /* Can't relocate kernel32 */ + RelocatableDll = FALSE; + } + } + + /* Check if this was a non-relocatable DLL or a known dll */ + if (!RelocatableDll && KnownDll) + { + /* Setup for hard error */ + HardErrorParameters[0] = (ULONG_PTR)&IllegalDll; + HardErrorParameters[1] = (ULONG_PTR)&OverlapDll; + + /* Raise the error */ + ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION, + 2, + 3, + HardErrorParameters, + OptionOk, + &Response); + + /* If initializing, increase the error count */ + if (LdrpInLdrInit) LdrpFatalHardErrorCount++; + + /* Don't do relocation */ + Status = STATUS_CONFLICTING_ADDRESSES; + goto NoRelocNeeded; + } + + /* Change the protection to prepare for relocation */ + Status = LdrpSetProtection(ViewBase, FALSE); + + /* Make sure we changed the protection */ + if (NT_SUCCESS(Status)) + { + /* Do the relocation */ + Status = LdrRelocateImageWithBias(ViewBase, 0LL, NULL, STATUS_SUCCESS, + STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT); + + if (NT_SUCCESS(Status)) + { + /* Stuff the image name in the TIB, for the debugger */ + ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; + Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; + + /* Map the DLL */ + Status = NtMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &ViewBase, + 0, + 0, + NULL, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + + /* Restore */ + Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; + + /* Return the protection */ + Status = LdrpSetProtection(ViewBase, TRUE); + } + } +//FailRelocate: + /* Handle any kind of failure */ + if (!NT_SUCCESS(Status)) + { + /* Remove it from the lists */ + RemoveEntryList(&LdrEntry->InLoadOrderLinks); + RemoveEntryList(&LdrEntry->InMemoryOrderModuleList); + RemoveEntryList(&LdrEntry->HashLinks); + + /* Unmap it, clear the entry */ + NtUnmapViewOfSection(NtCurrentProcess(), ViewBase); + LdrEntry = NULL; + } + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: Fixups %successfully re-applied @ %p\n", + NT_SUCCESS(Status) ? "s" : "uns", ViewBase); + } + } + else + { +NoRelocNeeded: + /* Not a DLL, or no relocation needed */ + Status = STATUS_SUCCESS; + + /* Stuff the image name in the TIB, for the debugger */ + ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; + Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer; + + /* Map the DLL */ + Status = NtMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &ViewBase, + 0, + 0, + NULL, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + + /* Restore */ + Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase); + } + } + } + + // FIXME: LdrpCheckCorImage() is missing + + /* Check if this is an SMP Machine and a DLL */ + if ((LdrpNumberOfProcessors > 1) && + (LdrEntry && (LdrEntry->Flags & LDRP_IMAGE_DLL))) + { + /* Validate the image for MP */ + LdrpValidateImageForMp(LdrEntry); + } + + // FIXME: LdrpCorUnloadImage() is missing + + /* Close section and return status */ + NtClose(SectionHandle); + return Status; } PLDR_DATA_TABLE_ENTRY @@ -126,6 +1277,8 @@ LdrpAllocateDataTableEntry(IN PVOID BaseAddress) PLDR_DATA_TABLE_ENTRY LdrEntry = NULL; PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader(BaseAddress); + DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress, NtHeader); + /* Make sure the header is valid */ if (NtHeader) { @@ -163,6 +1316,33 @@ LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderModuleList); } +VOID +NTAPI +LdrpFinalizeAndDeallocateDataTableEntry(PLDR_DATA_TABLE_ENTRY Entry) +{ + ASSERT(Entry != NULL); + + /* Release the activation context if it exists */ + if (Entry->EntryPointActivationContext) + { + /* Check if it wasn't already released */ + if ((HANDLE)Entry->EntryPointActivationContext != INVALID_HANDLE_VALUE) + { + RtlReleaseActivationContext(Entry->EntryPointActivationContext); + + /* Mark it as invalid */ + Entry->EntryPointActivationContext = INVALID_HANDLE_VALUE; + } + } + + /* Release the full dll name string */ + if (Entry->FullDllName.Buffer) + LdrpFreeUnicodeString(&Entry->FullDllName); + + /* Finally free the entry's memory */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Entry); +} + BOOLEAN NTAPI LdrpCheckForLoadedDllHandle(IN PVOID Base, @@ -231,7 +1411,9 @@ LdrpCheckForLoadedDll(IN PWSTR DllPath, PVOID ViewBase = NULL; SIZE_T ViewSize = 0; PIMAGE_NT_HEADERS NtHeader, NtHeader2; -DPRINT1("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath, DllName, Flag, RedirectedDll, LdrEntry); + + DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath, DllName, Flag, RedirectedDll, LdrEntry); + /* Check if a dll name was provided */ if (!DllName->Buffer || !DllName->Buffer[0]) return FALSE; @@ -499,7 +1681,7 @@ LdrpGetProcedureAddress(IN PVOID BaseAddress, if (Name) { /* Show debug message */ - if (ShowSnaps) DPRINT1("NAME - %s\n", Name->Buffer); + if (ShowSnaps) DbgPrint("NAME - %s\n", Name->Buffer); /* Make sure it's not too long */ if ((Name->Length + sizeof(CHAR) + sizeof(USHORT)) > MAXLONG) @@ -527,8 +1709,8 @@ LdrpGetProcedureAddress(IN PVOID BaseAddress, ImportName->Hint = 0; /* Copy the name and null-terminate it */ - RtlMoveMemory(&ImportName->Name, Name->Buffer, Name->Length); - ImportName->Name[Name->Length + 1] = 0; + RtlMoveMemory(ImportName->Name, Name->Buffer, Name->Length); + ImportName->Name[Name->Length] = 0; /* Clear the high bit */ ImageBase = ImportName; @@ -540,7 +1722,7 @@ LdrpGetProcedureAddress(IN PVOID BaseAddress, ImageBase = NULL; /* Show debug message */ - if (ShowSnaps) DPRINT1("ORDINAL - %lx\n", Ordinal); + if (ShowSnaps) DbgPrint("ORDINAL - %lx\n", Ordinal); if (Ordinal) { @@ -563,7 +1745,7 @@ LdrpGetProcedureAddress(IN PVOID BaseAddress, if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) { /* Invalid base */ - DPRINT1("Invalid base address\n"); + DPRINT1("Invalid base address %p\n", BaseAddress); Status = STATUS_DLL_NOT_FOUND; _SEH2_YIELD(goto Quickie;) } @@ -576,7 +1758,7 @@ LdrpGetProcedureAddress(IN PVOID BaseAddress, if (!ExportDir) { - DPRINT1("Image has no exports\n"); + DPRINT1("Image %wZ has no exports, but were trying to get procedure %s. BaseAddress asked %p, got entry BA %p\n", &LdrEntry->BaseDllName, Name ? Name->Buffer : NULL, BaseAddress, LdrEntry->DllBase); Status = STATUS_PROCEDURE_NOT_FOUND; _SEH2_YIELD(goto Quickie;) } @@ -657,8 +1839,474 @@ LdrpLoadDll(IN BOOLEAN Redirected, OUT PVOID *BaseAddress, IN BOOLEAN CallInit) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PPEB Peb = NtCurrentPeb(); + NTSTATUS Status = STATUS_SUCCESS; + PWCHAR p1, p2; + WCHAR NameBuffer[266]; + LPWSTR RawDllName; + UNICODE_STRING RawDllNameString; + PLDR_DATA_TABLE_ENTRY LdrEntry; + BOOLEAN InInit = LdrpInLdrInit; + + /* Find the name without the extension */ + p1 = DllName->Buffer; +StartLoop: + p2 = NULL; + while (*p1) + { + if (*p1++ == L'.') + { + p2 = p1; + } + else if (*p1 == L'\\') + { + goto StartLoop; + } + } + + /* Save the Raw DLL Name */ + RawDllName = NameBuffer; + if (DllName->Length >= sizeof(NameBuffer)) + { + /* The DLL's name is too long */ + return STATUS_NAME_TOO_LONG; + } + RtlMoveMemory(RawDllName, DllName->Buffer, DllName->Length); + + /* Check if no extension was found or if we got a slash */ + if (!p2 || *p2 == '\\') + { + /* Check that we have space to add one */ + if (DllName->Length + LdrApiDefaultExtension.Length >= sizeof(NameBuffer)) + { + /* No space to add the extension */ + return STATUS_NAME_TOO_LONG; + } + + /* Add it */ + RtlMoveMemory((PVOID)((ULONG_PTR)RawDllName + DllName->Length), + LdrApiDefaultExtension.Buffer, + LdrApiDefaultExtension.Length); + + /* Save the length to a unicode string */ + RawDllNameString.Length = DllName->Length + LdrApiDefaultExtension.Length; + + /* Null terminate it */ + RawDllName[RawDllNameString.Length / sizeof(WCHAR)] = 0; + } + else + { + /* Null terminate it */ + RawDllName[DllName->Length / sizeof(WCHAR)] = 0; + + /* Save the length to a unicode string */ + RawDllNameString.Length = DllName->Length; + } + + /* Now create a unicode string for the DLL's name */ + RawDllNameString.MaximumLength = sizeof(NameBuffer); + RawDllNameString.Buffer = NameBuffer; + + /* Check for init flag and acquire lock */ + if (!InInit) RtlEnterCriticalSection(&LdrpLoaderLock); + + /* Show debug message */ + if (ShowSnaps) + { + DPRINT1("LDR: LdrLoadDll, loading %ws from %ws\n", + RawDllName, + DllPath ? DllPath : L""); + } + + /* Check if the DLL is already loaded */ + if (!LdrpCheckForLoadedDll(DllPath, + &RawDllNameString, + FALSE, + Redirected, + &LdrEntry)) + { + /* Map it */ + Status = LdrpMapDll(DllPath, + DllPath, + NameBuffer, + DllCharacteristics, + FALSE, + Redirected, + &LdrEntry); + if (!NT_SUCCESS(Status)) goto Quickie; + + /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */ + if (DllCharacteristics && + (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) + { + LdrEntry->EntryPoint = NULL; + LdrEntry->Flags &= ~LDRP_IMAGE_DLL; + } + + /* FIXME Mark the DLL Ranges for Stack Traces later */ + + /* Make sure it's a DLL */ + if (LdrEntry->Flags & LDRP_IMAGE_DLL) + { + /* Check if this is a .NET Image */ + if (!(LdrEntry->Flags & LDRP_COR_IMAGE)) + { + /* Walk the Import Descriptor */ + Status = LdrpWalkImportDescriptor(DllPath, LdrEntry); + } + + /* Update load count, unless it's locked */ + if (LdrEntry->LoadCount != -1) LdrEntry->LoadCount++; + LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); + + /* Check if we failed */ + if (!NT_SUCCESS(Status)) + { + /* Clear entrypoint, and insert into list */ + LdrEntry->EntryPoint = NULL; + InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, + &LdrEntry->InInitializationOrderModuleList); + + /* Cancel the load and unload the DLL */ + LdrpClearLoadInProgress(); + LdrUnloadDll(LdrEntry->DllBase); + + /* Return the error */ + goto Quickie; + } + } + else if (LdrEntry->LoadCount != -1) + { + /* Increase load count */ + LdrEntry->LoadCount++; + } + + /* Insert it into the list */ + InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, + &LdrEntry->InInitializationOrderModuleList); + + /* If we have to run the entrypoint, make sure the DB is ready */ + if (CallInit && LdrpLdrDatabaseIsSetup) + { + /* FIXME: Notify Shim Engine */ + + /* Run the init routine */ + Status = LdrpRunInitializeRoutines(NULL); + if (!NT_SUCCESS(Status)) + { + /* Failed, unload the DLL */ + LdrUnloadDll(LdrEntry->DllBase); + } + } + else + { + /* The DB isn't ready, which means we were loaded because of a forwarder */ + Status = STATUS_SUCCESS; + } + } + else + { + /* We were already loaded. Are we a DLL? */ + if ((LdrEntry->Flags & LDRP_IMAGE_DLL) && (LdrEntry->LoadCount != -1)) + { + /* Increase load count */ + LdrEntry->LoadCount++; + LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); + + /* Clear the load in progress */ + LdrpClearLoadInProgress(); + } + else + { + /* Not a DLL, just increase the load count */ + if (LdrEntry->LoadCount != -1) LdrEntry->LoadCount++; + } + } + +Quickie: + /* Release the lock */ + if (!InInit) RtlLeaveCriticalSection(Peb->LoaderLock); + + /* Check for success */ + if (NT_SUCCESS(Status)) + { + /* Return the base address */ + *BaseAddress = LdrEntry->DllBase; + } + else + { + /* Nothing found */ + *BaseAddress = NULL; + } + + /* Return status */ + return Status; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +LdrUnloadDll(IN PVOID BaseAddress) +{ + NTSTATUS Status = STATUS_SUCCESS; + PPEB Peb = NtCurrentPeb(); + PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry; + PVOID EntryPoint; + PLIST_ENTRY NextEntry; + LIST_ENTRY UnloadList; + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx; + PVOID CorImageData; + ULONG ComSectionSize; + + /* Get the LDR Lock */ + if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock); + + /* Increase the unload count */ + LdrpActiveUnloadCount++; + + /* Skip unload */ + if (LdrpShutdownInProgress) goto Quickie; + + /* Make sure the DLL is valid and get its entry */ + if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) + { + Status = STATUS_DLL_NOT_FOUND; + goto Quickie; + } + + /* Check the current Load Count */ + if (LdrEntry->LoadCount != -1) + { + /* Decrease it */ + LdrEntry->LoadCount--; + + /* If it's a dll */ + if (LdrEntry->Flags & LDRP_IMAGE_DLL) + { + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Update the load count */ + LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT); + + /* Release the context */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + } + else + { + /* The DLL is locked */ + goto Quickie; + } + + /* Show debug message */ + if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n"); + + /* Check if this is our only unload */ + if (LdrpActiveUnloadCount == 1) + { + /* Initialize the unload list */ + InitializeListHead(&LdrpUnloadHead); + } + + /* Loop the modules to build the list */ + NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink; + while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList) + { + /* Get the entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); + NextEntry = NextEntry->Blink; + + /* Remove flag */ + LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS; + + /* If the load count is now 0 */ + if (!LdrEntry->LoadCount) + { + /* Show message */ + if (ShowSnaps) + { + DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n", + LdrpActiveUnloadCount, + LdrEntry->BaseDllName.Buffer, + LdrEntry->FullDllName.Buffer, + (ULONG)LdrEntry->LoadCount, + LdrEntry->EntryPoint); + } + + /* FIXME: Call Shim Engine and notify */ + + /* Unlink it */ + CurrentEntry = LdrEntry; + RemoveEntryList(&CurrentEntry->InInitializationOrderModuleList); + RemoveEntryList(&CurrentEntry->InMemoryOrderModuleList); + RemoveEntryList(&CurrentEntry->HashLinks); + + /* If there's more then one active unload */ + if (LdrpActiveUnloadCount > 1) + { + /* Flush the cached DLL handle and clear the list */ + LdrpLoadedDllHandleCache = NULL; + CurrentEntry->InMemoryOrderModuleList.Flink = NULL; + } + + /* Add the entry on the unload list */ + InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks); + } + } + + /* Only call the entrypoints once */ + if (LdrpActiveUnloadCount > 1) goto Quickie; + + /* Now loop the unload list and create our own */ + InitializeListHead(&UnloadList); + CurrentEntry = NULL; + NextEntry = LdrpUnloadHead.Flink; + while (NextEntry != &LdrpUnloadHead) + { + /* If we have an active entry */ + if (CurrentEntry) + { + /* Remove it */ + RemoveEntryList(&CurrentEntry->InLoadOrderLinks); + CurrentEntry = NULL; + + /* Reset list pointers */ + NextEntry = LdrpUnloadHead.Flink; + if (NextEntry == &LdrpUnloadHead) break; + } + + /* Get the current entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks); + + /* Log the Unload Event */ + //LdrpRecordUnloadEvent(LdrEntry); + + /* Set the entry and clear it from the list */ + CurrentEntry = LdrEntry; + LdrpLoadedDllHandleCache = NULL; + CurrentEntry->InMemoryOrderModuleList.Flink = NULL; + + /* Move it from the global to the local list */ + RemoveEntryList(&CurrentEntry->HashLinks); + InsertTailList(&UnloadList, &CurrentEntry->HashLinks); + + /* Get the entrypoint */ + EntryPoint = LdrEntry->EntryPoint; + + /* Check if we should call it */ + if (EntryPoint && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED)) + { + /* Show message */ + if (ShowSnaps) + { + DPRINT1("LDR: Calling deinit %lx\n", EntryPoint); + } + + /* Set up the Act Ctx */ + ActCtx.Size = sizeof(ActCtx); + ActCtx.Format = 1; + RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); + + /* Activate the ActCtx */ + RtlActivateActivationContextUnsafeFast(&ActCtx, + LdrEntry->EntryPointActivationContext); + + /* Call the entrypoint */ + LdrpCallDllEntry(LdrEntry->EntryPoint, + LdrEntry->DllBase, + DLL_PROCESS_DETACH, + NULL); + + /* Release the context */ + RtlDeactivateActivationContextUnsafeFast(&ActCtx); + } + + /* Remove it from the list */ + RemoveEntryList(&CurrentEntry->InLoadOrderLinks); + CurrentEntry = NULL; + NextEntry = LdrpUnloadHead.Flink; + } + + /* Now loop our local list */ + NextEntry = UnloadList.Flink; + while (NextEntry != &UnloadList) + { + /* Get the entry */ + LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks); + NextEntry = NextEntry->Flink; + CurrentEntry = LdrEntry; + + /* Notify Application Verifier */ + if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK) + { + DPRINT1("We don't support Application Verifier yet\n"); + } + + /* Show message */ + if (ShowSnaps) + { + DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer); + } + + /* Check if this is a .NET executable */ + if ((CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, + &ComSectionSize))) + { + /* FIXME */ + DPRINT1(".NET Images are not supported yet\n"); + } + + /* Check if we should unmap*/ + if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP)) + { + /* Unmap the DLL */ + Status = NtUnmapViewOfSection(NtCurrentProcess(), + CurrentEntry->DllBase); + } + + /* Unload the alternate resource module, if any */ + LdrUnloadAlternateResourceModule(CurrentEntry->DllBase); + + /* Send shutdown notification */ + //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress); + + /* Check if a Hotpatch is active */ + if (LdrEntry->PatchInformation) + { + /* FIXME */ + DPRINT1("We don't support Hotpatching yet\n"); + } + + /* Deallocate the Entry */ + LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry); + + /* If this is the cached entry, invalide it */ + if (LdrpGetModuleHandleCache == CurrentEntry) + { + LdrpGetModuleHandleCache = NULL; + } + } + +Quickie: + /* Decrease unload count */ + LdrpActiveUnloadCount--; + if (!LdrpInLdrInit) Status = RtlLeaveCriticalSection(Peb->LoaderLock); + + /* FIXME: Rundown the Hotpatch data, if present */ + + /* Return to caller */ + return Status; } ULONG @@ -692,4 +2340,111 @@ LdrpClearLoadInProgress() return ModulesCount; } +/* + * @implemented + */ +NTSTATUS NTAPI +LdrAddRefDll(IN ULONG Flags, + IN PVOID BaseAddress) +{ + PLDR_DATA_TABLE_ENTRY LdrEntry; + NTSTATUS Status = STATUS_SUCCESS; + ULONG Cookie; + BOOLEAN Locked = FALSE; + + /* Check for invalid flags */ + if (Flags & ~(LDR_PIN_MODULE)) + { + /* Fail with invalid parameter status if so */ + Status = STATUS_INVALID_PARAMETER; + goto quickie; + } + + /* Acquire the loader lock if not in init phase */ + if (!LdrpInLdrInit) + { + /* Acquire the lock */ + Status = LdrLockLoaderLock(0, NULL, &Cookie); + Locked = TRUE; + + if (!NT_SUCCESS(Status)) goto quickie; + } + + /* Get this module's data table entry */ + if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry)) + { + if (!LdrEntry) + { + /* Shouldn't happen */ + Status = STATUS_INTERNAL_ERROR; + goto quickie; + } + + /* If this is not a pinned module */ + if (LdrEntry->LoadCount != -1) + { + /* Update its load count */ + if (Flags & LDR_PIN_MODULE) + { + /* Pin it by setting load count to -1 */ + LdrEntry->LoadCount = -1; + LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN); + } + else + { + /* Increase its load count by one */ + LdrEntry->LoadCount++; + LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT); + } + + /* Clear load in progress */ + LdrpClearLoadInProgress(); + } + } + else + { + /* There was an error getting this module's handle, return invalid param status */ + Status = STATUS_INVALID_PARAMETER; + goto quickie; + } + +quickie: + if (!NT_SUCCESS(Status)) + { + if (ShowSnaps || + (Status != STATUS_NO_SUCH_FILE && + Status != STATUS_DLL_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND)) + { + DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress); + } + } + + /* Release the lock if needed */ + if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie); + + return Status; +} + + +BOOLEAN +NTAPI +LdrpFreeUnicodeString(PUNICODE_STRING String) +{ + BOOLEAN Result = FALSE; + + ASSERT(String != NULL); + + /* If Buffer is not NULL - free it */ + if (String->Buffer) + Result = RtlFreeHeap(RtlGetProcessHeap(), 0, String->Buffer); + + /* Zero it out */ + String->Length = 0; + String->MaximumLength = 0; + String->Buffer = NULL; + + return Result; +} + /* EOF */ diff --git a/reactos/dll/ntdll/ldr/startup.c b/reactos/dll/ntdll/ldr/startup.c index f063aefdc0d..90c2ca8b417 100644 --- a/reactos/dll/ntdll/ldr/startup.c +++ b/reactos/dll/ntdll/ldr/startup.c @@ -10,12 +10,11 @@ /* INCLUDES *****************************************************************/ #include -#define NDEBUG +//#define NDEBUG #include #include VOID RtlInitializeHeapManager(VOID); -VOID LdrpInitLoader(VOID); extern PTEB LdrpTopLevelDllBeingLoadedTeb; VOID NTAPI RtlpInitDeferedCriticalSection(VOID); VOID RtlpInitializeVectoredExceptionHandling(VOID); @@ -309,280 +308,4 @@ finish: return FALSE; } -NTSTATUS -NTAPI -LdrpInitializeProcess_(PCONTEXT Context, - PVOID SystemArgument1) -{ - PIMAGE_NT_HEADERS NTHeaders; - PEPFUNC EntryPoint; - PIMAGE_DOS_HEADER PEDosHeader; - PVOID ImageBase; - PPEB Peb = NtCurrentPeb(); - PLDR_DATA_TABLE_ENTRY NtModule; // ntdll - NLSTABLEINFO NlsTable; - WCHAR FullNtDllPath[MAX_PATH]; - SYSTEM_BASIC_INFORMATION SystemInformation; - NTSTATUS Status; - PVOID BaseAddress = SystemArgument1; - - DPRINT("LdrpInit()\n"); - DPRINT("Peb %p\n", Peb); - ImageBase = Peb->ImageBaseAddress; - DPRINT("ImageBase %p\n", ImageBase); - - if (ImageBase <= (PVOID) 0x1000) - { - DPRINT("ImageBase is null\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT); - } - - /* If MZ header exists */ - PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase; - NTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)ImageBase + PEDosHeader->e_lfanew); - DPRINT("PEDosHeader %p\n", PEDosHeader); - - if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE || - PEDosHeader->e_lfanew == 0L || - NTHeaders->Signature != IMAGE_NT_SIGNATURE) - { - DPRINT1("Image has bad header\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT); - } - - /* normalize process parameters */ - RtlNormalizeProcessParams(Peb->ProcessParameters); - - /* Initialize NLS data */ - RtlInitNlsTables(Peb->AnsiCodePageData, - Peb->OemCodePageData, - Peb->UnicodeCaseTableData, - &NlsTable); - RtlResetRtlTranslations(&NlsTable); - - /* Get number of processors */ - DPRINT("Here\n"); - Status = ZwQuerySystemInformation(SystemBasicInformation, - &SystemInformation, - sizeof(SYSTEM_BASIC_INFORMATION), - NULL); - DPRINT("Here2\n"); - if (!NT_SUCCESS(Status)) - { - ZwTerminateProcess(NtCurrentProcess(), Status); - } - - Peb->NumberOfProcessors = SystemInformation.NumberOfProcessors; - - /* Initialize Critical Section Data */ - RtlpInitDeferedCriticalSection(); - - /* Load execution options */ - LoadImageFileExecutionOptions(Peb); - - /* create process heap */ - RtlInitializeHeapManager(); - Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE, - NULL, - NTHeaders->OptionalHeader.SizeOfHeapReserve, - NTHeaders->OptionalHeader.SizeOfHeapCommit, - NULL, - NULL); - if (Peb->ProcessHeap == 0) - { - DPRINT1("Failed to create process heap\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES); - } - - /* Check for correct machine type */ - if (NTHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) - { - ULONG_PTR HardErrorParameters[1]; - UNICODE_STRING ImageNameU; - ANSI_STRING ImageNameA; - WCHAR *Ptr; - ULONG ErrorResponse; - - DPRINT1("Image %wZ is for a foreign architecture (0x%x).\n", - &Peb->ProcessParameters->ImagePathName, NTHeaders->FileHeader.Machine); - - /* Get the full image path name */ - ImageNameU = Peb->ProcessParameters->ImagePathName; - - /* Get the file name */ - Ptr = Peb->ProcessParameters->ImagePathName.Buffer + - (Peb->ProcessParameters->ImagePathName.Length / sizeof(WCHAR)) -1; - while ((Ptr >= Peb->ProcessParameters->ImagePathName.Buffer) && - (*Ptr != L'\\')) Ptr--; - ImageNameU.Buffer = Ptr + 1; - ImageNameU.Length = Peb->ProcessParameters->ImagePathName.Length - - (ImageNameU.Buffer - Peb->ProcessParameters->ImagePathName.Buffer) * sizeof(WCHAR); - ImageNameU.MaximumLength = ImageNameU.Length; - - /*`Convert to ANSI, harderror message needs that */ - RtlUnicodeStringToAnsiString(&ImageNameA, &ImageNameU, TRUE); - - /* Raise harderror */ - HardErrorParameters[0] = (ULONG_PTR)&ImageNameA; - NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, - 1, - 1, - HardErrorParameters, - OptionOk, - &ErrorResponse); - - RtlFreeAnsiString(&ImageNameA); - ZwTerminateProcess(NtCurrentProcess(), STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE); - } - - /* initialized vectored exception handling */ - RtlpInitializeVectoredExceptionHandling(); - - /* initalize peb lock support */ - RtlInitializeCriticalSection(&FastPebLock); - Peb->FastPebLock = &FastPebLock; - - /* initialize tls bitmaps */ - RtlInitializeBitMap(&TlsBitMap, Peb->TlsBitmapBits, TLS_MINIMUM_AVAILABLE); - RtlInitializeBitMap(&TlsExpansionBitMap, Peb->TlsExpansionBitmapBits, TLS_EXPANSION_SLOTS); - - Peb->TlsBitmap = &TlsBitMap; - Peb->TlsExpansionBitmap = &TlsExpansionBitMap; - Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE; - - /* Initialize table of callbacks for the kernel. */ - Peb->KernelCallbackTable = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - sizeof(PVOID) * - (USER32_CALLBACK_MAXIMUM + 1)); - if (Peb->KernelCallbackTable == NULL) - { - DPRINT1("Failed to create callback table\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES); - } - - /* initalize loader lock */ - RtlInitializeCriticalSection(&LdrpLoaderLock); - Peb->LoaderLock = &LdrpLoaderLock; - - /* create loader information */ - Peb->Ldr = (PPEB_LDR_DATA) RtlAllocateHeap(Peb->ProcessHeap, - 0, - sizeof(PEB_LDR_DATA)); - if (Peb->Ldr == NULL) - { - DPRINT1("Failed to create loader data\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES); - } - - Peb->Ldr->Length = sizeof(PEB_LDR_DATA); - Peb->Ldr->Initialized = FALSE; - Peb->Ldr->SsHandle = NULL; - InitializeListHead(&Peb->Ldr->InLoadOrderModuleList); - InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList); - InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList); - - /* Load compatibility settings */ - LoadCompatibilitySettings(Peb); - - /* build full ntdll path */ - wcscpy(FullNtDllPath, SharedUserData->NtSystemRoot); - wcscat(FullNtDllPath, L"\\system32\\ntdll.dll"); - - /* add entry for ntdll */ - NtModule = (PLDR_DATA_TABLE_ENTRY) - RtlAllocateHeap(Peb->ProcessHeap, - 0, - sizeof(LDR_DATA_TABLE_ENTRY)); - if (NtModule == NULL) - { - DPRINT1("Failed to create loader module entry (NTDLL)\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES); - } - memset(NtModule, 0, sizeof(LDR_DATA_TABLE_ENTRY)); - - NtModule->DllBase = BaseAddress; - NtModule->EntryPoint = 0; /* no entry point */ - RtlCreateUnicodeString(&NtModule->FullDllName, FullNtDllPath); - RtlCreateUnicodeString(&NtModule->BaseDllName, L"ntdll.dll"); - NtModule->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED; - - NtModule->LoadCount = -1; /* don't unload */ - NtModule->TlsIndex = -1; - NtModule->SectionPointer = NULL; - NtModule->CheckSum = 0; - - NTHeaders = RtlImageNtHeader(NtModule->DllBase); - NtModule->SizeOfImage = LdrpGetResidentSize(NTHeaders); - NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp; - - InsertTailList(&Peb->Ldr->InLoadOrderModuleList, - &NtModule->InLoadOrderLinks); - InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, - &NtModule->InInitializationOrderModuleList); - - /* add entry for executable (becomes first list entry) */ - LdrpImageEntry = (PLDR_DATA_TABLE_ENTRY) - RtlAllocateHeap(Peb->ProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(LDR_DATA_TABLE_ENTRY)); - if (LdrpImageEntry == NULL) - { - DPRINT1("Failed to create loader module infomation\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES); - } - - LdrpImageEntry->DllBase = Peb->ImageBaseAddress; - - if ((Peb->ProcessParameters == NULL) || - (Peb->ProcessParameters->ImagePathName.Length == 0)) - { - DPRINT1("Failed to access the process parameter block\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL); - } - - RtlCreateUnicodeString(&LdrpImageEntry->FullDllName, - Peb->ProcessParameters->ImagePathName.Buffer); - RtlCreateUnicodeString(&LdrpImageEntry->BaseDllName, - wcsrchr(LdrpImageEntry->FullDllName.Buffer, L'\\') + 1); - - DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &LdrpImageEntry->BaseDllName, &LdrpImageEntry->FullDllName); - - LdrpImageEntry->Flags = LDRP_ENTRY_PROCESSED; - LdrpImageEntry->LoadCount = -1; /* don't unload */ - LdrpImageEntry->TlsIndex = -1; - LdrpImageEntry->SectionPointer = NULL; - LdrpImageEntry->CheckSum = 0; - - NTHeaders = RtlImageNtHeader(LdrpImageEntry->DllBase); - LdrpImageEntry->SizeOfImage = LdrpGetResidentSize(NTHeaders); - LdrpImageEntry->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp; - - LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb(); - - InsertHeadList(&Peb->Ldr->InLoadOrderModuleList, - &LdrpImageEntry->InLoadOrderLinks); - - LdrpInitLoader(); - - EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL); - LdrpImageEntry->EntryPoint = EntryPoint; - - /* all required dlls are loaded now */ - Peb->Ldr->Initialized = TRUE; - - /* Check before returning that we can run the image safely. */ - if (EntryPoint == NULL) - { - DPRINT1("Failed to initialize image\n"); - ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT); - } - - /* Break into debugger */ - if (Peb->BeingDebugged) - DbgBreakPoint(); - - return STATUS_SUCCESS; -} - /* EOF */ diff --git a/reactos/dll/ntdll/ldr/utils.c b/reactos/dll/ntdll/ldr/utils.c index 9ce0cbb9feb..fe39e90053d 100644 --- a/reactos/dll/ntdll/ldr/utils.c +++ b/reactos/dll/ntdll/ldr/utils.c @@ -42,31 +42,12 @@ extern PLDR_DATA_TABLE_ENTRY LdrpImageEntry; static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref); static PVOID LdrFixupForward(PCHAR ForwardName); static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint); -static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL, - IN ULONG LoadFlags, - IN PUNICODE_STRING Name, - OUT PLDR_DATA_TABLE_ENTRY *Module, - OUT PVOID *BaseAddress OPTIONAL); -static VOID LdrpDetachProcess(BOOLEAN UnloadAll); -static NTSTATUS LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Unload); NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname ); NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module ); /* FUNCTIONS *****************************************************************/ -BOOLEAN -LdrMappedAsDataFile(PVOID *BaseAddress) -{ - if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1))) - { - *BaseAddress = (PVOID)((DWORD_PTR)*BaseAddress & ~((DWORD_PTR) PAGE_SIZE - 1)); - return TRUE; - } - - return FALSE; -} - static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked) { LONG LoadCount; @@ -105,193 +86,6 @@ static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEA return LoadCount; } -static PWSTR -LdrpQueryAppPaths(IN PCWSTR ImageName) -{ - PKEY_VALUE_PARTIAL_INFORMATION KeyInfo; - OBJECT_ATTRIBUTES ObjectAttributes; - WCHAR SearchPathBuffer[5*MAX_PATH]; - UNICODE_STRING ValueNameString; - UNICODE_STRING KeyName; - WCHAR NameBuffer[MAX_PATH]; - ULONG KeyInfoSize; - ULONG ResultSize; - PWCHAR Backslash; - HANDLE KeyHandle; - NTSTATUS Status; - PWSTR Path = NULL; - - _snwprintf(NameBuffer, - sizeof(NameBuffer) / sizeof(WCHAR), - L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s", - ImageName); - - RtlInitUnicodeString(&KeyName, NameBuffer); - - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenKey(&KeyHandle, - KEY_READ, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - DPRINT ("NtOpenKey() failed (Status %lx)\n", Status); - return NULL; - } - - KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR); - - KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize); - if (KeyInfo == NULL) - { - DPRINT("RtlAllocateHeap() failed\n"); - NtClose(KeyHandle); - return NULL; - } - - RtlInitUnicodeString(&ValueNameString, - L"Path"); - - Status = NtQueryValueKey(KeyHandle, - &ValueNameString, - KeyValuePartialInformation, - KeyInfo, - KeyInfoSize, - &ResultSize); - - if (!NT_SUCCESS(Status)) - { - NtClose(KeyHandle); - RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); - return NULL; - } - - RtlCopyMemory(SearchPathBuffer, - &KeyInfo->Data, - KeyInfo->DataLength); - - /* Free KeyInfo memory, we won't need it anymore */ - RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); - - /* Close the key handle */ - NtClose(KeyHandle); - - /* get application running path */ - wcscat(SearchPathBuffer, L";"); - wcscat(SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer); // FIXME: Don't rely on it being NULL-terminated!!! - - /* Remove trailing backslash */ - Backslash = wcsrchr(SearchPathBuffer, L'\\'); - if (Backslash) Backslash = L'\0'; - - wcscat(SearchPathBuffer, L";"); - - wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot); - wcscat(SearchPathBuffer, L"\\system32;"); - wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot); - wcscat(SearchPathBuffer, L";."); - - /* Copy it to the heap allocd memory */ - Path = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - (wcslen(SearchPathBuffer) + 1) * sizeof(WCHAR)); - - if (!Path) - { - DPRINT1("RtlAllocateHeap() failed\n"); - return NULL; - } - - wcscpy(Path, SearchPathBuffer); - - return Path; -} - -VOID -LdrpInitLoader(VOID) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING LinkTarget; - UNICODE_STRING Name; - HANDLE LinkHandle; - ULONG Length; - NTSTATUS Status; - - DPRINT("LdrpInitLoader() called for %wZ\n", &LdrpImageEntry->BaseDllName); - - /* Get handle to the 'KnownDlls' directory */ - RtlInitUnicodeString(&Name, - L"\\KnownDlls"); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenDirectoryObject(&LdrpKnownDllObjectDirectory, - DIRECTORY_QUERY | DIRECTORY_TRAVERSE, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status); - LdrpKnownDllObjectDirectory = NULL; - return; - } - - /* Allocate target name string */ - LinkTarget.Length = 0; - LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR); - LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - MAX_PATH * sizeof(WCHAR)); - if (LinkTarget.Buffer == NULL) - { - NtClose(LdrpKnownDllObjectDirectory); - LdrpKnownDllObjectDirectory = NULL; - return; - } - - RtlInitUnicodeString(&Name, - L"KnownDllPath"); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - LdrpKnownDllObjectDirectory, - NULL); - Status = NtOpenSymbolicLinkObject(&LinkHandle, - SYMBOLIC_LINK_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&LinkTarget); - NtClose(LdrpKnownDllObjectDirectory); - LdrpKnownDllObjectDirectory = NULL; - return; - } - - Status = NtQuerySymbolicLinkObject(LinkHandle, - &LinkTarget, - &Length); - NtClose(LinkHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&LinkTarget); - NtClose(LdrpKnownDllObjectDirectory); - LdrpKnownDllObjectDirectory = NULL; - } - - RtlCreateUnicodeString(&LdrpKnownDllPath, - LinkTarget.Buffer); - - RtlFreeUnicodeString(&LinkTarget); - - DPRINT("LdrpInitLoader() done\n"); -} - - /*************************************************************************** * NAME LOCAL * LdrAdjustDllName @@ -328,6 +122,8 @@ LdrAdjustDllName (PUNICODE_STRING FullDllName, PWCHAR Extension; PWCHAR Pointer; + DPRINT1("\n"); + Length = DllName->Length / sizeof(WCHAR); if (BaseName) @@ -379,6 +175,8 @@ LdrAddModuleEntry(PVOID ImageBase, { PLDR_DATA_TABLE_ENTRY Module; + DPRINT1("\n"); + Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY)); ASSERT(Module); memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY)); @@ -420,407 +218,6 @@ LdrAddModuleEntry(PVOID ImageBase, return(Module); } - -static NTSTATUS -LdrpMapKnownDll(IN PUNICODE_STRING DllName, - OUT PUNICODE_STRING FullDosName, - OUT PHANDLE SectionHandle) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - NTSTATUS Status; - - DPRINT("LdrpMapKnownDll() called\n"); - - if (LdrpKnownDllObjectDirectory == NULL) - { - DPRINT("Invalid 'KnownDlls' directory\n"); - return STATUS_UNSUCCESSFUL; - } - - DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath); - - InitializeObjectAttributes(&ObjectAttributes, - DllName, - OBJ_CASE_INSENSITIVE, - LdrpKnownDllObjectDirectory, - NULL); - Status = NtOpenSection(SectionHandle, - SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtOpenSection() failed for '%wZ' (Status 0x%08lx)\n", DllName, Status); - return Status; - } - - FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR); - FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR); - FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - FullDosName->MaximumLength); - if (FullDosName->Buffer == NULL) - { - FullDosName->Length = 0; - FullDosName->MaximumLength = 0; - return STATUS_SUCCESS; - } - - wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer); - wcscat(FullDosName->Buffer, L"\\"); - wcscat(FullDosName->Buffer, DllName->Buffer); - - DPRINT("FullDosName '%wZ'\n", FullDosName); - - DPRINT("LdrpMapKnownDll() done\n"); - - return STATUS_SUCCESS; -} - - -static NTSTATUS -LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL, - IN PUNICODE_STRING DllName, - OUT PUNICODE_STRING FullDosName, - IN BOOLEAN MapAsDataFile, - OUT PHANDLE SectionHandle) -{ - WCHAR *SearchPathBuffer = NULL; - WCHAR *ImagePathNameBufferPtr = NULL; - WCHAR DosName[MAX_PATH]; - UNICODE_STRING FullNtFileName; - UNICODE_STRING PathEnvironmentVar_U; - UNICODE_STRING PathName_U; - OBJECT_ATTRIBUTES FileObjectAttributes; - HANDLE FileHandle; - char BlockBuffer [1024]; - PIMAGE_DOS_HEADER DosHeader; - PIMAGE_NT_HEADERS NTHeaders; - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - ULONG len; - ULONG ImagePathLen; - - DPRINT("LdrpMapDllImageFile() called\n"); - - if (SearchPath == NULL) - { - /* get application running path */ - ImagePathNameBufferPtr = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer; - - /* Length of ImagePathName */ - ImagePathLen = wcslen(ImagePathNameBufferPtr); - - /* Subtract application name leaveing only the directory length */ - while (ImagePathLen && ImagePathNameBufferPtr[ImagePathLen - 1] != L'\\') - ImagePathLen--; - - /* Length of directory + semicolon */ - len = ImagePathLen + 1; - - /* Length of SystemRoot + "//system32" + semicolon*/ - len += wcslen(SharedUserData->NtSystemRoot) + 10; - /* Length of SystemRoot + semicolon */ - len += wcslen(SharedUserData->NtSystemRoot) + 1; - - RtlInitUnicodeString (&PathName_U, L"PATH"); - PathEnvironmentVar_U.Length = 0; - PathEnvironmentVar_U.MaximumLength = 0; - PathEnvironmentVar_U.Buffer = NULL; - - /* Get the path environment variable */ - Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U); - - /* Check that valid information was returned */ - if ((Status == STATUS_BUFFER_TOO_SMALL) && (PathEnvironmentVar_U.Length > 0)) - { - /* Allocate memory for the path env var */ - PathEnvironmentVar_U.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, PathEnvironmentVar_U.Length + sizeof(WCHAR)); - if (!PathEnvironmentVar_U.Buffer) - { - DPRINT1("Fatal! Out of Memory!!\n"); - return STATUS_NO_MEMORY; - } - PathEnvironmentVar_U.MaximumLength = PathEnvironmentVar_U.Length + sizeof(WCHAR); - - /* Retry */ - Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Unable to get path environment string!\n"); - ASSERT(FALSE); - } - /* Length of path evn var + semicolon */ - len += (PathEnvironmentVar_U.Length / sizeof(WCHAR)) + 1; - } - - /* Allocate the size needed to hold all the above paths + period */ - SearchPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (len + 2) * sizeof(WCHAR)); - if (!SearchPathBuffer) - { - DPRINT1("Fatal! Out of Memory!!\n"); - return STATUS_NO_MEMORY; - } - - wcsncpy(SearchPathBuffer, ImagePathNameBufferPtr, ImagePathLen); - wcscat (SearchPathBuffer, L";"); - wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot); - wcscat (SearchPathBuffer, L"\\system32;"); - wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot); - wcscat (SearchPathBuffer, L";"); - - if (PathEnvironmentVar_U.Buffer) - { - wcscat (SearchPathBuffer, PathEnvironmentVar_U.Buffer); - wcscat (SearchPathBuffer, L";"); - RtlFreeHeap(RtlGetProcessHeap(), 0, PathEnvironmentVar_U.Buffer); - } - wcscat (SearchPathBuffer, L"."); - - SearchPath = SearchPathBuffer; - } - - if (RtlDosSearchPath_U (SearchPath, - DllName->Buffer, - NULL, - MAX_PATH, - DosName, - NULL) == 0) - { - /* try to find active context dll */ - Status = find_actctx_dll(DllName->Buffer, DosName); - if(Status == STATUS_SUCCESS) - DPRINT("found %S for %S\n", DosName,DllName->Buffer); - else - return STATUS_DLL_NOT_FOUND; - } - - if (!RtlDosPathNameToNtPathName_U (DosName, - &FullNtFileName, - NULL, - NULL)) - { - DPRINT("Dll %wZ not found!\n", DllName); - return STATUS_DLL_NOT_FOUND; - } - - DPRINT("FullNtFileName %wZ\n", &FullNtFileName); - - InitializeObjectAttributes(&FileObjectAttributes, - &FullNtFileName, - 0, - NULL, - NULL); - - DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName); - - Status = NtOpenFile(&FileHandle, - GENERIC_READ|SYNCHRONIZE, - &FileObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Dll open of %wZ failed: Status = 0x%08lx\n", - &FullNtFileName, Status); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - FullNtFileName.Buffer); - return Status; - } - RtlFreeHeap (RtlGetProcessHeap (), - 0, - FullNtFileName.Buffer); - - if (!MapAsDataFile) - { - - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - BlockBuffer, - sizeof(BlockBuffer), - NULL, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("Dll header read failed: Status = 0x%08lx\n", Status); - NtClose(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_SIGNATURE) - || (DosHeader->e_lfanew == 0L) - || (*(PULONG)(NTHeaders) != IMAGE_NT_SIGNATURE)) - { - DPRINT("NTDLL format invalid\n"); - NtClose(FileHandle); - - return STATUS_UNSUCCESSFUL; - } - } - - /* - * Create a section for dll. - */ - Status = NtCreateSection(SectionHandle, - SECTION_ALL_ACCESS, - NULL, - NULL, - PAGE_READONLY, - MapAsDataFile ? SEC_COMMIT : SEC_IMAGE, - FileHandle); - NtClose(FileHandle); - - if (!NT_SUCCESS(Status)) - { - DPRINT("NTDLL create section failed: Status = 0x%08lx\n", Status); - return Status; - } - - RtlCreateUnicodeString(FullDosName, - DosName); - - return Status; -} - - - -/*************************************************************************** - * NAME EXPORTED - * LdrLoadDll - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - * - * NOTE - * - * @implemented - */ -NTSTATUS NTAPI -LdrLoadDll (IN PWSTR SearchPath OPTIONAL, - IN PULONG LoadFlags OPTIONAL, - IN PUNICODE_STRING Name, - OUT PVOID *BaseAddress /* also known as HMODULE*, and PHANDLE 'DllHandle' */) -{ - NTSTATUS Status; - PLDR_DATA_TABLE_ENTRY Module; - ULONG_PTR cookie; - PPEB Peb = NtCurrentPeb(); - - TRACE_LDR("LdrLoadDll loading %wZ%S%S with flags %d\n", - Name, - SearchPath ? L" from " : L"", - SearchPath ? SearchPath : L"", - LoadFlags ? *LoadFlags : 0); - - Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress); - - if (NT_SUCCESS(Status) && - (!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE))) - { - if (!create_module_activation_context( Module )) - { - RtlActivateActivationContext(0, Module->EntryPointActivationContext, &cookie); - } - - if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED)) - { - RtlEnterCriticalSection(Peb->LoaderLock); - Status = LdrpRunInitializeRoutines(NULL); - RtlLeaveCriticalSection(Peb->LoaderLock); - } - if (Module->EntryPointActivationContext) RtlDeactivateActivationContext(0, cookie); - } - - if ((!Module) && (NT_SUCCESS(Status))) - return Status; - - *BaseAddress = NT_SUCCESS(Status) ? Module->DllBase : NULL; - - return Status; -} - - -/*************************************************************************** - * NAME EXPORTED - * LdrFindEntryForAddress - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - * - * NOTE - * - * @implemented - */ -NTSTATUS NTAPI -LdrFindEntryForAddress(PVOID Address, - PLDR_DATA_TABLE_ENTRY *Module) -{ - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY ModulePtr; - - DPRINT("LdrFindEntryForAddress(Address %p)\n", Address); - - if (NtCurrentPeb()->Ldr == NULL) - return(STATUS_NO_MORE_ENTRIES); - - RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); - ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; - Entry = ModuleListHead->Flink; - if (Entry == ModuleListHead) - { - RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); - return(STATUS_NO_MORE_ENTRIES); - } - - while (Entry != ModuleListHead) - { - ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - - DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->DllBase); - - if ((Address >= ModulePtr->DllBase) && - ((ULONG_PTR)Address <= ((ULONG_PTR)ModulePtr->DllBase + ModulePtr->SizeOfImage))) - { - *Module = ModulePtr; - RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); - return(STATUS_SUCCESS); - } - - Entry = Entry->Flink; - } - - DPRINT("Failed to find module entry.\n"); - - RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); - return(STATUS_NO_MORE_ENTRIES); -} - - /*************************************************************************** * NAME LOCAL * LdrFindEntryForName @@ -944,6 +341,8 @@ LdrFixupForward(PCHAR ForwardName) PLDR_DATA_TABLE_ENTRY Module; PVOID BaseAddress; + DPRINT1("\n"); + strcpy(NameBuffer, ForwardName); p = strchr(NameBuffer, '.'); if (p != NULL) @@ -982,58 +381,6 @@ LdrFixupForward(PCHAR ForwardName) } -/********************************************************************** - * NAME LOCAL - * LdrGetExportByOrdinal - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - * - * NOTE - * - */ -static PVOID -LdrGetExportByOrdinal ( - PVOID BaseAddress, - ULONG Ordinal -) -{ - PIMAGE_EXPORT_DIRECTORY ExportDir; - ULONG ExportDirSize; - PDWORD * ExFunctions; - PVOID Function; - - ExportDir = (PIMAGE_EXPORT_DIRECTORY) - RtlImageDirectoryEntryToData (BaseAddress, - TRUE, - IMAGE_DIRECTORY_ENTRY_EXPORT, - &ExportDirSize); - - - ExFunctions = (PDWORD*)RVA(BaseAddress, ExportDir->AddressOfFunctions); - DPRINT("LdrGetExportByOrdinal(Ordinal %lu) = %p\n", - Ordinal, RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base])); - - Function = (0 != ExFunctions[Ordinal - ExportDir->Base] - ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] ) - : NULL); - - if (((ULONG)Function >= (ULONG)ExportDir) && - ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize)) - { - DPRINT("Forward: %s\n", (PCHAR)Function); - Function = LdrFixupForward((PCHAR)Function); - } - - return Function; -} - - /********************************************************************** * NAME LOCAL * LdrGetExportByName @@ -1201,6 +548,8 @@ LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, LONG_PTR Delta; NTSTATUS Status; + DPRINT1("\n"); + if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) { return STATUS_SUCCESS; @@ -1294,56 +643,6 @@ LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, return STATUS_SUCCESS; } -static NTSTATUS -LdrpGetOrLoadModule(PWCHAR SearchPath, - PCHAR Name, - PLDR_DATA_TABLE_ENTRY* Module, - BOOLEAN Load) -{ - ANSI_STRING AnsiDllName; - UNICODE_STRING DllName; - NTSTATUS Status; - - DPRINT("LdrpGetOrLoadModule() called for %s\n", Name); - - RtlInitAnsiString(&AnsiDllName, Name); - Status = RtlAnsiStringToUnicodeString(&DllName, &AnsiDllName, TRUE); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = LdrFindEntryForName (&DllName, Module, Load); - if (Load && !NT_SUCCESS(Status)) - { - Status = LdrpLoadModule(SearchPath, - 0, - &DllName, - Module, - NULL); - if (NT_SUCCESS(Status)) - { - Status = LdrFindEntryForName (&DllName, Module, FALSE); - } - if (!NT_SUCCESS(Status)) - { - ULONG ErrorResponse; - ULONG_PTR ErrorParameter = (ULONG_PTR)&AnsiDllName; - - DPRINT1("failed to load %wZ\n", &DllName); - - NtRaiseHardError(STATUS_DLL_NOT_FOUND, - 1, - 1, - &ErrorParameter, - OptionOk, - &ErrorResponse); - } - } - RtlFreeUnicodeString (&DllName); - return Status; -} - void RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName) { @@ -1353,6 +652,8 @@ RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName) ANSI_STRING DllNameAnsi; CHAR Buffer[8]; + DPRINT1("\n"); + if (!FuncName) { _snprintf(Buffer, 8, "# %ld", Ordinal); @@ -1372,993 +673,6 @@ RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName) RtlFreeAnsiString(&DllNameAnsi); } -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++; - } - - /* No need to fixup anything if IAT is empty */ - if (IATSize == 0) return STATUS_SUCCESS; - - /* 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); - RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName); - return STATUS_ENTRYPOINT_NOT_FOUND; - } - } - 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); - RtlpRaiseImportNotFound((CHAR*)pe_name->Name, - 0, - &ImportedModule->FullDllName); - return STATUS_ENTRYPOINT_NOT_FOUND; - } - } - 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(%p '%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 %p '%wZ', %p '%wZ', '%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++; - } - return STATUS_SUCCESS; -} - - -/********************************************************************** - * 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(IN PWSTR SearchPath OPTIONAL, - IN PLDR_DATA_TABLE_ENTRY Module) -{ - PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory; - PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent; - PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor; - PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent; - PIMAGE_TLS_DIRECTORY TlsDirectory; - ULONG TlsSize = 0; - NTSTATUS Status = STATUS_SUCCESS; - PLDR_DATA_TABLE_ENTRY ImportedModule; - PCHAR ImportedName; - PWSTR ModulePath; - ULONG Size; - ULONG_PTR cookie; - - DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module); - - /* Check for tls data */ - TlsDirectory = (PIMAGE_TLS_DIRECTORY) - RtlImageDirectoryEntryToData(Module->DllBase, - TRUE, - IMAGE_DIRECTORY_ENTRY_TLS, - &Size); - if (TlsDirectory) - { - TlsSize = TlsDirectory->EndAddressOfRawData - - TlsDirectory->StartAddressOfRawData - + TlsDirectory->SizeOfZeroFill; - - if (TlsSize > 0 && NtCurrentPeb()->Ldr->Initialized) - { - TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n", - &Module->BaseDllName); - TlsDirectory = NULL; - } - } - - if (!create_module_activation_context( Module )) - { - if (Module->EntryPointActivationContext == NULL) - { - DPRINT("EntryPointActivationContext has not be allocated\n"); - DPRINT("Module->DllBaseName %wZ\n", Module->BaseDllName); - } - RtlActivateActivationContext( 0, Module->EntryPointActivationContext, &cookie ); - } - - /* - * Process each import module. - */ - ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR) - RtlImageDirectoryEntryToData(Module->DllBase, - TRUE, - IMAGE_DIRECTORY_ENTRY_IMPORT, - &Size); - - BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR) - RtlImageDirectoryEntryToData(Module->DllBase, - TRUE, - IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, - &Size); - - if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL) - { - DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName); - return STATUS_UNSUCCESSFUL; - } - if (BoundImportDescriptor) - { - DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor); - - BoundImportDescriptorCurrent = BoundImportDescriptor; - while (BoundImportDescriptorCurrent->OffsetModuleName) - { - ImportedName = (PCHAR)BoundImportDescriptor + - BoundImportDescriptorCurrent->OffsetModuleName; - TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName); - Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to load %s\n", ImportedName); - return Status; - } - if (Module == ImportedModule) - { - LdrpDecrementLoadCount(Module, FALSE); - } - if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp) - { - TRACE_LDR("%wZ has stale binding to %wZ\n", - &Module->BaseDllName, &ImportedModule->BaseDllName); - Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to import %s\n", ImportedName); - return Status; - } - } - else - { - BOOLEAN WrongForwarder; - WrongForwarder = FALSE; - if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE) - { - TRACE_LDR("%wZ has stale binding to %s\n", - &Module->BaseDllName, ImportedName); - } - else - { - TRACE_LDR("%wZ has correct binding to %wZ\n", - &Module->BaseDllName, &ImportedModule->BaseDllName); - } - if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs) - { - PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef; - ULONG i; - PLDR_DATA_TABLE_ENTRY ForwarderModule; - PCHAR ForwarderName; - - BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1); - for (i = 0; - i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; - i++, BoundForwarderRef++) - { - ForwarderName = (PCHAR)BoundImportDescriptor + - BoundForwarderRef->OffsetModuleName; - TRACE_LDR("%wZ bound to %s via forwardes from %s\n", - &Module->BaseDllName, ForwarderName, ImportedName); - Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to load %s\n", ForwarderName); - return Status; - } - if (Module == ImportedModule) - { - LdrpDecrementLoadCount(Module, FALSE); - } - if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp || - ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE) - { - TRACE_LDR("%wZ has stale binding to %s\n", - &Module->BaseDllName, ForwarderName); - WrongForwarder = TRUE; - } - else - { - TRACE_LDR("%wZ has correct binding to %s\n", - &Module->BaseDllName, ForwarderName); - } - } - } - if (WrongForwarder || - ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE) - { - Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to import %s\n", ImportedName); - return Status; - } - } - else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE) - { - TRACE_LDR("Adjust imports for %s from %wZ\n", - ImportedName, &Module->BaseDllName); - Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to adjust import entries for %s\n", ImportedName); - return Status; - } - } - else if (WrongForwarder) - { - /* - * FIXME: - * Update only forwarders - */ - TRACE_LDR("Stale BIND %s from %wZ\n", - ImportedName, &Module->BaseDllName); - Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName); - if (!NT_SUCCESS(Status)) - { - DPRINT1("faild to import %s\n", ImportedName); - return Status; - } - } - else - { - /* nothing to do */ - } - } - BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1; - } - } - else if (ImportModuleDirectory) - { - DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory); - - ImportModuleDirectoryCurrent = ImportModuleDirectory; - while (ImportModuleDirectoryCurrent->Name) - { - ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name; - TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName); - - if (SearchPath == NULL) - { - ModulePath = LdrpQueryAppPaths(Module->BaseDllName.Buffer); - - Status = LdrpGetOrLoadModule(ModulePath, ImportedName, &ImportedModule, TRUE); - if (ModulePath != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath); - if (NT_SUCCESS(Status)) goto Success; - } - - Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to load %s\n", ImportedName); - break; - } -Success: - if (Module == ImportedModule) - { - LdrpDecrementLoadCount(Module, FALSE); - } - - TRACE_LDR("Initializing imports for %wZ from %s\n", - &Module->BaseDllName, ImportedName); - Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent); - if (!NT_SUCCESS(Status)) - { - DPRINT1("failed to import %s\n", ImportedName); - break; - } - ImportModuleDirectoryCurrent++; - } - - if (!NT_SUCCESS(Status)) - { - NTSTATUS errorStatus = Status; - - while (ImportModuleDirectoryCurrent >= ImportModuleDirectory) - { - ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name; - - Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE); - if (NT_SUCCESS(Status) && Module != ImportedModule) - { - Status = LdrpUnloadModule(ImportedModule, FALSE); - if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName); - } - ImportModuleDirectoryCurrent--; - } - return errorStatus; - } - } - - if (Module->EntryPointActivationContext) RtlDeactivateActivationContext( 0, cookie ); - - return STATUS_SUCCESS; -} - - -/********************************************************************** - * NAME - * LdrPEStartup - * - * DESCRIPTION - * 1. Relocate, if needed the EXE. - * 2. Fixup any imported symbol. - * 3. Compute the EXE's entry point. - * - * ARGUMENTS - * ImageBase - * Address at which the EXE's image - * is loaded. - * - * SectionHandle - * Handle of the section that contains - * the EXE's image. - * - * RETURN VALUE - * NULL on error; otherwise the entry point - * to call for initializing the DLL. - * - * REVISIONS - * - * NOTE - * 04.01.2004 hb Previous this function was used for all images (dll + exe). - * Currently the function is only used for the exe. - */ -PEPFUNC LdrPEStartup (PVOID ImageBase, - HANDLE SectionHandle, - PLDR_DATA_TABLE_ENTRY* Module, - PWSTR FullDosName) -{ - NTSTATUS Status; - PEPFUNC EntryPoint = NULL; - PIMAGE_DOS_HEADER DosHeader; - PIMAGE_NT_HEADERS NTHeaders; - PLDR_DATA_TABLE_ENTRY tmpModule; - PVOID ActivationContextStack; - - DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n", - ImageBase, SectionHandle); - - /* - * Overlay DOS and WNT headers structures - * to the DLL's image. - */ - DosHeader = (PIMAGE_DOS_HEADER) ImageBase; - NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)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) - { - DPRINT("LDR: Performing relocations\n"); - Status = LdrPerformRelocations(NTHeaders, ImageBase); - if (!NT_SUCCESS(Status)) - { - DPRINT1("LdrPerformRelocations() failed\n"); - return NULL; - } - } - - if (Module != NULL) - { - *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName); - (*Module)->SectionPointer = SectionHandle; - } - else - { - Module = &tmpModule; - Status = LdrFindEntryForAddress(ImageBase, Module); - if (!NT_SUCCESS(Status)) - { - return NULL; - } - } - - if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase) - { - (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE; - } - - /* Allocate memory for the ActivationContextStack */ - /* FIXME: Verify RtlAllocateActivationContextStack behavior */ - Status = RtlAllocateActivationContextStack(&ActivationContextStack); - if (NT_SUCCESS(Status)) - { - DPRINT("ActivationContextStack %x\n",ActivationContextStack); - DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK)ActivationContextStack)->ActiveFrame); - NtCurrentTeb()->ActivationContextStackPointer = ActivationContextStack; - NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL; - } - else - DPRINT1("Warning: Unable to allocate ActivationContextStack\n"); - - /* - * If the DLL's imports symbols from other - * modules, fixup the imported calls entry points. - */ - DPRINT("About to fixup imports\n"); - Status = LdrFixupImports(NULL, *Module); - if (!NT_SUCCESS(Status)) - { - DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName); - return NULL; - } - DPRINT("Fixup done\n"); - RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); - Status = LdrpInitializeTls(); - if (NT_SUCCESS(Status)) - { - Status = LdrpRunInitializeRoutines(NULL); - } - if (NT_SUCCESS(Status)) - { - LdrpTlsCallback((*Module)->DllBase, DLL_PROCESS_ATTACH); - } - - - RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); - if (!NT_SUCCESS(Status)) - { - return NULL; - } - - /* - * Compute the DLL's entry point's address. - */ - DPRINT("ImageBase = %p\n", ImageBase); - DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint); - if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0) - { - EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase - + NTHeaders->OptionalHeader.AddressOfEntryPoint); - } - DPRINT("LdrPEStartup() = %p\n",EntryPoint); - return EntryPoint; -} - -static NTSTATUS -LdrpLoadModule(IN PWSTR SearchPath OPTIONAL, - IN ULONG LoadFlags, - IN PUNICODE_STRING Name, - PLDR_DATA_TABLE_ENTRY *Module, - PVOID *BaseAddress OPTIONAL) -{ - UNICODE_STRING AdjustedName; - UNICODE_STRING FullDosName; - NTSTATUS Status; - PLDR_DATA_TABLE_ENTRY tmpModule; - HANDLE SectionHandle; - SIZE_T ViewSize; - PVOID ImageBase; - PIMAGE_NT_HEADERS NtHeaders; - BOOLEAN MappedAsDataFile; - PVOID ArbitraryUserPointer; - - if (Module == NULL) - { - Module = &tmpModule; - } - /* adjust the full dll name */ - LdrAdjustDllName(&AdjustedName, Name, FALSE); - - DPRINT("%wZ\n", &AdjustedName); - - MappedAsDataFile = FALSE; - /* Test if dll is already loaded */ - Status = LdrFindEntryForName(&AdjustedName, Module, TRUE); - if (NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&AdjustedName); - if (NULL != BaseAddress) - { - *BaseAddress = (*Module)->DllBase; - } - } - else - { - /* Open or create dll image section */ - Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle); - if (!NT_SUCCESS(Status)) - { - MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE)); - Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName, - MappedAsDataFile, &SectionHandle); - } - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", - &AdjustedName, Status); - RtlFreeUnicodeString(&AdjustedName); - return Status; - } - RtlFreeUnicodeString(&AdjustedName); - /* Map the dll into the process */ - ViewSize = 0; - ImageBase = 0; - ArbitraryUserPointer = NtCurrentTeb()->NtTib.ArbitraryUserPointer; - NtCurrentTeb()->NtTib.ArbitraryUserPointer = FullDosName.Buffer; - Status = NtMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &ImageBase, - 0, - 0, - NULL, - &ViewSize, - ViewShare, - 0, - PAGE_READONLY); - NtCurrentTeb()->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; - if (!NT_SUCCESS(Status)) - { - DPRINT1("map view of section failed (Status 0x%08lx)\n", Status); - RtlFreeUnicodeString(&FullDosName); - NtClose(SectionHandle); - return(Status); - } - if (NULL != BaseAddress) - { - *BaseAddress = ImageBase; - } - if (!MappedAsDataFile) - { - /* Get and check the NT headers */ - NtHeaders = RtlImageNtHeader(ImageBase); - if (NtHeaders == NULL) - { - DPRINT1("RtlImageNtHeaders() failed\n"); - NtUnmapViewOfSection (NtCurrentProcess (), ImageBase); - NtClose (SectionHandle); - RtlFreeUnicodeString(&FullDosName); - return STATUS_UNSUCCESSFUL; - } - } - DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase); - if (MappedAsDataFile) - { - ASSERT(NULL != BaseAddress); - if (NULL != BaseAddress) - { - *BaseAddress = (PVOID) ((char *) *BaseAddress + 1); - } - *Module = NULL; - RtlFreeUnicodeString(&FullDosName); - NtClose(SectionHandle); - return STATUS_SUCCESS; - } - /* If the base address is different from the - * one the DLL is actually loaded, perform any - * relocation. */ - if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase) - { - DPRINT1("Relocating (%lx -> %p) %wZ\n", - NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName); - Status = LdrPerformRelocations(NtHeaders, ImageBase); - if (!NT_SUCCESS(Status)) - { - DPRINT1("LdrPerformRelocations() failed\n"); - NtUnmapViewOfSection (NtCurrentProcess (), ImageBase); - NtClose (SectionHandle); - RtlFreeUnicodeString(&FullDosName); - return STATUS_UNSUCCESSFUL; - } - } - *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer); - (*Module)->SectionPointer = SectionHandle; - if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase) - { - (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE; - } - if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) - { - (*Module)->Flags |= LDRP_IMAGE_DLL; - } - /* fixup the imported calls entry points */ - Status = LdrFixupImports(SearchPath, *Module); - if (!NT_SUCCESS(Status)) - { - DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status); - NtUnmapViewOfSection (NtCurrentProcess (), ImageBase); - NtClose (SectionHandle); - RtlFreeUnicodeString (&FullDosName); - RtlFreeUnicodeString (&(*Module)->FullDllName); - RtlFreeUnicodeString (&(*Module)->BaseDllName); - RemoveEntryList (&(*Module)->InLoadOrderLinks); - return Status; - } - - RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); - InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList, - &(*Module)->InInitializationOrderModuleList); - RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); - } - return STATUS_SUCCESS; -} - -static NTSTATUS -LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, - BOOLEAN Unload) -{ - PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory; - PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor; - PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent; - PCHAR ImportedName; - PLDR_DATA_TABLE_ENTRY ImportedModule; - NTSTATUS Status = 0; - LONG LoadCount; - ULONG Size; - - if (Unload) - { - RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock); - } - - LoadCount = LdrpDecrementLoadCount(Module, Unload); - - TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount); - - if (LoadCount == 0) - { - /* ?????????????????? */ - } - else if (!(Module->Flags & LDRP_STATIC_LINK) && LoadCount == 1) - { - BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR) - RtlImageDirectoryEntryToData(Module->DllBase, - TRUE, - IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, - &Size); - if (BoundImportDescriptor) - { - /* dereferencing all imported modules, use the bound import descriptor */ - BoundImportDescriptorCurrent = BoundImportDescriptor; - while (BoundImportDescriptorCurrent->OffsetModuleName) - { - ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName; - TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName); - Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("unable to found imported modul %s\n", ImportedName); - } - else - { - if (Module != ImportedModule) - { - Status = LdrpUnloadModule(ImportedModule, FALSE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("unable to unload %s\n", ImportedName); - } - } - } - BoundImportDescriptorCurrent++; - } - } - else - { - ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR) - RtlImageDirectoryEntryToData(Module->DllBase, - TRUE, - IMAGE_DIRECTORY_ENTRY_IMPORT, - &Size); - if (ImportModuleDirectory) - { - /* dereferencing all imported modules, use the import descriptor */ - while (ImportModuleDirectory->Name) - { - ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name; - TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName); - Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("unable to found imported modul %s\n", ImportedName); - } - else - { - if (Module != ImportedModule) - { - Status = LdrpUnloadModule(ImportedModule, FALSE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("unable to unload %s\n", ImportedName); - } - } - } - ImportModuleDirectory++; - } - } - } - } - - if (Unload) - { - if (!(Module->Flags & LDRP_STATIC_LINK)) - { - LdrpDetachProcess(FALSE); - } - - RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); - } - return STATUS_SUCCESS; - -} - -/* - * @implemented - */ -NTSTATUS NTAPI -LdrUnloadDll (IN PVOID BaseAddress) -{ - PLDR_DATA_TABLE_ENTRY Module; - NTSTATUS Status; - - if (BaseAddress == NULL) - return STATUS_SUCCESS; - - if (LdrMappedAsDataFile(&BaseAddress)) - { - Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - else - { - Status = LdrFindEntryForAddress(BaseAddress, &Module); - if (NT_SUCCESS(Status)) - { - TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName); - Status = LdrpUnloadModule(Module, TRUE); - } - } - - return Status; -} - /* * @implemented */ @@ -2397,379 +711,16 @@ LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress) return Status; } -/* - * @implemented - */ -NTSTATUS NTAPI -LdrGetDllHandle(IN PWSTR DllPath OPTIONAL, - IN PULONG DllCharacteristics, - IN PUNICODE_STRING DllName, - OUT PVOID *DllHandle) -{ - PLDR_DATA_TABLE_ENTRY Module; - NTSTATUS Status; - - TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", - DllName, DllPath ? DllPath : L""); - - /* NULL is the current executable */ - if (DllName == NULL) - { - *DllHandle = LdrpImageEntry->DllBase; - DPRINT("BaseAddress 0x%lx\n", *DllHandle); - return STATUS_SUCCESS; - } - - Status = LdrFindEntryForName(DllName, &Module, FALSE); - if (NT_SUCCESS(Status)) - { - *DllHandle = Module->DllBase; - return STATUS_SUCCESS; - } - - DPRINT("Failed to find dll %wZ\n", DllName); - *DllHandle = NULL; - return STATUS_DLL_NOT_FOUND; -} - -/* - * @implemented - */ -NTSTATUS NTAPI -LdrAddRefDll(IN ULONG Flags, - IN PVOID BaseAddress) -{ - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - NTSTATUS Status; - - if (Flags & ~(LDR_PIN_MODULE)) - { - return STATUS_INVALID_PARAMETER; - } - - Status = STATUS_DLL_NOT_FOUND; - RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock); - ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; - Entry = ModuleListHead->Flink; - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - - if (Module->DllBase == BaseAddress) - { - if (Flags & LDR_PIN_MODULE) - { - Module->Flags |= LDRP_STATIC_LINK; - } - else - { - LdrpIncrementLoadCount(Module, - FALSE); - } - Status = STATUS_SUCCESS; - break; - } - Entry = Entry->Flink; - } - RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); - return Status; -} - -/* - * @implemented - */ -NTSTATUS NTAPI -LdrGetProcedureAddress (IN PVOID BaseAddress, - IN PANSI_STRING Name, - IN ULONG Ordinal, - OUT PVOID *ProcedureAddress) -{ - NTSTATUS Status = STATUS_PROCEDURE_NOT_FOUND; - if (Name && Name->Length) - { - TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name); - } - else - { - TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal); - } - - DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n", - BaseAddress, Name, Ordinal, ProcedureAddress); - - _SEH2_TRY - { - if (Name && Name->Length) - { - /* by name */ - *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff); - if (*ProcedureAddress != NULL) - { - Status = STATUS_SUCCESS; - } - DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name); - } - else - { - /* by ordinal */ - Ordinal &= 0x0000FFFF; - *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal); - if (*ProcedureAddress) - { - Status = STATUS_SUCCESS; - } - DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal); - } - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = STATUS_DLL_NOT_FOUND; - } - _SEH2_END; - - return Status; -} - -/********************************************************************** - * NAME LOCAL - * LdrpDetachProcess - * - * DESCRIPTION - * Unload dll's which are no longer referenced from others dll's - * - * ARGUMENTS - * none - * - * RETURN VALUE - * none - * - * REVISIONS - * - * NOTE - * The loader lock must be held on enty. - */ -static VOID -LdrpDetachProcess(BOOLEAN UnloadAll) -{ - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - static ULONG CallingCount = 0; - - DPRINT("LdrpDetachProcess() called for %wZ\n", - &LdrpImageEntry->BaseDllName); - - if (UnloadAll) - LdrpDllShutdownInProgress = TRUE; - - CallingCount++; - - ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; - Entry = ModuleListHead->Blink; - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); - if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) && - Module->Flags & LDRP_ENTRY_PROCESSED && - !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS)) - { - Module->Flags |= LDRP_UNLOAD_IN_PROGRESS; - if (Module == LdrpLastModule) - { - LdrpLastModule = NULL; - } - if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED) - { - TRACE_LDR("Unload %wZ - Calling entry point at %x\n", - &Module->BaseDllName, Module->EntryPoint); - - /* Check if it has TLS */ - if (Module->TlsIndex) - { - /* Call TLS */ - LdrpTlsCallback(Module->DllBase, DLL_PROCESS_ATTACH); - } - - if ((Module->Flags & LDRP_IMAGE_DLL) && Module->EntryPoint) - { - LdrpCallDllEntry(Module->EntryPoint, - Module->DllBase, - DLL_PROCESS_DETACH, - (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0)); - } - } - else - { - TRACE_LDR("Unload %wZ\n", &Module->BaseDllName); - } - Entry = ModuleListHead->Blink; - } - else - { - Entry = Entry->Blink; - } - } - - if (CallingCount == 1) - { - Entry = ModuleListHead->Blink; - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); - Entry = Entry->Blink; - if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS && - ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0)) - { - /* remove the module entry from the list */ - RemoveEntryList (&Module->InLoadOrderLinks); - RemoveEntryList (&Module->InInitializationOrderModuleList); - - NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase); - NtClose (Module->SectionPointer); - - TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName); - - RtlFreeUnicodeString (&Module->FullDllName); - RtlFreeUnicodeString (&Module->BaseDllName); - - RtlFreeHeap (RtlGetProcessHeap (), 0, Module); - } - } - } - CallingCount--; - DPRINT("LdrpDetachProcess() done\n"); -} - /* * @implemented */ BOOLEAN NTAPI RtlDllShutdownInProgress (VOID) { + DPRINT1("\n"); return LdrpDllShutdownInProgress; } -/* - * @implemented - */ -NTSTATUS NTAPI -LdrShutdownProcess (VOID) -{ - LdrpDetachProcess(TRUE); - return STATUS_SUCCESS; -} - -/* - * @implemented - */ -NTSTATUS -NTAPI -LdrpInitializeThread(IN PCONTEXT Context) -{ - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - NTSTATUS Status; - - DPRINT("LdrpAttachThread() called for %wZ\n", - &LdrpImageEntry->BaseDllName); - - RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock); - - Status = LdrpAllocateTls(); - - if (NT_SUCCESS(Status)) - { - ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; - Entry = ModuleListHead->Flink; - - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); - if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED && - !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) && - !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS)) - { - TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n", - &Module->BaseDllName, Module->EntryPoint); - - /* Check if it has TLS */ - if (Module->TlsIndex) - { - /* Call TLS */ - LdrpTlsCallback(Module->DllBase, DLL_THREAD_ATTACH); - } - - if ((Module->Flags & LDRP_IMAGE_DLL) && Module->EntryPoint) - LdrpCallDllEntry(Module->EntryPoint, Module->DllBase, DLL_THREAD_ATTACH, NULL); - } - Entry = Entry->Flink; - } - - Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink; - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - LdrpTlsCallback(Module->DllBase, DLL_THREAD_ATTACH); - } - - RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); - - DPRINT("LdrpAttachThread() done\n"); - - return Status; -} - - -/* - * @implemented - */ -NTSTATUS NTAPI -LdrShutdownThread (VOID) -{ - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - - DPRINT("LdrShutdownThread() called for %wZ\n", - &LdrpImageEntry->BaseDllName); - - RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock); - - ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList; - Entry = ModuleListHead->Blink; - while (Entry != ModuleListHead) - { - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList); - - if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED && - !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) && - !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS)) - { - TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n", - &Module->BaseDllName, Module->EntryPoint); - /* Check if it has TLS */ - if (Module->TlsIndex) - { - /* Call TLS */ - LdrpTlsCallback(Module->DllBase, DLL_THREAD_DETACH); - } - - if ((Module->Flags & LDRP_IMAGE_DLL) && Module->EntryPoint) - LdrpCallDllEntry(Module->EntryPoint, Module->DllBase, DLL_THREAD_DETACH, NULL); - } - Entry = Entry->Blink; - } - - /* Free TLS */ - LdrpFreeTls(); - RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); - - DPRINT("LdrShutdownThread() done\n"); - - return STATUS_SUCCESS; -} - /* * Compute size of an image as it is actually present in virt memory * (i.e. excluding NEVER_LOAD sections) @@ -2781,6 +732,8 @@ LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders) unsigned SectionIndex; ULONG ResidentSize; + DPRINT1("\n"); + SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader + NTHeaders->FileHeader.SizeOfOptionalHeader); ResidentSize = 0; @@ -2807,6 +760,7 @@ LdrProcessRelocationBlock( IN PUSHORT TypeOffset, IN LONG_PTR Delta) { + DPRINT1("\n"); return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta); } @@ -2814,6 +768,7 @@ BOOLEAN NTAPI LdrUnloadAlternateResourceModule(IN PVOID BaseAddress) { - UNIMPLEMENTED; + //FIXME: We don't implement alternate resources anyway, don't spam the log + //UNIMPLEMENTED; return FALSE; } diff --git a/reactos/dll/win32/kernel32/misc/ldr.c b/reactos/dll/win32/kernel32/misc/ldr.c index b383f1dd6a1..b2874cf3b73 100644 --- a/reactos/dll/win32/kernel32/misc/ldr.c +++ b/reactos/dll/win32/kernel32/misc/ldr.c @@ -443,20 +443,11 @@ LoadLibraryExW(LPCWSTR lpLibFileName, } } - /* HACK!!! FIXME */ - if (InWindows) - { - /* Call the API Properly */ - Status = LdrLoadDll(SearchPath, - &DllCharacteristics, - &DllName, - (PVOID*)&hInst); - } - else - { - /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */ - Status = LdrLoadDll(SearchPath, &dwFlags, &DllName, (PVOID*)&hInst); - } + /* Call the API Properly */ + Status = LdrLoadDll(SearchPath, + &DllCharacteristics, + &DllName, + (PVOID*)&hInst); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { diff --git a/reactos/lib/rtl/actctx.c b/reactos/lib/rtl/actctx.c index 2abea6e172c..71a5459a52c 100644 --- a/reactos/lib/rtl/actctx.c +++ b/reactos/lib/rtl/actctx.c @@ -2736,6 +2736,10 @@ NTAPI RtlAllocateActivationContextStack(IN PVOID *Context) { PACTIVATION_CONTEXT_STACK ContextStack; + + /* FIXME: Check if it's already allocated */ + //if (*Context) return STATUS_SUCCESS; + ContextStack = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof (ACTIVATION_CONTEXT_STACK) ); if (!ContextStack) { @@ -2798,7 +2802,16 @@ RtlActivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTE /* Return pointer to the activation frame */ return &Frame->Frame; #else - return NULL; + + RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame = &Frame->Frame; + + frame->Previous = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame; + frame->ActivationContext = Context; + frame->Flags = 0; + + NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame; + + return STATUS_SUCCESS; #endif } @@ -2806,7 +2819,6 @@ PRTL_ACTIVATION_CONTEXT_STACK_FRAME FASTCALL RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame) { -#if NEW_NTDLL_LOADER RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top; /* find the right frame */ @@ -2820,9 +2832,6 @@ RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CON NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame->Previous; return frame; -#else - return NULL; -#endif }