2011-03-14 22:06:25 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS NT User-Mode Library
|
|
|
|
* FILE: dll/ntdll/ldr/ldrutils.c
|
|
|
|
* PURPOSE: Internal Loader Utility Functions
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
|
|
* Aleksey Bragin (aleksey@reactos.org)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include <ntdll.h>
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2011-03-16 14:22:15 +00:00
|
|
|
PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache;
|
|
|
|
|
2011-03-21 22:58:47 +00:00
|
|
|
#define LDR_GET_HASH_ENTRY(x) (RtlUpcaseUnicodeChar((x)) & (LDR_HASH_TABLE_ENTRIES - 1))
|
|
|
|
|
2011-03-14 22:06:25 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
LdrpCallDllEntry(PDLLMAIN_FUNC EntryPoint,
|
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG Reason,
|
|
|
|
PVOID Context)
|
|
|
|
{
|
|
|
|
/* Call the entry */
|
|
|
|
return EntryPoint(BaseAddress, Reason, Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
LdrpTlsCallback(PVOID BaseAddress, ULONG Reason)
|
|
|
|
{
|
|
|
|
PIMAGE_TLS_DIRECTORY TlsDirectory;
|
|
|
|
PIMAGE_TLS_CALLBACK *Array, Callback;
|
|
|
|
ULONG Size;
|
|
|
|
|
|
|
|
/* Get the TLS Directory */
|
|
|
|
TlsDirectory = RtlImageDirectoryEntryToData(BaseAddress,
|
|
|
|
TRUE,
|
|
|
|
IMAGE_DIRECTORY_ENTRY_TLS,
|
|
|
|
&Size);
|
|
|
|
|
|
|
|
/* Protect against invalid pointers */
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Make sure it's valid and we have an array */
|
|
|
|
if (TlsDirectory && (Array = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks))
|
|
|
|
{
|
|
|
|
/* Display debug */
|
|
|
|
if (ShowSnaps)
|
|
|
|
{
|
|
|
|
DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
|
|
|
|
BaseAddress, TlsDirectory, Array);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop the array */
|
|
|
|
while (*Array)
|
|
|
|
{
|
|
|
|
/* Get the TLS Entrypoint */
|
|
|
|
Callback = *Array++;
|
|
|
|
|
|
|
|
/* Display debug */
|
|
|
|
if (ShowSnaps)
|
|
|
|
{
|
|
|
|
DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
|
|
|
|
BaseAddress, Callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call it */
|
|
|
|
LdrpCallDllEntry((PDLLMAIN_FUNC)Callback, BaseAddress, Reason, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
/* Do nothing */
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
}
|
|
|
|
|
2011-03-21 22:58:47 +00:00
|
|
|
PVOID
|
|
|
|
NTAPI
|
|
|
|
LdrpFetchAddressOfEntryPoint(PVOID ImageBase)
|
|
|
|
{
|
|
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
|
|
ULONG_PTR EntryPoint;
|
|
|
|
|
|
|
|
/* Get entry point offset from NT headers */
|
|
|
|
NtHeaders = RtlImageNtHeader(ImageBase);
|
|
|
|
EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint;
|
|
|
|
|
|
|
|
/* If it's 0 - return so */
|
|
|
|
if (!EntryPoint) return NULL;
|
|
|
|
|
|
|
|
/* Add image base */
|
|
|
|
EntryPoint += (ULONG_PTR)ImageBase;
|
|
|
|
|
|
|
|
/* Return calculated pointer */
|
|
|
|
return (PVOID)EntryPoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
LdrpMapDll(IN PWSTR SearchPath OPTIONAL,
|
|
|
|
IN PWSTR DllPath2,
|
|
|
|
IN PWSTR DllName OPTIONAL,
|
|
|
|
IN PULONG DllCharacteristics,
|
|
|
|
IN BOOLEAN Static,
|
|
|
|
IN BOOLEAN Redirect,
|
|
|
|
OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLDR_DATA_TABLE_ENTRY
|
|
|
|
NTAPI
|
|
|
|
LdrpAllocateDataTableEntry(IN PVOID BaseAddress)
|
|
|
|
{
|
|
|
|
PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
|
|
|
|
PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader(BaseAddress);
|
|
|
|
|
|
|
|
/* Make sure the header is valid */
|
|
|
|
if (NtHeader)
|
|
|
|
{
|
|
|
|
/* Allocate an entry */
|
|
|
|
LdrEntry = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
|
|
HEAP_ZERO_MEMORY,
|
|
|
|
sizeof(LDR_DATA_TABLE_ENTRY));
|
|
|
|
|
|
|
|
/* Make sure we got one */
|
|
|
|
if (LdrEntry)
|
|
|
|
{
|
|
|
|
/* Set it up */
|
|
|
|
LdrEntry->DllBase = BaseAddress;
|
|
|
|
LdrEntry->SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
|
|
|
|
LdrEntry->TimeDateStamp = NtHeader->FileHeader.TimeDateStamp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the entry */
|
|
|
|
return LdrEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
|
|
|
|
{
|
|
|
|
PPEB_LDR_DATA PebData = NtCurrentPeb()->Ldr;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
/* Get the Hash entry */
|
|
|
|
i = LDR_GET_HASH_ENTRY(LdrEntry->BaseDllName.Buffer[0]);
|
|
|
|
|
|
|
|
InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks);
|
|
|
|
InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks);
|
|
|
|
InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderModuleList);
|
|
|
|
}
|
|
|
|
|
2011-03-16 14:22:15 +00:00
|
|
|
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)
|
|
|
|
{
|
2011-03-22 12:41:52 +00:00
|
|
|
ULONG HashIndex;
|
|
|
|
PLIST_ENTRY ListHead, ListEntry;
|
|
|
|
PLDR_DATA_TABLE_ENTRY CurEntry;
|
|
|
|
BOOLEAN FullPath = FALSE;
|
|
|
|
PWCHAR wc;
|
|
|
|
WCHAR NameBuf[266];
|
|
|
|
UNICODE_STRING FullDllName, NtPathName;
|
|
|
|
ULONG Length;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE FileHandle, SectionHandle;
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
PVOID ViewBase = NULL;
|
|
|
|
SIZE_T ViewSize = 0;
|
|
|
|
PIMAGE_NT_HEADERS NtHeader, NtHeader2;
|
|
|
|
DPRINT1("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath, DllName, Flag, RedirectedDll, LdrEntry);
|
|
|
|
/* Check if a dll name was provided */
|
|
|
|
if (!DllName->Buffer || !DllName->Buffer[0]) return FALSE;
|
|
|
|
|
|
|
|
/* Look in the hash table if flag was set */
|
|
|
|
lookinhash:
|
|
|
|
if (Flag)
|
|
|
|
{
|
|
|
|
/* Get hash index */
|
|
|
|
HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]);
|
|
|
|
|
|
|
|
/* Traverse that list */
|
|
|
|
ListHead = &LdrpHashTable[HashIndex];
|
|
|
|
ListEntry = ListHead->Flink;
|
|
|
|
while (ListEntry != ListHead)
|
|
|
|
{
|
|
|
|
/* Get the current entry */
|
|
|
|
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
|
|
|
|
|
|
|
|
/* Check base name of that module */
|
|
|
|
if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE))
|
|
|
|
{
|
|
|
|
/* It matches, return it */
|
|
|
|
*LdrEntry = CurEntry;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Advance to the next entry */
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Module was not found, return failure */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if there is a full path in this DLL */
|
|
|
|
wc = DllName->Buffer;
|
|
|
|
while (*wc)
|
|
|
|
{
|
|
|
|
/* Check for a slash in the current position*/
|
|
|
|
if (*wc == L'\\' || *wc == L'/')
|
|
|
|
{
|
|
|
|
/* Found the slash, so dll name contains path */
|
|
|
|
FullPath = TRUE;
|
|
|
|
|
|
|
|
/* Setup full dll name string */
|
|
|
|
FullDllName.Buffer = NameBuf;
|
|
|
|
|
|
|
|
Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer,
|
|
|
|
DllName->Buffer,
|
|
|
|
NULL,
|
|
|
|
sizeof(NameBuf) - sizeof(UNICODE_NULL),
|
|
|
|
FullDllName.Buffer,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Check if that was successful */
|
|
|
|
if (!Length || Length > sizeof(NameBuf) - sizeof(UNICODE_NULL))
|
|
|
|
{
|
|
|
|
if (ShowSnaps)
|
|
|
|
{
|
|
|
|
DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
|
|
|
|
DllName->Buffer, Length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return failure */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Full dll name is found */
|
|
|
|
FullDllName.Length = Length;
|
|
|
|
FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
wc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Go check the hash table */
|
|
|
|
if (!FullPath)
|
|
|
|
{
|
|
|
|
Flag = TRUE;
|
|
|
|
goto lookinhash;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now go through the InLoadOrder module list */
|
|
|
|
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
|
|
|
ListEntry = ListHead->Flink;
|
|
|
|
|
|
|
|
while (ListEntry != ListHead)
|
|
|
|
{
|
|
|
|
/* Get the containing record of the current entry and advance to the next one */
|
|
|
|
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
|
|
|
|
/* Check if it's already being unloaded */
|
|
|
|
if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
|
|
|
|
|
|
|
|
/* Check if name matches */
|
|
|
|
if (RtlEqualUnicodeString(&FullDllName,
|
|
|
|
&CurEntry->FullDllName,
|
|
|
|
TRUE))
|
|
|
|
{
|
|
|
|
/* Found it */
|
|
|
|
*LdrEntry = CurEntry;
|
|
|
|
|
|
|
|
/* Find activation context */
|
|
|
|
Status = RtlFindActivationContextSectionString(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, DllName, NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The DLL was not found in the load order modules list. Perform a complex check */
|
|
|
|
|
|
|
|
/* Convert given path to NT path */
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer,
|
|
|
|
&NtPathName,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
/* Fail if conversion failed */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize object attributes and open it */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtPathName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
|
|
SYNCHRONIZE | FILE_EXECUTE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&Iosb,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
|
|
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
|
|
|
|
/* Free NT path name */
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
|
|
|
|
|
|
|
|
/* If opening the file failed - return failure */
|
|
|
|
if (!NT_SUCCESS(Status)) return FALSE;
|
|
|
|
|
|
|
|
/* Create a section for this file */
|
|
|
|
Status = NtCreateSection(&SectionHandle,
|
|
|
|
SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
PAGE_EXECUTE,
|
|
|
|
SEC_COMMIT,
|
|
|
|
FileHandle);
|
|
|
|
|
|
|
|
/* Close file handle */
|
|
|
|
NtClose(FileHandle);
|
|
|
|
|
|
|
|
/* If creating section failed - return failure */
|
|
|
|
if (!NT_SUCCESS(Status)) return FALSE;
|
|
|
|
|
|
|
|
/* Map view of this section */
|
|
|
|
Status = ZwMapViewOfSection(SectionHandle,
|
|
|
|
NtCurrentProcess(),
|
|
|
|
&ViewBase,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
&ViewSize,
|
|
|
|
ViewShare,
|
|
|
|
0,
|
|
|
|
PAGE_EXECUTE);
|
|
|
|
/* Close section handle */
|
|
|
|
NtClose(SectionHandle);
|
|
|
|
|
|
|
|
/* If section mapping failed - return failure */
|
|
|
|
if (!NT_SUCCESS(Status)) return FALSE;
|
|
|
|
|
|
|
|
/* Get pointer to the NT header of this section */
|
|
|
|
NtHeader = RtlImageNtHeader(ViewBase);
|
|
|
|
if (!NtHeader)
|
|
|
|
{
|
|
|
|
/* Unmap the section and fail */
|
|
|
|
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Go through the list of modules */
|
|
|
|
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
|
|
|
ListEntry = ListHead->Flink;
|
|
|
|
|
|
|
|
while (ListEntry != ListHead)
|
|
|
|
{
|
|
|
|
CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
|
|
|
|
/* Check if it's already being unloaded */
|
|
|
|
if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
|
|
|
|
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Check if timedate stamp and sizes match */
|
|
|
|
if (CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp &&
|
|
|
|
CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage)
|
|
|
|
{
|
|
|
|
/* Time, date and size match. Let's compare their headers */
|
|
|
|
NtHeader2 = RtlImageNtHeader(CurEntry->DllBase);
|
|
|
|
|
|
|
|
if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS)))
|
|
|
|
{
|
|
|
|
/* Headers match too! Finally ask the kernel to compare mapped files */
|
|
|
|
Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
_SEH2_YIELD(continue;)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This is our entry! */
|
|
|
|
*LdrEntry = CurEntry;
|
|
|
|
|
|
|
|
/* Unmap the section */
|
|
|
|
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
|
|
|
|
|
|
|
|
_SEH2_YIELD(return TRUE;)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
_SEH2_YIELD(break;)
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unmap the section */
|
|
|
|
NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
|
|
|
|
|
2011-03-16 14:22:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-03-17 10:59:54 +00:00
|
|
|
ULONG
|
|
|
|
NTAPI
|
|
|
|
LdrpClearLoadInProgress()
|
|
|
|
{
|
|
|
|
PLIST_ENTRY ListHead;
|
|
|
|
PLIST_ENTRY Entry;
|
|
|
|
PLDR_DATA_TABLE_ENTRY Module;
|
|
|
|
ULONG ModulesCount = 0;
|
|
|
|
|
|
|
|
/* Traverse the init list */
|
|
|
|
ListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
|
|
|
|
Entry = ListHead->Flink;
|
|
|
|
|
|
|
|
while (Entry != ListHead)
|
|
|
|
{
|
|
|
|
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
|
|
|
|
|
|
|
|
/* Clear load in progress flag */
|
|
|
|
Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
|
|
|
|
|
|
|
|
/* Increase counter for modules with entry point count but not processed yet */
|
|
|
|
if (Module->EntryPoint &&
|
|
|
|
!(Module->Flags & LDRP_ENTRY_PROCESSED)) ModulesCount++;
|
|
|
|
|
|
|
|
/* Advance to the next entry */
|
|
|
|
Entry = Entry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ModulesCount;
|
|
|
|
}
|
|
|
|
|
2011-03-14 22:06:25 +00:00
|
|
|
/* EOF */
|