kernelbase: Make memory writable in WriteProcessMemory if necessary.

This commit is contained in:
Alexandre Julliard 2024-06-18 12:08:03 +02:00
parent b639319830
commit 6ea77ec086
4 changed files with 73 additions and 15 deletions

View file

@ -206,10 +206,8 @@ static void test_VirtualAllocEx(void)
ok( b, "VirtualProtectEx, error %lu\n", GetLastError() );
bytes_written = 0xdeadbeef;
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
todo_wine
ok( !b, "WriteProcessMemory succeeded\n" );
if (!b) ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() );
todo_wine
ok( bytes_written == 0xdeadbeef, "%Iu bytes written\n", bytes_written );
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
todo_wine

View file

@ -46,6 +46,9 @@ WINE_DECLARE_DEBUG_CHANNEL(globalmem);
* Virtual memory functions
***********************************************************************/
static const SIZE_T page_mask = 0xfff;
#define ROUND_ADDR(addr) ((void *)((UINT_PTR)(addr) & ~page_mask))
#define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
/***********************************************************************
* DiscardVirtualMemory (kernelbase.@)
@ -537,7 +540,46 @@ BOOL WINAPI DECLSPEC_HOTPATCH VirtualUnlock( void *addr, SIZE_T size )
BOOL WINAPI DECLSPEC_HOTPATCH WriteProcessMemory( HANDLE process, void *addr, const void *buffer,
SIZE_T size, SIZE_T *bytes_written )
{
return set_ntstatus( NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ));
DWORD old_prot, prot = PAGE_TARGETS_NO_UPDATE | PAGE_ENCLAVE_NO_CHANGE | PAGE_EXECUTE_WRITECOPY;
MEMORY_BASIC_INFORMATION info;
void *base_addr;
SIZE_T region_size;
NTSTATUS status;
if (!VirtualQueryEx( process, addr, &info, sizeof(info) )) return FALSE;
switch (info.Protect)
{
case PAGE_READWRITE:
case PAGE_WRITECOPY:
case PAGE_EXECUTE_READWRITE:
case PAGE_EXECUTE_WRITECOPY:
/* already writable */
if ((status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ))) break;
NtFlushInstructionCache( process, addr, size );
break;
case PAGE_EXECUTE:
case PAGE_EXECUTE_READ:
/* make it writable */
base_addr = ROUND_ADDR( addr );
region_size = ROUND_SIZE( addr, size );
region_size = min( region_size, (char *)info.BaseAddress + info.RegionSize - (char *)base_addr );
status = NtProtectVirtualMemory( process, &base_addr, &region_size, prot, &old_prot );
if (status) break;
status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written );
if (!status) NtFlushInstructionCache( process, addr, size );
prot = PAGE_TARGETS_NO_UPDATE | PAGE_ENCLAVE_NO_CHANGE | old_prot;
NtProtectVirtualMemory( process, &base_addr, &region_size, prot, &old_prot );
break;
default:
/* not writable */
status = STATUS_ACCESS_VIOLATION;
break;
}
return set_ntstatus( status );
}

View file

@ -729,7 +729,7 @@ static void test_cross_process_notifications( HANDLE process, ULONG_PTR section,
WriteProcessMemory( process, (char *)addr + 0x1ffe, data, sizeof(data), &size );
entry = pop_from_work_list( &list->work_list );
todo_wine
todo_wine_if (current_machine == IMAGE_FILE_MACHINE_ARM64)
{
entry = expect_cross_work_entry( list, entry, CrossProcessPreVirtualProtect,
(char *)addr + 0x1000, 0x2000, 0x60000000 | PAGE_EXECUTE_WRITECOPY,

View file

@ -815,17 +815,35 @@ typedef struct DECLSPEC_ALIGN(8) MEM_EXTENDED_PARAMETER {
#define MEM_EXTENDED_PARAMETER_EC_CODE 0x00000040
#define MEM_EXTENDED_PARAMETER_IMAGE_NO_HPAT 0x00000080
#define PAGE_NOACCESS 0x01
#define PAGE_READONLY 0x02
#define PAGE_READWRITE 0x04
#define PAGE_WRITECOPY 0x08
#define PAGE_EXECUTE 0x10
#define PAGE_EXECUTE_READ 0x20
#define PAGE_EXECUTE_READWRITE 0x40
#define PAGE_EXECUTE_WRITECOPY 0x80
#define PAGE_GUARD 0x100
#define PAGE_NOCACHE 0x200
#define PAGE_WRITECOMBINE 0x400
#define PAGE_NOACCESS 0x00000001
#define PAGE_READONLY 0x00000002
#define PAGE_READWRITE 0x00000004
#define PAGE_WRITECOPY 0x00000008
#define PAGE_EXECUTE 0x00000010
#define PAGE_EXECUTE_READ 0x00000020
#define PAGE_EXECUTE_READWRITE 0x00000040
#define PAGE_EXECUTE_WRITECOPY 0x00000080
#define PAGE_GUARD 0x00000100
#define PAGE_NOCACHE 0x00000200
#define PAGE_WRITECOMBINE 0x00000400
#define PAGE_GRAPHICS_NOACCESS 0x00000800
#define PAGE_GRAPHICS_READONLY 0x00001000
#define PAGE_GRAPHICS_READWRITE 0x00002000
#define PAGE_GRAPHICS_EXECUTE 0x00004000
#define PAGE_GRAPHICS_EXECUTE_READ 0x00008000
#define PAGE_GRAPHICS_EXECUTE_READWRITE 0x00010000
#define PAGE_GRAPHICS_COHERENT 0x00020000
#define PAGE_GRAPHICS_NOCACHE 0x00040000
#define PAGE_ENCLAVE_MASK 0x10000000
#define PAGE_ENCLAVE_UNVALIDATED 0x20000000
#define PAGE_ENCLAVE_NO_CHANGE 0x20000000
#define PAGE_TARGETS_NO_UPDATE 0x40000000
#define PAGE_TARGETS_INVALID 0x40000000
#define PAGE_REVERT_TO_FILE_MAP 0x80000000
#define PAGE_ENCLAVE_THREAD_CONTROL 0x80000000
#define PAGE_ENCLAVE_DECOMMIT (PAGE_ENCLAVE_MASK | 0)
#define PAGE_ENCLAVE_SS_FIRST (PAGE_ENCLAVE_MASK | 1)
#define PAGE_ENCLAVE_SS_REST (PAGE_ENCLAVE_MASK | 2)
#define MEM_COMMIT 0x00001000
#define MEM_RESERVE 0x00002000