How is it that WriteProcessMemory succeeds in writing to read-only memory?

When you call Write­Process­Memory and tell it to write to memory that is read-only, the Write­Process­Memory succeeds. How can that be?

Because Write­Process­Memory tries really hard to please you.

As I noted some time ago, the primary audience for functions like Create­Remote­Thread and Write­Process­Memory is debuggers. And when debuggers try to patch memory, it's often for things like patching in a breakpoint instruction or doing some edit-and-continue magic. So the Write­Process­Memory tries really hard to get those bytes written. If the page is read-only, Write­Process­Memory temporarily changes the permission to read-write, updates the memory, and then restores the original permission.

"No need to thank me, just trying to help."

There is a race condition if the target process happens to be manipulating the page protection at the same time that Write­Process­Memory is. But that's okay, because the intended audience is debuggers, and debuggers will freeze the target process before trying to edit its memory.

There is no security hole here, because the way the Write­Process­Memory function changes the page protection is basically Virtual­Protect­Ex, so it will succeed only if you already could have modified the protections yourself anyway. If you didn't have permission to change the protections, then Write­Process­Memory's attempt to change the protections would fail too.

Comments (4)
  1. Still seems like it should require an option on WriteProcessMemory, or a process state flag, to have it successfully modify read-only memory.

  2. Ben Voigt says:

    This is unexpected. Not the part about being able to write to ordinarily read-only memory; that I would expect. The part about the race condition.

    I would have expected it to create a new page table entry for the same physical range, and full access through the new mapping.

    Also, if the debugger updates the access on the existing PTE, performs the access, and reverts the access, then the race condition is far more severe than “if the target process happens to be manipulating the page protection at the same time”. If the target process tries to write its own memory within the same page, at the same time, then the write will succeed improperly (and the access violation that should have occurred, won’t). That possibility to me indicates that a separate view of the same page is needed.

    1. The theory is that the debugger shouldn’t be trying to patch a process while it is running. The debugger should suspend all threads first, do the patching, and then resume execution. Otherwise, the running threads will see torn state, because WriteProcessMemory is not atomic.

  3. I stopped asking this kind of questions the very first day I updated my computer’s so-called “ROM BIOS”.

Comments are closed.

Skip to main content