[NTDLL]: Reimplemnt LdrDisableThreadCalloutsForDll using new loader APIS.

[NTDLL]: Fix LdrpInitializeProcess to use new loader relocation API instead of LdrRelocateImage. Warn if an EXE gets relocated since this was never supported in ReactOS.
[NTDLL]: Move APIs into ldrapi.c and delete 3 leftover cruft files.
This is the extent of my review for the moment. There are still many problems with the loader. It should've been tested/put in a branch. I found these 25 bugs in less than a day. Other problems remaining are missing SEH around loader lock, not too sure if the cookie generation is correct, cookies are ULONG_PTR not ULONGs, and haven't checked the PE loading code yet (only reviewed ldrapi.c).

svn path=/trunk/; revision=52585
This commit is contained in:
Alex Ionescu 2011-07-09 16:15:43 +00:00
parent c3743c23c3
commit 918511d9ea
7 changed files with 124 additions and 3914 deletions

View file

@ -102,6 +102,16 @@ LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
ULONG NTAPI
LdrpClearLoadInProgress();
NTSTATUS
NTAPI
LdrpSetProtection(PVOID ViewBase,
BOOLEAN Restore);
BOOLEAN
NTAPI
LdrpCheckForLoadedDllHandle(IN PVOID Base,
OUT PLDR_DATA_TABLE_ENTRY *LdrEntry);
BOOLEAN NTAPI
LdrpCheckForLoadedDll(IN PWSTR DllPath,
IN PUNICODE_STRING DllName,

File diff suppressed because it is too large Load diff

View file

@ -1122,4 +1122,90 @@ LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVO
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 */

View file

@ -1358,6 +1358,7 @@ LdrpInitializeProcess(IN PCONTEXT Context,
PLDR_DATA_TABLE_ENTRY NtLdrEntry;
PWCHAR Current;
ULONG ExecuteOptions = 0;
PVOID ViewBase;
/* Set a NULL SEH Filter */
RtlSetUnhandledExceptionFilter(NULL);
@ -1858,13 +1859,37 @@ LdrpInitializeProcess(IN PCONTEXT Context,
/* 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 */

View file

@ -1,311 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: dll/ntdll/ldr/startup.c
* PURPOSE: Process startup for PE executables
* PROGRAMMERS: Jean Michault
* Rex Jolliff (rex@lvcablemodem.com)
*/
/* INCLUDES *****************************************************************/
#include <ntdll.h>
//#define NDEBUG
#include <debug.h>
#include <win32k/callback.h>
VOID RtlInitializeHeapManager(VOID);
extern PTEB LdrpTopLevelDllBeingLoadedTeb;
VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
VOID RtlpInitializeVectoredExceptionHandling(VOID);
/* GLOBALS *******************************************************************/
extern PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
extern RTL_CRITICAL_SECTION FastPebLock;
extern RTL_BITMAP TlsBitMap;
extern RTL_BITMAP TlsExpansionBitMap;
#define VALUE_BUFFER_SIZE 256
/* FUNCTIONS *****************************************************************/
BOOLEAN
FASTCALL
ReadCompatibilitySetting(HANDLE Key,
LPWSTR Value,
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo,
DWORD * Buffer)
{
UNICODE_STRING ValueName;
NTSTATUS Status;
ULONG Length;
RtlInitUnicodeString(&ValueName, Value);
Status = NtQueryValueKey(Key,
&ValueName,
KeyValuePartialInformation,
ValueInfo,
VALUE_BUFFER_SIZE,
&Length);
if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
{
RtlFreeUnicodeString(&ValueName);
return FALSE;
}
RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
RtlFreeUnicodeString(&ValueName);
return TRUE;
}
VOID
FASTCALL
LoadImageFileExecutionOptions(PPEB Peb)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG Value = 0;
UNICODE_STRING ImageName;
UNICODE_STRING ImagePathName;
ULONG ValueSize;
extern ULONG RtlpDphGlobalFlags, RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
extern ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
extern WCHAR RtlpDphTargetDlls[512];
extern BOOLEAN RtlpPageHeapEnabled;
if (Peb->ProcessParameters &&
Peb->ProcessParameters->ImagePathName.Length > 0)
{
DPRINT("%wZ\n", &Peb->ProcessParameters->ImagePathName);
ImagePathName = Peb->ProcessParameters->ImagePathName;
ImageName.Buffer = ImagePathName.Buffer + ImagePathName.Length / sizeof(WCHAR);
ImageName.Length = 0;
while (ImagePathName.Buffer < ImageName.Buffer)
{
ImageName.Buffer--;
if (*ImageName.Buffer == L'\\')
{
ImageName.Buffer++;
break;
}
}
ImageName.Length = ImagePathName.Length -
(ImageName.Buffer - ImagePathName.Buffer) * sizeof(WCHAR);
ImageName.MaximumLength = ImageName.Length +
ImagePathName.MaximumLength - ImagePathName.Length;
DPRINT("%wZ\n", &ImageName);
/* global flag */
Status = LdrQueryImageFileExecutionOptions(&ImageName,
L"GlobalFlag",
REG_DWORD,
(PVOID)&Value,
sizeof(Value),
&ValueSize);
if (NT_SUCCESS(Status))
{
Peb->NtGlobalFlag = Value;
DPRINT("GlobalFlag: Value=0x%lx\n", Value);
}
else
{
/* Add debugging flags if there is no GlobalFlags override */
if (Peb->BeingDebugged)
{
Peb->NtGlobalFlag |= FLG_HEAP_VALIDATE_PARAMETERS |
FLG_HEAP_ENABLE_FREE_CHECK |
FLG_HEAP_ENABLE_TAIL_CHECK;
}
}
/* Handle the case when page heap is enabled */
if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
{
/* Disable all heap debugging flags so that no heap call goes via page heap branch */
Peb->NtGlobalFlag &= ~(FLG_HEAP_VALIDATE_PARAMETERS |
FLG_HEAP_VALIDATE_ALL |
FLG_HEAP_ENABLE_FREE_CHECK |
FLG_HEAP_ENABLE_TAIL_CHECK |
FLG_USER_STACK_TRACE_DB |
FLG_HEAP_ENABLE_TAGGING |
FLG_HEAP_ENABLE_TAG_BY_DLL);
/* Get page heap flags without checking return value */
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapFlags",
REG_DWORD,
(PVOID)&RtlpDphGlobalFlags,
sizeof(RtlpDphGlobalFlags),
&ValueSize);
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapSizeRangeStart",
REG_DWORD,
(PVOID)&RtlpPageHeapSizeRangeStart,
sizeof(RtlpPageHeapSizeRangeStart),
&ValueSize);
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapSizeRangeEnd",
REG_DWORD,
(PVOID)&RtlpPageHeapSizeRangeEnd,
sizeof(RtlpPageHeapSizeRangeEnd),
&ValueSize);
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapDllRangeStart",
REG_DWORD,
(PVOID)&RtlpPageHeapDllRangeStart,
sizeof(RtlpPageHeapDllRangeStart),
&ValueSize);
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapDllRangeEnd",
REG_DWORD,
(PVOID)&RtlpPageHeapDllRangeEnd,
sizeof(RtlpPageHeapDllRangeEnd),
&ValueSize);
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapTargetDlls",
REG_SZ,
(PVOID)RtlpDphTargetDlls,
sizeof(RtlpDphTargetDlls),
&ValueSize);
/* Now when all parameters are read, enable page heap */
RtlpPageHeapEnabled = TRUE;
}
}
}
BOOLEAN
FASTCALL
LoadCompatibilitySettings(PPEB Peb)
{
NTSTATUS Status;
HANDLE UserKey = NULL;
HANDLE KeyHandle;
HANDLE SubKeyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
UNICODE_STRING ValueName;
UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
ULONG Length;
DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
SPMajorVersion, SPMinorVersion = 0;
if (Peb->ProcessParameters &&
(Peb->ProcessParameters->ImagePathName.Length > 0))
{
Status = RtlOpenCurrentUser(KEY_READ, &UserKey);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
UserKey,
NULL);
Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
if (UserKey)
NtClose(UserKey);
return FALSE;
}
/* query version name for application */
ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer;
Status = NtQueryValueKey(KeyHandle,
&Peb->ProcessParameters->ImagePathName,
KeyValuePartialInformation,
ValueBuffer,
VALUE_BUFFER_SIZE,
&Length);
if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
{
NtClose(KeyHandle);
if (UserKey)
NtClose(UserKey);
return FALSE;
}
ValueName.Length = ValueInfo->DataLength;
ValueName.MaximumLength = ValueInfo->DataLength;
ValueName.Buffer = (PWSTR) ValueInfo->Data;
/* load version info */
InitializeObjectAttributes(&ObjectAttributes,
&ValueName,
OBJ_CASE_INSENSITIVE,
KeyHandle,
NULL);
Status = NtOpenKey(&SubKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
NtClose(KeyHandle);
if (UserKey)
NtClose(UserKey);
return FALSE;
}
DPRINT("Loading version information for: %wZ\n", &ValueName);
/* read settings from registry */
if (!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
goto finish;
if (!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
goto finish;
if (!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
goto finish;
if (!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
goto finish;
/* now assign the settings */
Peb->OSMajorVersion = (ULONG) MajorVersion;
Peb->OSMinorVersion = (ULONG) MinorVersion;
Peb->OSBuildNumber = (USHORT) BuildNumber;
Peb->OSPlatformId = (ULONG) PlatformId;
/* optional service pack version numbers */
if (ReadCompatibilitySetting(SubKeyHandle,
L"SPMajorVersion",
ValueInfo,
&SPMajorVersion) &&
ReadCompatibilitySetting(SubKeyHandle,
L"SPMinorVersion",
ValueInfo,
&SPMinorVersion))
{
Peb->OSCSDVersion = ((SPMajorVersion & 0xFF) << 8) |
(SPMinorVersion & 0xFF);
}
finish:
/* we're finished */
NtClose(SubKeyHandle);
NtClose(KeyHandle);
if (UserKey)
NtClose(UserKey);
return TRUE;
}
return FALSE;
}
/* EOF */

View file

@ -1,774 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: lib/ntdll/ldr/utils.c
* PURPOSE: Process startup for PE executables
* PROGRAMMERS: Jean Michault
* Rex Jolliff (rex@lvcablemodem.com)
* Michael Martin
*/
/*
* TODO:
* - Handle loading flags correctly
* - Handle errors correctly (unload dll's)
* - Implement a faster way to find modules (hash table)
* - any more ??
*/
/* INCLUDES *****************************************************************/
#include <ntdll.h>
#define NDEBUG
#include <debug.h>
#define LDRP_PROCESS_CREATION_TIME 0xffff
#define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
/* GLOBALS *******************************************************************/
#ifdef NDEBUG
#define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
#endif
static BOOLEAN LdrpDllShutdownInProgress = FALSE;
extern HANDLE LdrpKnownDllObjectDirectory;
extern UNICODE_STRING LdrpKnownDllPath;
static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
extern PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
/* PROTOTYPES ****************************************************************/
static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
static PVOID LdrFixupForward(PCHAR ForwardName);
static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname );
NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module );
/* FUNCTIONS *****************************************************************/
static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
{
LONG LoadCount;
if (!Locked)
{
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
}
LoadCount = Module->LoadCount;
if (Module->LoadCount > 0 && Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
{
Module->LoadCount--;
}
if (!Locked)
{
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
}
return LoadCount;
}
static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
{
LONG LoadCount;
if (!Locked)
{
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
}
LoadCount = Module->LoadCount;
if (Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
{
Module->LoadCount++;
}
if (!Locked)
{
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
}
return LoadCount;
}
/***************************************************************************
* NAME LOCAL
* LdrAdjustDllName
*
* DESCRIPTION
* Adjusts the name of a dll to a fully qualified name.
*
* ARGUMENTS
* FullDllName: Pointer to caller supplied storage for the fully
* qualified dll name.
* DllName: Pointer to the dll name.
* BaseName: TRUE: Only the file name is passed to FullDllName
* FALSE: The full path is preserved in FullDllName
*
* RETURN VALUE
* None
*
* REVISIONS
*
* NOTE
* A given path is not affected by the adjustment, but the file
* name only:
* ntdll --> ntdll.dll
* ntdll. --> ntdll
* ntdll.xyz --> ntdll.xyz
*/
static VOID
LdrAdjustDllName (PUNICODE_STRING FullDllName,
PUNICODE_STRING DllName,
BOOLEAN BaseName)
{
WCHAR Buffer[MAX_PATH];
ULONG Length;
PWCHAR Extension;
PWCHAR Pointer;
DPRINT1("\n");
Length = DllName->Length / sizeof(WCHAR);
if (BaseName)
{
/* get the base dll name */
Pointer = DllName->Buffer + Length;
Extension = Pointer;
do
{
--Pointer;
}
while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
Pointer++;
Length = Extension - Pointer;
memmove (Buffer, Pointer, Length * sizeof(WCHAR));
Buffer[Length] = L'\0';
}
else
{
/* get the full dll name */
memmove (Buffer, DllName->Buffer, DllName->Length);
Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
}
/* Build the DLL's absolute name */
Extension = wcsrchr (Buffer, L'.');
if ((Extension != NULL) && (*Extension == L'.'))
{
/* with extension - remove dot if it's the last character */
if (Buffer[Length - 1] == L'.')
Length--;
Buffer[Length] = 0;
}
else
{
/* name without extension - assume that it is .dll */
memmove (Buffer + Length, L".dll", 10);
}
RtlCreateUnicodeString(FullDllName, Buffer);
}
PLDR_DATA_TABLE_ENTRY
LdrAddModuleEntry(PVOID ImageBase,
PIMAGE_NT_HEADERS NTHeaders,
PWSTR FullDosName)
{
PLDR_DATA_TABLE_ENTRY Module;
DPRINT1("\n");
Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY));
ASSERT(Module);
memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
Module->DllBase = (PVOID)ImageBase;
Module->EntryPoint = (PVOID)NTHeaders->OptionalHeader.AddressOfEntryPoint;
if (Module->EntryPoint != 0)
Module->EntryPoint = (PVOID)((ULONG_PTR)Module->EntryPoint + (ULONG_PTR)Module->DllBase);
Module->SizeOfImage = LdrpGetResidentSize(NTHeaders);
if (NtCurrentPeb()->Ldr->Initialized == TRUE)
{
/* loading while app is running */
Module->LoadCount = 1;
}
else
{
/*
* loading while app is initializing
* dll must not be unloaded
*/
Module->LoadCount = LDRP_PROCESS_CREATION_TIME;
}
Module->Flags = 0;
Module->TlsIndex = -1;
Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
RtlCreateUnicodeString (&Module->FullDllName,
FullDosName);
RtlCreateUnicodeString (&Module->BaseDllName,
wcsrchr(FullDosName, L'\\') + 1);
DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
&Module->InLoadOrderLinks);
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
return(Module);
}
/***************************************************************************
* NAME LOCAL
* LdrFindEntryForName
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* NOTE
*
*/
static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name,
PLDR_DATA_TABLE_ENTRY *Module,
BOOLEAN Ref)
{
PLIST_ENTRY ModuleListHead;
PLIST_ENTRY Entry;
PLDR_DATA_TABLE_ENTRY ModulePtr;
BOOLEAN ContainsPath;
UNICODE_STRING AdjustedName;
DPRINT("LdrFindEntryForName(Name %wZ)\n", Name);
if (NtCurrentPeb()->Ldr == NULL)
return(STATUS_NO_MORE_ENTRIES);
RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Entry = ModuleListHead->Flink;
if (Entry == ModuleListHead)
{
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
return(STATUS_NO_MORE_ENTRIES);
}
// NULL is the current process
if (Name == NULL)
{
*Module = LdrpImageEntry;
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
return(STATUS_SUCCESS);
}
ContainsPath = (Name->Length >= 2 * sizeof(WCHAR) && L':' == Name->Buffer[1]);
LdrAdjustDllName (&AdjustedName, Name, !ContainsPath);
if (LdrpLastModule)
{
if ((!ContainsPath &&
0 == RtlCompareUnicodeString(&LdrpLastModule->BaseDllName, &AdjustedName, TRUE)) ||
(ContainsPath &&
0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
{
*Module = LdrpLastModule;
if (Ref && (*Module)->LoadCount != LDRP_PROCESS_CREATION_TIME)
{
(*Module)->LoadCount++;
}
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
RtlFreeUnicodeString(&AdjustedName);
return(STATUS_SUCCESS);
}
}
while (Entry != ModuleListHead)
{
ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, &AdjustedName);
if ((!ContainsPath &&
0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, &AdjustedName, TRUE)) ||
(ContainsPath &&
0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
{
*Module = LdrpLastModule = ModulePtr;
if (Ref && ModulePtr->LoadCount != LDRP_PROCESS_CREATION_TIME)
{
ModulePtr->LoadCount++;
}
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
RtlFreeUnicodeString(&AdjustedName);
return(STATUS_SUCCESS);
}
Entry = Entry->Flink;
}
DPRINT("Failed to find dll %wZ\n", Name);
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
RtlFreeUnicodeString(&AdjustedName);
return(STATUS_NO_MORE_ENTRIES);
}
/**********************************************************************
* NAME LOCAL
* LdrFixupForward
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* NOTE
*
*/
static PVOID
LdrFixupForward(PCHAR ForwardName)
{
CHAR NameBuffer[128];
UNICODE_STRING DllName;
NTSTATUS Status;
PCHAR p;
PLDR_DATA_TABLE_ENTRY Module;
PVOID BaseAddress;
DPRINT1("\n");
strcpy(NameBuffer, ForwardName);
p = strchr(NameBuffer, '.');
if (p != NULL)
{
*p = 0;
DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
RtlCreateUnicodeStringFromAsciiz (&DllName,
NameBuffer);
Status = LdrFindEntryForName (&DllName, &Module, FALSE);
/* FIXME:
* The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
*/
if (!NT_SUCCESS(Status))
{
Status = LdrLoadDll(NULL, NULL, &DllName, &BaseAddress);
if (NT_SUCCESS(Status))
{
Status = LdrFindEntryForName (&DllName, &Module, FALSE);
}
}
RtlFreeUnicodeString (&DllName);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer);
return NULL;
}
DPRINT("BaseAddress: %p\n", Module->DllBase);
return LdrGetExportByName(Module->DllBase, (PUCHAR)(p+1), -1);
}
return NULL;
}
/**********************************************************************
* NAME LOCAL
* LdrGetExportByName
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* NOTE
* AddressOfNames and AddressOfNameOrdinals are paralell tables,
* both with NumberOfNames entries.
*
*/
static PVOID
LdrGetExportByName(PVOID BaseAddress,
PUCHAR SymbolName,
WORD Hint)
{
PIMAGE_EXPORT_DIRECTORY ExportDir;
PDWORD *ExFunctions;
PDWORD *ExNames;
USHORT *ExOrdinals;
PVOID ExName;
ULONG Ordinal;
PVOID Function;
LONG minn, maxn;
ULONG ExportDirSize;
DPRINT("LdrGetExportByName %p %s %hu\n", BaseAddress, SymbolName, Hint);
ExportDir = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(BaseAddress,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportDirSize);
if (ExportDir == NULL)
{
DPRINT1("LdrGetExportByName(): no export directory, "
"can't lookup %s/%hu!\n", SymbolName, Hint);
return NULL;
}
//The symbol names may be missing entirely
if (ExportDir->AddressOfNames == 0)
{
DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
return NULL;
}
/*
* Get header pointers
*/
ExNames = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfNames);
ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
ExFunctions = (PDWORD *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
/*
* Check the hint first
*/
if (Hint < ExportDir->NumberOfNames)
{
ExName = RVA(BaseAddress, ExNames[Hint]);
if (strcmp(ExName, (PCHAR)SymbolName) == 0)
{
Ordinal = ExOrdinals[Hint];
Function = RVA(BaseAddress, ExFunctions[Ordinal]);
if (((ULONG)Function >= (ULONG)ExportDir) &&
((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
{
DPRINT("Forward: %s\n", (PCHAR)Function);
Function = LdrFixupForward((PCHAR)Function);
if (Function == NULL)
{
DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
}
return Function;
}
if (Function != NULL)
return Function;
}
}
/*
* Binary search
*/
minn = 0;
maxn = ExportDir->NumberOfNames - 1;
while (minn <= maxn)
{
LONG mid;
LONG res;
mid = (minn + maxn) / 2;
ExName = RVA(BaseAddress, ExNames[mid]);
res = strcmp(ExName, (PCHAR)SymbolName);
if (res == 0)
{
Ordinal = ExOrdinals[mid];
Function = RVA(BaseAddress, ExFunctions[Ordinal]);
if (((ULONG)Function >= (ULONG)ExportDir) &&
((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
{
DPRINT("Forward: %s\n", (PCHAR)Function);
Function = LdrFixupForward((PCHAR)Function);
if (Function == NULL)
{
DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
}
return Function;
}
if (Function != NULL)
return Function;
}
else if (minn == maxn)
{
DPRINT("LdrGetExportByName(): binary search failed\n");
break;
}
else if (res > 0)
{
maxn = mid - 1;
}
else
{
minn = mid + 1;
}
}
DPRINT("LdrGetExportByName(): failed to find %s\n",SymbolName);
return (PVOID)NULL;
}
/**********************************************************************
* NAME LOCAL
* LdrPerformRelocations
*
* DESCRIPTION
* Relocate a DLL's memory image.
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* NOTE
*
*/
NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
PVOID ImageBase)
{
PIMAGE_DATA_DIRECTORY RelocationDDir;
PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
ULONG Count, ProtectSize, OldProtect, OldProtect2;
PVOID Page, ProtectPage, ProtectPage2;
PUSHORT TypeOffset;
LONG_PTR Delta;
NTSTATUS Status;
DPRINT1("\n");
if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
{
return STATUS_SUCCESS;
}
RelocationDDir =
&NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
{
return STATUS_SUCCESS;
}
ProtectSize = PAGE_SIZE;
Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
RelocationDDir->VirtualAddress);
RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
RelocationDDir->VirtualAddress + RelocationDDir->Size);
while (RelocationDir < RelocationEnd &&
RelocationDir->SizeOfBlock > 0)
{
Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
sizeof(USHORT);
Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
TypeOffset = (PUSHORT)(RelocationDir + 1);
/* Unprotect the page(s) we're about to relocate. */
ProtectPage = Page;
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
PAGE_READWRITE,
&OldProtect);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to unprotect relocation target.\n");
return Status;
}
if (RelocationDir->VirtualAddress + PAGE_SIZE <
NTHeaders->OptionalHeader.SizeOfImage)
{
ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage2,
&ProtectSize,
PAGE_READWRITE,
&OldProtect2);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to unprotect relocation target (2).\n");
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
OldProtect,
&OldProtect);
return Status;
}
}
else
{
ProtectPage2 = NULL;
}
RelocationDir = LdrProcessRelocationBlock((ULONG_PTR)Page,
Count,
TypeOffset,
Delta);
if (RelocationDir == NULL)
return STATUS_UNSUCCESSFUL;
/* Restore old page protection. */
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
OldProtect,
&OldProtect);
if (ProtectPage2 != NULL)
{
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage2,
&ProtectSize,
OldProtect2,
&OldProtect2);
}
}
return STATUS_SUCCESS;
}
void
RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName)
{
ULONG ErrorResponse;
ULONG_PTR ErrorParameters[2];
ANSI_STRING ProcNameAnsi;
ANSI_STRING DllNameAnsi;
CHAR Buffer[8];
DPRINT1("\n");
if (!FuncName)
{
_snprintf(Buffer, 8, "# %ld", Ordinal);
FuncName = Buffer;
}
RtlInitAnsiString(&ProcNameAnsi, FuncName);
RtlUnicodeStringToAnsiString(&DllNameAnsi, DllName, TRUE);
ErrorParameters[0] = (ULONG_PTR)&ProcNameAnsi;
ErrorParameters[1] = (ULONG_PTR)&DllNameAnsi;
NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND,
2,
3,
ErrorParameters,
OptionOk,
&ErrorResponse);
RtlFreeAnsiString(&DllNameAnsi);
}
/*
* @implemented
*/
NTSTATUS NTAPI
LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
{
PLIST_ENTRY ModuleListHead;
PLIST_ENTRY Entry;
PLDR_DATA_TABLE_ENTRY Module;
NTSTATUS Status;
DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
Status = STATUS_DLL_NOT_FOUND;
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Entry = ModuleListHead->Flink;
while (Entry != ModuleListHead)
{
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
if (Module->DllBase == BaseAddress)
{
if (Module->TlsIndex == 0xFFFF)
{
Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
Status = STATUS_SUCCESS;
}
break;
}
Entry = Entry->Flink;
}
RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
return Status;
}
/*
* @implemented
*/
BOOLEAN NTAPI
RtlDllShutdownInProgress (VOID)
{
DPRINT1("\n");
return LdrpDllShutdownInProgress;
}
/*
* Compute size of an image as it is actually present in virt memory
* (i.e. excluding NEVER_LOAD sections)
*/
ULONG
LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
{
PIMAGE_SECTION_HEADER SectionHeader;
unsigned SectionIndex;
ULONG ResidentSize;
DPRINT1("\n");
SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
+ NTHeaders->FileHeader.SizeOfOptionalHeader);
ResidentSize = 0;
for (SectionIndex = 0;
SectionIndex < NTHeaders->FileHeader.NumberOfSections;
SectionIndex++)
{
if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
&& ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
{
ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
}
SectionHeader++;
}
return ResidentSize;
}
PIMAGE_BASE_RELOCATION
NTAPI
LdrProcessRelocationBlock(
IN ULONG_PTR Address,
IN ULONG Count,
IN PUSHORT TypeOffset,
IN LONG_PTR Delta)
{
DPRINT1("\n");
return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
}
BOOLEAN
NTAPI
LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
{
//FIXME: We don't implement alternate resources anyway, don't spam the log
//UNIMPLEMENTED;
return FALSE;
}

View file

@ -51,8 +51,6 @@
<file>ldrinit.c</file>
<file>ldrpe.c</file>
<file>ldrutils.c</file>
<file>startup.c</file>
<file>utils.c</file>
<file>actctx.c</file>
</directory>
<directory name="rtl">