/* GLOBALS *******************************************************************/
-LIST_ENTRY LdrpUnloadHead;
PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache, LdrpGetModuleHandleCache;
-
-#define LDR_GET_HASH_ENTRY(x) (RtlUpcaseUnicodeChar((x)) & (LDR_HASH_TABLE_ENTRIES - 1))
+BOOLEAN g_ShimsEnabled;
/* FUNCTIONS *****************************************************************/
+/* NOTE: Remove those two once our actctx support becomes better */
+NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
+{
+ NTSTATUS status;
+ LDR_RESOURCE_INFO info;
+ IMAGE_RESOURCE_DATA_ENTRY *entry;
+
+ info.Type = (ULONG)RT_MANIFEST;
+ info.Name = (ULONG)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
+ info.Language = 0;
+ if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
+ {
+ ACTCTXW ctx;
+ ctx.cbSize = sizeof(ctx);
+ ctx.lpSource = NULL;
+ ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
+ ctx.hModule = module->DllBase;
+ ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
+ status = RtlCreateActivationContext(0, (PVOID)&ctx, 0, NULL, NULL, &module->EntryPointActivationContext);
+ }
+ return status;
+}
+
+NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fullname )
+{
+ static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
+ static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
+
+ ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
+ ACTCTX_SECTION_KEYED_DATA data;
+ UNICODE_STRING nameW;
+ NTSTATUS status;
+ SIZE_T needed, size = 1024;
+ WCHAR *p;
+
+ RtlInitUnicodeString( &nameW, libname );
+ data.cbSize = sizeof(data);
+ status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
+ ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
+ &nameW, &data );
+ if (status != STATUS_SUCCESS) return status;
+
+ for (;;)
+ {
+ if (!(info = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
+ {
+ status = STATUS_NO_MEMORY;
+ goto done;
+ }
+ status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
+ AssemblyDetailedInformationInActivationContext,
+ info, size, &needed );
+ if (status == STATUS_SUCCESS) break;
+ if (status != STATUS_BUFFER_TOO_SMALL) goto done;
+ RtlFreeHeap( RtlGetProcessHeap(), 0, info );
+ size = needed;
+ }
+
+ DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath);
+ DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName);
+ if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName)
+ {
+ status = STATUS_SXS_KEY_NOT_FOUND;
+ goto done;
+ }
+
+ if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
+ {
+ DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
+
+ p++;
+ if (_wcsnicmp( p, info->lpAssemblyDirectoryName, dirlen ) || wcsicmp( p + dirlen, dotManifestW ))
+ {
+ /* manifest name does not match directory name, so it's not a global
+ * windows/winsxs manifest; use the manifest directory name instead */
+ dirlen = p - info->lpAssemblyManifestPath;
+ needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
+
+ p = fullname;
+ /*if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
+ {
+ status = STATUS_NO_MEMORY;
+ goto done;
+ }*/
+ memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
+ p += dirlen;
+ wcscpy( p, libname );
+ goto done;
+ }
+ }
+
+ needed = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR) +
+ sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
+
+ p = fullname;
+ //if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
+ //{
+ //status = STATUS_NO_MEMORY;
+ //goto done;
+ //}
+ wcscpy( p, SharedUserData->NtSystemRoot );
+ p += wcslen(p);
+ memcpy( p, winsxsW, sizeof(winsxsW) );
+ p += sizeof(winsxsW) / sizeof(WCHAR);
+ memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
+ p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
+ *p++ = '\\';
+ wcscpy( p, libname );
+
+done:
+ RtlFreeHeap( RtlGetProcessHeap(), 0, info );
+ RtlReleaseActivationContext( data.hActCtx );
+ DPRINT("%S\n", fullname);
+ return status;
+}
+
+
+NTSTATUS
+NTAPI
+LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut,
+ IN ULONG Length)
+{
+ /* Sanity checks */
+ ASSERT(StringOut);
+ ASSERT(Length <= UNICODE_STRING_MAX_BYTES);
+
+ /* Assume failure */
+ StringOut->Length = 0;
+
+ /* Make sure it's not mis-aligned */
+ if (Length & 1)
+ {
+ /* Fail */
+ StringOut->Buffer = NULL;
+ StringOut->MaximumLength = 0;
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Allocate the string*/
+ StringOut->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ StringOut->Length + sizeof(WCHAR));
+ if (!StringOut->Buffer)
+ {
+ /* Fail */
+ StringOut->MaximumLength = 0;
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Null-terminate it */
+ StringOut->Buffer[StringOut->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ /* Check if this is a maximum-sized string */
+ if (StringOut->Length != UNICODE_STRING_MAX_BYTES)
+ {
+ /* It's not, so set the maximum length to be one char more */
+ StringOut->MaximumLength = StringOut->Length + sizeof(UNICODE_NULL);
+ }
+ else
+ {
+ /* The length is already the maximum possible */
+ StringOut->MaximumLength = UNICODE_STRING_MAX_BYTES;
+ }
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn)
+{
+ ASSERT(StringIn != NULL);
+
+ /* If Buffer is not NULL - free it */
+ if (StringIn->Buffer)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn->Buffer);
+ }
+
+ /* Zero it out */
+ RtlInitEmptyUnicodeString(StringIn, NULL, 0);
+}
BOOLEAN
NTAPI
LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint,
OUT PUNICODE_STRING UpdateString)
{
PIMAGE_BOUND_FORWARDER_REF NewImportForwarder;
-
-
PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry;
PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
PIMAGE_THUNK_DATA FirstThunk;
/* Show snaps */
if (ShowSnaps)
{
- DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount);
+ DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount);
}
}
/* Show snaps */
if (ShowSnaps)
{
- DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount);
+ DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount);
}
}
/* Show snaps */
if (ShowSnaps)
{
- DPRINT1("LDR: Flags %d %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount);
+ DPRINT1("LDR: Flags %lu %wZ (%lx)\n", Flags, ImportNameUnic, Entry->LoadCount);
}
}
/* Protect against invalid pointers */
_SEH2_TRY
{
- /* Make sure it's valid and we have an array */
- Array = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
- if ((TlsDirectory) && (Array))
+ /* Make sure it's valid */
+ if (TlsDirectory)
{
- /* Display debug */
- if (ShowSnaps)
- {
- DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
- BaseAddress, TlsDirectory, Array);
- }
-
- /* Loop the array */
- while (*Array)
+ /* Get the array */
+ Array = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
+ if (Array)
{
- /* Get the TLS Entrypoint */
- Callback = *Array++;
-
/* Display debug */
if (ShowSnaps)
{
- DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
- BaseAddress, Callback);
+ DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
+ BaseAddress, TlsDirectory, Array);
}
- /* Call it */
- LdrpCallInitRoutine((PDLL_INIT_ROUTINE)Callback,
- BaseAddress,
- Reason,
- NULL);
+ /* Loop the array */
+ while (*Array)
+ {
+ /* Get the TLS Entrypoint */
+ Callback = *Array++;
+
+ /* Display debug */
+ if (ShowSnaps)
+ {
+ DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
+ BaseAddress, Callback);
+ }
+
+ /* Call it */
+ LdrpCallInitRoutine((PDLL_INIT_ROUTINE)Callback,
+ BaseAddress,
+ Reason,
+ NULL);
+ }
}
}
}
DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
&FullName);
}
-
+
/* Failure case, close section handle */
NtClose(*SectionHandle);
*SectionHandle = NULL;
PWCHAR NameBuffer, p1, p2 = 0;
ULONG Length;
ULONG BufSize = 500;
+ NTSTATUS Status;
/* Allocate space for full DLL name */
FullDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize + sizeof(UNICODE_NULL));
if (!Length || Length > BufSize)
{
- if (ShowSnaps)
+ /* HACK: Try to find active context dll */
+ Status = find_actctx_dll(DllName, FullDllName->Buffer);
+ if(Status == STATUS_SUCCESS)
{
- DPRINT1("LDR: LdrResolveDllName - Unable to find ");
- DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer);
+ Length = wcslen(FullDllName->Buffer) * sizeof(WCHAR);
+ DPRINT1("found %S for %S\n", FullDllName->Buffer, DllName);
}
+ else
+ {
+ /* NOTE: This code should remain after removing the hack */
+ if (ShowSnaps)
+ {
+ DPRINT1("LDR: LdrResolveDllName - Unable to find ");
+ DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer);
+ }
- RtlFreeUnicodeString(FullDllName);
- return FALSE;
+ RtlFreeUnicodeString(FullDllName);
+ return FALSE;
+ }
}
/* Construct full DLL name */
return (PVOID)EntryPoint;
}
-/* NOTE: This function is broken, wrong number of parameters, no SxS, etc */
-HANDLE
+/* NOTE: This function is partially missing SxS */
+NTSTATUS
NTAPI
LdrpCheckForKnownDll(PWSTR DllName,
PUNICODE_STRING FullDllName,
- PUNICODE_STRING BaseDllName)
+ PUNICODE_STRING BaseDllName,
+ HANDLE *SectionHandle)
{
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Section = NULL;
PCHAR p1;
PWCHAR p2;
+ /* Zero initialize provided parameters */
+ if (SectionHandle) *SectionHandle = 0;
+
+ if (FullDllName)
+ {
+ FullDllName->Length = 0;
+ FullDllName->MaximumLength = 0;
+ FullDllName->Buffer = NULL;
+ }
+
+ if (BaseDllName)
+ {
+ BaseDllName->Length = 0;
+ BaseDllName->MaximumLength = 0;
+ BaseDllName->Buffer = NULL;
+ }
+
+ /* If any of these three params are missing then fail */
+ if (!SectionHandle || !FullDllName || !BaseDllName)
+ return STATUS_INVALID_PARAMETER;
+
+ /* Check the Loader Lock */
+ LdrpEnsureLoaderLockIsHeld();
+
/* Upgrade DllName to a unicode string */
RtlInitUnicodeString(&DllNameUnic, DllName);
+ /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
+
/* Get the activation context */
Status = RtlFindActivationContextSectionString(0,
NULL,
if (Status == STATUS_SXS_SECTION_NOT_FOUND ||
Status == STATUS_SXS_KEY_NOT_FOUND)
{
+ /* NOTE: Here it's beneficial to allocate one big unicode string
+ using LdrpAllocateUnicodeString instead of fragmenting the heap
+ with two allocations as it's done now. */
+
/* Set up BaseDllName */
BaseDllName->Length = DllNameUnic.Length;
BaseDllName->MaximumLength = DllNameUnic.MaximumLength;
BaseDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
DllNameUnic.MaximumLength);
- if (!BaseDllName->Buffer) return NULL;
+ if (!BaseDllName->Buffer)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Failure;
+ }
/* Copy the contents there */
RtlMoveMemory(BaseDllName->Buffer, DllNameUnic.Buffer, DllNameUnic.MaximumLength);
FullDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullDllName->MaximumLength);
if (!FullDllName->Buffer)
{
- /* Free base name and fail */
- RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName->Buffer);
- return NULL;
+ Status = STATUS_NO_MEMORY;
+ goto Failure;
}
RtlMoveMemory(FullDllName->Buffer, LdrpKnownDllPath.Buffer, LdrpKnownDllPath.Length);
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
- /* Opening failed, free resources */
- Section = NULL;
- RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName->Buffer);
- RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName->Buffer);
+ /* Clear status in case it was just not found */
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) Status = STATUS_SUCCESS;
+ goto Failure;
}
+
+ /* Pass section handle to the caller and return success */
+ *SectionHandle = Section;
+ return STATUS_SUCCESS;
}
- else
- {
- if (!NT_SUCCESS(Status)) Section = NULL;
- }
- /* Return section handle */
- return Section;
+Failure:
+ /* Close section object if it was opened */
+ if (Section) NtClose(Section);
+
+ /* Free string resources */
+ if (BaseDllName->Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, BaseDllName->Buffer);
+ if (FullDllName->Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, FullDllName->Buffer);
+
+ /* Return status */
+ return Status;
}
NTSTATUS
}
/* Try to find a Known DLL */
- SectionHandle = LdrpCheckForKnownDll(DllName,
- &FullDllName,
- &BaseDllName);
+ Status = LdrpCheckForKnownDll(DllName,
+ &FullDllName,
+ &BaseDllName,
+ &SectionHandle);
+
+ if (!NT_SUCCESS(Status) && (Status != STATUS_DLL_NOT_FOUND))
+ {
+ /* Failure */
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
+ __FUNCTION__,
+ DllName,
+ Status);
+
+ return Status;
+ }
}
SkipCheck:
/* 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
*/
ImageBase = (ULONG_PTR)NtHeaders->OptionalHeader.ImageBase;
ImageEnd = ImageBase + ViewSize;
- DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%p -> %p)\n", DllName, ImageBase, ViewBase);
+ DPRINT1("LDR: LdrpMapDll Relocating Image Name %ws (%lu -> %p)\n", DllName, ImageBase, ViewBase);
/* Scan all the modules */
ListHead = &Peb->Ldr->InLoadOrderModuleList;
}
}
- /* Check if this was a non-relocatable DLL or a known dll */
- if (!RelocatableDll && KnownDll)
+ /* Known DLLs are not allowed to be relocated */
+ if (KnownDll && !RelocatableDll)
{
/* Setup for hard error */
HardErrorParameters[0] = (ULONG_PTR)&IllegalDll;
/* Stuff the image name in the TIB, for the debugger */
ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer;
-
+#if 0
/* Map the DLL */
Status = NtMapViewOfSection(SectionHandle,
NtCurrentProcess(),
ViewShare,
0,
PAGE_READWRITE);
-
+#endif
/* Restore */
Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
/* Stuff the image name in the TIB, for the debugger */
ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer;
-
+#if 0
/* Map the DLL */
Status = NtMapViewOfSection(SectionHandle,
NtCurrentProcess(),
ViewShare,
0,
PAGE_READWRITE);
-
+#endif
/* Restore */
Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
{
PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
PIMAGE_NT_HEADERS NtHeader;
- DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress, NtHeader);
/* Make sure the header is valid */
NtHeader = RtlImageNtHeader(BaseAddress);
+ DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress, NtHeader);
+
if (NtHeader)
{
/* Allocate an entry */
/* Insert into hash table */
i = LDR_GET_HASH_ENTRY(LdrEntry->BaseDllName.Buffer[0]);
InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks);
-
+
/* Insert into other lists */
InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks);
InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderModuleList);
return FALSE;
}
+NTSTATUS
+NTAPI
+LdrpResolveFullName(IN PUNICODE_STRING OriginalName,
+ IN PUNICODE_STRING PathName,
+ IN PUNICODE_STRING FullPathName,
+ IN PUNICODE_STRING *ExpandedName)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+// RTL_PATH_TYPE PathType;
+// BOOLEAN InvalidName;
+ ULONG Length;
+
+ /* Display debug output if snaps are on */
+ if (ShowSnaps)
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Expanding full name of %wZ\n",
+ __FUNCTION__,
+ OriginalName);
+ }
+
+ /* FIXME: Lock the PEB */
+ //RtlEnterCriticalSection(&FastPebLock);
+#if 0
+ /* Get the path name */
+ Length = RtlGetFullPathName_Ustr(OriginalName,
+ PathName->Length,
+ PathName->Buffer,
+ NULL,
+ &InvalidName,
+ &PathType);
+#else
+ Length = 0;
+#endif
+ if (!(Length) || (Length > UNICODE_STRING_MAX_BYTES))
+ {
+ /* Fail */
+ Status = STATUS_NAME_TOO_LONG;
+ goto Quickie;
+ }
+
+ /* Check if the length hasn't changed */
+ if (Length <= PathName->Length)
+ {
+ /* Return the same thing */
+ *ExpandedName = PathName;
+ PathName->Length = (USHORT)Length;
+ goto Quickie;
+ }
+
+ /* Sanity check */
+ ASSERT(Length >= sizeof(WCHAR));
+
+ /* Allocate a string */
+ Status = LdrpAllocateUnicodeString(FullPathName, Length - sizeof(WCHAR));
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Now get the full path again */
+#if 0
+ Length = RtlGetFullPathName_Ustr(OriginalName,
+ FullPathName->Length,
+ FullPathName->Buffer,
+ NULL,
+ &InvalidName,
+ &PathType);
+#else
+ Length = 0;
+#endif
+ if (!(Length) || (Length > FullPathName->Length))
+ {
+ /* Fail */
+ LdrpFreeUnicodeString(FullPathName);
+ Status = STATUS_NAME_TOO_LONG;
+ }
+ else
+ {
+ /* Return the expanded name */
+ *ExpandedName = FullPathName;
+ FullPathName->Length = (USHORT)Length;
+ }
+
+Quickie:
+ /* FIXME: Unlock the PEB */
+ //RtlLeaveCriticalSection(&FastPebLock);
+
+ /* Display debug output if snaps are on */
+ if (ShowSnaps)
+ {
+ /* Check which output to use -- failure or success */
+ if (NT_SUCCESS(Status))
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Expanded to %wZ\n",
+ __FUNCTION__,
+ *ExpandedName);
+ }
+ else
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Failed to expand %wZ; 0x%08x\n",
+ __FUNCTION__,
+ OriginalName,
+ Status);
+ }
+ }
+
+ /* If we failed, return NULL */
+ if (!NT_SUCCESS(Status)) *ExpandedName = NULL;
+
+ /* Return status */
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+LdrpSearchPath(IN PWCHAR *SearchPath,
+ IN PWCHAR DllName,
+ IN PUNICODE_STRING PathName,
+ IN PUNICODE_STRING FullPathName,
+ IN PUNICODE_STRING *ExpandedName)
+{
+ BOOLEAN TryAgain = FALSE;
+ PWCHAR ActualSearchPath = *SearchPath;
+ UNICODE_STRING TestName;
+ NTSTATUS Status;
+ PWCHAR Buffer, BufEnd = NULL;
+ ULONG Length = 0;
+ WCHAR p;
+ //PWCHAR pp;
+
+ /* Check if we don't have a search path */
+ if (!ActualSearchPath) *SearchPath = LdrpDefaultPath.Buffer;
+
+ /* Display debug output if snaps are on */
+ if (ShowSnaps)
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Looking for %ws in %ws\n",
+ __FUNCTION__,
+ DllName,
+ *SearchPath);
+ }
+
+ /* Check if we're dealing with a relative path */
+ if (RtlDetermineDosPathNameType_U(DllName) != RtlPathTypeRelative)
+ {
+ /* Good, we're not. Create the name string */
+ Status = RtlInitUnicodeStringEx(&TestName, DllName);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Make sure it exists */
+ #if 0
+ if (!RtlDoesFileExists_UstrEx(&TestName, TRUE))
+ {
+ /* It doesn't, fail */
+ Status = STATUS_DLL_NOT_FOUND;
+ goto Quickie;
+ }
+ #endif
+
+ /* Resolve the full name */
+ Status = LdrpResolveFullName(&TestName,
+ PathName,
+ FullPathName,
+ ExpandedName);
+ goto Quickie;
+ }
+
+ /* FIXME: Handle relative case semicolon-lookup here */
+
+ /* Calculate length */
+ Length += (ULONG)wcslen(DllName) + sizeof(UNICODE_NULL);
+ if (Length > UNICODE_STRING_MAX_CHARS)
+ {
+ /* Too long, fail */
+ Status = STATUS_NAME_TOO_LONG;
+ goto Quickie;
+ }
+
+ /* Allocate buffer */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
+ if (!Buffer)
+ {
+ /* Fail */
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* FIXME: Setup TestName here */
+ Status = STATUS_NOT_FOUND;
+
+ /* Start loop */
+ do
+ {
+ /* Get character */
+ p = *ActualSearchPath;
+ if (!(p) || (p == ';'))
+ {
+ /* FIXME: We don't have a character, or is a semicolon.*/
+
+ /* Display debug output if snaps are on */
+ if (ShowSnaps)
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Looking for %ws\n",
+ __FUNCTION__,
+ Buffer);
+ }
+
+ /* Sanity check */
+ TestName.Length = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR);
+#if 0
+ ASSERT(TestName.Length < TestName.MaximumLength);
+#endif
+
+ /* Check if the file exists */
+ #if 0
+ if (RtlDoesFileExists_UstrEx(&TestName, FALSE))
+ #endif
+ {
+ /* It does. Reallocate the buffer */
+ TestName.MaximumLength = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR) + sizeof(WCHAR);
+ TestName.Buffer = RtlReAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ Buffer,
+ TestName.MaximumLength);
+ if (!TestName.Buffer)
+ {
+ /* Keep the old one */
+ TestName.Buffer = Buffer;
+ }
+ else
+ {
+ /* Update buffer */
+ Buffer = TestName.Buffer;
+ }
+
+ /* Make sure we have a buffer at least */
+ ASSERT(TestName.Buffer);
+
+ /* Resolve the name */
+ *SearchPath = ActualSearchPath++;
+ Status = LdrpResolveFullName(&TestName,
+ PathName,
+ FullPathName,
+ ExpandedName);
+ break;
+ }
+
+ /* Update buffer end */
+ BufEnd = Buffer;
+
+ /* Update string position */
+ //pp = ActualSearchPath++;
+ }
+ else
+ {
+ /* Otherwise, write the character */
+ *BufEnd = p;
+ BufEnd++;
+ }
+
+ /* Check if the string is empty, meaning we're done */
+ if (!(*ActualSearchPath)) TryAgain = TRUE;
+
+ /* Advance in the string */
+ ActualSearchPath++;
+ } while (!TryAgain);
+
+ /* Check if we had a buffer and free it */
+ if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+
+Quickie:
+ /* Check if we got here through failure */
+ if (!NT_SUCCESS(Status)) *ExpandedName = NULL;
+
+ /* Display debug output if snaps are on */
+ if (ShowSnaps)
+ {
+ /* Check which output to use -- failure or success */
+ if (NT_SUCCESS(Status))
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Returning %wZ\n",
+ __FUNCTION__,
+ *ExpandedName);
+ }
+ else
+ {
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
+ __FUNCTION__,
+ DllName,
+ ActualSearchPath,
+ Status);
+ }
+ }
+
+ /* Return status */
+ return Status;
+}
+
+
+/* NOTE: This function is b0rked and in the process of being slowly unf*cked */
BOOLEAN
NTAPI
LdrpCheckForLoadedDll(IN PWSTR DllPath,
PVOID ViewBase = NULL;
SIZE_T ViewSize = 0;
PIMAGE_NT_HEADERS NtHeader, NtHeader2;
-
- DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath, DllName, Flag, RedirectedDll, LdrEntry);
+ DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry);
/* Check if a dll name was provided */
- if (!DllName->Buffer || !DllName->Buffer[0]) return FALSE;
+ if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE;
+
+ /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
+ /* FIXME: Warning, code does not support redirection at all */
/* Look in the hash table if flag was set */
lookinhash:
while (*wc)
{
/* Check for a slash in the current position*/
- if (*wc == L'\\' || *wc == L'/')
+ if ((*wc == L'\\') || (*wc == L'/'))
{
/* Found the slash, so dll name contains path */
FullPath = TRUE;
/* Setup full dll name string */
FullDllName.Buffer = NameBuf;
+ /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer,
DllName->Buffer,
NULL,
NULL);
/* Check if that was successful */
- if (!Length || Length > sizeof(NameBuf) - sizeof(UNICODE_NULL))
+ if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL))))
{
+ /* HACK: Try to find active context dll */
+ Status = find_actctx_dll(DllName->Buffer, FullDllName.Buffer);
+ if(Status == STATUS_SUCCESS)
+ {
+ Length = wcslen(FullDllName.Buffer) * sizeof(WCHAR);
+ DPRINT1("found %S for %S\n", FullDllName.Buffer, DllName->Buffer);
+ }
+ else
+ {
+
if (ShowSnaps)
{
DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
/* Return failure */
return FALSE;
+ }
}
/* Full dll name is found */
goto lookinhash;
}
- /* Now go through the InLoadOrder module list */
+ /* FIXME: Warning, activation context missing */
+ /* NOTE: From here on down, everything looks good */
+
+ /* Loop the module list */
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
ListEntry = ListHead->Flink;
-
while (ListEntry != ListHead)
{
- /* Get the containing record of the current entry and advance to the next one */
- CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+ /* Get the current entry and advance to the next one */
+ CurEntry = CONTAINING_RECORD(ListEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
ListEntry = ListEntry->Flink;
- /* Check if it's already being unloaded */
+ /* Check if it's being unloaded */
if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
/* Check if name matches */
{
/* Found it */
*LdrEntry = CurEntry;
-
- /* Find activation context */
- //Status = RtlFindActivationContextSectionString(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, DllName, NULL);
- //if (!NT_SUCCESS(Status))
- // return FALSE;
- //else
return TRUE;
}
}
- /* The DLL was not found in the load order modules list. Perform a complex check */
-
/* Convert given path to NT path */
if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer,
&NtPathName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
-
Status = NtOpenFile(&FileHandle,
SYNCHRONIZE | FILE_EXECUTE,
&ObjectAttributes,
/* Create a section for this file */
Status = NtCreateSection(&SectionHandle,
- SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
+ SECTION_MAP_READ |
+ SECTION_MAP_EXECUTE |
+ SECTION_MAP_WRITE,
NULL,
NULL,
PAGE_EXECUTE,
ViewShare,
0,
PAGE_EXECUTE);
+
/* Close section handle */
NtClose(SectionHandle);
if (!NT_SUCCESS(Status)) return FALSE;
/* Get pointer to the NT header of this section */
- NtHeader = RtlImageNtHeader(ViewBase);
- if (!NtHeader)
+ Status = RtlImageNtHeaderEx(0, ViewBase, ViewSize, &NtHeader);
+ if (!(NT_SUCCESS(Status)) || !(NtHeader))
{
/* Unmap the section and fail */
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
return FALSE;
}
- /* Go through the list of modules */
+ /* Go through the list of modules again */
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
ListEntry = ListHead->Flink;
-
while (ListEntry != ListHead)
{
- CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+ /* Get the current entry and advance to the next one */
+ CurEntry = CONTAINING_RECORD(ListEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
ListEntry = ListEntry->Flink;
- /* Check if it's already being unloaded */
+ /* Check if it's in the process of being unloaded */
if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
+ /* The header is untrusted, use SEH */
_SEH2_TRY
{
/* Check if timedate stamp and sizes match */
- if (CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp &&
- CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage)
+ if ((CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp) &&
+ (CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage))
{
/* Time, date and size match. Let's compare their headers */
NtHeader2 = RtlImageNtHeader(CurEntry->DllBase);
-
if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS)))
{
/* Headers match too! Finally ask the kernel to compare mapped files */
Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase);
-
- if (!NT_SUCCESS(Status))
- {
- _SEH2_YIELD(continue;)
- }
- else
+ if (NT_SUCCESS(Status))
{
- /* This is our entry! */
+ /* This is our entry!, unmap and return success */
*LdrEntry = CurEntry;
-
- /* Unmap the section */
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
-
_SEH2_YIELD(return TRUE;)
}
}
_SEH2_END;
}
- /* Unmap the section */
+ /* Unmap the section and fail */
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
-
return FALSE;
}
{
PPEB Peb = NtCurrentPeb();
NTSTATUS Status = STATUS_SUCCESS;
- PWCHAR p1, p2;
- WCHAR NameBuffer[266];
- LPWSTR RawDllName;
- UNICODE_STRING RawDllNameString;
+ const WCHAR *p;
+ BOOLEAN GotExtension;
+ WCHAR c;
+ WCHAR NameBuffer[MAX_PATH + 6];
+ UNICODE_STRING RawDllName;
PLDR_DATA_TABLE_ENTRY LdrEntry;
BOOLEAN InInit = LdrpInLdrInit;
- /* Find the name without the extension */
- p1 = DllName->Buffer;
-StartLoop:
- p2 = NULL;
- while (*p1)
+ /* Save the Raw DLL Name */
+ if (DllName->Length >= sizeof(NameBuffer)) return STATUS_NAME_TOO_LONG;
+ RtlInitEmptyUnicodeString(&RawDllName, NameBuffer, sizeof(NameBuffer));
+ RtlCopyUnicodeString(&RawDllName, DllName);
+
+ /* Find the extension, if present */
+ p = DllName->Buffer + DllName->Length / sizeof(WCHAR) - 1;
+ GotExtension = FALSE;
+ while (p >= DllName->Buffer)
{
- if (*p1++ == L'.')
+ c = *p--;
+ if (c == L'.')
{
- p2 = p1;
+ GotExtension = TRUE;
+ break;
}
- else if (*p1 == L'\\')
+ else if (c == L'\\')
{
- goto StartLoop;
+ break;
}
}
- /* 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 == '\\')
+ /* If no extension was found, add the default extension */
+ if (!GotExtension)
{
/* Check that we have space to add one */
- if (DllName->Length + LdrApiDefaultExtension.Length >= sizeof(NameBuffer))
+ if ((DllName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >=
+ sizeof(NameBuffer))
{
/* No space to add the extension */
+ DbgPrintEx(81, //DPFLTR_LDR_ID,
+ 0,
+ "LDR: %s - Dll name missing extension; with extension "
+ "added the name is too long\n"
+ " DllName: (@ %p) \"%wZ\"\n"
+ " DllName->Length: %u\n",
+ __FUNCTION__,
+ DllName,
+ DllName,
+ DllName->Length);
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;
+ /* Add it. Needs to be null terminated, thus the length check above */
+ (VOID)RtlAppendUnicodeStringToString(&RawDllName,
+ &LdrApiDefaultExtension);
}
- /* 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,
+ DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
+ &RawDllName,
DllPath ? DllPath : L"");
}
/* Check if the DLL is already loaded */
if (!LdrpCheckForLoadedDll(DllPath,
- &RawDllNameString,
+ &RawDllName,
FALSE,
Redirected,
&LdrEntry))
&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: Need to mark the DLL range for the stack DB */
+ //RtlpStkMarkDllRange(LdrEntry);
- /* FIXME Mark the DLL Ranges for Stack Traces later */
+ /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
+ if ((DllCharacteristics) &&
+ (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
+ {
+ /* This is not a DLL, so remove such data */
+ LdrEntry->EntryPoint = NULL;
+ LdrEntry->Flags &= ~LDRP_IMAGE_DLL;
+ }
/* Make sure it's a DLL */
if (LdrEntry->Flags & LDRP_IMAGE_DLL)
InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
&LdrEntry->InInitializationOrderModuleList);
- /* Cancel the load and unload the DLL */
+ /* Cancel the load */
LdrpClearLoadInProgress();
+
+ /* Unload the DLL */
+ if (ShowSnaps)
+ {
+ DbgPrint("LDR: Unloading %wZ due to error %x walking "
+ "import descriptors",
+ DllName,
+ Status);
+ }
LdrUnloadDll(LdrEntry->DllBase);
/* Return the error */
if (CallInit && LdrpLdrDatabaseIsSetup)
{
/* FIXME: Notify Shim Engine */
+ if (g_ShimsEnabled)
+ {
+ /* Call it */
+ //ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
+ //ShimLoadCallback(LdrEntry);
+ }
/* Run the init routine */
Status = LdrpRunInitializeRoutines(NULL);
if (!NT_SUCCESS(Status))
{
/* Failed, unload the DLL */
+ if (ShowSnaps)
+ {
+ DbgPrint("LDR: Unloading %wZ because either its init "
+ "routine or one of its static imports failed; "
+ "status = 0x%08lx\n",
+ DllName,
+ Status);
+ }
LdrUnloadDll(LdrEntry->DllBase);
}
}
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 != 0xFFFF)
- {
- /* 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 */
- LdrpCallInitRoutine(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) RtlLeaveCriticalSection(Peb->LoaderLock);
-
- /* FIXME: Rundown the Hotpatch data, if present */
-
- /* Return to caller */
- return Status;
-}
-
ULONG
NTAPI
LdrpClearLoadInProgress(VOID)
return ModulesCount;
}
-VOID
-NTAPI
-LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn)
-{
- ASSERT(StringIn != NULL);
-
- /* If Buffer is not NULL - free it */
- if (StringIn->Buffer)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, StringIn->Buffer);
- }
-
- /* Zero it out */
- RtlInitEmptyUnicodeString(StringIn, NULL, 0);
-}
-
/* EOF */