/* 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");
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;
ULONG LdrpNumberOfTlsEntries;
ULONG LdrpNumberOfProcessors;
PVOID NtDllBase;
-LARGE_INTEGER RtlpTimeout;
+extern LARGE_INTEGER RtlpTimeout;
BOOLEAN RtlpTimeoutDisable;
LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
LIST_ENTRY LdrpDllNotificationList;
BOOLEAN ShowSnaps;
ULONG LdrpFatalHardErrorCount;
+ULONG LdrpActiveUnloadCount;
//extern LIST_ENTRY RtlCriticalSectionList;
VOID RtlpInitializeVectoredExceptionHandling(VOID);
VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
-VOID RtlInitializeHeapManager(VOID);
+VOID NTAPI RtlInitializeHeapManager(VOID);
extern BOOLEAN RtlpPageHeapEnabled;
-extern ULONG RtlpDphGlobalFlags;
+
+ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
+ULONG RtlpShutdownProcessFlags; // TODO: Use it
NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
-NTSTATUS NTAPI
-LdrpInitializeProcess_(PCONTEXT Context,
- PVOID SystemArgument1);
+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\n",
+ DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
NtCurrentTeb()->RealClientId.UniqueThread,
NtCurrentTeb()->RealClientId.UniqueProcess,
&Peb->ProcessParameters->ImagePathName);
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 */
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);
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 */
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],
NTSTATUS
NTAPI
-LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PULONG Options)
+LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName, PPEB Peb, BOOLEAN SystemWide, BOOLEAN ReadAdvancedOptions)
{
- UNIMPLEMENTED;
- *Options = 0;
+ /* 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;
}
PPEB Peb = NtCurrentPeb();
BOOLEAN IsDotNetImage = FALSE;
BOOLEAN FreeCurDir = FALSE;
- //HKEY CompatKey;
+ //HANDLE CompatKey;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
//LPWSTR ImagePathBuffer;
ULONG ConfigSize;
UNICODE_STRING CurrentDirectory;
- ULONG ExecuteOptions;
+ HANDLE OptionsKey;
ULONG HeapFlags;
PIMAGE_NT_HEADERS NtHeader;
LPWSTR NtDllName = NULL;
- NTSTATUS Status;
+ NTSTATUS Status, ImportStatus;
NLSTABLEINFO NlsTable;
PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
PTEB Teb = NtCurrentTeb();
ULONG i;
PWSTR ImagePath;
ULONG DebugProcessHeapOnly = 0;
- WCHAR FullNtDllPath[MAX_PATH];
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 normalized */
- if (Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED)
+ /* 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);
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,
/* Normalize the parameters */
ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
- ProcessParameters = Peb->ProcessParameters;
if (ProcessParameters)
{
/* Save the Image and Command Line Names */
}
/* 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)
{
- DPRINT1("LDR: PID: 0x%x started - '%wZ'\n",
+ DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
Teb->ClientId.UniqueProcess,
&CommandLine);
}
}
/* 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 */
}
/* Allocate an Activation Context Stack */
- Status = RtlAllocateActivationContextStack((PVOID *)&Teb->ActivationContextStackPointer);
+ Status = RtlAllocateActivationContextStack(&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,
/* Reset DPH if requested */
if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
{
- RtlpDphGlobalFlags &= ~0x40;
+ RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
RtlpPageHeapEnabled = FALSE;
}
}
}
/* 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\\");
&ObjectAttributes);
/* Check if it exists */
- if (!NT_SUCCESS(Status))
- {
- /* It doesn't, so assume System32 */
- LdrpKnownDllObjectDirectory = NULL;
- RtlInitUnicodeString(&LdrpKnownDllPath, FullPath.Buffer);
- LdrpKnownDllPath.Length -= sizeof(WCHAR);
- }
- else
+ if (NT_SUCCESS(Status))
{
/* Open the Known DLLs Path */
+ RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
InitializeObjectAttributes(&ObjectAttributes,
&KnownDllString,
OBJ_CASE_INSENSITIVE,
}
}
+ /* 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)
{
else
{
/* We need a valid path */
+ DPRINT1("No valid DllPath was given!\n");
LdrpInitFailure(STATUS_INVALID_PARAMETER);
}
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,
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");
}
}
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
if (!ImageFileName.Buffer[0])
{
/* Use the same Base name */
- NtLdrEntry->BaseDllName = NtLdrEntry->BaseDllName;
+ NtLdrEntry->BaseDllName = NtLdrEntry->FullDllName;
}
else
{
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);
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))
if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
{
/* Load kernel32 and call BasePostImportInit... */
- DPRINT1("Unimplemented codepath!\n");
+ DPRINT("Unimplemented codepath!\n");
}
/* Walk the IAT and load all the DLLs */
- LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
+ ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
/* Check if relocation is needed */
if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
{
- DPRINT("LDR: Performing relocations\n");
- Status = LdrPerformRelocations(NtHeader, Peb->ImageBaseAddress);
+ 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("LdrPerformRelocations() failed\n");
+ 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 */
/* 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))
{
/* Check for Application Compatibility Goo */
//LdrQueryApplicationCompatibilityGoo(hKey);
- DPRINT1("Querying app compat hacks is missing!\n");
+ DPRINT("Querying app compat hacks is missing!\n");
}
/*
/* Check if we have a user-defined Post Process Routine */
if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
{
- DPRINT1("CP\n");
/* Call it */
Peb->PostProcessInitRoutine();
}
- ///* Close the key if we have one opened */
- //if (hKey) NtClose(hKey);
-DbgBreakPoint();
+ /* Close the key if we have one opened */
+ if (OptionsKey) NtClose(OptionsKey);
+
/* Return status */
return Status;
}
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)
_SEH2_TRY
{
/* Initialize the Process */
- LoaderStatus = LdrpInitializeProcess_(Context,
+ LoaderStatus = LdrpInitializeProcess(Context,
SystemArgument1);
/* Check for success and if MinimumStackCommit was requested */