reactos/reactos/dll/ntdll/ldr/ldrapi.c

1196 lines
36 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS NT User Mode Library
* FILE: dll/ntdll/ldr/ldrapi.c
* PURPOSE: PE Loader Public APIs
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntdll.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
LONG LdrpLoaderLockAcquisitonCount;
BOOLEAN LdrpShowRecursiveLoads, LdrpBreakOnRecursiveDllLoads;
2011-06-24 21:30:09 +00:00
UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL");
/* FUNCTIONS *****************************************************************/
ULONG_PTR
FORCEINLINE
LdrpMakeCookie(VOID)
{
/* Generate a cookie */
return (((ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) |
_InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrUnlockLoaderLock(IN ULONG Flags,
IN ULONG Cookie OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie);
/* Check for valid flags */
if (Flags & ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* Flags are invalid, check how to fail */
if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
}
/* A normal failure */
return STATUS_INVALID_PARAMETER_1;
}
/* If we don't have a cookie, just return */
if (!Cookie) return STATUS_SUCCESS;
/* Validate the cookie */
if ((Cookie & 0xF0000000) ||
((Cookie >> 16) ^ ((ULONG)(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF)))
{
DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
/* Invalid cookie, check how to fail */
if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
}
/* A normal failure */
return STATUS_INVALID_PARAMETER_2;
}
/* Ready to release the lock */
if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* Do a direct leave */
RtlLeaveCriticalSection(&LdrpLoaderLock);
}
else
{
/* Wrap this in SEH, since we're not supposed to raise */
_SEH2_TRY
{
/* Leave the lock */
RtlLeaveCriticalSection(&LdrpLoaderLock);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* We should use the LDR Filter instead */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* All done */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrLockLoaderLock(IN ULONG Flags,
OUT PULONG Disposition OPTIONAL,
OUT PULONG_PTR Cookie OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN InInit = LdrpInLdrInit;
DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Disposition, Cookie);
/* Zero out the outputs */
if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID;
if (Cookie) *Cookie = 0;
/* Validate the flags */
if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS |
LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY))
{
/* Flags are invalid, check how to fail */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
}
/* A normal failure */
return STATUS_INVALID_PARAMETER_1;
}
/* Make sure we got a cookie */
if (!Cookie)
{
/* No cookie check how to fail */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_3);
}
/* A normal failure */
return STATUS_INVALID_PARAMETER_3;
}
/* Do or Do Not. There is no Try */
ASSERT((Disposition != NULL) || !(Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY));
/* If the flag is set, make sure we have a valid pointer to use */
if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Disposition))
{
/* No pointer to return the data to */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
}
/* Fail */
return STATUS_INVALID_PARAMETER_2;
}
/* Return now if we are in the init phase */
if (InInit) return STATUS_SUCCESS;
/* Check what locking semantic to use */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
{
/* Check if we should enter or simply try */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
{
/* Do a try */
if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
{
/* It's locked */
*Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
}
else
{
/* It worked */
*Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
*Cookie = LdrpMakeCookie();
}
}
else
{
/* Do a enter */
RtlEnterCriticalSection(&LdrpLoaderLock);
/* See if result was requested */
if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
*Cookie = LdrpMakeCookie();
}
}
else
{
/* Wrap this in SEH, since we're not supposed to raise */
_SEH2_TRY
{
/* Check if we should enter or simply try */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
{
/* Do a try */
if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
{
/* It's locked */
*Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
}
else
{
/* It worked */
*Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
*Cookie = LdrpMakeCookie();
}
}
else
{
/* Do an enter */
RtlEnterCriticalSection(&LdrpLoaderLock);
/* See if result was requested */
if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
*Cookie = LdrpMakeCookie();
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* We should use the LDR Filter instead */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* Return status */
return Status;
}
2011-06-24 21:30:09 +00:00
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *BaseAddress)
{
WCHAR StringBuffer[MAX_PATH];
UNICODE_STRING DllString1, DllString2;
BOOLEAN RedirectedDll = FALSE;
NTSTATUS Status;
ULONG Cookie;
PUNICODE_STRING OldTldDll;
PTEB Teb = NtCurrentTeb();
/* Initialize the strings */
RtlInitEmptyUnicodeString(&DllString2, NULL, 0);
2011-06-24 21:30:09 +00:00
DllString1.Buffer = StringBuffer;
DllString1.Length = 0;
DllString1.MaximumLength = sizeof(StringBuffer);
/* Check if the SxS Assemblies specify another file */
Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
DllName,
&LdrApiDefaultExtension,
&DllString1,
&DllString2,
&DllName,
NULL,
NULL,
NULL);
/* Check success */
if (NT_SUCCESS(Status))
{
/* Let Ldrp know */
RedirectedDll = TRUE;
}
else if (Status != STATUS_SXS_KEY_NOT_FOUND)
{
/* Unrecoverable SxS failure; did we get a string? */
if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
return Status;
2011-06-24 21:30:09 +00:00
}
/* Lock the loader lock */
LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
/* Check if there's a TLD DLL being loaded */
OldTldDll = LdrpTopLevelDllBeingLoaded;
if (OldTldDll)
2011-06-24 21:30:09 +00:00
{
/* This is a recursive load, do something about it? */
if ((ShowSnaps) || (LdrpShowRecursiveLoads) || (LdrpBreakOnRecursiveDllLoads))
2011-06-24 21:30:09 +00:00
{
/* Print out debug messages */
DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
Teb->RealClientId.UniqueProcess,
Teb->RealClientId.UniqueThread);
DPRINT1("[%lx, %lx] Previous DLL being loaded \"%wZ\"\n",
Teb->RealClientId.UniqueProcess,
Teb->RealClientId.UniqueThread,
OldTldDll);
DPRINT1("[%lx, %lx] DLL being requested \"%wZ\"\n",
Teb->RealClientId.UniqueProcess,
Teb->RealClientId.UniqueThread,
DllName);
/* Was it initializing too? */
if (!LdrpCurrentDllInitializer)
{
DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n",
Teb->RealClientId.UniqueProcess,
Teb->RealClientId.UniqueThread);
}
else
{
DPRINT1("[%lx, %lx] DLL whose initializer was currently running \"%wZ\"\n",
Teb->ClientId.UniqueProcess,
Teb->ClientId.UniqueThread,
&LdrpCurrentDllInitializer->BaseDllName);
}
}
}
/* Set this one as the TLD DLL being loaded*/
LdrpTopLevelDllBeingLoaded = DllName;
/* Load the DLL */
Status = LdrpLoadDll(RedirectedDll,
SearchPath,
DllCharacteristics,
DllName,
BaseAddress,
TRUE);
if (NT_SUCCESS(Status))
{
Status = STATUS_SUCCESS;
}
else if ((Status != STATUS_NO_SUCH_FILE) &&
(Status != STATUS_DLL_NOT_FOUND) &&
(Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
(Status != STATUS_DLL_INIT_FAILED))
{
// 85 == DPFLTR_LDR_ID;
DbgPrintEx(85,
DPFLTR_WARNING_LEVEL,
"LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
__FUNCTION__,
DllName,
Status);
}
2011-06-24 21:30:09 +00:00
/* Restore the old TLD DLL */
LdrpTopLevelDllBeingLoaded = OldTldDll;
/* Release the lock */
LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
/* Do we have a redirect string? */
if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
/* Return */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrFindEntryForAddress(PVOID Address,
PLDR_DATA_TABLE_ENTRY *Module)
{
PLIST_ENTRY ListHead, NextEntry;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PIMAGE_NT_HEADERS NtHeader;
PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr;
ULONG_PTR DllBase, DllEnd;
DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
/* Nothing to do */
if (!Ldr) return STATUS_NO_MORE_ENTRIES;
/* Get the current entry */
LdrEntry = Ldr->EntryInProgress;
if (LdrEntry)
{
/* Get the NT Headers */
NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
if (NtHeader)
{
/* Get the Image Base */
DllBase = (ULONG_PTR)LdrEntry->DllBase;
DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
/* Check if they match */
if (((ULONG_PTR)Address >= DllBase) &&
((ULONG_PTR)Address < DllEnd))
{
/* Return it */
*Module = LdrEntry;
return STATUS_SUCCESS;
}
}
}
2011-06-24 21:30:09 +00:00
/* Loop the module list */
ListHead = &Ldr->InMemoryOrderModuleList;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the entry and NT Headers */
LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
if (NtHeader)
2011-06-24 21:30:09 +00:00
{
/* Get the Image Base */
DllBase = (ULONG_PTR)LdrEntry->DllBase;
DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
/* Check if they match */
if (((ULONG_PTR)Address >= DllBase) &&
((ULONG_PTR)Address < DllEnd))
{
/* Return it */
*Module = LdrEntry;
return STATUS_SUCCESS;
}
/* Next Entry */
NextEntry = NextEntry->Flink;
}
}
/* Nothing found */
// 85 == DPFLTR_LDR_ID;
DbgPrintEx(85, DPFLTR_WARNING_LEVEL, "LDR: %s() exiting 0x%08lx\n", __FUNCTION__, STATUS_NO_MORE_ENTRIES);
2011-06-24 21:30:09 +00:00
return STATUS_NO_MORE_ENTRIES;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrGetDllHandleEx(IN ULONG Flags,
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle OPTIONAL)
{
NTSTATUS Status;
2011-06-24 21:30:09 +00:00
PLDR_DATA_TABLE_ENTRY LdrEntry;
UNICODE_STRING RedirectName, DllString1, RawDllName;
PUNICODE_STRING pRedirectName, CompareName;
2011-06-24 21:30:09 +00:00
PWCHAR p1, p2, p3;
BOOLEAN Locked, RedirectedDll;
ULONG_PTR Cookie;
ULONG LoadFlag, Length;
2011-06-24 21:30:09 +00:00
/* Initialize the strings */
RtlInitEmptyUnicodeString(&DllString1, NULL, 0);
RtlInitEmptyUnicodeString(&RawDllName, NULL, 0);
2011-06-24 21:30:09 +00:00
RedirectName = *DllName;
pRedirectName = &RedirectName;
/* Initialize state */
RedirectedDll = Locked = FALSE;
LdrEntry = NULL;
Cookie = 0;
2011-06-24 21:30:09 +00:00
/* Clear the handle */
if (DllHandle) *DllHandle = NULL;
/* Check for a valid flag combination */
if ((Flags & ~(LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) ||
(!DllHandle && !(Flags & LDR_GET_DLL_HANDLE_EX_PIN)))
2011-06-24 21:30:09 +00:00
{
DPRINT1("Flags are invalid or no DllHandle given\n");
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
2011-06-24 21:30:09 +00:00
}
/* If not initializing */
if (!LdrpInLdrInit)
{
/* Acquire the lock */
Status = LdrLockLoaderLock(0, NULL, &Cookie);
if (!NT_SUCCESS(Status)) goto Quickie;
/* Remember we own it */
2011-06-24 21:30:09 +00:00
Locked = TRUE;
}
/* Check if the SxS Assemblies specify another file */
Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
pRedirectName,
&LdrApiDefaultExtension,
NULL,
&DllString1,
&pRedirectName,
NULL,
NULL,
NULL);
/* Check success */
if (NT_SUCCESS(Status))
{
/* Let Ldrp know */
RedirectedDll = TRUE;
}
else if (Status != STATUS_SXS_KEY_NOT_FOUND)
{
/* Unrecoverable SxS failure; */
goto Quickie;
}
else
{
ASSERT(pRedirectName == &RedirectName);
}
/* Set default failure code */
Status = STATUS_DLL_NOT_FOUND;
2011-06-24 21:30:09 +00:00
/* Use the cache if we can */
if (LdrpGetModuleHandleCache)
{
/* Check if we were redirected */
if (RedirectedDll)
{
/* Check the flag */
if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED))
2011-06-24 21:30:09 +00:00
{
goto DontCompare;
}
/* Use the right name */
CompareName = &LdrpGetModuleHandleCache->FullDllName;
2011-06-24 21:30:09 +00:00
}
else
{
/* Check the flag */
if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)
2011-06-24 21:30:09 +00:00
{
goto DontCompare;
}
/* Use the right name */
CompareName = &LdrpGetModuleHandleCache->BaseDllName;
2011-06-24 21:30:09 +00:00
}
/* Check if the name matches */
if (RtlEqualUnicodeString(pRedirectName,
CompareName,
TRUE))
{
/* Skip the rest */
LdrEntry = LdrpGetModuleHandleCache;
/* Return success */
Status = STATUS_SUCCESS;
goto Quickie;
2011-06-24 21:30:09 +00:00
}
}
DontCompare:
/* Find the name without the extension */
p1 = pRedirectName->Buffer;
p2 = NULL;
p3 = &p1[pRedirectName->Length / sizeof(WCHAR)];
2011-06-24 21:30:09 +00:00
while (p1 != p3)
{
if (*p1++ == L'.')
{
p2 = p1;
}
else if (*p1 == L'\\')
{
p2 = NULL;
2011-06-24 21:30:09 +00:00
}
}
/* Check if no extension was found or if we got a slash */
if (!(p2) || (*p2 == L'\\') || (*p2 == L'/'))
2011-06-24 21:30:09 +00:00
{
/* Check that we have space to add one */
Length = pRedirectName->Length +
LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL);
if (Length >= UNICODE_STRING_MAX_BYTES)
2011-06-24 21:30:09 +00:00
{
/* No space to add the extension */
Status = STATUS_NAME_TOO_LONG;
goto Quickie;
2011-06-24 21:30:09 +00:00
}
/* Setup the string */
RawDllName.MaximumLength = Length;
ASSERT(Length >= sizeof(UNICODE_NULL));
2011-06-24 21:30:09 +00:00
RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
RawDllName.MaximumLength);
if (!RawDllName.Buffer)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
2011-06-24 21:30:09 +00:00
/* Copy the string and add extension */
RtlCopyUnicodeString(&RawDllName, pRedirectName);
RtlAppendUnicodeStringToString(&RawDllName, &LdrApiDefaultExtension);
2011-06-24 21:30:09 +00:00
}
else
{
/* Check if there's something in the name */
Length = pRedirectName->Length;
if (Length)
2011-06-24 21:30:09 +00:00
{
/* Check and remove trailing period */
if (pRedirectName->Buffer[Length / sizeof(WCHAR) - sizeof(ANSI_NULL)] == '.')
2011-06-24 21:30:09 +00:00
{
/* Decrease the size */
pRedirectName->Length -= sizeof(WCHAR);
}
}
/* Setup the string */
RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR);
RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
RawDllName.MaximumLength);
if (!RawDllName.Buffer)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
2011-06-24 21:30:09 +00:00
/* Copy the string */
RtlCopyUnicodeString(&RawDllName, pRedirectName);
2011-06-24 21:30:09 +00:00
}
/* Display debug string */
if (ShowSnaps)
{
DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
2011-06-24 21:30:09 +00:00
&RawDllName,
DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"");
}
/* Do the lookup */
if (LdrpCheckForLoadedDll(DllPath,
&RawDllName,
((ULONG_PTR)DllPath == 1) ? TRUE : FALSE,
RedirectedDll,
&LdrEntry))
{
/* Update cached entry */
LdrpGetModuleHandleCache = LdrEntry;
/* Return success */
Status = STATUS_SUCCESS;
}
else
{
/* Make sure to NULL this */
LdrEntry = NULL;
}
Quickie:
/* The success path must have a valid loader entry */
ASSERT((LdrEntry != NULL) == NT_SUCCESS(Status));
2011-06-24 21:30:09 +00:00
/* Check if we got an entry and success */
DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL);
if ((LdrEntry) && (NT_SUCCESS(Status)))
2011-06-24 21:30:09 +00:00
{
/* Check if the DLL is locked */
if ((LdrEntry->LoadCount != 0xFFFF) &&
!(Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT))
2011-06-24 21:30:09 +00:00
{
/* Check what to do with the load count */
if (Flags & LDR_GET_DLL_HANDLE_EX_PIN)
2011-06-24 21:30:09 +00:00
{
/* Pin it */
LdrEntry->LoadCount = 0xFFFF;
LoadFlag = LDRP_UPDATE_PIN;
}
else
{
/* Increase the load count */
LdrEntry->LoadCount++;
LoadFlag = LDRP_UPDATE_REFCOUNT;
2011-06-24 21:30:09 +00:00
}
/* Update the load count now */
LdrpUpdateLoadCount2(LdrEntry, LoadFlag);
LdrpClearLoadInProgress();
2011-06-24 21:30:09 +00:00
}
/* Check if the caller is requesting the handle */
if (DllHandle) *DllHandle = LdrEntry->DllBase;
2011-06-24 21:30:09 +00:00
}
2011-06-24 21:30:09 +00:00
/* Free string if needed */
if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1);
/* Free the raw DLL Name if needed */
if (RawDllName.Buffer)
{
/* Free the heap-allocated buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer);
2011-06-24 21:30:09 +00:00
RawDllName.Buffer = NULL;
}
/* Release lock */
if (Locked)
{
LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS,
Cookie);
}
2011-06-24 21:30:09 +00:00
/* Return */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle)
{
/* Call the newer API */
return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT,
2011-06-24 21:30:09 +00:00
DllPath,
DllCharacteristics,
DllName,
DllHandle);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrGetProcedureAddress(IN PVOID BaseAddress,
IN PANSI_STRING Name,
IN ULONG Ordinal,
OUT PVOID *ProcedureAddress)
{
/* Call the internal routine and tell it to execute DllInit */
return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
IN PLDR_CALLBACK Callback,
IN PVOID CallbackContext,
OUT PUSHORT ImageCharacteristics)
{
FILE_STANDARD_INFORMATION FileStandardInfo;
PIMAGE_IMPORT_DESCRIPTOR ImportData;
PIMAGE_SECTION_HEADER LastSection;
IO_STATUS_BLOCK IoStatusBlock;
PIMAGE_NT_HEADERS NtHeader;
HANDLE SectionHandle;
SIZE_T ViewSize;
PVOID ViewBase;
BOOLEAN Result, NoActualCheck;
NTSTATUS Status;
PVOID ImportName;
ULONG Size;
DPRINT("LdrVerifyImageMatchesChecksum() called\n");
/* If the handle has the magic KnownDll flag, skip actual checksums */
NoActualCheck = ((ULONG_PTR)FileHandle & 1);
/* Create the section */
Status = NtCreateSection(&SectionHandle,
SECTION_MAP_EXECUTE,
NULL,
NULL,
PAGE_EXECUTE,
SEC_COMMIT,
FileHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status);
return Status;
}
/* Map the section */
ViewSize = 0;
ViewBase = NULL;
Status = NtMapViewOfSection(SectionHandle,
NtCurrentProcess(),
&ViewBase,
0,
0,
NULL,
&ViewSize,
ViewShare,
0,
PAGE_EXECUTE);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status);
NtClose(SectionHandle);
return Status;
}
/* Get the file information */
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileStandardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status);
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
NtClose(SectionHandle);
return Status;
}
/* Protect with SEH */
_SEH2_TRY
{
/* Check if this is the KnownDll hack */
if (NoActualCheck)
{
/* Don't actually do it */
Result = TRUE;
}
else
{
/* Verify the checksum */
Result = LdrVerifyMappedImageMatchesChecksum(ViewBase,
FileStandardInfo.EndOfFile.LowPart,
FileStandardInfo.EndOfFile.LowPart);
}
/* Check if a callback was supplied */
if ((Result) && (Callback))
{
/* Get the NT Header */
NtHeader = RtlImageNtHeader(ViewBase);
/* Check if caller requested this back */
if (ImageCharacteristics)
{
/* Return to caller */
*ImageCharacteristics = NtHeader->FileHeader.Characteristics;
}
/* Get the Import Directory Data */
ImportData = RtlImageDirectoryEntryToData(ViewBase,
FALSE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&Size);
/* Make sure there is one */
if (ImportData)
{
/* Loop the imports */
while (ImportData->Name)
{
/* Get the name */
ImportName = RtlImageRvaToVa(NtHeader,
ViewBase,
ImportData->Name,
&LastSection);
/* Notify the callback */
Callback(CallbackContext, ImportName);
ImportData++;
}
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
Result = FALSE;
}
_SEH2_END;
/* Unmap file and close handle */
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
NtClose(SectionHandle);
/* Return status */
return Result ? Status : STATUS_IMAGE_CHECKSUM_MISMATCH;
}
NTSTATUS
NTAPI
LdrQueryProcessModuleInformationEx(IN ULONG ProcessId,
IN ULONG Reserved,
IN PRTL_PROCESS_MODULES ModuleInformation,
IN ULONG Size,
OUT PULONG ReturnedSize OPTIONAL)
{
PLIST_ENTRY ModuleListHead, InitListHead;
PLIST_ENTRY Entry, InitEntry;
PLDR_DATA_TABLE_ENTRY Module, InitModule;
PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
NTSTATUS Status = STATUS_SUCCESS;
ULONG UsedSize = sizeof(ULONG);
ANSI_STRING AnsiString;
PCHAR p;
DPRINT("LdrQueryProcessModuleInformation() called\n");
/* Acquire loader lock */
RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
/* Check if we were given enough space */
if (Size < UsedSize)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
ModuleInformation->NumberOfModules = 0;
ModulePtr = &ModuleInformation->Modules[0];
Status = STATUS_SUCCESS;
}
/* Traverse the list of modules */
_SEH2_TRY
{
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Entry = ModuleListHead->Flink;
while (Entry != ModuleListHead)
{
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
DPRINT(" Module %wZ\n", &Module->FullDllName);
/* Increase the used size */
UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
if (UsedSize > Size)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
ModulePtr->ImageBase = Module->DllBase;
ModulePtr->ImageSize = Module->SizeOfImage;
ModulePtr->Flags = Module->Flags;
ModulePtr->LoadCount = Module->LoadCount;
ModulePtr->MappedBase = NULL;
ModulePtr->InitOrderIndex = 0;
ModulePtr->LoadOrderIndex = ModuleInformation->NumberOfModules;
/* Now get init order index by traversing init list */
InitListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
InitEntry = InitListHead->Flink;
while (InitEntry != InitListHead)
{
InitModule = CONTAINING_RECORD(InitEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
/* Increase the index */
ModulePtr->InitOrderIndex++;
/* Quit the loop if our module is found */
if (InitModule == Module) break;
/* Advance to the next entry */
InitEntry = InitEntry->Flink;
}
/* Prepare ANSI string with the module's name */
AnsiString.Length = 0;
AnsiString.MaximumLength = sizeof(ModulePtr->FullPathName);
AnsiString.Buffer = ModulePtr->FullPathName;
RtlUnicodeStringToAnsiString(&AnsiString,
&Module->FullDllName,
FALSE);
/* Calculate OffsetToFileName field */
p = strrchr(ModulePtr->FullPathName, '\\');
if (p != NULL)
ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
else
ModulePtr->OffsetToFileName = 0;
/* Advance to the next module in the output list */
ModulePtr++;
/* Increase number of modules */
if (ModuleInformation)
ModuleInformation->NumberOfModules++;
}
/* Go to the next entry in the modules list */
Entry = Entry->Flink;
}
/* Set returned size if it was provided */
if (ReturnedSize)
*ReturnedSize = UsedSize;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Ignoring the exception */
} _SEH2_END;
/* Release the lock */
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
DPRINT("LdrQueryProcessModuleInformation() done\n");
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation,
IN ULONG Size,
OUT PULONG ReturnedSize OPTIONAL)
{
/* Call Ex version of the API */
return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize);
}
NTSTATUS
NTAPI
LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVOID Context)
{
PLIST_ENTRY ListHead, ListEntry;
PLDR_DATA_TABLE_ENTRY LdrEntry;
NTSTATUS Status;
ULONG Cookie;
BOOLEAN Stop = FALSE;
/* Check parameters */
if ((ReservedFlag) || !(EnumProc)) return STATUS_INVALID_PARAMETER;
/* Acquire the loader lock */
Status = LdrLockLoaderLock(0, NULL, &Cookie);
if (!NT_SUCCESS(Status)) return Status;
/* Loop all the modules and call enum proc */
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
ListEntry = ListHead->Flink;
while (ListHead != ListEntry)
{
/* Get the entry */
LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
/* Call the enumeration proc inside SEH */
_SEH2_TRY
{
EnumProc(LdrEntry, Context, &Stop);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Ignoring the exception */
} _SEH2_END;
/* Break if we were asked to stop enumeration */
if (Stop)
{
/* Release loader lock */
Status = LdrUnlockLoaderLock(0, Cookie);
/* Reset any successful status to STATUS_SUCCESS, but leave
failure to the caller */
if (NT_SUCCESS(Status))
Status = STATUS_SUCCESS;
/* Return any possible failure status */
return Status;
}
/* Advance to the next module */
ListEntry = ListEntry->Flink;
}
/* Release loader lock, it must succeed this time */
Status = LdrUnlockLoaderLock(0, Cookie);
ASSERT(NT_SUCCESS(Status));
/* Return success */
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
{
PLDR_DATA_TABLE_ENTRY LdrEntry;
NTSTATUS Status;
BOOLEAN LockHeld;
ULONG_PTR Cookie;
DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
/* Don't do it during shutdown */
if (LdrpShutdownInProgress) return STATUS_SUCCESS;
/* Check if we should grab the lock */
LockHeld = FALSE;
if (!LdrpInLdrInit)
{
/* Grab the lock */
Status = LdrLockLoaderLock(0, NULL, &Cookie);
if (!NT_SUCCESS(Status)) return Status;
LockHeld = TRUE;
}
/* Make sure the DLL is valid and get its entry */
Status = STATUS_DLL_NOT_FOUND;
if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
{
/* Get if it has a TLS slot */
if (!LdrEntry->TlsIndex)
{
/* It doesn't, so you're allowed to call this */
LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
Status = STATUS_SUCCESS;
}
}
/* Check if the lock was held */
if (LockHeld)
{
/* Release it */
LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
}
/* Return the status */
return Status;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
RtlDllShutdownInProgress(VOID)
{
/* Return the internal global */
return LdrpShutdownInProgress;
}
/*
* @implemented
*/
PIMAGE_BASE_RELOCATION
NTAPI
LdrProcessRelocationBlock(IN ULONG_PTR Address,
IN ULONG Count,
IN PUSHORT TypeOffset,
IN LONG_PTR Delta)
{
return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
}
/*
* @unimplemented
*/
BOOLEAN
NTAPI
LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
{
static BOOLEAN WarnedOnce = FALSE;
if (WarnedOnce == FALSE) { UNIMPLEMENTED; WarnedOnce = TRUE; }
return FALSE;
}
/* EOF */