Official site anti-cheat Ultra Core Protector

Home Download F.A.Q. Addons Monitor Forum Support Advertise English version site UCP Anti-Cheat  Russian version site UCP Anti-Cheat
Ultra Core Protector - is the client-server anti-cheat freeware, for server protection from unscrupulous players.

Abilities Supported games  
Half-Life
Condition Zero
Counter-Strike 1.6
Day of Defeat
Adrenaline Gamer
Team Fortress Classic
Counter-Strike Source
MU Online
Ragnarok Online
Half-Life 2 Deathmatch
Adrenaline Gamer 2
Team Fortress 2
Window HiJacking with DirectX rendering (without HDC usable for detection)

In my previous post Window HiJacking: Don’t let your overlay betray you I presented a technique to hijack a window belonging and maintained by another process to draw our overlay, preventing anti-cheats to find and analyse our cheats starting from the the detection of their overlay window.

In this previous article, I provided a ready to run example that starts notepad (not as a child process to avoid this detection vector), then modifies its window to be usable for overlays and finally I drew texts and shapes like we do for cheating overlays with GDI.

Following that, other highly skilled members including @namazso @dracorx and @JD96 gave it a try to find simple ways to detect the hijacking.

Among their findings, @JD96 found a clever way to find programs having a handle to device context (HDC) of windows belonging to other processes like I did in my example.
Indeed doing so allowed to detect the hijacking of my example, since my example overlay was using GDI that requires to get the HDC to blit the final frame to the hijacked window.

However, any detection method based on GDI handles enumeration would fail if I did not need an HDC to draw in the hijacked window.

In this present article, I go one step further by hijacking a window and rendering to it with DirectX instead of GDI to avoid getting an HDC, attempting to evade @JD96’s detection method.

I haven’t recoded his detector, but I checked with Nirsoft’s GDIView, a freeware enumerating and presenting GDI handles per process and DirectX doesn’t seem to get an HDC to the hijacked window that could be used for detection.
DirectX does generate 2 HDC but they are memory-only DCs, the function WindowFromDC indicates that these DCs belong to no window, therefore, these HDCs shouldn’t be usable for detection.

I include in the source the creation of a thread that will spawn a console and prompt you for HDC IDs (get them from GDIView) and will then check if a window is associated to it so you can observe that there is no GDI handle link between the hijacking program and the hijacked window that could be usable for detection.

I also include 3 commented lines that GetDC and output WindowFromDC to show that if we did indeed get an HDC to the target window, we would have a GDI link.

In the example I use the code from a DirectX tutorial exercise to make 2 draw 2 cubes spinning around, I was too lazy to make a demo overlay but it’s enough to see it in action.

Binary:
I uploaded a compiled version (Debug mode without optmisations to generate a cleaner binary if you want to debug it for some reason)

Source:
Do not forget forget to include the DirectX SDK in the includes and library directories of your project.

main.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")

#pragma warning(disable:4996) // Only required for the console (freopen function deprecated)

#define HJWND_PROGRAM L"notepad.exe"
#define MAX_CLASSNAME 255
#define MAX_WNDNAME 255

using namespace std;

//Global Declarations - Interfaces//
IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;
ID3D11Buffer* squareIndexBuffer;
ID3D11DepthStencilView* depthStencilView;
ID3D11Texture2D* depthStencilBuffer;
ID3D11Buffer* squareVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;
ID3D11Buffer* cbPerObjectBuffer;
///////////////**************new**************////////////////////
ID3D11RasterizerState* WireFrame;
///////////////**************new**************////////////////////

//Global Declarations - Others
LPCTSTR WndClassName = L"firstwindow";
HWND hwnd = NULL;
HRESULT hr;

const int Width = GetSystemMetrics(SM_CXSCREEN);
const int Height = GetSystemMetrics(SM_CYSCREEN);

XMMATRIX WVP;
XMMATRIX cube1World;
XMMATRIX cube2World;
XMMATRIX camView;
XMMATRIX camProjection;

XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;

XMMATRIX Rotation;
XMMATRIX Scale;
XMMATRIX Translation;
float rot = 0.01f;

//Function Prototypes
bool InitializeDirect3d11App(HINSTANCE hInstance);
void CleanUp();
bool InitScene();
void UpdateScene();
void DrawScene();
bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed);
int messageloop();
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

//Create effects constant buffer's structure
struct cbPerObject { XMMATRIX WVP; };

cbPerObject cbPerObj;

//Vertex Structure and Vertex Layout (Input Layout) - Overloaded Vertex Structure
struct Vertex {
Vertex() {}
Vertex(float x, float y, float z, float cr, float cg, float cb, float ca) : pos(x, y, z), color(cr, cg, cb, ca) {}
XMFLOAT3 pos;
XMFLOAT4 color;
};

D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE(layout);

// Structs
struct WindowsFinderParams {
DWORD pidOwner = NULL;
wstring wndClassName = L"";
wstring wndName = L"";
RECT pos = { 0, 0, 0, 0 };
POINT res = { 0, 0 };
float percentAllScreens = 0.0f;
float percentMainScreen = 0.0f;
DWORD style = NULL;
DWORD styleEx = NULL;
bool satisfyAllCriteria = false;
vector hwnds;
};

// Prototypes
vector WindowsFinder(WindowsFinderParams params);
BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM lParam);
HWND HiJackNotepadWindow();
vector GetPIDs(wstring targetProcessName);
void ExperimentCheckDCsWindow();

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
//InitializeWindow(hInstance, nCmdShow, Width, Height, true);
hwnd = HiJackNotepadWindow();
if (!hwnd)
return EXIT_FAILURE;
if (!InitializeDirect3d11App(hInstance))
return EXIT_FAILURE;
if (!InitScene())
return EXIT_FAILURE;

SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW);

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ExperimentCheckDCsWindow, 0, 0, 0);

messageloop();

CleanUp();

return EXIT_SUCCESS;
}

HWND HiJackNotepadWindow() {
HWND hwndHiHjacked = NULL;

// Remove previous windows
vector existingNotepads = GetPIDs(HJWND_PROGRAM);
if (!existingNotepads.empty()) {
for (int i(0); i < existingNotepads.size(); ++i) { // Terminating processes HANDLE hOldProcess = OpenProcess(PROCESS_TERMINATE, FALSE, existingNotepads[i]); TerminateProcess(hOldProcess, 0); CloseHandle(hOldProcess); } } system("start notepad"); // Start notepad, and not as child process, so easy :) /* // Starts notepad (as child process, unsafe) wchar_t wWinDir[MAX_PATH] = L""; GetWindowsDirectory(wWinDir, MAX_PATH); wstring winDir = wWinDir; wstring notepadExe = winDir + L"\\notepad.exe"; STARTUPINFO si; SecureZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; SecureZeroMemory(&pi, sizeof(pi)); if (!CreateProcess(notepadExe.c_str(), 0, 0, 0, 0, 0, 0, 0, &si, &pi)) return false; */ // Finding notepad's window (we could just use FindWindow but then it would be OS language dependent) vector notepads = GetPIDs(HJWND_PROGRAM);
if (notepads.empty() || notepads.size() > 1) // Should check if more than one to be more strict
return hwndHiHjacked;
WindowsFinderParams params;
params.pidOwner = notepads[0];
params.style = WS_VISIBLE;
params.satisfyAllCriteria = true;
vector hwnds;
int attempt = 0; // The process takes a bit of time to initialise and spawn the window, will try during 5 sec before time out
while (hwndHiHjacked == NULL || attempt > 50) {
Sleep(100);
hwnds = WindowsFinder(params);
if (hwnds.size() > 1)
return hwndHiHjacked;
hwndHiHjacked = hwnds[0];
++attempt;
}
if (!hwndHiHjacked)
return hwndHiHjacked;

// Making the window usable for overlay puposes
SetMenu(hwndHiHjacked, NULL);
SetWindowLongPtr(hwndHiHjacked, GWL_STYLE, WS_VISIBLE);
SetWindowLongPtr(hwndHiHjacked, GWL_EXSTYLE, WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT); // WS_EX_NOACTIVATE and WS_EX_TOOLWINDOW removes it from taskbar
//SetWindowPos(hwndHiHjacked, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW); // DX fails to init if I do that here for some reason

// Quick and dirty transparency
SetLayeredWindowAttributes(hwndHiHjacked, RGB(0, 0, 0), 0, LWA_COLORKEY);

return hwndHiHjacked;
}

vector GetPIDs(wstring targetProcessName) {
vector pids;
if (targetProcessName == L"")
return pids;
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W entry;
entry.dwSize = sizeof entry;
if (!Process32FirstW(snap, &entry)) {
CloseHandle(snap);
return pids;
}
do {
if (wstring(entry.szExeFile) == targetProcessName) {
pids.emplace_back(entry.th32ProcessID);
}
} while (Process32NextW(snap, &entry));
CloseHandle(snap);
return pids;
}

BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM lParam) {
WindowsFinderParams& params = *(WindowsFinderParams*)lParam;

unsigned char satisfiedCriteria = 0, unSatisfiedCriteria = 0;

// If looking for windows of a specific PDI
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
if (params.pidOwner != NULL)
if (params.pidOwner == pid)
++satisfiedCriteria; // Doesn't belong to the process targeted
else
++unSatisfiedCriteria;

// If looking for windows of a specific class
wchar_t className[MAX_CLASSNAME] = L"";
GetClassName(hwnd, className, MAX_CLASSNAME);
wstring classNameWstr = className;
if (params.wndClassName != L"")
if (params.wndClassName == classNameWstr)
++satisfiedCriteria; // Not the class targeted
else
++unSatisfiedCriteria;

// If looking for windows with a specific name
wchar_t windowName[MAX_WNDNAME] = L"";
GetWindowText(hwnd, windowName, MAX_CLASSNAME);
wstring windowNameWstr = windowName;
if (params.wndName != L"")
if (params.wndName == windowNameWstr)
++satisfiedCriteria; // Not the class targeted
else
++unSatisfiedCriteria;

// If looking for window at a specific position
RECT pos;
GetWindowRect(hwnd, &pos);
if (params.pos.left || params.pos.top || params.pos.right || params.pos.bottom)
if (params.pos.left == pos.left && params.pos.top == pos.top && params.pos.right == pos.right && params.pos.bottom == pos.bottom)
++satisfiedCriteria;
else
++unSatisfiedCriteria;

// If looking for window of a specific size
POINT res = { pos.right - pos.left, pos.bottom - pos.top };
if (params.res.x || params.res.y)
if (res.x == params.res.x && res.y == params.res.y)
++satisfiedCriteria;
else
++unSatisfiedCriteria;

// If looking for windows taking more than a specific percentage of all the screens
float ratioAllScreensX = res.x / GetSystemMetrics(SM_CXSCREEN);
float ratioAllScreensY = res.y / GetSystemMetrics(SM_CYSCREEN);
float percentAllScreens = ratioAllScreensX * ratioAllScreensY * 100;
if (params.percentAllScreens != 0.0f)
if (percentAllScreens >= params.percentAllScreens)
++satisfiedCriteria;
else
++unSatisfiedCriteria;

// If looking for windows taking more than a specific percentage or the main screen
RECT desktopRect;
GetWindowRect(GetDesktopWindow(), &desktopRect);
POINT desktopRes = { desktopRect.right - desktopRect.left, desktopRect.bottom - desktopRect.top };
float ratioMainScreenX = res.x / desktopRes.x;
float ratioMainScreenY = res.y / desktopRes.y;
float percentMainScreen = ratioMainScreenX * ratioMainScreenY * 100;
if (params.percentMainScreen != 0.0f)
if (percentAllScreens >= params.percentMainScreen)
++satisfiedCriteria;
else
++unSatisfiedCriteria;

// Looking for windows with specific styles
LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
if (params.style)
if (params.style & style)
++satisfiedCriteria;
else
++unSatisfiedCriteria;

// Looking for windows with specific extended styles
LONG_PTR styleEx = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
if (params.styleEx)
if (params.styleEx & styleEx)
++satisfiedCriteria;
else
++unSatisfiedCriteria;

if (!satisfiedCriteria)
return TRUE;

if (params.satisfyAllCriteria && unSatisfiedCriteria)
return TRUE;

// If looking for multiple windows
params.hwnds.push_back(hwnd);
return TRUE;
}

vector WindowsFinder(WindowsFinderParams params) {
EnumWindows(EnumWindowsCallback, (LPARAM)¶ms);
return params.hwnds;
}

bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed) {
typedef struct _WNDCLASS {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;

WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
wc.lpszMenuName = NULL;
wc.lpszClassName = WndClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if (!RegisterClassEx(&wc)) {
MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR);
return false;
}

hwnd = CreateWindowEx(NULL, WndClassName, L"Lesson 4 - Begin Drawing", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL);

if (!hwnd) {
MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR);
return false;
}

ShowWindow(hwnd, ShowWnd);
UpdateWindow(hwnd);

return true;
}

bool InitializeDirect3d11App(HINSTANCE hInstance) {
//Describe our SwapChain Buffer
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
bufferDesc.Width = Width;
bufferDesc.Height = Height;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

//Describe our SwapChain
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd; // hwnd
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

//Create our SwapChain
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);

//Create our BackBuffer
ID3D11Texture2D* BackBuffer;
hr = SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);

//Create our Render Target
hr = d3d11Device->CreateRenderTargetView(BackBuffer, NULL, &renderTargetView);
BackBuffer->Release();

//Describe our Depth/Stencil Buffer
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = Width;
depthStencilDesc.Height = Height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;

//Create the Depth/Stencil View
d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);

//Set our Render Target
d3d11DevCon->OMSetRenderTargets(1, &renderTargetView, depthStencilView);

return true;
}

void CleanUp() {
//Release the COM Objects we created
SwapChain->Release();
d3d11Device->Release();
d3d11DevCon->Release();
renderTargetView->Release();
squareVertBuffer->Release();
squareIndexBuffer->Release();
VS->Release();
PS->Release();
VS_Buffer->Release();
PS_Buffer->Release();
vertLayout->Release();
depthStencilView->Release();
depthStencilBuffer->Release();
cbPerObjectBuffer->Release();
///////////////**************new**************////////////////////
WireFrame->Release();
///////////////**************new**************////////////////////
}

bool InitScene() {
//Compile Shaders from shader file
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0);
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0);

//Create the Shader Objects
hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);

//Set Vertex and Pixel Shaders
d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);

//Create the vertex buffer
Vertex v[] = {
Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f),
Vertex(-1.0f, +1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f),
Vertex(+1.0f, +1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f),
Vertex(+1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f),
Vertex(-1.0f, -1.0f, +1.0f, 0.0f, 1.0f, 1.0f, 1.0f),
Vertex(-1.0f, +1.0f, +1.0f, 1.0f, 1.0f, 1.0f, 1.0f),
Vertex(+1.0f, +1.0f, +1.0f, 1.0f, 0.0f, 1.0f, 1.0f),
Vertex(+1.0f, -1.0f, +1.0f, 1.0f, 0.0f, 0.0f, 1.0f),
};

DWORD indices[] = {
// front face
0, 1, 2,
0, 2, 3,

// back face
4, 6, 5,
4, 7, 6,

// left face
4, 5, 1,
4, 1, 0,

// right face
3, 2, 6,
3, 6, 7,

// top face
1, 5, 6,
1, 6, 2,

// bottom face
4, 0, 3,
4, 3, 7
};

D3D11_BUFFER_DESC indexBufferDesc;
ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);

d3d11DevCon->IASetIndexBuffer(squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 8;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = v;
hr = d3d11Device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &squareVertBuffer);

//Set the vertex buffer
UINT stride = sizeof(Vertex);
UINT offset = 0;
d3d11DevCon->IASetVertexBuffers(0, 1, &squareVertBuffer, &stride, &offset);

//Create the Input Layout
hr = d3d11Device->CreateInputLayout(layout, numElements, VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), &vertLayout);

//Set the Input Layout
d3d11DevCon->IASetInputLayout(vertLayout);

//Set Primitive Topology
d3d11DevCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

//Create the Viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = Width;
viewport.Height = Height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;

//Set the Viewport
d3d11DevCon->RSSetViewports(1, &viewport);

//Create the buffer to send to the cbuffer in effect file
D3D11_BUFFER_DESC cbbd;
ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerObject);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;
hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);

//Camera information
camPosition = XMVectorSet(0.0f, 3.0f, -8.0f, 0.0f);
camTarget = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
camUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

//Set the View matrix
camView = XMMatrixLookAtLH(camPosition, camTarget, camUp);

//Set the Projection matrix
camProjection = XMMatrixPerspectiveFovLH(0.4f*3.14f, (float)Width / Height, 1.0f, 1000.0f);

///////////////**************new**************////////////////////
D3D11_RASTERIZER_DESC wfdesc;
ZeroMemory(&wfdesc, sizeof(D3D11_RASTERIZER_DESC));
wfdesc.FillMode = D3D11_FILL_WIREFRAME;
wfdesc.CullMode = D3D11_CULL_NONE;
hr = d3d11Device->CreateRasterizerState(&wfdesc, &WireFrame);

d3d11DevCon->RSSetState(WireFrame);
///////////////**************new**************////////////////////

return true;
}

void UpdateScene() {
//Keep the cubes rotating
rot += .0005f;
if (rot > 6.26f)
rot = 0.0f;

//Reset cube1World
cube1World = XMMatrixIdentity();

//Define cube1's world space matrix
XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
Rotation = XMMatrixRotationAxis(rotaxis, rot);
Translation = XMMatrixTranslation(0.0f, 0.0f, 4.0f);

//Set cube1's world space using the transformations
cube1World = Translation * Rotation;

//Reset cube2World
cube2World = XMMatrixIdentity();

//Define cube2's world space matrix
Rotation = XMMatrixRotationAxis(rotaxis, -rot);
Scale = XMMatrixScaling(1.3f, 1.3f, 1.3f);

//Set cube2's world space matrix
cube2World = Rotation * Scale;
}

void DrawScene() {
//Clear our backbuffer
float bgColor[4] = { (0.0f, 0.0f, 0.0f, 0.0f) };
d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

//Refresh the Depth/Stencil view
d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

//Set the WVP matrix and send it to the constant buffer in effect file
WVP = cube1World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);

//Draw the first cube
d3d11DevCon->DrawIndexed(36, 0, 0);

WVP = cube2World * camView * camProjection;
cbPerObj.WVP = XMMatrixTranspose(WVP);
d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);

//Draw the second cube
d3d11DevCon->DrawIndexed(36, 0, 0);

//Present the backbuffer to the screen
SwapChain->Present(0, 0);
}

int messageloop() {
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (true)
{
BOOL PeekMessageL(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg);

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
// run game code
UpdateScene();
DrawScene();
}
}
return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) {
DestroyWindow(hwnd);
}
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

void ExperimentCheckDCsWindow() {
// For experiments (HDC handles are negative! e.g. 0xffffffffffb41d27 use kernel address in GDIView)
AllocConsole();
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);

//HDC hdcNotepad = GetDC(hwnd);
//cout << "HWND notepad: 0x" << WindowFromDC(hdcNotepad) << endl; //cout << "HDC notepad: 0x" << hex << hdcNotepad << endl; while (true) { HWND hwndFromHdc = NULL; DWORD64 hdcId = NULL; cout << "HDC: 0x"; cin >> hex >> hdcId;
HDC hdcTgt = NULL;
CopyMemory(&hdcTgt, &hdcId, sizeof(HDC));
hwndFromHdc = WindowFromDC(hdcTgt);
cout << "HWND 0x" << hex << hwndFromHdc << endl; } FreeConsole(); }

Since this is an exercise from a tutorial you'll also need to add this file in the directory of the binary (or in the working directory if you execute from Visual Studio directly).

Sorry about that.

Effects.fx
cbuffer cbPerObject{ float4x4 WVP; };
struct VS_OUTPUT {
float4 Pos : SV_POSITION;
float4 Color : COLOR;
};
VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR) {
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.Color = inColor;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET { return input.Color; }

You should see notepad opening quickly and then DirectX will start rendering the cubes like that:

Guys, I let you check the "detectability" of all this without the HDC.

Hopefully this will be useful and harder to detect

Have a good one.