Hiding data in GPU VRAM using Direct3D 11
Previously I wrote some code which copied data to NVIDIA VRAM using CUDA. Other researchers wrote code that copied data to GPU VRAM using OpenGL.
I decided to write code that copied data to the GPU using the native Windows API, making it possible to hide data in GPU VRAM regardless of GPU architecture.
Unsurprisingly, the native Windows API to do graphics stuff is a little weird. It is a combination of COM (Component Object Model) and regular WINAPI functionality (or rather, pseudo WINAPI, it still ends up wrapping to some funky COM-like stuff).
The attached code copies data string "Kitty cat" to GPU VRAM and then retrieves it back. GPU VRAM is freed when the COM object is released.
The retrieved string ("Kitty cat") is stored in "TryBuffer".
Note anything can (hypothetically) be pushed to GPU VRAM — including your payloads, binary, compressed files, etc as long as there is sufficient memory available.
Cheers - smelly
#include <Windows.h>
#include <d3d11.h>
#pragma comment(lib, "d3d11.lib")
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
PVOID ImplCopyMemory(_Inout_ PVOID Destination, _In_ CONST PVOID Source, _In_ SIZE_T Length)
{
PBYTE D = (PBYTE)Destination;
PBYTE S = (PBYTE)Source;
while (Length--)
*D++ = *S++;
return Destination;
}
BOOL Id3d11PullMemoryFromGPUMemory(ID3D11DeviceContext* Context, ID3D11Buffer* DataIn, ID3D11Buffer* DataOut, PVOID Buffer, SIZE_T BufferSize)
{
D3D11_MAPPED_SUBRESOURCE Mapped = { 0 };
HRESULT Result = S_OK;
BOOL bFlag = FALSE;
if (!DataIn || !DataOut)
goto EXIT_ROUTINE;
Context->CopyResource(DataOut, DataIn);
Result = Context->Map(DataOut, 0, D3D11_MAP_READ, 0, &Mapped);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
bFlag = TRUE;
ImplCopyMemory(Buffer, Mapped.pData, BufferSize);
EXIT_ROUTINE:
if (bFlag)
Context->Unmap(DataOut, 0);
return bFlag;
}
BOOL Id3d11MoveMemoryToGPUMemory(ID3D11DeviceContext* Context, ID3D11Buffer* DataIn, PVOID Buffer)
{
if (Context)
Context->UpdateSubresource(DataIn, 0, NULL, Buffer, 0, 0);
return TRUE;
}
ID3D11Buffer* AllocateD3d11Memory(ID3D11Device* Device, DWORD Size, BOOL ReadbackRoutine)
{
D3D11_BUFFER_DESC Description = {0};
ID3D11Buffer* Buffer = NULL;
Description.ByteWidth = Size;
Description.Usage = ReadbackRoutine ? D3D11_USAGE_STAGING : D3D11_USAGE_DEFAULT;
Description.CPUAccessFlags = ReadbackRoutine ? D3D11_CPU_ACCESS_READ : 0;
Description.BindFlags = ReadbackRoutine ? 0 : D3D11_BIND_UNORDERED_ACCESS;
if (Device->CreateBuffer(&Description, NULL, &Buffer) != S_OK)
return NULL;
return Buffer;
}
INT main(VOID)
{
HRESULT Result = S_OK;
ID3D11Device* Device = NULL;
ID3D11DeviceContext* Context = NULL;
ID3D11Buffer* In = NULL;
ID3D11Buffer* Out = NULL;
BYTE Buffer[10] = "Kitty cat"; //example buffer
BYTE TryBuffer[10] = { 0 };
Result = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &Device, NULL, &Context);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
In = AllocateD3d11Memory(Device, ARRAY_SIZE(Buffer), FALSE);
if (In == NULL)
goto EXIT_ROUTINE;
Out = AllocateD3d11Memory(Device, ARRAY_SIZE(Buffer), TRUE);
if (Out == NULL)
goto EXIT_ROUTINE;
Id3d11MoveMemoryToGPUMemory(Context, In, Buffer);
Id3d11PullMemoryFromGPUMemory(Context, In, Out, TryBuffer, ARRAY_SIZE(TryBuffer));
EXIT_ROUTINE:
if (In)
In->Release();
if (Out)
Out->Release();
if (Device)
Device->Release();
if (Context)
Context->Release();
return ERROR_SUCCESS;
}
Last updated