PE Structures
Last updated
Last updated
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
When Portable Executable (PE) files are executed in Windows, the Windows PE loader is responsible for reading the PE file and loading it into memory such that it can be executed. PE files when loaded into memory, they follow the PE format, such as starting with a PE header etc.
Since malicious code is commonly loaded in PE format, defenders use the presence of PE structures in memory as an indicator of potential malicious code, which can then be sent for analysis.
In this section we will be using PE headers to locate, dump and analyze a standard beacon payload in memory to show how PE headers can be used by defenders as part of their detection/hunting methodology.
First, we will be executing a beacon shellcode using a simple shellcode runner. The demo.exe runner works fine.
Open x64dbg and search for the PE header string "This program cannot be run in DOS mode"
Based on that string, these memory addresses all contain PE data, which may be executable. By clicking into these addresses, we can read the PE data as shown below.
Now that we have located a PE file in memory, lets extract it for analysis. Right click the memory address and dump it to a file.
Now, upload the dumped file to VirusTotal to simulate an AV/EDR checking a PE structure for malicious content.
*REMINDER: DO NOT UPLOAD ANY CUSTOM TOOLING TO VIRUSTOTAL*
As you can see, VirusTotal was able to identify the PE data as malicious (Meterpreter and Beacon results). This shows how the presence of the PE structure can get us caught in memory.
Most techniques of avoiding PE headers in memory involve either overwriting them when not needed, or using a type of code that is not PE based.
For example, methods that do not involve the Windows PE loader such as Reflective DLL Injection and Process Hollowing (and variants) still leave a PE header in memory, due to the main payload data being loaded from PE format and executed similar to how the Windows PE loader does it normally.
When performing such techniques, unnecessary memory artifacts should be overwritten once no longer needed, such as the PE structures and reflective loader. Tools such as Donut and sRDI implement this concept. Beacon also applies this concept, which can be enabled in the Malleable config.
Other techniques such as .NET assembly loading also leave a PE header in memory.
.NET is a whole topic in itself, and this post better explains .NET in memory tradecraft better than I can.
Another way to avoid PE structures is to write and inject your payload as position independent code (PIC) (a.k.a. raw assembly). This was explained in this talk:
A similar effect can be achieved using tools such as Donut and sRDI to convert PEs into injectable shellcode, but as shown in the video (and the project documentation) it does not actually convert a PE into pure shellcode but rather uses in memory PE loading techniques, overwriting the PE structures after execution to prevent detection. Whether or not this OPSEC vs convenience tradeoff is worth it depends on your engagement and target defenses.
PE headers can be used by blue teams to locate potentially malicious memory regions for analysis, but by removing it or using non PE based execution techniques we can evade PE based in memory signatures.