2011-03-15 18:56:17 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @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 & ~1)
|
|
|
|
{
|
|
|
|
/* Flags are invalid, check how to fail */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* The caller wants us to raise status */
|
|
|
|
RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* 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 */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* The caller wants us to raise status */
|
|
|
|
RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* A normal failure */
|
|
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ready to release the lock */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* 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 Result OPTIONAL,
|
|
|
|
OUT PULONG Cookie OPTIONAL)
|
|
|
|
{
|
|
|
|
LONG OldCount;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2011-03-16 14:22:15 +00:00
|
|
|
BOOLEAN InInit = LdrpInLdrInit;
|
2011-03-15 18:56:17 +00:00
|
|
|
|
|
|
|
DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Result, Cookie);
|
|
|
|
|
|
|
|
/* Zero out the outputs */
|
|
|
|
if (Result) *Result = 0;
|
|
|
|
if (Cookie) *Cookie = 0;
|
|
|
|
|
|
|
|
/* Validate the flags */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS |
|
2011-03-15 18:56:17 +00:00
|
|
|
LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY))
|
|
|
|
{
|
|
|
|
/* Flags are invalid, check how to fail */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* 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 */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* The caller wants us to raise status */
|
|
|
|
RtlRaiseStatus(STATUS_INVALID_PARAMETER_3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* A normal failure */
|
|
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the flag is set, make sure we have a valid pointer to use */
|
|
|
|
if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Result))
|
|
|
|
{
|
|
|
|
/* No pointer to return the data to */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* 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 */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
|
2011-03-15 18:56:17 +00:00
|
|
|
{
|
|
|
|
/* 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 */
|
2011-04-04 19:35:24 +00:00
|
|
|
*Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
|
2011-03-15 18:56:17 +00:00
|
|
|
goto Quickie;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* It worked */
|
2011-04-04 19:35:24 +00:00
|
|
|
*Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
|
2011-03-15 18:56:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Do a enter */
|
|
|
|
RtlEnterCriticalSection(&LdrpLoaderLock);
|
|
|
|
|
|
|
|
/* See if result was requested */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Result) *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
|
2011-03-15 18:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Increase the acquisition count */
|
|
|
|
OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
|
|
|
|
|
|
|
|
/* Generate a cookie */
|
|
|
|
*Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
|
|
|
|
}
|
|
|
|
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 */
|
2011-04-04 19:35:24 +00:00
|
|
|
*Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
|
2011-03-15 18:56:17 +00:00
|
|
|
_SEH2_YIELD(return STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* It worked */
|
2011-04-04 19:35:24 +00:00
|
|
|
*Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
|
2011-03-15 18:56:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Do an enter */
|
|
|
|
RtlEnterCriticalSection(&LdrpLoaderLock);
|
|
|
|
|
|
|
|
/* See if result was requested */
|
2011-04-04 19:35:24 +00:00
|
|
|
if (Result) *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
|
2011-03-15 18:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Increase the acquisition count */
|
|
|
|
OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
|
|
|
|
|
|
|
|
/* Generate a cookie */
|
|
|
|
*Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
/* We should use the LDR Filter instead */
|
|
|
|
Status = _SEH2_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
Quickie:
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2011-03-16 09:52:41 +00:00
|
|
|
/*
|
|
|
|
* @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 = 0;
|
|
|
|
PVOID ViewBase = NULL;
|
|
|
|
BOOLEAN Result;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PVOID ImportName;
|
|
|
|
ULONG Size;
|
|
|
|
|
|
|
|
DPRINT("LdrVerifyImageMatchesChecksum() called\n");
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
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
|
|
|
|
{
|
|
|
|
/* Verify the checksum */
|
|
|
|
Result = LdrVerifyMappedImageMatchesChecksum(ViewBase,
|
|
|
|
ViewSize,
|
|
|
|
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_IMAGE_CHECKSUM_MISMATCH : Status;
|
|
|
|
}
|
|
|
|
|
2011-03-16 14:22:15 +00:00
|
|
|
/*
|
|
|
|
* @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)
|
|
|
|
{
|
2011-03-17 10:59:54 +00:00
|
|
|
InitModule = CONTAINING_RECORD(InitEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
|
2011-03-16 14:22:15 +00:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2011-03-30 21:21:42 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2011-03-31 11:32:57 +00:00
|
|
|
LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVOID Context)
|
2011-03-30 21:21:42 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-03-15 18:56:17 +00:00
|
|
|
/* EOF */
|