mirror of
https://github.com/reactos/reactos.git
synced 2025-07-28 12:01:55 +00:00
[NTDLL_VISTA:LDR] Implement DLL Notification (#6795)
Implement DLL Load Notification, an NT6+ feature. https://learn.microsoft.com/en-us/windows/win32/devnotes/dll-load-notification - [RTL] Sync `RTL_STATIC_LIST_HEAD` and `RtlFailFast` from XDK to NDK. - [NTDLL_VISTA] Introduce ntdll_vista_static static library and link both ntdll_vista and ntdll to it. - [NDK][LDR] Add and fix DLL Notification definitions. - [NTDLL_VISTA] Code improvements. - [NTDLL_VISTA:LDR] Implement Dll Notification. - [NTDLL][NTDLL_APITEST] Add Dll Notification API test.
This commit is contained in:
parent
6988b4e2c4
commit
ccf1e97aa1
22 changed files with 539 additions and 53 deletions
|
@ -65,7 +65,7 @@ set_module_type(ntdll win32dll ENTRYPOINT 0)
|
|||
set_subsystem(ntdll console)
|
||||
################# END HACK #################
|
||||
|
||||
target_link_libraries(ntdll etwtrace csrlib rtl rtl_um rtl_vista ntdllsys libcntpr uuid ${PSEH_LIB})
|
||||
target_link_libraries(ntdll ntdll_vista_static etwtrace csrlib rtl rtl_um rtl_vista ntdllsys libcntpr uuid ${PSEH_LIB})
|
||||
if(DLL_EXPORT_VERSION GREATER_EQUAL 0x600)
|
||||
target_link_libraries(ntdll cryptlib)
|
||||
endif()
|
||||
|
|
|
@ -170,7 +170,7 @@
|
|||
@ stdcall LdrQueryImageFileKeyOption(ptr ptr long ptr long ptr)
|
||||
@ stdcall -stub -version=0x600+ LdrQueryModuleServiceTags(ptr ptr ptr)
|
||||
@ stdcall LdrQueryProcessModuleInformation(ptr long ptr)
|
||||
@ stdcall -stub -version=0x600+ LdrRegisterDllNotification(long ptr ptr ptr)
|
||||
@ stdcall -version=0x600+ LdrRegisterDllNotification(long ptr ptr ptr)
|
||||
@ stdcall -stub -version=0x600+ LdrRemoveLoadAsDataTable(ptr ptr ptr long)
|
||||
@ stub -version=0x600+ LdrResFindResource
|
||||
@ stub -version=0x600+ LdrResFindResourceDirectory
|
||||
|
@ -185,7 +185,7 @@
|
|||
@ stub -version=0x600+ LdrUnloadAlternateResourceModuleEx
|
||||
@ stdcall LdrUnloadDll(ptr)
|
||||
@ stdcall LdrUnlockLoaderLock(long ptr)
|
||||
@ stdcall -stub -version=0x600+ LdrUnregisterDllNotification(ptr)
|
||||
@ stdcall -version=0x600+ LdrUnregisterDllNotification(ptr)
|
||||
@ stdcall LdrVerifyImageMatchesChecksum(ptr long long long)
|
||||
@ stdcall -stub -version=0x600+ LdrVerifyImageMatchesChecksumEx(ptr ptr)
|
||||
@ stub -version=0x600+ LdrpResGetMappingSize
|
||||
|
|
|
@ -229,6 +229,15 @@ VOID
|
|||
NTAPI
|
||||
LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry);
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LdrpSendDllNotifications(
|
||||
_In_ PLDR_DATA_TABLE_ENTRY DllEntry,
|
||||
_In_ ULONG NotificationReason);
|
||||
|
||||
#endif /* (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA) */
|
||||
|
||||
/* path.c */
|
||||
BOOLEAN
|
||||
|
@ -242,6 +251,11 @@ NTAPI
|
|||
RtlpInitializeKeyedEvent(
|
||||
VOID);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpCloseKeyedEvent(
|
||||
VOID);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpInitializeThreadPooling(
|
||||
|
|
|
@ -1497,6 +1497,11 @@ LdrUnloadDll(
|
|||
DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer);
|
||||
}
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
|
||||
/* Send shutdown notification */
|
||||
LdrpSendDllNotifications(CurrentEntry, LDR_DLL_NOTIFICATION_REASON_UNLOADED);
|
||||
#endif
|
||||
|
||||
/* Check if this is a .NET executable */
|
||||
CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
|
||||
TRUE,
|
||||
|
@ -1520,9 +1525,6 @@ LdrUnloadDll(
|
|||
/* Unload the alternate resource module, if any */
|
||||
LdrUnloadAlternateResourceModule(CurrentEntry->DllBase);
|
||||
|
||||
/* FIXME: Send shutdown notification */
|
||||
//LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
|
||||
|
||||
/* Check if a Hotpatch is active */
|
||||
if (LdrEntry->PatchInformation)
|
||||
{
|
||||
|
|
|
@ -56,9 +56,7 @@ ULONG LdrpNumberOfProcessors;
|
|||
PVOID NtDllBase;
|
||||
extern LARGE_INTEGER RtlpTimeout;
|
||||
extern BOOLEAN RtlpTimeoutDisable;
|
||||
PVOID LdrpHeap;
|
||||
LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
|
||||
LIST_ENTRY LdrpDllNotificationList;
|
||||
HANDLE LdrpKnownDllObjectDirectory;
|
||||
UNICODE_STRING LdrpKnownDllPath;
|
||||
WCHAR LdrpKnownDllPathBuffer[128];
|
||||
|
@ -2008,9 +2006,8 @@ LdrpInitializeProcess(IN PCONTEXT Context,
|
|||
//Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
|
||||
//Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
|
||||
|
||||
/* Setup Callout Lock and Notification list */
|
||||
/* Setup Callout Lock */
|
||||
//RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
|
||||
InitializeListHead(&LdrpDllNotificationList);
|
||||
|
||||
/* For old executables, use 16-byte aligned heap */
|
||||
if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
|
||||
|
|
|
@ -1226,7 +1226,12 @@ SkipCheck:
|
|||
/* Insert this entry */
|
||||
LdrpInsertMemoryTableEntry(LdrEntry);
|
||||
|
||||
// LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
|
||||
LdrpSendDllNotifications(LdrEntry, LDR_DLL_NOTIFICATION_REASON_LOADED);
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
LdrEntry->Flags |= LDRP_LOAD_NOTIFICATIONS_SENT; /* LdrEntry->LoadNotificationsSent = TRUE; */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Check for invalid CPU Image */
|
||||
if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
|
||||
|
|
|
@ -11,12 +11,15 @@ include_directories(
|
|||
${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys)
|
||||
|
||||
list(APPEND SOURCE
|
||||
DllMain.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ntdll_vista.def)
|
||||
ldr/ldrinit.c
|
||||
ldr/ldrnotify.c)
|
||||
|
||||
add_library(ntdll_vista MODULE ${SOURCE} ntdll_vista.rc)
|
||||
add_library(ntdll_vista_static ${SOURCE})
|
||||
target_link_libraries(ntdll_vista_static)
|
||||
add_dependencies(ntdll_vista_static psdk)
|
||||
add_library(ntdll_vista MODULE DllMain.c ${CMAKE_CURRENT_BINARY_DIR}/ntdll_vista.def ntdll_vista.rc)
|
||||
set_module_type(ntdll_vista win32dll ENTRYPOINT DllMain 12)
|
||||
target_link_libraries(ntdll_vista smlib rtl_vista)
|
||||
target_link_libraries(ntdll_vista ntdll_vista_static smlib rtl_vista ${PSEH_LIB})
|
||||
if(ARCH STREQUAL "arm")
|
||||
target_link_libraries(ntdll_vista chkstk)
|
||||
endif()
|
||||
|
|
|
@ -1,25 +1,4 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winreg.h>
|
||||
#include <winuser.h>
|
||||
#include <winwlx.h>
|
||||
#include <ndk/rtltypes.h>
|
||||
#include <ndk/umfuncs.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpInitializeKeyedEvent(VOID);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpCloseKeyedEvent(VOID);
|
||||
#include "ntdll_vista.h"
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
|
|
3
dll/ntdll/nt_0600/ldr/ldrinit.c
Normal file
3
dll/ntdll/nt_0600/ldr/ldrinit.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "ntdll_vista.h"
|
||||
|
||||
PVOID LdrpHeap;
|
154
dll/ntdll/nt_0600/ldr/ldrnotify.c
Normal file
154
dll/ntdll/nt_0600/ldr/ldrnotify.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* PROJECT: ReactOS NT Layer/System API
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: DLL Load Notification Implementation
|
||||
* COPYRIGHT: Copyright 2024 Ratin Gao <ratin@knsoft.org>
|
||||
*/
|
||||
|
||||
#include "ntdll_vista.h"
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
typedef struct _LDR_DLL_NOTIFICATION_ENTRY
|
||||
{
|
||||
LIST_ENTRY List;
|
||||
PLDR_DLL_NOTIFICATION_FUNCTION Callback;
|
||||
PVOID Context;
|
||||
} LDR_DLL_NOTIFICATION_ENTRY, *PLDR_DLL_NOTIFICATION_ENTRY;
|
||||
|
||||
static RTL_STATIC_LIST_HEAD(LdrpDllNotificationList);
|
||||
|
||||
/* Initialize critical section statically */
|
||||
static RTL_CRITICAL_SECTION LdrpDllNotificationLock;
|
||||
static RTL_CRITICAL_SECTION_DEBUG LdrpDllNotificationLockDebug = {
|
||||
.CriticalSection = &LdrpDllNotificationLock
|
||||
};
|
||||
static RTL_CRITICAL_SECTION LdrpDllNotificationLock = {
|
||||
&LdrpDllNotificationLockDebug,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LdrRegisterDllNotification(
|
||||
_In_ ULONG Flags,
|
||||
_In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
|
||||
_In_opt_ PVOID Context,
|
||||
_Out_ PVOID *Cookie)
|
||||
{
|
||||
PLDR_DLL_NOTIFICATION_ENTRY NewEntry;
|
||||
|
||||
/* Check input parameters */
|
||||
if (Flags != 0 || NotificationFunction == NULL || Cookie == NULL)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Allocate new entry and assign input values */
|
||||
NewEntry = RtlAllocateHeap(LdrpHeap, 0, sizeof(*NewEntry));
|
||||
if (NewEntry == NULL)
|
||||
{
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
NewEntry->Callback = NotificationFunction;
|
||||
NewEntry->Context = Context;
|
||||
|
||||
/* Add node to the end of global list */
|
||||
RtlEnterCriticalSection(&LdrpDllNotificationLock);
|
||||
InsertTailList(&LdrpDllNotificationList, &NewEntry->List);
|
||||
RtlLeaveCriticalSection(&LdrpDllNotificationLock);
|
||||
|
||||
/* Cookie is address of the new entry */
|
||||
*Cookie = NewEntry;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LdrUnregisterDllNotification(
|
||||
_In_ PVOID Cookie)
|
||||
{
|
||||
NTSTATUS Status = STATUS_DLL_NOT_FOUND;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
/* Find entry to remove */
|
||||
RtlEnterCriticalSection(&LdrpDllNotificationLock);
|
||||
for (Entry = LdrpDllNotificationList.Flink;
|
||||
Entry != &LdrpDllNotificationList;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
if (Entry == Cookie)
|
||||
{
|
||||
RemoveEntryList(Entry);
|
||||
Status = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RtlLeaveCriticalSection(&LdrpDllNotificationLock);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
RtlFreeHeap(LdrpHeap, 0, Entry);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LdrpSendDllNotifications(
|
||||
_In_ PLDR_DATA_TABLE_ENTRY DllEntry,
|
||||
_In_ ULONG NotificationReason)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PLDR_DLL_NOTIFICATION_ENTRY NotificationEntry;
|
||||
LDR_DLL_NOTIFICATION_DATA NotificationData;
|
||||
|
||||
/*
|
||||
* LDR_DLL_LOADED_NOTIFICATION_DATA and LDR_DLL_UNLOADED_NOTIFICATION_DATA
|
||||
* currently are the same. Use C_ASSERT to ensure it, then fill either of them.
|
||||
*/
|
||||
#define LdrpAssertDllNotificationDataMember(x)\
|
||||
C_ASSERT(FIELD_OFFSET(LDR_DLL_NOTIFICATION_DATA, Loaded.x) ==\
|
||||
FIELD_OFFSET(LDR_DLL_NOTIFICATION_DATA, Unloaded.x))
|
||||
|
||||
C_ASSERT(sizeof(NotificationData.Loaded) == sizeof(NotificationData.Unloaded));
|
||||
LdrpAssertDllNotificationDataMember(Flags);
|
||||
LdrpAssertDllNotificationDataMember(FullDllName);
|
||||
LdrpAssertDllNotificationDataMember(BaseDllName);
|
||||
LdrpAssertDllNotificationDataMember(DllBase);
|
||||
LdrpAssertDllNotificationDataMember(SizeOfImage);
|
||||
|
||||
#undef LdrpAssertDllNotificationDataMember
|
||||
|
||||
NotificationData.Loaded.Flags = 0; /* Reserved and always 0, not DllEntry->Flags */
|
||||
NotificationData.Loaded.FullDllName = &DllEntry->FullDllName;
|
||||
NotificationData.Loaded.BaseDllName = &DllEntry->BaseDllName;
|
||||
NotificationData.Loaded.DllBase = DllEntry->DllBase;
|
||||
NotificationData.Loaded.SizeOfImage = DllEntry->SizeOfImage;
|
||||
|
||||
/* Send notification to all registered callbacks */
|
||||
RtlEnterCriticalSection(&LdrpDllNotificationLock);
|
||||
_SEH2_TRY
|
||||
{
|
||||
for (Entry = LdrpDllNotificationList.Flink;
|
||||
Entry != &LdrpDllNotificationList;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
NotificationEntry = CONTAINING_RECORD(Entry, LDR_DLL_NOTIFICATION_ENTRY, List);
|
||||
NotificationEntry->Callback(NotificationReason,
|
||||
&NotificationData,
|
||||
NotificationEntry->Context);
|
||||
}
|
||||
}
|
||||
_SEH2_FINALLY
|
||||
{
|
||||
RtlLeaveCriticalSection(&LdrpDllNotificationLock);
|
||||
}
|
||||
_SEH2_END;
|
||||
}
|
21
dll/ntdll/nt_0600/ntdll_vista.h
Normal file
21
dll/ntdll/nt_0600/ntdll_vista.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#define _NTSYSTEM_
|
||||
#define _NTDLLBUILD_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnt.h>
|
||||
|
||||
#define NTOS_MODE_USER
|
||||
#include <ndk/rtlfuncs.h>
|
||||
#include <ndk/umfuncs.h>
|
||||
#include <ndk/ldrfuncs.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include "../include/ntdllp.h"
|
|
@ -1,3 +1,6 @@
|
|||
@ stdcall LdrRegisterDllNotification(long ptr ptr ptr)
|
||||
@ stdcall LdrUnregisterDllNotification(ptr)
|
||||
|
||||
@ stdcall RtlInitializeConditionVariable(ptr)
|
||||
@ stdcall RtlWakeConditionVariable(ptr)
|
||||
@ stdcall RtlWakeAllConditionVariable(ptr)
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
|
||||
add_subdirectory(load_notifications)
|
||||
add_subdirectory(empty_dll)
|
||||
|
||||
include_directories($<TARGET_FILE_DIR:load_notifications>)
|
||||
include_directories($<TARGET_FILE_DIR:empty_dll>)
|
||||
include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
|
||||
spec2def(ntdll_apitest.exe ntdll_apitest.spec)
|
||||
|
||||
list(APPEND SOURCE
|
||||
DllLoadNotification.c
|
||||
LdrEnumResources.c
|
||||
LdrLoadDll.c
|
||||
load_notifications.c
|
||||
|
@ -118,6 +121,7 @@ list(APPEND PCH_SKIP_SOURCE
|
|||
testlist.c)
|
||||
|
||||
add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/load_notifications/load_notifications.dll)
|
||||
add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/empty_dll/empty_dll.dll)
|
||||
|
||||
add_executable(ntdll_apitest
|
||||
${SOURCE}
|
||||
|
@ -135,7 +139,7 @@ target_link_libraries(ntdll_apitest rtl_test_lib wine uuid ${PSEH_LIB})
|
|||
set_module_type(ntdll_apitest win32cui)
|
||||
add_importlibs(ntdll_apitest msvcrt advapi32 kernel32 ntdll)
|
||||
add_pch(ntdll_apitest precomp.h "${PCH_SKIP_SOURCE}")
|
||||
add_dependencies(ntdll_apitest load_notifications)
|
||||
add_dependencies(ntdll_apitest load_notifications empty_dll)
|
||||
|
||||
if(NOT MSVC)
|
||||
set_source_files_properties(RtlGetFullPathName_UstrEx.c PROPERTIES COMPILE_OPTIONS "-Wno-format")
|
||||
|
|
235
modules/rostests/apitests/ntdll/DllLoadNotification.c
Normal file
235
modules/rostests/apitests/ntdll/DllLoadNotification.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* PROJECT: ReactOS API Tests
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Test for DLL Load Notification API
|
||||
* COPYRIGHT: Copyright 2024 Ratin Gao <ratin@knsoft.org>
|
||||
*/
|
||||
|
||||
#define UNICODE
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <winuser.h>
|
||||
|
||||
static WCHAR g_szDllPath[MAX_PATH];
|
||||
static UNICODE_STRING g_usDllPath;
|
||||
static UNICODE_STRING g_usDllName;
|
||||
static volatile LONG g_lDllLoadCount = 0;
|
||||
|
||||
typedef
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
FN_LdrRegisterDllNotification(
|
||||
_In_ ULONG Flags,
|
||||
_In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
|
||||
_In_opt_ PVOID Context,
|
||||
_Out_ PVOID* Cookie);
|
||||
|
||||
typedef
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
FN_LdrUnregisterDllNotification(
|
||||
_In_ PVOID Cookie);
|
||||
|
||||
static BOOL ExtractResource(
|
||||
_In_z_ PCWSTR SavePath,
|
||||
_In_ PCWSTR ResourceType,
|
||||
_In_ PCWSTR ResourceName)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
DWORD dwWritten, dwSize;
|
||||
HGLOBAL hGlobal;
|
||||
LPVOID pData;
|
||||
HANDLE hFile;
|
||||
HRSRC hRsrc;
|
||||
|
||||
/* Load resource */
|
||||
if ((hRsrc = FindResourceW(NULL, ResourceName, ResourceType)) == NULL ||
|
||||
(dwSize = SizeofResource(NULL, hRsrc)) == 0 ||
|
||||
(hGlobal = LoadResource(NULL, hRsrc)) == NULL ||
|
||||
(pData = LockResource(hGlobal)) == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Save to file */
|
||||
hFile = CreateFileW(SavePath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
bSuccess = WriteFile(hFile, pData, dwSize, &dwWritten, NULL);
|
||||
CloseHandle(hFile);
|
||||
if (!bSuccess)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (dwWritten != dwSize)
|
||||
{
|
||||
trace("Extract resource failed, written size (%lu) is not actual size (%lu)\n", dwWritten, dwSize);
|
||||
DeleteFileW(SavePath);
|
||||
SetLastError(ERROR_INCORRECT_SIZE);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static VOID NTAPI DllLoadCallback(
|
||||
_In_ ULONG NotificationReason,
|
||||
_In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData,
|
||||
_In_opt_ PVOID Context)
|
||||
{
|
||||
LONG lRet;
|
||||
HMODULE* phNotifiedDllBase = Context;
|
||||
|
||||
/*
|
||||
* Verify the data,
|
||||
* NotificationData->Loaded and NotificationData->Unloaded currently are the same.
|
||||
*/
|
||||
|
||||
/* Verify the FullDllName and BaseDllName */
|
||||
ok_eq_ulong(NotificationData->Loaded.Flags, 0UL);
|
||||
lRet = RtlCompareUnicodeString(NotificationData->Loaded.FullDllName,
|
||||
(PCUNICODE_STRING)&g_usDllPath,
|
||||
TRUE);
|
||||
ok_eq_long(lRet, 0L);
|
||||
lRet = RtlCompareUnicodeString(NotificationData->Loaded.BaseDllName,
|
||||
(PCUNICODE_STRING)&g_usDllName,
|
||||
TRUE);
|
||||
ok_eq_long(lRet, 0L);
|
||||
|
||||
/*
|
||||
* Verify SizeOfImage and read SizeOfImage from PE header,
|
||||
* make sure the DLL is not unmapped, the memory is still accessible.
|
||||
*/
|
||||
ok_eq_ulong(NotificationData->Loaded.SizeOfImage,
|
||||
RtlImageNtHeader(NotificationData->Loaded.DllBase)->OptionalHeader.SizeOfImage);
|
||||
|
||||
/* Reason can be load or unload */
|
||||
ok(NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED ||
|
||||
NotificationReason == LDR_DLL_NOTIFICATION_REASON_UNLOADED, "Incorrect NotificationReason\n");
|
||||
if (NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
|
||||
{
|
||||
*phNotifiedDllBase = NotificationData->Loaded.DllBase;
|
||||
InterlockedIncrement(&g_lDllLoadCount);
|
||||
}
|
||||
else if (NotificationReason == LDR_DLL_NOTIFICATION_REASON_UNLOADED)
|
||||
{
|
||||
InterlockedDecrement(&g_lDllLoadCount);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(DllLoadNotification)
|
||||
{
|
||||
WCHAR szTempPath[MAX_PATH];
|
||||
PCWSTR pszDllName;
|
||||
HMODULE hNtDll, hTestDll, hNotifiedDllBase;
|
||||
FN_LdrRegisterDllNotification* pfnLdrRegisterDllNotification;
|
||||
FN_LdrUnregisterDllNotification* pfnLdrUnregisterDllNotification;
|
||||
NTSTATUS Status;
|
||||
PVOID Cookie1, Cookie2;
|
||||
|
||||
/* Load functions */
|
||||
hNtDll = GetModuleHandleW(L"ntdll.dll");
|
||||
if (hNtDll == NULL)
|
||||
{
|
||||
skip("GetModuleHandleW for ntdll failed with 0x%08lX\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
pfnLdrRegisterDllNotification = (FN_LdrRegisterDllNotification*)GetProcAddress(hNtDll, "LdrRegisterDllNotification");
|
||||
pfnLdrUnregisterDllNotification = (FN_LdrUnregisterDllNotification*)GetProcAddress(hNtDll, "LdrUnregisterDllNotification");
|
||||
if (!pfnLdrRegisterDllNotification || !pfnLdrUnregisterDllNotification)
|
||||
{
|
||||
skip("ntdll.dll!Ldr[Un]RegisterDllNotification not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract DLL to temp directory */
|
||||
if (!GetTempPathW(ARRAYSIZE(szTempPath), szTempPath))
|
||||
{
|
||||
skip("GetTempPathW failed with 0x%08lX\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
if (GetTempFileNameW(szTempPath, L"DLN", 0, g_szDllPath) == 0)
|
||||
{
|
||||
skip("GetTempFileNameW failed with 0x%08lX\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
RtlInitUnicodeString(&g_usDllPath, g_szDllPath);
|
||||
pszDllName = wcsrchr(g_szDllPath, L'\\') + 1;
|
||||
if (pszDllName == NULL)
|
||||
{
|
||||
skip("Find file name of %ls failed\n", g_szDllPath);
|
||||
return;
|
||||
}
|
||||
RtlInitUnicodeString(&g_usDllName, pszDllName);
|
||||
if (!ExtractResource(g_szDllPath, RT_RCDATA, MAKEINTRESOURCEW(102)))
|
||||
{
|
||||
skip("ExtractResource failed with 0x%08lX\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register DLL load notification callback */
|
||||
hNotifiedDllBase = NULL;
|
||||
Cookie1 = NULL;
|
||||
Cookie2 = NULL;
|
||||
Status = pfnLdrRegisterDllNotification(0, DllLoadCallback, &hNotifiedDllBase, &Cookie1);
|
||||
ok_eq_bool(NT_SUCCESS(Status), TRUE);
|
||||
ok(Cookie1 != NULL, "Cookie1 is NULL\n");
|
||||
|
||||
/* Register the callback again is valid */
|
||||
Status = pfnLdrRegisterDllNotification(0, DllLoadCallback, &hNotifiedDllBase, &Cookie2);
|
||||
ok_eq_bool(NT_SUCCESS(Status), TRUE);
|
||||
ok(Cookie2 != NULL, "Cookie2 is NULL\n");
|
||||
|
||||
/* Load the test DLL */
|
||||
hTestDll = LoadLibraryW(g_szDllPath);
|
||||
if (!hTestDll)
|
||||
{
|
||||
skip("LoadLibraryW failed with 0x%08lX\n", GetLastError());
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Verify the Dll base received in callback and returned via context */
|
||||
ok_eq_pointer(hNotifiedDllBase, hTestDll);
|
||||
|
||||
/* The count should be 2 because the callback was registered twice */
|
||||
ok_eq_long(g_lDllLoadCount, 2L);
|
||||
|
||||
/*
|
||||
* Callback will not be triggered because following
|
||||
* load and unload actions change the DLL reference count only
|
||||
*/
|
||||
LoadLibraryW(g_szDllPath);
|
||||
ok_eq_long(g_lDllLoadCount, 2L);
|
||||
FreeLibrary(hTestDll);
|
||||
ok_eq_long(g_lDllLoadCount, 2L);
|
||||
|
||||
/* Unregister the callback once */
|
||||
Status = pfnLdrUnregisterDllNotification(Cookie1);
|
||||
ok_eq_bool(NT_SUCCESS(Status), TRUE);
|
||||
|
||||
/* Unload the test DLL */
|
||||
if (FreeLibrary(hTestDll))
|
||||
{
|
||||
/* The count will decrease 1 because the last callback still there */
|
||||
ok_eq_long(g_lDllLoadCount, 1L);
|
||||
}
|
||||
else
|
||||
{
|
||||
skip("FreeLibrary failed with 0x%08lX\n", GetLastError());
|
||||
}
|
||||
|
||||
/* Unregister the last callback */
|
||||
Status = pfnLdrUnregisterDllNotification(Cookie2);
|
||||
ok_eq_bool(NT_SUCCESS(Status), TRUE);
|
||||
|
||||
_exit:
|
||||
DeleteFileW(g_szDllPath);
|
||||
}
|
6
modules/rostests/apitests/ntdll/empty_dll/CMakeLists.txt
Normal file
6
modules/rostests/apitests/ntdll/empty_dll/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
add_library(empty_dll MODULE empty_dll.c)
|
||||
set_module_type(empty_dll win32dll ENTRYPOINT DllMain 12)
|
||||
add_importlibs(empty_dll kernel32 ntdll)
|
||||
add_dependencies(empty_dll psdk)
|
||||
add_rostests_file(TARGET empty_dll)
|
11
modules/rostests/apitests/ntdll/empty_dll/empty_dll.c
Normal file
11
modules/rostests/apitests/ntdll/empty_dll/empty_dll.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <windows.h>
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
DllMain(
|
||||
_In_ HINSTANCE hinstDLL,
|
||||
_In_ DWORD fdwReason,
|
||||
_In_ LPVOID lpvReserved)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
|
||||
101 10 "load_notifications.dll"
|
||||
102 10 "empty_dll.dll"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define STANDALONE
|
||||
#include <apitest.h>
|
||||
|
||||
extern void func_DllLoadNotification(void);
|
||||
extern void func_LdrEnumResources(void);
|
||||
extern void func_LdrLoadDll(void);
|
||||
extern void func_load_notifications(void);
|
||||
|
@ -107,6 +108,7 @@ extern void func_UserModeException(void);
|
|||
|
||||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "DllLoadNotification", func_DllLoadNotification },
|
||||
{ "LdrEnumResources", func_LdrEnumResources },
|
||||
{ "LdrLoadDll", func_LdrLoadDll },
|
||||
{ "load_notifications", func_load_notifications },
|
||||
|
|
|
@ -147,6 +147,23 @@ LdrEnumerateLoadedModules(
|
|||
_In_opt_ PVOID Context
|
||||
);
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LdrRegisterDllNotification(
|
||||
_In_ ULONG Flags,
|
||||
_In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
|
||||
_In_opt_ PVOID Context,
|
||||
_Out_ PVOID* Cookie);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LdrUnregisterDllNotification(
|
||||
_In_ PVOID Cookie);
|
||||
|
||||
#endif /* (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA) */
|
||||
|
||||
#ifdef NTOS_MODE_USER
|
||||
NTSYSAPI
|
||||
BOOLEAN
|
||||
|
|
|
@ -37,7 +37,11 @@ Author:
|
|||
//
|
||||
#define LDRP_STATIC_LINK 0x00000002
|
||||
#define LDRP_IMAGE_DLL 0x00000004
|
||||
#if (NTDDI_VERSION < NTDDI_WIN8)
|
||||
#define LDRP_SHIMENG_SUPPRESSED_ENTRY 0x00000008
|
||||
#else
|
||||
#define LDRP_LOAD_NOTIFICATIONS_SENT 0x00000008
|
||||
#endif
|
||||
#define LDRP_IMAGE_INTEGRITY_FORCED 0x00000020
|
||||
#define LDRP_LOAD_IN_PROGRESS 0x00001000
|
||||
#define LDRP_UNLOAD_IN_PROGRESS 0x00002000
|
||||
|
@ -196,26 +200,39 @@ typedef struct _LDR_ENUM_RESOURCE_INFO
|
|||
//
|
||||
// DLL Notifications
|
||||
//
|
||||
#define LDR_DLL_NOTIFICATION_REASON_LOADED 1
|
||||
#define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2
|
||||
|
||||
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA
|
||||
{
|
||||
ULONG Flags;
|
||||
PUNICODE_STRING FullDllName;
|
||||
PUNICODE_STRING BaseDllName;
|
||||
PCUNICODE_STRING FullDllName;
|
||||
PCUNICODE_STRING BaseDllName;
|
||||
PVOID DllBase;
|
||||
ULONG SizeOfImage;
|
||||
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;
|
||||
|
||||
typedef VOID
|
||||
(NTAPI *PLDR_DLL_LOADED_NOTIFICATION_CALLBACK)(
|
||||
_In_ BOOLEAN Type,
|
||||
_In_ struct _LDR_DLL_LOADED_NOTIFICATION_DATA *Data
|
||||
);
|
||||
|
||||
typedef struct _LDR_DLL_LOADED_NOTIFICATION_ENTRY
|
||||
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA
|
||||
{
|
||||
LIST_ENTRY NotificationListEntry;
|
||||
PLDR_DLL_LOADED_NOTIFICATION_CALLBACK Callback;
|
||||
} LDR_DLL_LOADED_NOTIFICATION_ENTRY, *PLDR_DLL_LOADED_NOTIFICATION_ENTRY;
|
||||
ULONG Flags;
|
||||
PCUNICODE_STRING FullDllName;
|
||||
PCUNICODE_STRING BaseDllName;
|
||||
PVOID DllBase;
|
||||
ULONG SizeOfImage;
|
||||
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
|
||||
|
||||
typedef union _LDR_DLL_NOTIFICATION_DATA
|
||||
{
|
||||
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
||||
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
||||
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;
|
||||
typedef const LDR_DLL_NOTIFICATION_DATA *PCLDR_DLL_NOTIFICATION_DATA;
|
||||
|
||||
typedef VOID
|
||||
(NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)(
|
||||
_In_ ULONG NotificationReason,
|
||||
_In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData,
|
||||
_In_opt_ PVOID Context);
|
||||
|
||||
//
|
||||
// Alternate Resources Support
|
||||
|
|
|
@ -39,6 +39,18 @@ extern "C" {
|
|||
//
|
||||
// List Functions
|
||||
//
|
||||
|
||||
DECLSPEC_NORETURN
|
||||
FORCEINLINE
|
||||
VOID
|
||||
RtlFailFast(
|
||||
_In_ ULONG Code)
|
||||
{
|
||||
__fastfail(Code);
|
||||
}
|
||||
|
||||
#define RTL_STATIC_LIST_HEAD(x) LIST_ENTRY x = { &x, &x }
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InitializeListHead(
|
||||
|
|
|
@ -22,6 +22,9 @@ $if (_WDMDDK_ || _WINNT_)
|
|||
#define FAST_FAIL_MRDATA_MODIFIED 19
|
||||
#define FAST_FAIL_INVALID_FAST_FAIL_CODE 0xFFFFFFFF
|
||||
|
||||
$endif(_WDMDDK_ || _WINNT_)
|
||||
$if (_WDMDDK_)
|
||||
|
||||
DECLSPEC_NORETURN
|
||||
FORCEINLINE
|
||||
VOID
|
||||
|
@ -31,9 +34,6 @@ RtlFailFast(
|
|||
__fastfail(Code);
|
||||
}
|
||||
|
||||
$endif(_WDMDDK_ || _WINNT_)
|
||||
$if (_WDMDDK_)
|
||||
|
||||
#if !defined(NO_KERNEL_LIST_ENTRY_CHECKS) && (defined(_M_CEE_PURE) || defined(_M_CEE_SAFE))
|
||||
#define NO_KERNEL_LIST_ENTRY_CHECKS
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue