Hijacking Discord's internal overlay without a single detection vector.

Max McNeal

Introduction

Discord, the popular communication platform for gamers, has an intriguing feature: an in-game overlay that allows users to interact with Discord while playing games. This overlay is powered by a whitelisted internal module, known as DiscordHook64.dll, which integrates with games in a unique way. This article dives into the technical details of how this module operates and explores the possibilities of hijacking it for custom modifications.

Understanding DiscordHook64.dll

The DiscordHook64.dll is a critical component of Discord's in-game overlay functionality.

Games load this module using the SetWindowHookEx function, a standard method in Windows programming for intercepting various system events.

The primary function of DiscordHook64.dll is to copy the game's framebuffer — essentially a portion of RAM containing a current image to be displayed on the screen — into a memory-mapped file. This technique enables Discord's overlay to render on top of the game without directly altering the game's code or rendering pipeline.

Demonstration #1 - Hijack named pipe

The simplest demonstration of this technique would be to create a named file mapping object of FILE_MAP_ALL_ACCESS to DiscordOverlay_Framebuffer_Memory_XXXX.

// Header structure
typedef struct Header
{
    std::uint32_t size;     // SIZE OF MAPPED BUFFER
    std::uint64_t sequence; // FRAME SEQUENCE NUMBER, INCREASE AFTER PRESENT
    std::uint32_t width;    // FRAME WIDTH
    std::uint32_t height;   // FRAME HEIGHT
    std::uint8_t  data[1];
};

This structure includes details like frame count, dimensions of the image, and the actual buffer where the image data is stored in a B8G8R8A8 format (representing the color channels and alpha transparency).

std::string mapped_filename = "DiscordOverlay_Framebuffer_Memory_" + std::to_string(PROCESS_ID);
auto file = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, mapped_filename.c_str());

// ENSURE WE HAVE A VALID HANDLE
if (!file || file == INVALID_HANDLE_VALUE)
    return false;

// CAST INTO AFOREMENTIONED HEADER STRUCTURE
return static_cast(MapViewOfFile(file, FILE_MAP_ALL_ACCESS, 0, 0, 0));

In this function, a memory-mapped file is opened and mapped into the address space of the calling process. This mapping is what allows the overlay to access and modify the framebuffer data.

Notes

A finished proof-of-concept may be found on this project's repository, here.

While the prospect of customizing Discord's overlay is enticing, it also raises significant security concerns which makes it very important to approach such things with caution. Understanding the technical workings of such systems is crucial for both developers and users to ensure a safe and enjoyable gaming experience.

GO BACK HOME