NitoTech

Game Vulnerability Researcher | Anti-Cheat Enthusiast

Check out my
other Posts!

My Favorite Projects

Here are some of my favorite projects I've worked on



How do Cheat Overlays Work? (Direct3D 9 Overlay Concept)

Sep 14, 2025 | Direct3D 9 Overlay Concept

Introduction

Have you ever wanted to create an overlay for your cheats and wern't sure where to start? Keep reading, and I will show you how to setup your environment as well as the concepts behind creating an overlay.

Overlays are great because they can help cheat developers as well as potential users of a cheat keep up with specific values or toggled cheats. Allowing for more clarity on how the cheat operates and it's capabilities.

Disclaimer, this post will speak on the concepts behind creating an overlay for a game.
A future post will have code that you can follow along with!

Please hover over any words highlighted in purple to get a description of what they mean!

What is required to create an overlay?

Things you need:

Identifying what graphics API your game uses

While some games may make the graphics API it uses obvious through launch options, checking the games imports, or by other means. Sometimes it can be difficult to identify what graphics API a game is using.

To address this issue, we can utilize MSI Afterburner. Which you can download from the official MSI website.
You'll want to make sure to pay attention and install Rivatuner Statistics Server during the installation process. As it is needed in order to use the overlay within MSI Afterburner

After it's been installed, you can follow these instructions to display the graphics API within the overlay:

  1. Launch the appication, and navigate to Properties (Cog Wheel Icon)
  2. Then you'll go to the Monitoring tab and within Graph, scroll down and click on Frametime
  3. Below the Graph, you'll see the check box for Show in On-Screen Display, enable that option, then hit Apply and OK.

Now the next time you launch a full-screen game, you'll see the graphics API displayed in the top left corner.

I learned this technique from "y4k ;; lucky doG" on Steam. Please feel free to check out their original post here: How to find out a game's rendering API with MSI Afterburner

Downloading the SDK

You can download the SDK from here: Microsoft legacy SDK download

The SDK has already reached it's End of Life and is no longer supported. If you run into any issues installing the SDK it's usually because you already have a version of it installed.

You'll need to uninstall your current version and run the installer again so you can gaurentee you have DirectX 9 installed which is included with this installer

Setting up your IDE

Within your IDE of choice (I use Visual Studio, so the following instructions are for that IDE)

  1. You can right click on your solution and go to properties
  2. Navigate to VC++ Directories, then edit your Include Directories to be (ENTER THIS AT A LATER TIME)
  3. Then within that same page, you'll edit your Library Directories to be (ENTER THIS AT A LATER TIME)
  4. Afterwards you can press apply, then press ok, and your IDE will be setup to include the Direct3D and DirectX includes and libraries!

These instructions assume you already have a solution created for your cheat.

How does a Direct3D overlay work?

What does a Graphics API do?

Before we create our overlay it's important to understand how it works before hand!

Direct3D 9 is a Graphics API, that allows us to utilize commands to communicate and control a GPU in order to render images, 2D, and 3D graphics on our screens. Graphic API's vary depending on what operating system you are using as well as what specific software you're using.

For example, the Graphics API's utilized by Windows are Direct3D 9 - Direct3D 11.1 as well as OpenGL.

To create an overlay we first have to use Direct3D to render new graphics to our screen. So how do we do this?

I originally assumed that we would utilize the game's internal engine to render our overlay, which may be possible, but to my current knowledge is not how it works. Instead, we setup an environment very similar to how game engines utilize graphics API's and we interact with our GPU directly to render graphics on top of the game. As mentioned above, since graphics APIs can vary depending on the software of OS we want to make sure that whichever applications we are creating an overlay for uses the same API.

Gathering information about the screen

After we have confirmed that our application uses the same API, we have to gather information about the screen we're rendering to. That can look like something like this:


void Overlay::getGameWindowInfo()
{
	windowInfo.gameWindowHandle = FindWindowA(0, "<Insert Game Window Name>"); // 0 is used to find any top-level window that matches the listed window name

	if (windowInfo.gameWindowHandle)
	{
		GetWindowThreadProcessId(windowInfo.gameWindowHandle, &windowInfo.gameWindowProcID);  // Gets Proccess ID of our targeted Window
		gameHandle = OpenProcess(PROCESS_ALL_ACCESS, false, windowInfo.gameWindowProcID);     // Gets the handle for the Process
		GetWindowRect(windowInfo.gameWindowHandle, &windowInfo.rect);                         // Gets the dimensions of the window
		overlayInfo.width = windowInfo.rect.right - windowInfo.rect.left;                     // Calculate window width
		overlayInfo.height = windowInfo.rect.bottom - windowInfo.rect.top;                    // Calculate window height

		MoveWindow(overlayInfo.overlayWindowHandle, windowInfo.rect.left, windowInfo.rect.top, overlayInfo.width, overlayInfo.height, true); // Used to move our overlay to the targeted area, and paint it over the current window

		overlayInfo.margin = { 0, 0, overlayInfo.width, overlayInfo.height };
	}
}
                    

This function is responsible for grabbing information from our games screen, such as the process ID, handle, and the dimensions of our screen. This information will be used later to help us place our overlay properly on the screen.

Creating our overlay

In order to create our overlay we need to create a new Window that we will then show on the screen. We can do this using the CreateWindowEx function. According to MSDN, this function creates an "overlapped, pop-up, or child window with an extended style."

We'd then want to utilize SetLayeredWindowAttributes which allows us to set the opacity and transparency color keys of our newly created Window. Then we can show our window using ShowWindow with the SW_SHOW flag.

The function to do this would look similar to this:


void Overlay::createAndShowOverlay()
{
	overlayInfo.overlayWindowHandle = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT, L"Cheat Overlay", L"Cheat Overlay", WS_POPUP, 1, 1, overlayInfo.width, overlayInfo.height, 0, 0, hInstance, 0);
	SetLayeredWindowAttributes(overlayInfo.overlayWindowHandle, RGB(0, 0, 0), 255, LWA_COLORKEY | LWA_ALPHA);
	ShowWindow(overlayInfo.overlayWindowHandle, SW_SHOW);
	DwmExtendFrameIntoClientArea(overlayInfo.overlayWindowHandle, &overlayInfo.margin);
}
                    

Initializing Direct3D

We have to initialize Direct3D 9Ex to create an object which allow us to enumerate and retrieve capabilities of a device.

Next, we will go through and interact with a D3D (Direct3D) paramaters structure and set up the paramaters we want for our overlay.

Finally, we will create a device, which is how Direct3D communicates with our GPU. Giving it the information we gathered from previous functions along with the parameters we just set.

The code for this can look like this:


void Overlay::Direct3D9XInit(HWND hwnd)
{
	hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pObject);     // Creates an IDirect3D9Ex interface to create Direct 3D 9Ex objects

	ZeroMemory(&m_D3DParam, sizeof(m_D3DParam));             // Initializes our D3DPRESENT_PARAMETERS with all zeros

	m_D3DParam.Windowed = true;                              // If application (our game) runs windowed
	m_D3DParam.BackBufferFormat = D3DFMT_A8R8G8B8;           // Defines how color or depth information is stored
	m_D3DParam.BackBufferWidth = overlayInfo.width;          // Width of the new swap chain's back buffer in pixels (Our overlay's width)
	m_D3DParam.BackBufferHeight = overlayInfo.height;        // Height of the new swap chain's back buffer in pixels (Our overlay's height)
	m_D3DParam.EnableAutoDepthStencil = true;                // Makes Direct3D manage depth buffers for the application
	m_D3DParam.AutoDepthStencilFormat = D3DFMT_D16;          // The format of the automatic depth-stencil surface the device will create
	m_D3DParam.SwapEffect = D3DSWAPEFFECT_DISCARD;           // When rendering, this makes it present the back buffer, then discard it

	// Creates a device to represent the display adapter
	hr = m_pObject->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_D3DParam, 0, &m_pDevice);
}
                    

Rendering in Direct3D

The final step of our overlay process, rendering our overlay to the screen.

When rendering with Direct3D everything that we are going to render is going to be included between Device->BeginScene() and
Device->EndScene().

There are so many ways that you can render and draw to a screen and it would be too much to include here. I will include a link to the MSDN where you can see all a wide range of examples of all the things you can draw and make in the references.

For example, if we wanted to create a square overlay for our screen we could utilize the D3DXCreateLine() function to initialize the drawing object, and then call the Draw() function from that object.

One thing that can be complicated when creating shapes and text on our screen is that everything requires coordinates so that Direct3D can know where we want to draw each of our lines and the style of how we want to connect each vertex.

I will be covering rendering a lot more in my future post explaining the code behind creating a cheat overlay. So if you're interested in that, I hope you'll check out that post in the future as well!

The last thing we have to do after EndScene() is to call PresentEx() while swaps to the swapchain's next buffer. This enables us to swap out the currently rendered frame with a frame that has been rendered on the back buffer to avoid screen tearing.

Afterwards our user will see the newly rendered screen and then we will perform cleanup by calling the Clean() function. Which according to MSDN, "Clears one or more surfaces such as a render target, multiple render targets, a stencil buffer, and a depth buffer".

Now we have officially rendered our overlay to the screen!

Conclusion

Now that I have a better understanding on the concept of how creating an overlay for a game cheat works. I will begin to work on creating my own overlay program! It was fun to learn about how much goes into creating an overlay, along with the process that graphic API's play. I hope whoever reads this blog was able to learn something as well!

If you have any feedback or want to share what you've created please feel free to reach out! You can contact me through Twitter/X or by the email listed in Contacts


Please take care, take some time to learn something new, and happy game hacking!

NitoTech

Additional Resources:

Documentation:

MSDN - Direct3D 9 Graphics
MSDN - DirectX Graphics

Videos:

Guided Hacking - Skyrim Overlay Example
CasualGamer - External Overlay in C++