[NTDLL/LDR]

- Rewrite LdrQueryProcessModuleInformation.
- Start committing PE loader related code (quite a lot of it, and still not all parts yet), unused right now so won't break anything.

svn path=/trunk/; revision=51065
This commit is contained in:
Aleksey Bragin 2011-03-16 14:22:15 +00:00
parent 4b2c1d1a6b
commit 3f20ae61b8
7 changed files with 967 additions and 104 deletions

View file

@ -23,14 +23,42 @@ typedef BOOL
/* Global data */
extern RTL_CRITICAL_SECTION LdrpLoaderLock;
extern BOOLEAN LdrpInLdrInit;
/* ldrinit.c */
NTSTATUS NTAPI LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL);
NTSTATUS NTAPI LdrpInitializeTls(VOID);
NTSTATUS NTAPI LdrpAllocateTls(VOID);
VOID NTAPI LdrpFreeTls(VOID);
VOID NTAPI LdrpTlsCallback(PVOID BaseAddress, ULONG Reason);
BOOLEAN NTAPI LdrpCallDllEntry(PDLLMAIN_FUNC EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context);
/* ldrpe.c */
NTSTATUS
NTAPI
LdrpSnapThunk(IN PVOID ExportBase,
IN PVOID ImportBase,
IN PIMAGE_THUNK_DATA OriginalThunk,
IN OUT PIMAGE_THUNK_DATA Thunk,
IN PIMAGE_EXPORT_DIRECTORY ExportEntry,
IN ULONG ExportSize,
IN BOOLEAN Static,
IN LPSTR DllName);
/* ldrutils.c */
NTSTATUS NTAPI
LdrpGetProcedureAddress(IN PVOID BaseAddress,
IN PANSI_STRING Name,
IN ULONG Ordinal,
OUT PVOID *ProcedureAddress,
IN BOOLEAN ExecuteInit);
NTSTATUS NTAPI
LdrpLoadDll(IN BOOLEAN Redirected,
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *BaseAddress,
IN BOOLEAN CallInit);
/* FIXME: Cleanup this mess */
typedef NTSTATUS (NTAPI *PEPFUNC)(PPEB);

View file

@ -109,8 +109,7 @@ LdrLockLoaderLock(IN ULONG Flags,
{
LONG OldCount;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN InInit = FALSE; // FIXME
//BOOLEAN InInit = LdrpInLdrInit;
BOOLEAN InInit = LdrpInLdrInit;
DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Result, Cookie);
@ -378,4 +377,157 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
return !Result ? STATUS_IMAGE_CHECKSUM_MISMATCH : Status;
}
/*
* @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);
}
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(Entry, 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);
}
/* EOF */

View file

@ -20,6 +20,10 @@ HKEY Wow64ExecOptionsKey;
UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
BOOLEAN LdrpInLdrInit;
PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
//RTL_BITMAP TlsBitMap;
//RTL_BITMAP TlsExpansionBitMap;
//RTL_BITMAP FlsBitMap;
@ -329,6 +333,267 @@ LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
FALSE);
}
NTSTATUS
NTAPI
LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
{
#if 0
PLDR_DATA_TABLE_ENTRY LocalArray[16];
PLIST_ENTRY ListHead;
PLIST_ENTRY NextEntry;
PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
PVOID EntryPoint;
ULONG Count, i;
//ULONG BreakOnInit;
NTSTATUS Status = STATUS_SUCCESS;
PPEB Peb = NtCurrentPeb();
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
ULONG BreakOnDllLoad;
PTEB OldTldTeb;
DPRINT1("LdrpRunInitializeRoutines() called for %wZ\n", &LdrpImageEntry->BaseDllName);
/* Check the Loader Lock */
LdrpEnsureLoaderLockIsHeld();
/* Get the number of entries to call */
if ((Count = LdrpClearLoadInProgress()))
{
/* Check if we can use our local buffer */
if (Count > 16)
{
/* Allocate space for all the entries */
LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
0,
Count * sizeof(LdrRootEntry));
if (!LdrRootEntry) return STATUS_NO_MEMORY;
}
else
{
/* Use our local array */
LdrRootEntry = LocalArray;
}
}
else
{
/* Don't need one */
LdrRootEntry = NULL;
}
/* Show debug message */
if (ShowSnaps)
{
DPRINT1("[%x,%x] LDR: Real INIT LIST for Process %wZ pid %u %0x%x\n",
NtCurrentTeb()->RealClientId.UniqueThread,
NtCurrentTeb()->RealClientId.UniqueProcess,
Peb->ProcessParameters->ImagePathName,
NtCurrentTeb()->RealClientId.UniqueThread,
NtCurrentTeb()->RealClientId.UniqueProcess);
}
/* Loop in order */
ListHead = &Peb->Ldr->InInitializationOrderModuleList;
NextEntry = ListHead->Flink;
i = 0;
while (NextEntry != ListHead)
{
/* Get the Data Entry */
LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
/* Check if we have a Root Entry */
if (LdrRootEntry)
{
/* Check flags */
if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
{
/* Setup the Cookie for the DLL */
//LdrpInitSecurityCookie(LdrEntry);
UNIMPLEMENTED;
/* Check for valid entrypoint */
if (LdrEntry->EntryPoint)
{
/* Write in array */
LdrRootEntry[i] = LdrEntry;
/* Display debug message */
if (ShowSnaps)
{
DPRINT1("[%x,%x] LDR: %wZ init routine %p\n",
NtCurrentTeb()->RealClientId.UniqueThread,
NtCurrentTeb()->RealClientId.UniqueProcess,
&LdrEntry->FullDllName,
LdrEntry->EntryPoint);
}
i++;
}
}
}
/* Set the flag */
LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
NextEntry = NextEntry->Flink;
}
/* If we got a context, then we have to call Kernel32 for TS support */
if (Context)
{
/* Check if we have one */
//if (Kernel32ProcessInitPostImportfunction)
//{
/* Call it */
//Kernel32ProcessInitPostImportfunction();
//}
/* Clear it */
//Kernel32ProcessInitPostImportfunction = NULL;
UNIMPLEMENTED;
}
/* No root entry? return */
if (!LdrRootEntry) return STATUS_SUCCESS;
/* Set the TLD TEB */
OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
/* Loop */
i = 0;
while (i < Count)
{
/* Get an entry */
LdrEntry = LdrRootEntry[i];
/* FIXME: Verifiy NX Compat */
/* Move to next entry */
i++;
/* Get its entrypoint */
EntryPoint = LdrEntry->EntryPoint;
/* Are we being debugged? */
BreakOnDllLoad = 0;
if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
{
/* Check if we should break on load */
Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
L"BreakOnDllLoad",
REG_DWORD,
&BreakOnDllLoad,
sizeof(ULONG),
NULL);
if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
}
/* Break if aksed */
if (BreakOnDllLoad)
{
/* Check if we should show a message */
if (ShowSnaps)
{
DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
DPRINT1(" - About to call init routine at %lx\n", EntryPoint);
}
/* Break in debugger */
DbgBreakPoint();
}
/* Make sure we have an entrypoint */
if (EntryPoint)
{
/* Save the old Dll Initializer and write the current one */
OldInitializer = LdrpCurrentDllInitializer;
LdrpCurrentDllInitializer = LdrEntry;
/* Set up the Act Ctx */
ActCtx.Size = sizeof(ActCtx);
ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
RtlZeroMemory(&ActCtx, sizeof(ActCtx));
/* Activate the ActCtx */
RtlActivateActivationContextUnsafeFast(&ActCtx,
LdrEntry->EntryPointActivationContext);
/* Check if it has TLS */
if (LdrEntry->TlsIndex && Context)
{
/* Call TLS */
LdrpTlsCallback(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
}
/* Call the Entrypoint */
DPRINT1("%wZ - Calling entry point at %x for thread attaching\n",
&LdrEntry->BaseDllName, EntryPoint);
LdrpCallDllEntry(EntryPoint,
LdrEntry->DllBase,
DLL_PROCESS_ATTACH,
Context);
/* Deactivate the ActCtx */
RtlDeactivateActivationContextUnsafeFast(&ActCtx);
/* Save the Current DLL Initializer */
LdrpCurrentDllInitializer = OldInitializer;
/* Mark the entry as processed */
LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
}
}
/* Loop in order */
ListHead = &Peb->Ldr->InInitializationOrderModuleList;
NextEntry = NextEntry->Flink;
while (NextEntry != ListHead)
{
/* Get the Data Entrry */
LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
/* FIXME: Verify NX Compat */
/* Next entry */
NextEntry = NextEntry->Flink;
}
/* Check for TLS */
if (LdrpImageHasTls && Context)
{
/* Set up the Act Ctx */
ActCtx.Size = sizeof(ActCtx);
ActCtx.Frame.Flags = ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
RtlZeroMemory(&ActCtx, sizeof(ActCtx));
/* Activate the ActCtx */
RtlActivateActivationContextUnsafeFast(&ActCtx,
LdrpImageEntry->EntryPointActivationContext);
/* Do TLS callbacks */
LdrpTlsCallback(Peb->ImageBaseAddress, DLL_PROCESS_DETACH);
/* Deactivate the ActCtx */
RtlDeactivateActivationContextUnsafeFast(&ActCtx);
}
/* Restore old TEB */
LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
/* Check if the array is in the heap */
if (LdrRootEntry != LocalArray)
{
/* Free the array */
RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
}
/* Return to caller */
DPRINT("LdrpAttachProcess() done\n");
return Status;
#else
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
#endif
}
NTSTATUS
NTAPI
LdrpInitializeTls(VOID)

View file

@ -0,0 +1,273 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: lib/ntdll/ldr/ldrpe.c
* PURPOSE: Loader Functions dealing low-level PE Format structures
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *****************************************************************/
#include <ntdll.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
ULONG LdrpFatalHardErrorCount;
PVOID LdrpManifestProberRoutine;
/* PROTOTYPES ****************************************************************/
#define IMAGE_REL_BASED_HIGH3ADJ 11
NTSTATUS
NTAPI
LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
IN LPSTR ImportName,
IN PVOID DllBase,
OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
OUT PBOOLEAN Existing);
/* FUNCTIONS *****************************************************************/
USHORT NTAPI
LdrpNameToOrdinal(LPSTR ImportName,
ULONG NumberOfNames,
PVOID ExportBase,
PULONG NameTable,
PUSHORT OrdinalTable)
{
UNIMPLEMENTED;
return 0;
}
NTSTATUS
NTAPI
LdrpSnapThunk(IN PVOID ExportBase,
IN PVOID ImportBase,
IN PIMAGE_THUNK_DATA OriginalThunk,
IN OUT PIMAGE_THUNK_DATA Thunk,
IN PIMAGE_EXPORT_DIRECTORY ExportEntry,
IN ULONG ExportSize,
IN BOOLEAN Static,
IN LPSTR DllName)
{
BOOLEAN IsOrdinal;
USHORT Ordinal;
ULONG OriginalOrdinal = 0;
PIMAGE_IMPORT_BY_NAME AddressOfData;
PULONG NameTable;
PUSHORT OrdinalTable;
LPSTR ImportName;
USHORT Hint;
NTSTATUS Status;
ULONG_PTR HardErrorParameters[3];
UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
ANSI_STRING TempString;
ULONG Mask;
ULONG Response;
PULONG AddressOfFunctions;
UNICODE_STRING TempUString;
ANSI_STRING ForwarderName;
PANSI_STRING ForwardName;
PVOID ForwarderHandle;
ULONG ForwardOrdinal;
/* Check if the snap is by ordinal */
if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
{
/* Get the ordinal number, and its normalized version */
OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base);
}
else
{
/* First get the data VA */
AddressOfData = (PIMAGE_IMPORT_BY_NAME)
((ULONG_PTR)ImportBase +
((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
/* Get the name */
ImportName = (LPSTR)AddressOfData->Name;
/* Now get the VA of the Name and Ordinal Tables */
NameTable = (PULONG)((ULONG_PTR)ExportBase +
(ULONG_PTR)ExportEntry->AddressOfNames);
OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
(ULONG_PTR)ExportEntry->AddressOfNameOrdinals);
/* Get the hint */
Hint = AddressOfData->Hint;
/* Try to get a match by using the hint */
if (((ULONG)Hint < ExportEntry->NumberOfNames) &&
(!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
{
/* We got a match, get the Ordinal from the hint */
Ordinal = OrdinalTable[Hint];
}
else
{
/* Well bummer, hint didn't work, do it the long way */
Ordinal = LdrpNameToOrdinal(ImportName,
ExportEntry->NumberOfNames,
ExportBase,
NameTable,
OrdinalTable);
}
}
/* Check if the ordinal is invalid */
if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions)
{
FailurePath:
/* Is this a static snap? */
if (Static)
{
/* These are critical errors. Setup a string for the DLL name */
RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
/* Set it as the parameter */
HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
Mask = 2;
/* Check if we have an ordinal */
if (IsOrdinal)
{
/* Then set the ordinal as the 1st parameter */
HardErrorParameters[0] = OriginalOrdinal;
}
else
{
/* We don't, use the entrypoint. Set up a string for it */
RtlInitAnsiString(&TempString, ImportName);
RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
&TempString,
TRUE);
/* Set it as the parameter */
HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
Mask = 3;
}
/* Raise the error */
NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
STATUS_ENTRYPOINT_NOT_FOUND,
2,
Mask,
HardErrorParameters,
OptionOk,
&Response);
/* Increase the error count */
if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
/* Free our string */
RtlFreeUnicodeString(&HardErrorDllName);
if (!IsOrdinal)
{
/* Free our second string. Return entrypoint error */
RtlFreeUnicodeString(&HardErrorEntryPointName);
RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
}
/* Return ordinal error */
RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
}
/* Set this as a bad DLL */
Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
/* Return the right error code */
Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
STATUS_ENTRYPOINT_NOT_FOUND;
}
else
{
/* The ordinal seems correct, get the AddressOfFunctions VA */
AddressOfFunctions = (PULONG)
((ULONG_PTR)ExportBase +
(ULONG_PTR)ExportEntry->AddressOfFunctions);
/* Write the function pointer*/
Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
/* Make sure it's within the exports */
if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) &&
(Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize)))
{
/* Get the Import and Forwarder Names */
ImportName = (LPSTR)Thunk->u1.Function;
ForwarderName.Buffer = ImportName;
ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName);
ForwarderName.MaximumLength = ForwarderName.Length;
Status = RtlAnsiStringToUnicodeString(&TempUString,
&ForwarderName,
TRUE);
/* Make sure the conversion was OK */
if (NT_SUCCESS(Status))
{
/* Load the forwarder, free the temp string */
Status = LdrpLoadDll(FALSE,
NULL,
NULL,
&TempUString,
&ForwarderHandle,
FALSE);
RtlFreeUnicodeString(&TempUString);
}
/* If the load or conversion failed, use the failure path */
if (!NT_SUCCESS(Status)) goto FailurePath;
/* Now set up a name for the actual forwarder dll */
RtlInitAnsiString(&ForwarderName,
ImportName + ForwarderName.Length + sizeof(CHAR));
/* Check if it's an ordinal forward */
if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
{
/* We don't have an actual function name */
ForwardName = NULL;
/* Convert the string into an ordinal */
Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
0,
&ForwardOrdinal);
/* If this fails, then error out */
if (!NT_SUCCESS(Status)) goto FailurePath;
}
else
{
/* Import by name */
ForwardName = &ForwarderName;
}
/* Get the pointer */
Status = LdrpGetProcedureAddress(ForwarderHandle,
ForwardName,
ForwardOrdinal,
(PVOID*)&Thunk->u1.Function,
FALSE);
/* If this fails, then error out */
if (!NT_SUCCESS(Status)) goto FailurePath;
}
else
{
/* It's not within the exports, let's hope it's valid */
if (!AddressOfFunctions[Ordinal]) goto FailurePath;
}
/* If we got here, then it's success */
Status = STATUS_SUCCESS;
}
/* Return status */
return Status;
}
/* EOF */

View file

@ -15,6 +15,8 @@
/* GLOBALS *******************************************************************/
PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache;
/* FUNCTIONS *****************************************************************/
BOOLEAN
@ -80,4 +82,248 @@ LdrpTlsCallback(PVOID BaseAddress, ULONG Reason)
_SEH2_END;
}
BOOLEAN
NTAPI
LdrpCheckForLoadedDllHandle(IN PVOID Base,
OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
{
PLDR_DATA_TABLE_ENTRY Current;
PLIST_ENTRY ListHead, Next;
/* Check the cache first */
if (LdrpLoadedDllHandleCache && LdrpLoadedDllHandleCache->DllBase == Base)
{
/* We got lucky, return the cached entry */
*LdrEntry = LdrpLoadedDllHandleCache;
return TRUE;
}
/* Time for a lookup */
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Next = ListHead->Flink;
while(Next != ListHead)
{
/* Get the current entry */
Current = CONTAINING_RECORD(Next,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
/* Make sure it's not unloading and check for a match */
if ((Current->InMemoryOrderModuleList.Flink) && (Base == Current->DllBase))
{
/* Save in cache */
LdrpLoadedDllHandleCache = Current;
/* Return it */
*LdrEntry = Current;
return TRUE;
}
/* Move to the next one */
Next = Next->Flink;
}
/* Nothing found */
return FALSE;
}
BOOLEAN
NTAPI
LdrpCheckForLoadedDll(IN PWSTR DllPath,
IN PUNICODE_STRING DllName,
IN BOOLEAN Flag,
IN BOOLEAN RedirectedDll,
OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
{
UNIMPLEMENTED;
return FALSE;
}
NTSTATUS
NTAPI
LdrpGetProcedureAddress(IN PVOID BaseAddress,
IN PANSI_STRING Name,
IN ULONG Ordinal,
OUT PVOID *ProcedureAddress,
IN BOOLEAN ExecuteInit)
{
NTSTATUS Status = STATUS_SUCCESS;
UCHAR ImportBuffer[64];
PLDR_DATA_TABLE_ENTRY LdrEntry;
IMAGE_THUNK_DATA Thunk;
PVOID ImageBase;
PIMAGE_IMPORT_BY_NAME ImportName = NULL;
PIMAGE_EXPORT_DIRECTORY ExportDir;
ULONG ExportDirSize;
PLIST_ENTRY Entry;
/* Show debug message */
if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by ");
/* Check if we got a name */
if (Name)
{
/* Show debug message */
if (ShowSnaps) DPRINT1("NAME - %s\n", Name->Buffer);
/* Make sure it's not too long */
if ((Name->Length + sizeof(CHAR) + sizeof(USHORT)) > MAXLONG)
{
/* Won't have enough space to add the hint */
return STATUS_NAME_TOO_LONG;
}
/* Check if our buffer is large enough */
if (Name->Length >= (sizeof(ImportBuffer) - sizeof(CHAR)))
{
/* Allocate from heap, plus 2 bytes for the Hint */
ImportName = RtlAllocateHeap(RtlGetProcessHeap(),
0,
Name->Length + sizeof(CHAR) +
sizeof(USHORT));
}
else
{
/* Use our internal buffer */
ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer;
}
/* Clear the hint */
ImportName->Hint = 0;
/* Copy the name and null-terminate it */
RtlMoveMemory(&ImportName->Name, Name->Buffer, Name->Length);
ImportName->Name[Name->Length + 1] = 0;
/* Clear the high bit */
ImageBase = ImportName;
Thunk.u1.AddressOfData = 0;
}
else
{
/* Do it by ordinal */
ImageBase = NULL;
/* Show debug message */
if (ShowSnaps) DPRINT1("ORDINAL - %lx\n", Ordinal);
if (Ordinal)
{
Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG;
}
else
{
/* No ordinal */
DPRINT1("No ordinal and no name\n");
return STATUS_INVALID_PARAMETER;
}
}
/* Acquire lock unless we are initting */
if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock);
_SEH2_TRY
{
/* Try to find the loaded DLL */
if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
{
/* Invalid base */
DPRINT1("Invalid base address\n");
Status = STATUS_DLL_NOT_FOUND;
_SEH2_YIELD(goto Quickie;)
}
/* Get the pointer to the export directory */
ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportDirSize);
if (!ExportDir)
{
DPRINT1("Image has no exports\n");
Status = STATUS_PROCEDURE_NOT_FOUND;
_SEH2_YIELD(goto Quickie;)
}
/* Now get the thunk */
Status = LdrpSnapThunk(LdrEntry->DllBase,
ImageBase,
&Thunk,
&Thunk,
ExportDir,
ExportDirSize,
FALSE,
NULL);
/* Finally, see if we're supposed to run the init routines */
if (ExecuteInit)
{
/*
* It's possible a forwarded entry had us load the DLL. In that case,
* then we will call its DllMain. Use the last loaded DLL for this.
*/
Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink;
LdrEntry = CONTAINING_RECORD(Entry,
LDR_DATA_TABLE_ENTRY,
InInitializationOrderModuleList);
/* Make sure we didn't process it yet*/
if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
{
/* Call the init routine */
_SEH2_TRY
{
Status = LdrpRunInitializeRoutines(NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Make sure we're OK till here */
if (NT_SUCCESS(Status))
{
/* Return the address */
*ProcedureAddress = (PVOID)Thunk.u1.Function;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Just ignore exceptions */
}
_SEH2_END;
Quickie:
/* Cleanup */
if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer))
{
/* We allocated from heap, free it */
RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName);
}
/* Release the CS if we entered it */
if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock);
/* We're done */
return Status;
}
NTSTATUS
NTAPI
LdrpLoadDll(IN BOOLEAN Redirected,
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *BaseAddress,
IN BOOLEAN CallInit)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -2848,108 +2848,6 @@ LdrShutdownThread (VOID)
return STATUS_SUCCESS;
}
/***************************************************************************
* NAME EXPORTED
* LdrQueryProcessModuleInformation
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* NOTE
*
* @implemented
*/
NTSTATUS NTAPI
LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
IN ULONG Size OPTIONAL,
OUT PULONG ReturnedSize)
{
PLIST_ENTRY ModuleListHead;
PLIST_ENTRY Entry;
PLDR_DATA_TABLE_ENTRY Module;
PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
NTSTATUS Status = STATUS_SUCCESS;
ULONG UsedSize = sizeof(ULONG);
ANSI_STRING AnsiString;
PCHAR p;
DPRINT("LdrQueryProcessModuleInformation() called\n");
// FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
if (ModuleInformation == NULL || Size == 0)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
ModuleInformation->NumberOfModules = 0;
ModulePtr = &ModuleInformation->Modules[0];
Status = STATUS_SUCCESS;
}
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);
if (UsedSize > Size)
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else if (ModuleInformation != NULL)
{
ModulePtr->Section = 0;
ModulePtr->MappedBase = NULL; // FIXME: ??
ModulePtr->ImageBase = Module->DllBase;
ModulePtr->ImageSize = Module->SizeOfImage;
ModulePtr->Flags = Module->Flags;
ModulePtr->LoadOrderIndex = 0; // FIXME: ??
ModulePtr->InitOrderIndex = 0; // FIXME: ??
ModulePtr->LoadCount = Module->LoadCount;
AnsiString.Length = 0;
AnsiString.MaximumLength = 256;
AnsiString.Buffer = ModulePtr->FullPathName;
RtlUnicodeStringToAnsiString(&AnsiString,
&Module->FullDllName,
FALSE);
p = strrchr(ModulePtr->FullPathName, '\\');
if (p != NULL)
ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
else
ModulePtr->OffsetToFileName = 0;
ModulePtr++;
ModuleInformation->NumberOfModules++;
}
UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
Entry = Entry->Flink;
}
RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
if (ReturnedSize != 0)
*ReturnedSize = UsedSize;
DPRINT("LdrQueryProcessModuleInformation() done\n");
return(Status);
}
/*
* Compute size of an image as it is actually present in virt memory
* (i.e. excluding NEVER_LOAD sections)

View file

@ -49,6 +49,7 @@
<directory name="ldr">
<file>ldrapi.c</file>
<file>ldrinit.c</file>
<file>ldrpe.c</file>
<file>ldrutils.c</file>
<file>startup.c</file>
<file>utils.c</file>