Tested on Windows 21H1, Visual Studio 2019 (v142) and an NVIDIA GTX860M.
GPUSleep
moves the beacon image to GPU memory before the beacon sleeps, and move it back to main memory after sleeping.
The idea is to hook HeapAlloc
and Sleep
. Encrypt (XOR) the heap allocated by the beacon and move all PE sections + heap segments to GPU memory using nvcuda.dll
imports.
Comes with a pre-compiled
libMinHook.x64.lib
, you night want to compile your own.
Using the technique described by waldo-irc, heap segments allocated by the beacon are XOR encrypted before moving them to GPU memory.
Cobalt Strike beacon uses malloc
instead of HeapAlloc
or RtlHeapAlloc
. So the functions that are doing the actual allocation are inside msvcrt.dll
or ucrtbase.dll
(I didn't really looked into it...)
The line if (!strcmp(lpBaseName, "msvcrt.dll") || !strcmp(lpBaseName, "ucrtbase.dll"))
filters which allocations are going to be encrypted.
A basic test DLL is provided. Modify code to use.
printf("LoadingBeacon\n");
//dll = LoadLibraryA("beacon.dll");
//Test DLL
run1(heapMap);
GPUSleep
will load an unstaged beacon.dll
file with LoadLibraryA
. The code has not been tested with reflective loading or other in memory loading techniques but if HMODULE dll
points to a valid PE image everything should work.
Pretty sure it's full of bugs...
Like, you need to refresh cuda context every time HookedSleep
is called and I don't know why...
void HookedSleep(DWORD dwMilliseconds) {
std::cout << "Hooked Sleep!\n";
// so Context cannot be init before CS beacon is fired up, I dunno why... If init before, cuda returns error 201
Context = initCuda(&Api, &Context);
[...]
Big thanks to @smelly__vx, it's actually his code that gave me the idea.
LockdExeDemo by @waldo-irc
GpuMemoryAbuse.cpp by @smelly__vx
minihook by @TsudaKageyu