diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a564af6e6f9..964ce7bcf68 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -6738,6 +6738,56 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf return status; } +#ifdef __APPLE__ +static int is_apple_silicon(void) +{ + static int apple_silicon_status, did_check = 0; + if (!did_check) + { + /* returns 0 for native process or on error, 1 for translated */ + int ret = 0; + size_t size = sizeof(ret); + if (sysctlbyname( "sysctl.proc_translated", &ret, &size, NULL, 0 ) == -1) + apple_silicon_status = 0; + else + apple_silicon_status = ret; + + did_check = 1; + } + + return apple_silicon_status; +} + +/* CW HACK 18947 + * If mach_vm_write() is used to modify code cross-process (which is how we implement + * NtWriteVirtualMemory), Rosetta won't notice the change and will execute the "old" code. + * + * To work around this, after the write completes, + * toggle the executable bit (from inside the target process) on/off for any executable + * pages that were modified, to force Rosetta to re-translate it. + */ +static void toggle_executable_pages_for_rosetta( HANDLE process, void *addr, SIZE_T size ) +{ + MEMORY_BASIC_INFORMATION info; + NTSTATUS status; + SIZE_T ret; + + if (!is_apple_silicon()) + return; + + status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, &info, sizeof(info), &ret ); + + if (!status && (info.AllocationProtect & 0xf0)) + { + DWORD origprot, noexec; + noexec = info.AllocationProtect & ~0xf0; + if (!noexec) noexec = PAGE_NOACCESS; + + NtProtectVirtualMemory( process, &addr, &size, noexec, &origprot ); + NtProtectVirtualMemory( process, &addr, &size, origprot, &noexec ); + } +} +#endif /*********************************************************************** * NtWriteVirtualMemory (NTDLL.@) @@ -6759,6 +6809,10 @@ NTSTATUS WINAPI NtWriteVirtualMemory( HANDLE process, void *addr, const void *bu size = reply->written; } SERVER_END_REQ; + +#ifdef __APPLE__ + toggle_executable_pages_for_rosetta( process, addr, size ); +#endif } else {