/* INCLUDES *****************************************************************/
#include <ntdll.h>
+#include <callback.h>
+
#define NDEBUG
#include <debug.h>
+
/* GLOBALS *******************************************************************/
-HKEY ImageExecOptionsKey;
-HKEY Wow64ExecOptionsKey;
+HANDLE ImageExecOptionsKey;
+HANDLE Wow64ExecOptionsKey;
UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
+UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
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;
-//RTL_BITMAP TlsBitMap;
-//RTL_BITMAP TlsExpansionBitMap;
-//RTL_BITMAP FlsBitMap;
+RTL_BITMAP TlsBitMap;
+RTL_BITMAP TlsExpansionBitMap;
+RTL_BITMAP FlsBitMap;
BOOLEAN LdrpImageHasTls;
LIST_ENTRY LdrpTlsList;
ULONG LdrpNumberOfTlsEntries;
ULONG LdrpNumberOfProcessors;
-
-RTL_CRITICAL_SECTION LdrpLoaderLock;
+PVOID NtDllBase;
+extern LARGE_INTEGER RtlpTimeout;
+BOOLEAN RtlpTimeoutDisable;
+LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
+LIST_ENTRY LdrpDllNotificationList;
+HANDLE LdrpKnownDllObjectDirectory;
+UNICODE_STRING LdrpKnownDllPath;
+WCHAR LdrpKnownDllPathBuffer[128];
+UNICODE_STRING LdrpDefaultPath;
+
+PEB_LDR_DATA PebLdr;
+
+RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
+RTL_CRITICAL_SECTION LdrpLoaderLock =
+{
+ &LdrpLoaderLockDebug,
+ -1,
+ 0,
+ 0,
+ 0,
+ 0
+};
+RTL_CRITICAL_SECTION FastPebLock;
BOOLEAN ShowSnaps;
ULONG LdrpFatalHardErrorCount;
+ULONG LdrpActiveUnloadCount;
+
+//extern LIST_ENTRY RtlCriticalSectionList;
VOID RtlpInitializeVectoredExceptionHandling(VOID);
VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
+VOID NTAPI RtlInitializeHeapManager(VOID);
+extern BOOLEAN RtlpPageHeapEnabled;
+
+ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
+ULONG RtlpShutdownProcessFlags; // TODO: Use it
+
+NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
+void actctx_init(void);
+
+#ifdef _WIN64
+#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
+#else
+#define DEFAULT_SECURITY_COOKIE 0xBB40E64E
+#endif
/* FUNCTIONS *****************************************************************/
NTAPI
LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
IN BOOLEAN Wow64,
- OUT PHKEY NewKeyHandle)
+ OUT PHANDLE NewKeyHandle)
{
- PHKEY RootKeyLocation;
+ PHANDLE RootKeyLocation;
HANDLE RootKey;
UNICODE_STRING SubKeyString;
OBJECT_ATTRIBUTES ObjectAttributes;
/* Setup the object attributes */
InitializeObjectAttributes(&ObjectAttributes,
- Wow64 ?
+ Wow64 ?
&Wow64OptionsString : &ImageExecOptionsString,
OBJ_CASE_INSENSITIVE,
NULL,
/* Extract the name */
SubKeyString = *SubKey;
p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
- while (SubKey->Length)
+ while (SubKeyString.Length)
{
if (p1[-1] == L'\\') break;
p1--;
SubKeyString.Length -= sizeof(*p1);
}
SubKeyString.Buffer = p1;
- SubKeyString.Length = SubKeyString.MaximumLength - SubKeyString.Length - sizeof(WCHAR);
+ SubKeyString.Length = SubKey->Length - SubKeyString.Length;
/* Setup the object attributes */
InitializeObjectAttributes(&ObjectAttributes,
*/
NTSTATUS
NTAPI
-LdrQueryImageFileKeyOption(IN HKEY KeyHandle,
+LdrQueryImageFileKeyOption(IN HANDLE KeyHandle,
IN PCWSTR ValueName,
IN ULONG Type,
OUT PVOID Buffer,
if (!NT_SUCCESS(Status)) return Status;
/* Query the value */
- Status = NtQueryValueKey(KeyHandle,
+ Status = ZwQueryValueKey(KeyHandle,
&ValueNameString,
KeyValuePartialInformation,
KeyValueInformation,
KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
0,
KeyInfoSize);
- if (KeyInfo == NULL)
+ if (KeyValueInformation != NULL)
+ {
+ /* Try again */
+ Status = ZwQueryValueKey(KeyHandle,
+ &ValueNameString,
+ KeyValuePartialInformation,
+ KeyValueInformation,
+ KeyInfoSize,
+ &ResultSize);
+ FreeHeap = TRUE;
+ }
+ else
{
/* Give up this time */
Status = STATUS_NO_MEMORY;
}
-
- /* Try again */
- Status = NtQueryValueKey(KeyHandle,
- &ValueNameString,
- KeyValuePartialInformation,
- KeyValueInformation,
- KeyInfoSize,
- &ResultSize);
- FreeHeap = TRUE;
}
/* Check for success */
{
/* OK, we know what you want... */
IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
- IntegerString.Length = KeyValueInformation->DataLength -
+ IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
sizeof(WCHAR);
- IntegerString.MaximumLength = KeyValueInformation->DataLength;
+ IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
}
}
/* Check if buffer was in heap */
if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
- /* Close key and return */
- NtClose(KeyHandle);
+ /* Return status */
return Status;
}
IN BOOLEAN Wow64)
{
NTSTATUS Status;
- HKEY KeyHandle;
+ HANDLE KeyHandle;
/* Open a handle to the key */
Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
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;
NTAPI
LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
{
- PVOID Cookie;
+ PULONG_PTR Cookie;
+ LARGE_INTEGER Counter;
+ ULONG_PTR 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))
+ {
+ /* Make up a cookie from a bunch of values which may uniquely represent
+ current moment of time, environment, etc */
+ NtQueryPerformanceCounter(&Counter, NULL);
+
+ NewCookie = Counter.LowPart ^ Counter.HighPart;
+ NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueProcess;
+ NewCookie ^= (ULONG)NtCurrentTeb()->ClientId.UniqueThread;
+
+ /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
+ while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
+ {
+ YieldProcessor();
+ };
+
+ /* Calculate the milliseconds value and xor it to the cookie */
+ NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
+ (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
+
+ /* Make the cookie 16bit if necessary */
+ if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
+
+ /* If the result is 0 or the same as we got, just subtract one from the existing value
+ and that's it */
+ if ((NewCookie == 0) || (NewCookie == *Cookie))
+ {
+ NewCookie = *Cookie - 1;
+ }
+
+ /* Set the new cookie value */
+ *Cookie = NewCookie;
+ }
}
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 (%p/%p)\n",
+ &LdrpImageEntry->BaseDllName,
+ NtCurrentTeb()->RealClientId.UniqueProcess,
+ NtCurrentTeb()->RealClientId.UniqueThread);
+
+ /* Allocate an Activation Context Stack */
+ DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
+ Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
+ if (!NT_SUCCESS(Status))
+ {
+ 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 */
+ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
+ }
+ }
+
+ /* Make sure we're not shutting down */
+ if (!LdrpShutdownInProgress)
+ {
+ /* Call the Entrypoint */
+ DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
+ &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
+ NtCurrentTeb()->RealClientId.UniqueProcess,
+ NtCurrentTeb()->RealClientId.UniqueThread);
+ LdrpCallInitRoutine(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 */
+ LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
+
+ /* Deactivate the ActCtx */
+ RtlDeactivateActivationContextUnsafeFast(&ActCtx);
+ }
+
+ DPRINT("LdrpInitializeThread() done\n");
+}
+
NTSTATUS
NTAPI
LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
PTEB OldTldTeb;
BOOLEAN DllStatus;
- DPRINT("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry->BaseDllName);
+ DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
+ &LdrpImageEntry->BaseDllName,
+ NtCurrentTeb()->RealClientId.UniqueProcess,
+ NtCurrentTeb()->RealClientId.UniqueThread);
/* Check the Loader Lock */
LdrpEnsureLoaderLockIsHeld();
/* Allocate space for all the entries */
LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
0,
- Count * sizeof(LdrRootEntry));
+ Count * sizeof(*LdrRootEntry));
if (!LdrRootEntry) return STATUS_NO_MEMORY;
}
else
/* Show debug message */
if (ShowSnaps)
{
- DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ pid %u %0x%x\n",
+ DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
NtCurrentTeb()->RealClientId.UniqueThread,
NtCurrentTeb()->RealClientId.UniqueProcess,
- Peb->ProcessParameters->ImagePathName,
- NtCurrentTeb()->RealClientId.UniqueThread,
- NtCurrentTeb()->RealClientId.UniqueProcess);
+ &Peb->ProcessParameters->ImagePathName);
}
/* Loop in order */
if (LdrEntry->EntryPoint)
{
/* Write in array */
+ ASSERT(i < Count);
LdrRootEntry[i] = LdrEntry;
/* Display debug message */
if (ShowSnaps)
{
- DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
+ DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
NtCurrentTeb()->RealClientId.UniqueThread,
NtCurrentTeb()->RealClientId.UniqueProcess,
&LdrEntry->FullDllName,
/* Clear it */
//Kernel32ProcessInitPostImportfunction = NULL;
- UNIMPLEMENTED;
+ //UNIMPLEMENTED;
}
/* No root entry? return */
sizeof(ULONG),
NULL);
if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
+
+ /* Reset status back to STATUS_SUCCESS */
+ Status = STATUS_SUCCESS;
}
/* Break if aksed */
/* Set up the Act Ctx */
ActCtx.Size = sizeof(ActCtx);
- ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
- RtlZeroMemory(&ActCtx, sizeof(ActCtx));
+ ActCtx.Format = 1;
+ RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
/* Activate the ActCtx */
RtlActivateActivationContextUnsafeFast(&ActCtx,
if (LdrEntry->TlsIndex && Context)
{
/* Call TLS */
- LdrpTlsCallback(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
+ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
}
/* Call the Entrypoint */
DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
&LdrEntry->BaseDllName, EntryPoint);
}
- DllStatus = LdrpCallDllEntry(EntryPoint,
+ DllStatus = LdrpCallInitRoutine(EntryPoint,
LdrEntry->DllBase,
DLL_PROCESS_ATTACH,
Context);
{
/* Set up the Act Ctx */
ActCtx.Size = sizeof(ActCtx);
- ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
- RtlZeroMemory(&ActCtx, 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_ATTACH);
+ LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
/* Deactivate the ActCtx */
RtlDeactivateActivationContextUnsafeFast(&ActCtx);
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 */
+ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH);
+ }
+
+ /* Call the Entrypoint */
+ DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
+ &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
+ LdrpCallInitRoutine(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 */
+ LdrpCallTlsInitializers(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 */
+ LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH);
+ }
+ }
+
+ /* Make sure we're not shutting down */
+ if (!LdrpShutdownInProgress)
+ {
+ /* Call the Entrypoint */
+ DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
+ &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
+ LdrpCallInitRoutine(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 */
+ LdrpCallTlsInitializers(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)
PTEB Teb = NtCurrentTeb();
PLIST_ENTRY NextEntry, ListHead;
PLDRP_TLS_DATA TlsData;
- ULONG TlsDataSize;
+ SIZE_T TlsDataSize;
PVOID *TlsVector;
/* Check if we have any entries */
- if (LdrpNumberOfTlsEntries)
- return 0;
+ if (!LdrpNumberOfTlsEntries)
+ return STATUS_SUCCESS;
/* Allocate the vector array */
TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
NextEntry = NextEntry->Flink;
/* Allocate this vector */
- TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
+ TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
TlsData->TlsDirectory.StartAddressOfRawData;
TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
0,
/* Show debug message */
if (ShowSnaps)
{
- DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
+ DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
TlsVector,
TlsData->TlsDirectory.Characteristics,
&TlsVector[TlsData->TlsDirectory.Characteristics],
TlsVector);
}
+NTSTATUS
+NTAPI
+LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName, PPEB Peb, BOOLEAN SystemWide, BOOLEAN ReadAdvancedOptions)
+{
+ /* If global flags request DPH, perform some additional actions */
+ if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
+ {
+ // TODO: Read advanced DPH flags from the registry if requested
+ if (ReadAdvancedOptions)
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Enable page heap */
+ RtlpPageHeapEnabled = TRUE;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
+{
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
+
+ /* Return error if we were not provided a pointer where to save the options key handle */
+ if (!OptionsKey) return STATUS_INVALID_HANDLE;
+
+ /* Zero initialize the optinos key pointer */
+ *OptionsKey = NULL;
+
+ /* Open the options key */
+ Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
+
+ /* Save it if it was opened successfully */
+ if (NT_SUCCESS(Status))
+ *OptionsKey = KeyHandle;
+
+ if (KeyHandle)
+ {
+ /* There are image specific options, read them starting with NXCOMPAT */
+ Status = LdrQueryImageFileKeyOption(KeyHandle,
+ L"ExecuteOptions",
+ 4,
+ &ExecuteOptions,
+ sizeof(ExecuteOptions),
+ 0);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* TODO: Set execution options for the process */
+ /*
+ if (ExecuteOptions == 0)
+ ExecuteOptions = 1;
+ else
+ ExecuteOptions = 2;
+ ZwSetInformationProcess(NtCurrentProcess(),
+ ProcessExecuteFlags,
+ &ExecuteOptions,
+ sizeof(ULONG));*/
+
+ }
+
+ /* Check if this image uses large pages */
+ if (Peb->ImageUsesLargePages)
+ {
+ /* TODO: If it does, open large page key */
+ UNIMPLEMENTED;
+ }
+
+ /* Get various option values */
+ LdrQueryImageFileKeyOption(KeyHandle,
+ L"DisableHeapLookaside",
+ REG_DWORD,
+ &RtlpDisableHeapLookaside,
+ sizeof(RtlpDisableHeapLookaside),
+ NULL);
+
+ LdrQueryImageFileKeyOption(KeyHandle,
+ L"ShutdownFlags",
+ REG_DWORD,
+ &RtlpShutdownProcessFlags,
+ sizeof(RtlpShutdownProcessFlags),
+ NULL);
+
+ LdrQueryImageFileKeyOption(KeyHandle,
+ L"MinimumStackCommitInBytes",
+ REG_DWORD,
+ &MinimumStackCommit,
+ sizeof(MinimumStackCommit),
+ NULL);
+
+ /* Update PEB's minimum stack commit if it's lower */
+ if (Peb->MinimumStackCommit < MinimumStackCommit)
+ Peb->MinimumStackCommit = MinimumStackCommit;
+
+ /* Set the global flag */
+ Status = LdrQueryImageFileKeyOption(KeyHandle,
+ L"GlobalFlag",
+ REG_DWORD,
+ &GlobalFlag,
+ sizeof(GlobalFlag),
+ NULL);
+
+ if (NT_SUCCESS(Status))
+ Peb->NtGlobalFlag = GlobalFlag;
+ else
+ GlobalFlag = 0;
+
+ /* Call AVRF if necessary */
+ if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
+ {
+ Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
+ }
+ }
+ }
+ else
+ {
+ /* There are no image-specific options, so perform global initialization */
+ if (Peb->NtGlobalFlag & (FLG_POOL_ENABLE_TAIL_CHECK | FLG_HEAP_PAGE_ALLOCS))
+ {
+ /* Initialize app verifier package */
+ Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+LdrpInitializeProcess(IN PCONTEXT Context,
+ IN PVOID SystemArgument1)
+{
+ RTL_HEAP_PARAMETERS HeapParameters;
+ ULONG ComSectionSize;
+ //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
+ PVOID OldShimData;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ //UNICODE_STRING LocalFileName, FullImageName;
+ HANDLE SymLinkHandle;
+ //ULONG DebugHeapOnly;
+ UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
+ PPEB Peb = NtCurrentPeb();
+ BOOLEAN IsDotNetImage = FALSE;
+ BOOLEAN FreeCurDir = FALSE;
+ //HANDLE CompatKey;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+ //LPWSTR ImagePathBuffer;
+ ULONG ConfigSize;
+ UNICODE_STRING CurrentDirectory;
+ HANDLE OptionsKey;
+ ULONG HeapFlags;
+ PIMAGE_NT_HEADERS NtHeader;
+ LPWSTR NtDllName = NULL;
+ NTSTATUS Status, ImportStatus;
+ NLSTABLEINFO NlsTable;
+ PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
+ PTEB Teb = NtCurrentTeb();
+ PLIST_ENTRY ListHead;
+ PLIST_ENTRY NextEntry;
+ ULONG i;
+ PWSTR ImagePath;
+ ULONG DebugProcessHeapOnly = 0;
+ PLDR_DATA_TABLE_ENTRY NtLdrEntry;
+ PWCHAR Current;
+ ULONG ExecuteOptions = 0;
+ PVOID ViewBase;
+
+ /* Set a NULL SEH Filter */
+ RtlSetUnhandledExceptionFilter(NULL);
+
+ /* Get the image path */
+ ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
+
+ /* Check if it's not normalized */
+ if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
+ {
+ /* Normalize it*/
+ ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
+ }
+
+ /* Create a unicode string for the Image Path */
+ ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
+ ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
+ ImagePathName.Buffer = ImagePath;
+
+ /* Get the NT Headers */
+ NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
+
+ /* Get the execution options */
+ Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
+
+ /* Check if this is a .NET executable */
+ if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
+ &ComSectionSize))
+ {
+ /* Remeber this for later */
+ IsDotNetImage = TRUE;
+ }
+
+ /* Save the NTDLL Base address */
+ NtDllBase = SystemArgument1;
+
+ /* If this is a Native Image */
+ if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
+ {
+ /* Then do DLL Validation */
+ LdrpDllValidation = TRUE;
+ }
+
+ /* Save the old Shim Data */
+ OldShimData = Peb->pShimData;
+
+ /* Clear it */
+ Peb->pShimData = NULL;
+
+ /* Save the number of processors and CS Timeout */
+ LdrpNumberOfProcessors = Peb->NumberOfProcessors;
+ RtlpTimeout = Peb->CriticalSectionTimeout;
+
+ /* Normalize the parameters */
+ ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
+ if (ProcessParameters)
+ {
+ /* Save the Image and Command Line Names */
+ ImageFileName = ProcessParameters->ImagePathName;
+ CommandLine = ProcessParameters->CommandLine;
+ }
+ else
+ {
+ /* It failed, initialize empty strings */
+ RtlInitUnicodeString(&ImageFileName, NULL);
+ RtlInitUnicodeString(&CommandLine, NULL);
+ }
+
+ /* Initialize NLS data */
+ RtlInitNlsTables(Peb->AnsiCodePageData,
+ Peb->OemCodePageData,
+ Peb->UnicodeCaseTableData,
+ &NlsTable);
+
+ /* Reset NLS Translations */
+ RtlResetRtlTranslations(&NlsTable);
+
+ /* Get the Image Config Directory */
+ LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
+ &ConfigSize);
+
+ /* Setup the Heap Parameters */
+ RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
+ HeapFlags = HEAP_GROWABLE;
+ HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
+
+ /* Check if we have Configuration Data */
+ if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
+ {
+ /* FIXME: Custom heap settings and misc. */
+ DPRINT1("We don't support LOAD_CONFIG data yet\n");
+ }
+
+ /* Check for custom affinity mask */
+ if (Peb->ImageProcessAffinityMask)
+ {
+ /* Set it */
+ Status = NtSetInformationProcess(NtCurrentProcess(),
+ ProcessAffinityMask,
+ &Peb->ImageProcessAffinityMask,
+ sizeof(Peb->ImageProcessAffinityMask));
+ }
+
+ /* Check if verbose debugging (ShowSnaps) was requested */
+ ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
+
+ /* Start verbose debugging messages right now if they were requested */
+ if (ShowSnaps)
+ {
+ DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
+ Teb->ClientId.UniqueProcess,
+ &CommandLine);
+ }
+
+ /* If the timeout is too long */
+ if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
+ {
+ /* Then disable CS Timeout */
+ RtlpTimeoutDisable = TRUE;
+ }
+
+ /* Initialize Critical Section Data */
+ RtlpInitDeferedCriticalSection();
+
+ /* Initialize VEH Call lists */
+ RtlpInitializeVectoredExceptionHandling();
+
+ /* Set TLS/FLS Bitmap data */
+ Peb->FlsBitmap = &FlsBitMap;
+ Peb->TlsBitmap = &TlsBitMap;
+ Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
+
+ /* Initialize FLS Bitmap */
+ RtlInitializeBitMap(&FlsBitMap,
+ Peb->FlsBitmapBits,
+ FLS_MAXIMUM_AVAILABLE);
+ RtlSetBit(&FlsBitMap, 0);
+
+ /* Initialize TLS Bitmap */
+ RtlInitializeBitMap(&TlsBitMap,
+ Peb->TlsBitmapBits,
+ TLS_MINIMUM_AVAILABLE);
+ RtlSetBit(&TlsBitMap, 0);
+ RtlInitializeBitMap(&TlsExpansionBitMap,
+ Peb->TlsExpansionBitmapBits,
+ TLS_EXPANSION_SLOTS);
+ RtlSetBit(&TlsExpansionBitMap, 0);
+
+ /* Initialize the Hash Table */
+ for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
+ {
+ InitializeListHead(&LdrpHashTable[i]);
+ }
+
+ /* 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;
+ RtlInitializeCriticalSection(&LdrpLoaderLock);
+ LdrpLoaderLockInit = TRUE;
+
+ /* Check if User Stack Trace Database support was requested */
+ if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
+ {
+ DPRINT1("We don't support user stack trace databases yet\n");
+ }
+
+ /* Setup Fast PEB Lock */
+ RtlInitializeCriticalSection(&FastPebLock);
+ Peb->FastPebLock = &FastPebLock;
+ //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
+ //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
+
+ /* Setup Callout Lock and Notification list */
+ //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
+ InitializeListHead(&LdrpDllNotificationList);
+
+ /* For old executables, use 16-byte aligned heap */
+ if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
+ (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
+ {
+ HeapFlags |= HEAP_CREATE_ALIGN_16;
+ }
+
+ /* Setup the Heap */
+ RtlInitializeHeapManager();
+ Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
+ NULL,
+ NtHeader->OptionalHeader.SizeOfHeapReserve,
+ NtHeader->OptionalHeader.SizeOfHeapCommit,
+ NULL,
+ &HeapParameters);
+
+ if (!Peb->ProcessHeap)
+ {
+ DPRINT1("Failed to create process heap\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Allocate an Activation Context Stack */
+ Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ // FIXME: Loader private heap is missing
+ //DPRINT1("Loader private heap is missing\n");
+
+ /* Check for Debug Heap */
+ if (OptionsKey)
+ {
+ /* Query the setting */
+ Status = LdrQueryImageFileKeyOption(OptionsKey,
+ L"DebugProcessHeapOnly",
+ REG_DWORD,
+ &DebugProcessHeapOnly,
+ sizeof(ULONG),
+ NULL);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Reset DPH if requested */
+ if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
+ {
+ RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
+ RtlpPageHeapEnabled = FALSE;
+ }
+ }
+ }
+
+ /* Build the NTDLL Path */
+ FullPath.Buffer = StringBuffer;
+ FullPath.Length = 0;
+ FullPath.MaximumLength = sizeof(StringBuffer);
+ RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
+ RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
+ RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
+
+ /* Open the Known DLLs directory */
+ RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KnownDllString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
+ DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
+ &ObjectAttributes);
+
+ /* Check if it exists */
+ if (NT_SUCCESS(Status))
+ {
+ /* Open the Known DLLs Path */
+ RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KnownDllString,
+ OBJ_CASE_INSENSITIVE,
+ LdrpKnownDllObjectDirectory,
+ NULL);
+ Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
+ SYMBOLIC_LINK_QUERY,
+ &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ /* Query the path */
+ LdrpKnownDllPath.Length = 0;
+ LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
+ LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
+ Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
+ NtClose(SymLinkHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
+ return Status;
+ }
+ }
+ }
+
+ /* Check if we failed */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Aassume System32 */
+ LdrpKnownDllObjectDirectory = NULL;
+ RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
+ LdrpKnownDllPath.Length -= sizeof(WCHAR);
+ }
+
+ /* If we have process parameters, get the default path and current path */
+ if (ProcessParameters)
+ {
+ /* Check if we have a Dll Path */
+ if (ProcessParameters->DllPath.Length)
+ {
+ /* Get the path */
+ LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
+ }
+ else
+ {
+ /* We need a valid path */
+ DPRINT1("No valid DllPath was given!\n");
+ LdrpInitFailure(STATUS_INVALID_PARAMETER);
+ }
+
+ /* Set the current directory */
+ CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
+
+ /* Check if it's empty or invalid */
+ if ((!CurrentDirectory.Buffer) ||
+ (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
+ (!CurrentDirectory.Length))
+ {
+ /* Allocate space for the buffer */
+ CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
+ 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,
+ SharedUserData->NtSystemRoot,
+ 3 * sizeof(WCHAR));
+ CurrentDirectory.Buffer[3] = UNICODE_NULL;
+ CurrentDirectory.Length = 3 * sizeof(WCHAR);
+ CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
+
+ FreeCurDir = TRUE;
+ DPRINT("Using dynamically allocd curdir\n");
+ }
+ else
+ {
+ /* Use the local buffer */
+ DPRINT("Using local system root\n");
+ }
+ }
+
+ /* Setup Loader Data */
+ Peb->Ldr = &PebLdr;
+ InitializeListHead(&PebLdr.InLoadOrderModuleList);
+ InitializeListHead(&PebLdr.InMemoryOrderModuleList);
+ InitializeListHead(&PebLdr.InInitializationOrderModuleList);
+ PebLdr.Length = sizeof(PEB_LDR_DATA);
+ PebLdr.Initialized = TRUE;
+
+ /* Allocate a data entry for the Image */
+ LdrpImageEntry = NtLdrEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
+
+ /* Set it up */
+ NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
+ NtLdrEntry->LoadCount = -1;
+ NtLdrEntry->EntryPointActivationContext = 0;
+ NtLdrEntry->FullDllName = ImageFileName;
+
+ if (IsDotNetImage)
+ NtLdrEntry->Flags = LDRP_COR_IMAGE;
+ else
+ NtLdrEntry->Flags = 0;
+
+ /* Check if the name is empty */
+ if (!ImageFileName.Buffer[0])
+ {
+ /* Use the same Base name */
+ NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
+ }
+ else
+ {
+ /* Find the last slash */
+ Current = ImageFileName.Buffer;
+ while (*Current)
+ {
+ if (*Current++ == '\\')
+ {
+ /* Set this path */
+ NtDllName = Current;
+ }
+ }
+
+ /* Did we find anything? */
+ if (!NtDllName)
+ {
+ /* Use the same Base name */
+ NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
+ }
+ else
+ {
+ /* Setup the name */
+ NtLdrEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
+ NtLdrEntry->BaseDllName.MaximumLength = NtLdrEntry->BaseDllName.Length + sizeof(WCHAR);
+ NtLdrEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
+ (ImageFileName.Length - NtLdrEntry->BaseDllName.Length));
+ }
+ }
+
+ /* Processing done, insert it */
+ LdrpInsertMemoryTableEntry(NtLdrEntry);
+ NtLdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
+
+ /* Now add an entry for NTDLL */
+ NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
+ NtLdrEntry->Flags = LDRP_IMAGE_DLL;
+ NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
+ NtLdrEntry->LoadCount = -1;
+ NtLdrEntry->EntryPointActivationContext = 0;
+
+ 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;
+
+ /* Processing done, insert it */
+ LdrpNtDllDataTableEntry = NtLdrEntry;
+ LdrpInsertMemoryTableEntry(NtLdrEntry);
+
+ /* Let the world know */
+ if (ShowSnaps)
+ {
+ DPRINT1("LDR: NEW PROCESS\n");
+ DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
+ DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
+ DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
+ }
+
+ /* Link the Init Order List */
+ InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
+ &LdrpNtDllDataTableEntry->InInitializationOrderModuleList);
+
+ /* Initialize Wine's active context implementation for the current process */
+ actctx_init();
+
+ /* Set the current directory */
+ Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, check if we should free it */
+ if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
+
+ /* Set it to the NT Root */
+ CurrentDirectory = NtSystemRoot;
+ RtlSetCurrentDirectory_U(&CurrentDirectory);
+ }
+ else
+ {
+ /* We're done with it, free it */
+ if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
+ }
+
+ /* Check if we should look for a .local file */
+ if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
+ {
+ /* FIXME */
+ DPRINT1("We don't support .local overrides yet\n");
+ }
+
+ /* Check if the Application Verifier was enabled */
+ if (Peb->NtGlobalFlag & FLG_POOL_ENABLE_TAIL_CHECK)
+ {
+ /* FIXME */
+ DPRINT1("We don't support Application Verifier yet\n");
+ }
+
+ if (IsDotNetImage)
+ {
+ /* FIXME */
+ DPRINT1("We don't support .NET applications yet\n");
+ }
+
+ /* FIXME: Load support for Terminal Services */
+ if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ {
+ /* Load kernel32 and call BasePostImportInit... */
+ DPRINT("Unimplemented codepath!\n");
+ }
+
+ /* Walk the IAT and load all the DLLs */
+ ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
+
+ /* Check if relocation is needed */
+ if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
+ {
+ DPRINT1("LDR: Performing EXE relocation\n");
+
+ /* Change the protection to prepare for relocation */
+ ViewBase = Peb->ImageBaseAddress;
+ Status = LdrpSetProtection(ViewBase, FALSE);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Do the relocation */
+ Status = LdrRelocateImageWithBias(ViewBase,
+ 0LL,
+ NULL,
+ STATUS_SUCCESS,
+ STATUS_CONFLICTING_ADDRESSES,
+ STATUS_INVALID_IMAGE_FORMAT);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("LdrRelocateImageWithBias() failed\n");
+ return Status;
+ }
+
+ /* Check if a start context was provided */
+ if (Context)
+ {
+ DPRINT1("WARNING: Relocated EXE Context");
+ UNIMPLEMENTED; // We should support this
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ /* Restore the protection */
+ Status = LdrpSetProtection(ViewBase, TRUE);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Lock the DLLs */
+ ListHead = &Peb->Ldr->InLoadOrderModuleList;
+ NextEntry = ListHead->Flink;
+ while (ListHead != NextEntry)
+ {
+ NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+ NtLdrEntry->LoadCount = -1;
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Phase 0 is done */
+ LdrpLdrDatabaseIsSetup = TRUE;
+
+ /* Check whether all static imports were properly loaded and return here */
+ if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
+
+ /* Initialize TLS */
+ Status = LdrpInitializeTls();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
+ Status);
+ return Status;
+ }
+
+ /* FIXME Mark the DLL Ranges for Stack Traces later */
+
+ /* Notify the debugger now */
+ if (Peb->BeingDebugged)
+ {
+ /* Break */
+ DbgBreakPoint();
+
+ /* Update show snaps again */
+ ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
+ }
+
+ /* Validate the Image for MP Usage */
+ if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
+
+ /* Check NX Options */
+ if (SharedUserData->NXSupportPolicy == 1)
+ {
+ ExecuteOptions = 0xD;
+ }
+ else if (!SharedUserData->NXSupportPolicy)
+ {
+ ExecuteOptions = 0xA;
+ }
+
+ /* Let Mm know */
+ ZwSetInformationProcess(NtCurrentProcess(),
+ ProcessExecuteFlags,
+ &ExecuteOptions,
+ sizeof(ULONG));
+
+ /* Check if we had Shim Data */
+ if (OldShimData)
+ {
+ /* Load the Shim Engine */
+ Peb->AppCompatInfo = NULL;
+ //LdrpLoadShimEngine(OldShimData, ImagePathName, OldShimData);
+ DPRINT1("We do not support shims yet\n");
+ }
+ else
+ {
+ /* Check for Application Compatibility Goo */
+ //LdrQueryApplicationCompatibilityGoo(hKey);
+ DPRINT("Querying app compat hacks is missing!\n");
+ }
+
+ /*
+ * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
+ * incompatible images.
+ */
+
+ /* Now call the Init Routines */
+ Status = LdrpRunInitializeRoutines(Context);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
+ Status);
+ return Status;
+ }
+
+ /* FIXME: Unload the Shim Engine if it was loaded */
+
+ /* Check if we have a user-defined Post Process Routine */
+ if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
+ {
+ /* Call it */
+ Peb->PostProcessInitRoutine();
+ }
+
+ /* Close the key if we have one opened */
+ if (OptionsKey) NtClose(OptionsKey);
+
+ /* Return status */
+ return Status;
+}
+
VOID
NTAPI
LdrpInitFailure(NTSTATUS Status)
{
ULONG Response;
+ PPEB Peb = NtCurrentPeb();
/* Print a debug message */
- DPRINT1("LDR: Process initialization failure; NTSTATUS = %08lx\n", Status);
+ DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
+ &Peb->ProcessParameters->ImagePathName, Status);
/* Raise a hard error */
if (!LdrpFatalHardErrorCount)
MEMORY_BASIC_INFORMATION MemoryBasicInfo;
PPEB Peb = NtCurrentPeb();
- DPRINT("LdrpInit()\n");
+ DPRINT("LdrpInit() %p/%p\n",
+ NtCurrentTeb()->RealClientId.UniqueProcess,
+ NtCurrentTeb()->RealClientId.UniqueThread);
/* Check if we have a deallocation stack */
if (!Teb->DeallocationStack)
/* Let other code know we're initializing */
LdrpInLdrInit = TRUE;
- /* Initialize Critical Section Data */
- RtlpInitDeferedCriticalSection();
-
- /* Initialize VEH Call lists */
- RtlpInitializeVectoredExceptionHandling();
-
/* Protect with SEH */
_SEH2_TRY
{