/* 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( &module->EntryPointActivationContext, &ctx );
+ }
+ 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,
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:
}
}
- /* 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;
PWCHAR Buffer, BufEnd = NULL;
ULONG Length = 0;
WCHAR p;
- PWCHAR pp;
+ //PWCHAR pp;
/* Check if we don't have a search path */
if (!ActualSearchPath) *SearchPath = LdrpDefaultPath.Buffer;
{
/* Get character */
p = *ActualSearchPath;
- if (!(p) && (p == ';'))
+ if (!(p) || (p == ';'))
{
/* FIXME: We don't have a character, or is a semicolon.*/
/* 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
BufEnd = Buffer;
/* Update string position */
- pp = ActualSearchPath++;
+ //pp = ActualSearchPath++;
}
else
{
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' %d %d %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;
/* 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:
if (Flag)
/* Check if that was successful */
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 */
Flag = TRUE;
goto lookinhash;
}
-
+
/* FIXME: Warning, activation context missing */
/* NOTE: From here on down, everything looks good */
/* Check if it's in the process of being unloaded */
if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
-
+
/* The header is untrusted, use SEH */
_SEH2_TRY
{
{
/* Headers match too! Finally ask the kernel to compare mapped files */
Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase);
- if (!NT_SUCCESS(Status))
- {
- /* Almost identical, but not quite, keep trying */
- _SEH2_YIELD(continue;)
- }
- else
+ if (NT_SUCCESS(Status))
{
/* This is our entry!, unmap and return success */
*LdrEntry = CurEntry;
{
PPEB Peb = NtCurrentPeb();
NTSTATUS Status = STATUS_SUCCESS;
- PWCHAR p1, p2;
+ const WCHAR *p;
+ BOOLEAN GotExtension;
WCHAR c;
- WCHAR NameBuffer[266];
- LPWSTR RawDllName;
- UNICODE_STRING RawDllNameString;
+ 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;
- 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)
{
- c = *p1++;
+ c = *p--;
if (c == L'.')
{
- p2 = p1;
+ GotExtension = TRUE;
+ break;
}
else if (c == L'\\')
{
- p2 = NULL;
+ break;
}
}
- /* Save the Raw DLL Name */
- RawDllName = NameBuffer;
- if (DllName->Length >= sizeof(NameBuffer)) 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(UNICODE_NULL)) >=
return STATUS_NAME_TOO_LONG;
}
- /* FIXME: CLEAN THIS UP WITH Rtl String Functions */
- /* 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))
Redirected,
&LdrEntry);
if (!NT_SUCCESS(Status)) goto Quickie;
-
+
/* FIXME: Need to mark the DLL range for the stack DB */
//RtlpStkMarkDllRange(LdrEntry);
/* Cancel the load */
LdrpClearLoadInProgress();
-
+
/* Unload the DLL */
if (ShowSnaps)
{
//ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
//ShimLoadCallback(LdrEntry);
}
-
+
/* Run the init routine */
Status = LdrpRunInitializeRoutines(NULL);
if (!NT_SUCCESS(Status))