I’ve recently released a process hollowing packer: RISCyPacker (https://github.com/RISCYBusiness/RISCYpacker). This hollower technique is unique in the fact that it is able to hollow a process dynamically (without process suspension) and without using some of the more sketchy Win APIs. This means no WriteProcessMemory, QueueUserApc, CreateRemoteThread, SetThreadContext calls. While I didn’t get around to testing with all AV, this technique should go undetected. For you Reversers, I attached a POC binary packed by it (end of article), so you can see how it works.
If you are motivated enough to test with more AV, let me know, Id be interested to hear
How It Works
Most process hollowing techniques rely on suspension of process, writing to remote memory, manipulating context (SetThreadContext/CreateRemoteThread/QueueUserAPC) and Resuming. The RISCyPacker technique trims the fat by only using Memory Modification steps (NtUnMapViewOfSection/NtMapViewOfSection) to accomplish a hollow.
In order for this to work, we need to be establish a guarantee that our thread can Unmap/Map remote executable memory before the remote thread is scheduled. If we go half-cocked (ie: only an unmap), we will get crashes since the thread’s EIP will point to nothing when its scheduled. Luckily we can use some thread priority and affinity to help us:
Create local Thread with High Priority
Set Remote Process’ Thread to Low Priority
The Affinity settings are of course required, since multicore processors may affect up our desired scheduling priorities we set. By putting them both on the same core, with different priorities, we can properly queue them up, allowing manipulation of remote memory before remote thread can access it.
Conceptual steps on how this hollower works (example w/ ftp.exe)
The injected NOP sled happens to also contain shellcode to load and built the IAT for the injected process.
A few things this packer must keep in mind, is a set of processes that can support a non-suspension injection. Some processes you want to hollow into, will immediately exit upon start (ie: xcopy.exe w/ no arguments) and thus miss the injection opportunity. For now, I only tested with ping.exe which was a good candidate for this. In the event a proc early exits, the hotswap technique will still work, it will just require a suspension (does not require CREATE_SUSPENDED, but rather suspended after normal creation (more stealthy)
RISCyPacker does not currently support x64/TLS/Exports.
Proof of concept exe for reversers. Password is “notinfected”
Note on Stalled Apps
Some processes you hollow into may be in a blocking state (in a system library) by the time you hollow. This means it will not call back into it’s image base that we applied a NOP sled to. To get around this you can memswap libraries and externally trigger an enter. (For example, kernel32 can be unmapped/mapped and then a Kill process call to the hollowed process, this will force the stalling application to enter into kernel32/NOP sled you mapped).