Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1277 lines
36 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ldrapi.c
Abstract:
This module implements the Ldr APIs that can be linked with
an application to perform loader services. All of the APIs in
this component are implemented in a DLL. They are not part of the
DLL snap procedure.
Author:
Mike O'Leary (mikeol) 23-Mar-1990
Revision History:
--*/
#include "ldrp.h"
#define DLLEXTENSION ((PWSTR)".\0d\0l\0l\0\0") // .dll
ULONG
LdrpClearLoadInProgress(
VOID
);
NTSTATUS
LdrLoadDll (
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
)
/*++
Routine Description:
This function loads a DLL into the calling process address space.
Arguments:
DllPath - Supplies the search path to be used to locate the DLL.
DllCharacteristics - Supplies an optional DLL characteristics flag,
that if specified is used to match against the dll being loaded.
DllName - Supplies the name of the DLL to load.
DllHandle - Returns a handle to the loaded DLL.
Return Value:
TBD
--*/
{
return LdrpLoadDll(DllPath,DllCharacteristics,DllName,DllHandle,TRUE);
}
NTSTATUS
NTAPI
LdrpLoadDll(
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle,
IN BOOLEAN RunInitRoutines
)
{
PPEB Peb;
NTSTATUS st;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PWSTR ActualDllName;
PWCH p, pp;
UNICODE_STRING ActualDllNameStr;
#if defined (WX86)
PWX86TIB Wx86Tib;
#endif
BOOLEAN Wx86KnownDll = FALSE;
WCHAR FreeBuffer[266];
Peb = NtCurrentPeb();
st = STATUS_SUCCESS;
try {
//
// Grab Peb lock and Snap All Links to specified DLL
//
if ( LdrpInLdrInit == FALSE ) {
RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
#if defined (WX86)
Wx86Tib = Wx86CurrentTib();
if (Wx86Tib) {
if (Wx86Tib->UseKnownWx86Dll) {
Wx86KnownDll = Wx86Tib->UseKnownWx86Dll;
Wx86Tib->UseKnownWx86Dll = FALSE;
}
}
#endif
p = DllName->Buffer;
pp = NULL;
while (*p) {
if (*p++ == (WCHAR)'.') {
//
// pp will point to first character after last '.'
//
pp = p;
}
}
ActualDllName = FreeBuffer;
if ( DllName->Length >= sizeof(FreeBuffer)) {
return STATUS_NAME_TOO_LONG;
}
RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length);
if (!pp || *pp == (WCHAR)'\\') {
//
// No extension found (just ..\)
//
if ( DllName->Length+10 >= sizeof(FreeBuffer) ) {
return STATUS_NAME_TOO_LONG;
}
RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DLLEXTENSION, 10);
}
else {
ActualDllName[DllName->Length >> 1] = UNICODE_NULL;
}
if (ShowSnaps) {
DbgPrint("LDR: LdrLoadDll, loading %ws from %ws\n",
ActualDllName,
ARGUMENT_PRESENT(DllPath) ? DllPath : L""
);
}
RtlInitUnicodeString(&ActualDllNameStr,ActualDllName);
ActualDllNameStr.MaximumLength = sizeof(FreeBuffer);
if (!LdrpCheckForLoadedDll( DllPath,
&ActualDllNameStr,
FALSE,
Wx86KnownDll,
&LdrDataTableEntry
)
) {
st = LdrpMapDll(DllPath,
ActualDllName,
DllCharacteristics,
FALSE,
Wx86KnownDll,
&LdrDataTableEntry
);
if (!NT_SUCCESS(st)) {
return st;
}
if (ARGUMENT_PRESENT( DllCharacteristics ) &&
*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE
) {
LdrDataTableEntry->EntryPoint = 0;
LdrDataTableEntry->Flags &= ~LDRP_IMAGE_DLL;
}
//
// and walk the import descriptor.
//
if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) {
try {
st = LdrpWalkImportDescriptor(
DllPath,
LdrDataTableEntry
);
}
except(EXCEPTION_EXECUTE_HANDLER) {
st = GetExceptionCode();
}
if ( LdrDataTableEntry->LoadCount != 0xffff ) {
LdrDataTableEntry->LoadCount++;
}
LdrpReferenceLoadedDll(LdrDataTableEntry);
if (!NT_SUCCESS(st)) {
LdrDataTableEntry->EntryPoint = NULL;
InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
&LdrDataTableEntry->InInitializationOrderLinks);
LdrpClearLoadInProgress();
LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
return st;
}
}
else {
if ( LdrDataTableEntry->LoadCount != 0xffff ) {
LdrDataTableEntry->LoadCount++;
}
}
//
// Add init routine to list
//
InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
&LdrDataTableEntry->InInitializationOrderLinks);
//
// If the loader data base is not fully setup, this load was because
// of a forwarder in the static load set. Can't run init routines
// yet because the load counts are NOT set
//
if ( RunInitRoutines && LdrpLdrDatabaseIsSetup ) {
try {
st = LdrpRunInitializeRoutines(NULL);
if ( !NT_SUCCESS(st) ) {
LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
}
}
except( EXCEPTION_EXECUTE_HANDLER ) {
LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
return GetExceptionCode();
}
}
else {
st = STATUS_SUCCESS;
}
}
else {
//
// Count it. And everything that it imports.
//
if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL &&
LdrDataTableEntry->LoadCount != 0xffff ) {
LdrDataTableEntry->LoadCount++;
LdrpReferenceLoadedDll(LdrDataTableEntry);
//
// Now clear the Load in progress bits
//
LdrpClearLoadInProgress();
}
else {
if ( LdrDataTableEntry->LoadCount != 0xffff ) {
LdrDataTableEntry->LoadCount++;
}
}
}
}
finally {
if ( LdrpInLdrInit == FALSE ) {
RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
}
if ( NT_SUCCESS(st) ) {
*DllHandle = (PVOID)LdrDataTableEntry->DllBase;
}
else {
*DllHandle = NULL;
}
return st;
}
NTSTATUS
LdrGetDllHandle (
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
)
/*++
Routine Description:
This function locates the specified DLL and returns its handle.
Arguments:
DllPath - Supplies the search path to be used to locate the DLL.
DllCharacteristics - Supplies an optional DLL characteristics flag,
that if specified is used to match against the dll being loaded.
DllName - Supplies the name of the DLL to load.
DllHandle - Returns a handle to the loaded DLL.
Return Value:
TBD
--*/
{
NTSTATUS st;
PPEB Peb;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PWSTR ActualDllName;
PWCH p, pp;
UNICODE_STRING ActualDllNameStr;
#if defined (WX86)
PWX86TIB Wx86Tib;
#endif
BOOLEAN Wx86KnownDll = FALSE;
WCHAR FreeBuffer[266];
DllCharacteristics;
Peb = NtCurrentPeb();
st = STATUS_DLL_NOT_FOUND;
try {
//
// Grab Peb lock
//
if ( LdrpInLdrInit == FALSE ) {
RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
#if defined (WX86)
Wx86Tib = Wx86CurrentTib();
if (Wx86Tib) {
if (Wx86Tib->UseKnownWx86Dll) {
Wx86KnownDll = Wx86Tib->UseKnownWx86Dll;
Wx86Tib->UseKnownWx86Dll = FALSE;
}
//
// No module handle cache lookup for Wx86,
// (relies on unique basename)
//
LdrpGetModuleHandleCache = NULL;
}
#endif
if ( LdrpGetModuleHandleCache ) {
if (RtlEqualUnicodeString(DllName,
&LdrpGetModuleHandleCache->BaseDllName,
TRUE
)) {
*DllHandle = (PVOID)LdrpGetModuleHandleCache->DllBase;
st = STATUS_SUCCESS;
leave;
}
}
p = DllName->Buffer;
pp = NULL;
while (*p) {
if (*p++ == (WCHAR)'.') {
//
// pp will point to first character after last '.'
//
pp = p;
}
}
ActualDllName = FreeBuffer;
if ( DllName->Length >= sizeof(FreeBuffer)) {
return STATUS_NAME_TOO_LONG;
}
RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length);
if (!pp || *pp == (WCHAR)'\\') {
//
// No extension found (just ..\)
//
if ( DllName->Length+10 >= sizeof(FreeBuffer) ) {
return STATUS_NAME_TOO_LONG;
}
RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DLLEXTENSION, 10);
}
else {
//
// see if the name ends in . If it does, trim out the trailing
// .
//
if ( ActualDllName[ (DllName->Length-2) >> 1] == L'.' ) {
DllName->Length -= 2;
}
ActualDllName[DllName->Length >> 1] = UNICODE_NULL;
}
//
// Check the LdrTable to see if Dll has already been loaded
// into this image.
//
RtlInitUnicodeString(&ActualDllNameStr,ActualDllName);
ActualDllNameStr.MaximumLength = sizeof(FreeBuffer);
if (ShowSnaps) {
DbgPrint("LDR: LdrGetDllHandle, searching for %ws from %ws\n",
ActualDllName,
ARGUMENT_PRESENT(DllPath) ? (DllPath == (PWSTR)1 ? L"" : DllPath) : L""
);
}
//
// sort of a hack, but done to speed up GetModuleHandle. kernel32
// now does a two pass call here to avoid computing
// process dll path
//
if (LdrpCheckForLoadedDll( DllPath,
&ActualDllNameStr,
(BOOLEAN)(DllPath == (PWSTR)1 ? TRUE : FALSE),
Wx86KnownDll,
&LdrDataTableEntry
)
) {
*DllHandle = (PVOID)LdrDataTableEntry->DllBase;
LdrpGetModuleHandleCache = LdrDataTableEntry;
st = STATUS_SUCCESS;
}
} finally {
if ( LdrpInLdrInit == FALSE ) {
RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
}
return st;
}
NTSTATUS
LdrDisableThreadCalloutsForDll (
IN PVOID DllHandle
)
/*++
Routine Description:
This function disables thread attach and detach notification
for the specified DLL.
Arguments:
DllHandle - Supplies a handle to the DLL to disable.
Return Value:
TBD
--*/
{
NTSTATUS st;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
st = STATUS_SUCCESS;
try {
if ( LdrpInLdrInit == FALSE ) {
RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
if ( LdrpShutdownInProgress ) {
return STATUS_SUCCESS;
}
if (LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
if ( LdrDataTableEntry->TlsIndex ) {
st = STATUS_DLL_NOT_FOUND;
}
else {
LdrDataTableEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
}
}
}
finally {
if ( LdrpInLdrInit == FALSE ) {
RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
}
return st;
}
NTSTATUS
LdrUnloadDll (
IN PVOID DllHandle
)
/*++
Routine Description:
This function unloads the DLL from the specified process
Arguments:
DllHandle - Supplies a handle to the DLL to unload.
Return Value:
TBD
--*/
{
NTSTATUS st;
PPEB Peb;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PLDR_DATA_TABLE_ENTRY Entry;
PDLL_INIT_ROUTINE InitRoutine;
LIST_ENTRY LocalUnloadHead;
PLIST_ENTRY Next;
Peb = NtCurrentPeb();
st = STATUS_SUCCESS;
try {
//
// Grab Peb lock and decrement reference count of all affected DLLs
//
if ( LdrpInLdrInit == FALSE ) {
RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
LdrpActiveUnloadCount++;
if ( LdrpShutdownInProgress ) {
goto leave_finally;
}
if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
st = STATUS_DLL_NOT_FOUND;
goto leave_finally;
}
//
// Now that we have the data table entry, unload it
//
if ( LdrDataTableEntry->LoadCount != 0xffff ) {
LdrDataTableEntry->LoadCount--;
if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL ) {
LdrpDereferenceLoadedDll(LdrDataTableEntry);
}
} else {
//
// if the load count is 0xffff, then we do not need to recurse
// through this DLL's import table.
//
// Additionally, we don't have to scan more LoadCount == 0
// modules since nothing could have happened as a result of a free on this
// DLL.
goto leave_finally;
}
//
// Now process init routines and then in a second pass, unload
// DLLs
//
if (ShowSnaps) {
DbgPrint("LDR: UNINIT LIST\n");
}
if (LdrpActiveUnloadCount == 1 ) {
InitializeListHead(&LdrpUnloadHead);
}
//
// Go in reverse order initialization order and build
// the unload list
//
Next = Peb->Ldr->InInitializationOrderModuleList.Blink;
while ( Next != &Peb->Ldr->InInitializationOrderModuleList) {
LdrDataTableEntry
= (PLDR_DATA_TABLE_ENTRY)
(CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks));
Next = Next->Blink;
LdrDataTableEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
if (LdrDataTableEntry->LoadCount == 0) {
if (ShowSnaps) {
DbgPrint(" (%d) [%ws] %ws (%lx) deinit %lx\n",
LdrpActiveUnloadCount,
LdrDataTableEntry->BaseDllName.Buffer,
LdrDataTableEntry->FullDllName.Buffer,
(ULONG)LdrDataTableEntry->LoadCount,
LdrDataTableEntry->EntryPoint
);
}
Entry = LdrDataTableEntry;
RemoveEntryList(&Entry->InInitializationOrderLinks);
RemoveEntryList(&Entry->InMemoryOrderLinks);
RemoveEntryList(&Entry->HashLinks);
if ( LdrpActiveUnloadCount > 1 ) {
LdrpLoadedDllHandleCache = NULL;
Entry->InMemoryOrderLinks.Flink = NULL;
}
InsertTailList(&LdrpUnloadHead,&Entry->HashLinks);
}
}
//
// End of new code
//
//
// We only do init routine call's and module free's at the top level,
// so if the active count is > 1, just return
//
if (LdrpActiveUnloadCount > 1 ) {
goto leave_finally;
}
//
// Now that the unload list is built, walk through the unload
// list in order and call the init routine. The dll must remain
// on the InLoadOrderLinks so that the pctoheader stuff will
// still work
//
InitializeListHead(&LocalUnloadHead);
Entry = NULL;
Next = LdrpUnloadHead.Flink;
while ( Next != &LdrpUnloadHead ) {
top:
if ( Entry ) {
RemoveEntryList(&(Entry->InLoadOrderLinks));
Entry = NULL;
Next = LdrpUnloadHead.Flink;
if (Next == &LdrpUnloadHead ) {
goto bottom;
}
}
LdrDataTableEntry
= (PLDR_DATA_TABLE_ENTRY)
(CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
//
// Remove dll from the global unload list and place
// on the local unload list. This is because the global list
// can change during the callout to the init routine
//
Entry = LdrDataTableEntry;
LdrpLoadedDllHandleCache = NULL;
Entry->InMemoryOrderLinks.Flink = NULL;
RemoveEntryList(&Entry->HashLinks);
InsertTailList(&LocalUnloadHead,&Entry->HashLinks);
//
// If the function has an init routine, call it.
//
InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint;
if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) {
try {
if (ShowSnaps) {
DbgPrint("LDR: Calling deinit %lx\n",InitRoutine);
}
#if defined (WX86)
if (!Wx86CurrentTib() ||
LdrpRunWx86DllEntryPoint(InitRoutine,
NULL,
LdrDataTableEntry->DllBase,
DLL_PROCESS_DETACH,
NULL
) == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
#endif
{
(InitRoutine)(LdrDataTableEntry->DllBase,DLL_PROCESS_DETACH, NULL);
}
RemoveEntryList(&Entry->InLoadOrderLinks);
Entry = NULL;
Next = LdrpUnloadHead.Flink;
}
except(EXCEPTION_EXECUTE_HANDLER){
goto top;
}
} else {
RemoveEntryList(&(Entry->InLoadOrderLinks));
Entry = NULL;
Next = LdrpUnloadHead.Flink;
}
}
bottom:
#if defined (WX86)
if (Wx86CurrentTib() && Wx86DllMapNotify) {
//
// Notify Wx86 that the modules are about to be unmapped. This
// must be done in a separate pass from the unmap loop, as wx86.dll
// might be in the list of modules to unmap.
//
Next = LocalUnloadHead.Flink;
while ( Next != &LocalUnloadHead ) {
LdrDataTableEntry
= (PLDR_DATA_TABLE_ENTRY)
(CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
Next = Next->Flink;
(*Wx86DllMapNotify)(LdrDataTableEntry->DllBase, FALSE, NULL);
}
}
#endif
//
// Now, go through the modules and unmap them
//
Next = LocalUnloadHead.Flink;
while ( Next != &LocalUnloadHead ) {
LdrDataTableEntry
= (PLDR_DATA_TABLE_ENTRY)
(CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
Next = Next->Flink;
Entry = LdrDataTableEntry;
#if DBG
RtlLogEvent( LdrpUnloadModuleEventId,
0,
&LdrDataTableEntry->FullDllName,
LdrDataTableEntry->DllBase
);
#endif // DBG
if (ShowSnaps) {
DbgPrint("LDR: Unmapping [%ws]\n",
LdrDataTableEntry->BaseDllName.Buffer
);
}
st = NtUnmapViewOfSection(NtCurrentProcess(),Entry->DllBase);
ASSERT(NT_SUCCESS(st));
if (Entry->FullDllName.Buffer) {
RtlFreeUnicodeString(&Entry->FullDllName);
}
if (Entry->BaseDllName.Buffer) {
RtlFreeUnicodeString(&Entry->BaseDllName);
}
if ( Entry == LdrpGetModuleHandleCache ) {
LdrpGetModuleHandleCache = NULL;
}
RtlFreeHeap(Peb->ProcessHeap, 0,Entry);
}
leave_finally:;
}
finally {
LdrpActiveUnloadCount--;
if ( LdrpInLdrInit == FALSE ) {
RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
}
return st;
}
NTSTATUS
LdrGetProcedureAddress (
IN PVOID DllHandle,
IN PANSI_STRING ProcedureName OPTIONAL,
IN ULONG ProcedureNumber OPTIONAL,
OUT PVOID *ProcedureAddress
)
{
return LdrpGetProcedureAddress(DllHandle,ProcedureName,ProcedureNumber,ProcedureAddress,TRUE);
}
NTSTATUS
LdrpGetProcedureAddress (
IN PVOID DllHandle,
IN PANSI_STRING ProcedureName OPTIONAL,
IN ULONG ProcedureNumber OPTIONAL,
OUT PVOID *ProcedureAddress,
IN BOOLEAN RunInitRoutines
)
/*++
Routine Description:
This function locates the address of the specified procedure in the
specified DLL and returns its address.
Arguments:
DllHandle - Supplies a handle to the DLL that the address is being
looked up in.
ProcedureName - Supplies that address of a string that contains the
name of the procedure to lookup in the DLL. If this argument is
not specified, then the ProcedureNumber is used.
ProcedureNumber - Supplies the procedure number to lookup. If
ProcedureName is specified, then this argument is ignored.
Otherwise, it specifies the procedure ordinal number to locate
in the DLL.
ProcedureAddress - Returns the address of the procedure found in
the DLL.
Return Value:
TBD
--*/
{
NTSTATUS st;
UCHAR FunctionNameBuffer[64];
PUCHAR src, dst;
ULONG cb, ExportSize;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
IMAGE_THUNK_DATA Thunk;
PVOID ImageBase;
PIMAGE_IMPORT_BY_NAME FunctionName;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PLIST_ENTRY Next;
if (ShowSnaps) {
DbgPrint("LDR: LdrGetProcedureAddress by ");
}
FunctionName = NULL;
if ( ARGUMENT_PRESENT(ProcedureName) ) {
if (ShowSnaps) {
DbgPrint("NAME - %s\n", ProcedureName->Buffer);
}
//
// BUGBUG need STRING to PSZ
//
if (ProcedureName->Length >= sizeof( FunctionNameBuffer )-1 ) {
FunctionName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TEMP_TAG ),ProcedureName->Length+1+sizeof(USHORT));
if ( !FunctionName ) {
return STATUS_INVALID_PARAMETER;
}
} else {
FunctionName = (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer;
}
FunctionName->Hint = 0;
cb = ProcedureName->Length;
src = ProcedureName->Buffer;
dst = FunctionName->Name;
ImageBase = NtCurrentPeb()->ImageBaseAddress;
while (cb--) {
*dst++ = *src++;
}
*dst = '\0';
Thunk.u1.AddressOfData = FunctionName;
} else {
if (ShowSnaps) {
DbgPrint("ORDINAL - %lx\n", ProcedureNumber);
}
if (ProcedureNumber) {
Thunk.u1.Ordinal = ProcedureNumber | IMAGE_ORDINAL_FLAG;
} else {
return STATUS_INVALID_PARAMETER;
}
}
if ( LdrpInLdrInit == FALSE ) {
RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
try {
if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
st = STATUS_DLL_NOT_FOUND;
return st;
}
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
LdrDataTableEntry->DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize
);
if (!ExportDirectory) {
return STATUS_PROCEDURE_NOT_FOUND;
}
st = LdrpSnapThunk(LdrDataTableEntry->DllBase,
0,
&Thunk,
&Thunk,
ExportDirectory,
ExportSize,
FALSE,
NULL
);
if ( RunInitRoutines ) {
//
// Look at last entry in init order list. If entry processed
// flag is not set, then a forwarded dll was loaded during the
// getprocaddr call and we need to run init routines
//
Next = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink;
LdrDataTableEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
if ( !(LdrDataTableEntry->Flags & LDRP_ENTRY_PROCESSED) ) {
try {
st = LdrpRunInitializeRoutines(NULL);
}
except( EXCEPTION_EXECUTE_HANDLER ) {
st = GetExceptionCode();
}
}
}
if ( NT_SUCCESS(st) ) {
*ProcedureAddress = Thunk.u1.Function;
}
} finally {
if ( FunctionName && (FunctionName != (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer) ) {
RtlFreeHeap(RtlProcessHeap(),0,FunctionName);
}
if ( LdrpInLdrInit == FALSE ) {
RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
}
return st;
}
NTSTATUS
NTAPI
LdrVerifyImageMatchesChecksum (
IN HANDLE ImageFileHandle,
IN PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine OPTIONAL,
IN PVOID ImportCallbackParameter,
OUT PUSHORT ImageCharacteristics OPTIONAL
)
{
NTSTATUS Status;
HANDLE Section;
PVOID ViewBase;
ULONG ViewSize;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION StandardInfo;
PIMAGE_SECTION_HEADER LastRvaSection;
BOOLEAN b;
Status = NtCreateSection(
&Section,
SECTION_MAP_EXECUTE,
NULL,
NULL,
PAGE_EXECUTE,
SEC_COMMIT,
ImageFileHandle
);
if ( !NT_SUCCESS(Status) ) {
return Status;
}
ViewBase = NULL;
ViewSize = 0;
Status = NtMapViewOfSection(
Section,
NtCurrentProcess(),
(PVOID *)&ViewBase,
0L,
0L,
NULL,
&ViewSize,
ViewShare,
0L,
PAGE_EXECUTE
);
if ( !NT_SUCCESS(Status) ) {
NtClose(Section);
return Status;
}
//
// now the image is mapped as a data file... Calculate it's size and then
// check it's checksum
//
Status = NtQueryInformationFile(
ImageFileHandle,
&IoStatusBlock,
&StandardInfo,
sizeof(StandardInfo),
FileStandardInformation
);
if ( !NT_SUCCESS(Status) ) {
NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
NtClose(Section);
return Status;
}
try {
b = LdrVerifyMappedImageMatchesChecksum(ViewBase,StandardInfo.EndOfFile.LowPart);
if (b && ARGUMENT_PRESENT( ImportCallbackRoutine )) {
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
ULONG ImportSize;
PCHAR ImportName;
//
// Caller wants to enumerate the import descriptors while we have
// the image mapped. Call back to their routine for each module
// name in the import descriptor table.
//
LastRvaSection = NULL;
NtHeaders = RtlImageNtHeader( ViewBase );
if (ARGUMENT_PRESENT( ImageCharacteristics )) {
*ImageCharacteristics = NtHeaders->FileHeader.Characteristics;
}
ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)
RtlImageDirectoryEntryToData( ViewBase,
FALSE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ImportSize
);
if (ImportDescriptor != NULL) {
while (ImportDescriptor->Name) {
ImportName = (PSZ)RtlImageRvaToVa( NtHeaders,
ViewBase,
ImportDescriptor->Name,
&LastRvaSection
);
(*ImportCallbackRoutine)( ImportCallbackParameter, ImportName );
ImportDescriptor += 1;
}
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
NtClose(Section);
return STATUS_IMAGE_CHECKSUM_MISMATCH;
}
NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
NtClose(Section);
if ( !b ) {
Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
}
return Status;
}
NTSTATUS
LdrQueryProcessModuleInformation(
OUT PRTL_PROCESS_MODULES ModuleInformation,
IN ULONG ModuleInformationLength,
OUT PULONG ReturnLength OPTIONAL
)
{
NTSTATUS Status;
PPEB Peb;
PLIST_ENTRY LoadOrderListHead;
PLIST_ENTRY InitOrderListHead;
ULONG RequiredLength;
PLIST_ENTRY Next;
PLIST_ENTRY Next1;
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry1;
ANSI_STRING AnsiString;
PUCHAR s;
Peb = NtCurrentPeb();
//
// Grab Peb lock and capture information about of DLLs loaded in current process.
//
if ( LdrpInLdrInit == FALSE ) {
RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
try {
RequiredLength = FIELD_OFFSET( RTL_PROCESS_MODULES, Modules );
if (ModuleInformationLength < RequiredLength) {
Status = STATUS_INFO_LENGTH_MISMATCH;
ModuleInfo = NULL;
}
else {
ModuleInformation->NumberOfModules = 0;
ModuleInfo = &ModuleInformation->Modules[ 0 ];
Status = STATUS_SUCCESS;
}
LoadOrderListHead = &Peb->Ldr->InLoadOrderModuleList;
InitOrderListHead = &Peb->Ldr->InInitializationOrderModuleList;
Next = LoadOrderListHead->Flink;
while ( Next != LoadOrderListHead ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks
);
RequiredLength += sizeof( RTL_PROCESS_MODULE_INFORMATION );
if (ModuleInformationLength < RequiredLength) {
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else {
ModuleInfo->MappedBase = NULL;
ModuleInfo->ImageBase = LdrDataTableEntry->DllBase;
ModuleInfo->ImageSize = LdrDataTableEntry->SizeOfImage;
ModuleInfo->Flags = LdrDataTableEntry->Flags;
ModuleInfo->LoadCount = LdrDataTableEntry->LoadCount;
ModuleInfo->LoadOrderIndex = (USHORT)(ModuleInformation->NumberOfModules);
ModuleInfo->InitOrderIndex = 0;
Next1 = InitOrderListHead->Flink;
while ( Next1 != InitOrderListHead ) {
LdrDataTableEntry1 = CONTAINING_RECORD( Next1,
LDR_DATA_TABLE_ENTRY,
InInitializationOrderLinks
);
ModuleInfo->InitOrderIndex++;
if (LdrDataTableEntry1 == LdrDataTableEntry) {
break;
}
Next1 = Next1->Flink;
}
AnsiString.Buffer = ModuleInfo->FullPathName;
AnsiString.Length = 0;
AnsiString.MaximumLength = sizeof( ModuleInfo->FullPathName );
RtlUnicodeStringToAnsiString( &AnsiString,
&LdrDataTableEntry->FullDllName,
FALSE
);
s = AnsiString.Buffer + AnsiString.Length;
while (s > AnsiString.Buffer && *--s) {
if (*s == (UCHAR)OBJ_NAME_PATH_SEPARATOR) {
s++;
break;
}
}
ModuleInfo->OffsetToFileName = (USHORT)(s - AnsiString.Buffer);
ModuleInfo++;
}
if (ModuleInformation != NULL) {
ModuleInformation->NumberOfModules++;
}
Next = Next->Flink;
}
if (ARGUMENT_PRESENT( ReturnLength )) {
*ReturnLength = RequiredLength;
}
}
finally {
if ( LdrpInLdrInit == FALSE ) {
RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
}
}
return( Status );
}
#if defined(MIPS)
VOID
LdrProcessStarterHelper(
IN PPROCESS_STARTER_ROUTINE ProcessStarter,
IN PVOID RealStartAddress
)
/*++
Routine Description:
This function is used to call the code that calls the initial entry point
of a win32 process. On all other platforms, this wrapper is not used since
they can cope with a process entrypoint being in kernel32 prior to it being
mapped.
Arguments:
ProcessStarter - Supplies the address of the function in Kernel32 that ends up
calling the real process entrypoint
RealStartAddress - Supplies the real start address of the process
.
Return Value:
None.
--*/
{
(ProcessStarter)(RealStartAddress);
NtTerminateProcess(NtCurrentProcess(),0);
}
#endif