
Thread Stack Spoofing - PoC for an advanced In-Memory evasion technique allowing to better hide injected shellcode's memory allocation from scanners and analysts.
A PoC implementation for an advanced in-memory evasion technique that spoofs Thread Call Stack. This technique allows to bypass thread-based memory examination rules and better hide shellcodes while in-process memory.
This is an example implementation for Thread Stack Spoofing technique aiming to evade Malware Analysts, AVs and EDRs looking for references to shellcode's frames in an examined thread's call stack. The idea is to hide references to the shellcode on thread's call stack thus masquerading allocations containing malware's code.
Implementation along with my ShellcodeFluctuation brings Offensive Security community sample implementations to catch up on the offering made by commercial C2 products, so that we can do no worse in our Red Team toolings. 💪
Current implementation differs heavily to what was originally published.
This is because I realised there is a way simpler approach to terminate thread's call stack processal and hide shellcode's related frames by simply writing 0 to the return address of the first frame we control:
void WINAPI MySleep(DWORD _dwMilliseconds)
{
[...]
auto overwrite = (PULONG_PTR)_AddressOfReturnAddress();
const auto origReturnAddress = *overwrite;
*overwrite = 0;
[...]
*overwrite = origReturnAddress;
}
The previous implementation, utilising StackWalk64 can be accessed in this commit c250724.
This implementation is much more stable and works nicely on both Debug and Release under two architectures - x64 and x86.
This is how a call stack may look like when it is NOT spoofed:

This in turn, when thread stack spoofing is enabled:

Above we can see that the last frame on our call stack is our MySleep callback.
One can wonder does it immediately brings opportunities new IOCs? Hunting rules can look for threads having call stacks not unwinding into following expected thread entry points located within system libraries:
kernel32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21
However the call stack of the spoofed thread may look rather odd at first, a brief examination of my system shown, that there are other threads not unwinding to the above entry points as well:

The above screenshot shows a thread of unmodified Total Commander x64. As we can see, its call stack pretty much resembles our own in terms of initial call stack frames.
Why should we care about carefully faking our call stack when there are processes exhibiting traits that we can simply mimic?
The rough algorithm is following:
dbghelp.dll, call SymInitializekernel32!Sleep pointing back to our callback.VirtualAlloc + memcpy + CreateThread. The thread should start from our runShellcode function to avoid having Thread's StartAddress point into somewhere unexpected and anomalous (such as ntdll!RtlUserThreadStart+0x21)MySleep callback gets invoked.0 which effectively should finish the call stack.::SleepEx is made to let the Beacon's sleep while waiting for further communication.Function return addresses are scattered all around the thread's stack memory area, pointed to by RBP/EBP register.
In order to find them on the stack, we need to firstly collect frame pointers, then dereference them for overwriting:

(the above image was borrowed from Eli Bendersky's post named Stack frame layout on x86-64)
*(PULONG_PTR)(frameAddr + sizeof(void*)) = Fake_Return_Address;
Initial implementation of ThreadStackSpoofer did that in walkCallStack and spoofCallStack functions, however the current implementation shows that these efforts are not required to maintain stealthy call stack.
Use case:
C:\> ThreadStackSpoofer.exe <shellcode> <spoof>
Where:
<shellcode> is a path to the shellcode file<spoof> when 1 or true will enable thread stack spoofing and anything else disables it.Example run that spoofs beacon's thread call stack:
PS D:\dev2\ThreadStackSpoofer> .\x64\Release\ThreadStackSpoofer.exe .\tests\beacon64.bin 1
[.] Reading shellcode bytes...
[.] Hooking kernel32!Sleep...
[.] Injecting shellcode...
[+] Shellcode is now running.
[>] Original return address: 0x1926747bd51. Finishing call stack...
===> MySleep(5000)
[<] Restoring original return address...
[>] Original return address: 0x1926747bd51. Finishing call stack...
===> MySleep(5000)
[<] Restoring original return address...
[>] Original return address: 0x1926747bd51. Finishing call stack...
Look at the code and its implementation, understand the concept and re-implement the concept within your own Shellcode Loaders that you utilise to deliver your Red Team engagements. This is an yet another technique for advanced in-memory evasion that increases your Teams' chances for not getting caught by Anti-Viruses, EDRs and Malware Analysts taking look at your implants.
While developing your advanced shellcode loader, you might also want to implement:
BeaconEyeRW (from RX/RWX) and encrypt their contents - using Shellcode Fluctuation technique - right before sleeping (that could evade scanners such as Moneta or pe-sieve)As it's been pointed out to me, the technique here is not yet truly holding up to its name for being a stack spoofer. Since we're merely overwriting return addresses on the thread's stack, we're not spoofing the remaining areas of the stack itself. Moreover we're leaving our call stack unwindable meaking it look anomalous since the system will not be able to properly walk the entire call stack frames chain.