This implements the VirtualProtectFromApp function in kernelbase, which was previously a commented out stub.
Even though this function is meant for UWP apps, it is usable in desktop apps, as specified in [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-v...).
Fixes Wine-Bug: [https://bugs.winehq.org/show_bug.cgi?id=58482%5D(https://bugs.winehq.org/sho...)
-- v5: ntdll: Set old_prot in NtProtectVirtualMemory() to PAGE_NOACCESS if it fails kernelbase/tests: Add tests for VirtualProtectFromApp
From: Kareem Aladli karimri@protonmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58482 Signed-off-by: Kareem Aladli karimri@protonmail.com --- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/memory.c | 9 +++++++++ include/winbase.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 545c30a1eb8..48471834735 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1729,7 +1729,7 @@ @ stdcall VirtualLock(ptr long) @ stdcall VirtualProtect(ptr long long ptr) @ stdcall VirtualProtectEx(long ptr long long ptr) -# @ stub VirtualProtectFromApp +@ stdcall VirtualProtectFromApp(ptr long long ptr) @ stdcall VirtualQuery(ptr ptr long) @ stdcall VirtualQueryEx(long ptr ptr long) @ stdcall VirtualUnlock(ptr long) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 9bf8e291cbe..34c83eb428b 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -572,6 +572,15 @@ BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtectEx( HANDLE process, void *addr, SIZE return set_ntstatus( NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot )); }
+/*********************************************************************** + * VirtualProtectFromApp (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtectFromApp( void *addr, SIZE_T size, + ULONG new_prot, ULONG *old_prot ) +{ + /* Contrary to the documentation, VirtualProtectFromApp allows write+execute on desktop. */ + return VirtualProtect( addr, size, new_prot, old_prot ); +}
/*********************************************************************** * VirtualQuery (kernelbase.@) diff --git a/include/winbase.h b/include/winbase.h index 29a3ea8fbce..b4fae70dda1 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2479,6 +2479,7 @@ WINBASEAPI BOOL WINAPI VirtualFreeEx(HANDLE,LPVOID,SIZE_T,DWORD); WINBASEAPI BOOL WINAPI VirtualLock(LPVOID,SIZE_T); WINBASEAPI BOOL WINAPI VirtualProtect(LPVOID,SIZE_T,DWORD,LPDWORD); WINBASEAPI BOOL WINAPI VirtualProtectEx(HANDLE,LPVOID,SIZE_T,DWORD,LPDWORD); +WINBASEAPI BOOL WINAPI VirtualProtectFromApp(LPVOID,SIZE_T,ULONG,PULONG); WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID,PMEMORY_BASIC_INFORMATION,SIZE_T); WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE,LPCVOID,PMEMORY_BASIC_INFORMATION,SIZE_T); WINBASEAPI BOOL WINAPI VirtualUnlock(LPVOID,SIZE_T);
From: Kareem Aladli karimri@protonmail.com
--- dlls/kernelbase/tests/process.c | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index 90d6b5204eb..0b1a83cfcca 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -38,6 +38,7 @@ static LPVOID (WINAPI *pMapViewOfFile3)(HANDLE, HANDLE, PVOID, ULONG64 offset, S static LPVOID (WINAPI *pVirtualAlloc2)(HANDLE, void *, SIZE_T, DWORD, DWORD, MEM_EXTENDED_PARAMETER *, ULONG); static LPVOID (WINAPI *pVirtualAlloc2FromApp)(HANDLE, void *, SIZE_T, DWORD, DWORD, MEM_EXTENDED_PARAMETER *, ULONG); static PVOID (WINAPI *pVirtualAllocFromApp)(PVOID, SIZE_T, DWORD, DWORD); +static BOOL (WINAPI *pVirtualProtectFromApp)(LPVOID,SIZE_T,ULONG,PULONG); static HANDLE (WINAPI *pOpenFileMappingFromApp)( ULONG, BOOL, LPCWSTR); static HANDLE (WINAPI *pCreateFileMappingFromApp)(HANDLE, PSECURITY_ATTRIBUTES, ULONG, ULONG64, PCWSTR); static LPVOID (WINAPI *pMapViewOfFileFromApp)(HANDLE, ULONG, ULONG64, SIZE_T); @@ -481,6 +482,44 @@ static void test_VirtualAlloc2FromApp(void) } }
+static void test_VirtualProtectFromApp(void) +{ + ULONG old_prot; + void *p; + BOOL ret; + + if (!pVirtualProtectFromApp) + { + win_skip("VirtualProtectFromApp is not available.\n"); + return; + } + + SetLastError(0xdeadbeef); + p = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + ok(p && GetLastError() == 0xdeadbeef, "Got unexpected mem %p, GetLastError() %lu.\n", p, GetLastError()); + ret = pVirtualProtectFromApp(p, 0x1000, PAGE_READONLY, &old_prot); + ok(ret && old_prot == PAGE_READWRITE, "Failed to change protection old_prot %lu, GetLastError() %lu\n", + old_prot, GetLastError()); + + ret = pVirtualProtectFromApp(p, 0x100000, PAGE_READWRITE, &old_prot); + ok(!ret && old_prot == PAGE_NOACCESS, "Call worked with overflowing size old_prot %lu\n", old_prot); + + ret = pVirtualProtectFromApp(p, 0x1000, PAGE_EXECUTE_READ, NULL); + ok(!ret, "Call worked without old_prot\n"); + + ret = pVirtualProtectFromApp(p, 0x1000, PAGE_GUARD, &old_prot); + /* Windows WoW64 sets old_prot to something bogus for an unknown reason */ + ok(!ret, "Call worked with an invalid new_prot parameter old_prot %lu\n", old_prot); + + /* Works on desktop, but not on UWP */ + ret = pVirtualProtectFromApp(p, 0x1000, PAGE_EXECUTE_READWRITE, &old_prot); + ok(ret && old_prot == PAGE_READONLY, "Failed to change protection old_prot %lu, GetLastError() %lu\n", + old_prot, GetLastError()); + + ret = VirtualFree(p, 0, MEM_RELEASE); + ok(ret, "Failed to free mem error %lu.\n", GetLastError()); +} + static void test_OpenFileMappingFromApp(void) { OBJECT_BASIC_INFORMATION info; @@ -601,6 +640,7 @@ static void init_funcs(void) X(VirtualAlloc2); X(VirtualAlloc2FromApp); X(VirtualAllocFromApp); + X(VirtualProtectFromApp); X(UnmapViewOfFile2);
hmod = GetModuleHandleA("ntdll.dll"); @@ -618,6 +658,7 @@ START_TEST(process) test_VirtualAlloc2(); test_VirtualAllocFromApp(); test_VirtualAlloc2FromApp(); + test_VirtualProtectFromApp(); test_OpenFileMappingFromApp(); test_CreateFileMappingFromApp(); test_MapViewOfFileFromApp();
From: Kareem Aladli karimri@protonmail.com
--- dlls/ntdll/unix/virtual.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index e733e3ffdd6..c5408cbb5da 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5350,6 +5350,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
if (!old_prot) return STATUS_ACCESS_VIOLATION; + *old_prot = PAGE_NOACCESS;
if (process != NtCurrentProcess()) {