mirror of
https://github.com/reactos/reactos.git
synced 2025-04-27 17:10:22 +00:00
[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:
parent
4b2c1d1a6b
commit
3f20ae61b8
7 changed files with 967 additions and 104 deletions
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
273
reactos/dll/ntdll/ldr/ldrpe.c
Normal file
273
reactos/dll/ntdll/ldr/ldrpe.c
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue