Throwback to college

When I started my Bachelor’s Degree in Computer Science, one of our first courses was an introduction to C++, where we learned all about variables, conditions, loops, recursion, and of course – pointers.
Later on we proceeded to learn more advanced topics, such as inheritance, polymorphism and… pointers to pointers. While we were told that our variables and functions needed to be documented and have concise and revealing names to better understand their purpose, a friend of mine stuck to laconic phrasing, with naming conventions such as “bigNum” for a variable or “makePointer” for a function. His best idea for a name for a function that creates a pointer to a given pointer was: “make_pp”. 😉
Two Doors, One Guard

Unlike us college students back in the day, the Windows internals API has (for the most of it) concise names for its functions. When we see functions such as “WriteFile” or “ReadProcessMemory”, we’ve got a pretty good idea of what they are supposed to do. AV and EDR vendors follow the same logic; functions such as “WriteProcessMemory”, “memcpy” and other direct buffer overwrites are well–hooked by antivirus and endpoint detection systems, and the first thing defenders monitor when malware tries to build or inject payloads. But what if I told you don’t need direct writes at all?
“Indirect Memory Writing” is a somewhat stealthy method, that abuses benign Windows APIs to write attacker–controlled bytes into memory without ever using a traditional memory writing primitive!

What Is Indirect Memory Writing?

At its core: Instead of explicitly copying bytes into memory (e.g., via “WriteProcessMemory”), you use legitimate Windows APIs that already write back status or completion values into pointers you control. These are APIs with “out” parameters – the very mechanisms the OS uses to report counts or results – only repurposed as write primitives.

For example:
The function “ReadFile” accepts pointers where the OS stores the number of bytes written or read upon completion. If you control that “out” pointer, you control where the OS writes the value – and thus can feed arbitrary bytes into a target buffer!
From the defender’s perspective, these calls look like normal file or memory operations; no obvious memory-write behavior to trip heuristic scanners. You Keep Using That Word

How Windows Memory APIs Enable the Trick

Let’s review the syntax for the “ReadProcessMemory” function: ReadProcessMemory Prototype The official purpose (per Microsoft documentation) is simple: Read data from another process’s memory – providing:

  • hProcess: handle to the target process
  • lpBaseAddress: address to read from
  • lpBuffer: where the read data goes
  • nSize: number of bytes to read
  • lpNumberOfBytesRead: pointer where the OS reports how many bytes were read

This last one - the “out” parameter pointer - is where the magic happens! Although documented as a read API, the OS writes the return count into the memory pointed to by this parameter. If that pointer points to an arbitrary executable region you control, that “status” write becomes an injection primitive.
So instead of doing:

WriteProcessMemory(targetProc, addr, buffer, size, &written);

You trigger:

ReadProcessMemory(
  -1,
  dummyBuf,
  dummyBuf,
  payloadByte,
  targetMemory+offset
);

and let the OS write payloadByte into targetMemory+offset via the lpNumberOfBytesRead pointer – byte by byte. You Were Supposed To READ From Memory

Why This Breaks the Defensive Model

Modern EDR and Antivirus solutions typically rely on:
✔️ API hook monitoring
✔️ Signature matching
✔️ Behavioral heuristics tied to known write primitives (e.g., WriteProcessMemory, VirtualAlloc + memcpy)

But indirect memory writing never calls those directly. Instead, it hides in fully legitimate API usage. Security vendors haven’t usually looked for unusual write targets via “read” APIs, so this technique creates a blind spot: A write primitive that looks like normal Windows behavior.

Real Proof-of-Concept: Indirect-Shellcode-Executor

The GitHub project Indirect‑Shellcode‑Executor on GitHub by researcher Mimorep shows a full offensive tool that operationalizes this trick in Rust. It does three powerful things:

  1. Remote Payload Execution – Fetches shellcode from a C2 server (sometimes hidden inside benign files like images) without direct writes.
  2. Terminal Injection – Injects raw shellcode provided via CLI input.
  3. File-Based Execution – Loads payloads from local files and write them into executable memory indirectly.

By forcing the OS to write shellcode bytes via an “unhooked” path, it creates a write primitive beneath the radar of tools that only monitor known write APIs.

In Conclusion

Indirect memory writing turns a 30-year-old API design choice (“out” pointers) into a weapon. It’s a reminder that every legitimate API behavior is also an attack surface, and that defensive models must evolve from names and signatures to semantics and context.
This technique is not just clever – it’s dangerous, and it’s reshaping how we think about stealthy memory manipulation on Windows.