FPS方框透视辅助开发教学7:番外篇之D3D9方框透视绘制-游戏安全逆向社区论坛-技术社区-学技术网

FPS方框透视辅助开发教学7:番外篇之D3D9方框透视绘制

效果视频

 

前情回顾

手把手教你开发一款方框透视外挂【已完结】

FPS方框透视辅助开发教学1:数据挖掘和基本绘制
https://www.52xuejishu.com/forum-post/337.html

FPS方框透视辅助开发教学2:编写代码读取玩家数据
https://www.52xuejishu.com/forum-post/339.html

FPS方框透视辅助开发教学3:屏幕坐标转换算法、绘制文本到敌人
https://www.52xuejishu.com/forum-post/340.html

FPS方框透视辅助开发教学4:屏幕坐标转换算法完整解析
https://www.52xuejishu.com/forum-post/345.html

FPS方框透视辅助开发教学5:绘制所有敌人射线和距离
https://www.52xuejishu.com/forum-post/347.html

FPS方框透视辅助开发教学6:实现GDI绘制方框透视(完结)
https://www.52xuejishu.com/forum-post/349.html

想学习游戏辅助开发没地方?

来这里,我们有基础版299和专业版2024

【基础版】包含4套教学,赠送价值158过检测过保护CE

B站平台可直达下单,手机访问效果最佳

https://mall.bilibili.com/neul-next/detailuniversal/detail.html?isMerchant=1&page=detailuniversal_detail&saleType=10&itemsId=11262567&loadingShow=1&noTitleBar=1

包含:

学习游戏安全,加入游戏安全逆向基础版社区,现在优惠价299
游戏安全逆向:入门科普大全解
https://study.163.com/course/courseMain.htm?courseId=1212474809&share=2&shareId=1020678503
游戏安全逆向工程师:CE基础
https://study.163.com/course/courseMain.htm?courseId=1209141829&share=2&shareId=1020678503
C语言0基础入门游戏辅助开发实践
https://study.163.com/course/courseMain.htm?courseId=1213365801&share=2&shareId=1020678503
易语言0基础游戏辅助电脑脚本开发(正在更新ing)
https://study.163.com/course/courseMain.htm?courseId=1213780852&share=2&shareId=1020678503

优惠下单链接,学习游戏修改作弊、辅助脚本开发、飞天遁地透视自瞄辅助技术,您的最佳选择:
平台下单地址https://mall.bilibili.com/neul-next/detailuniversal/detail.html?isMerchant=1&page=detailuniversal_detail&saleType=10&itemsId=11262567&loadingShow=1&noTitleBar=1
下单后承诺以上四套内容全部开通在网易云课堂、永久观看时效、指导答疑
下单后即赠送过网络游戏检测保护的CE游戏修改器一套(价值158)

【专业版】包含12套教学,内容更多,工具更丰富,详情联系i-xiaodi

https://mall.bilibili.com/neul-next/detailuniversal/detail.html?isMerchant=1&page=detailuniversal_detail&saleType=10&itemsId=11262678&loadingShow=1&noTitleBar=1

初识D3D9

Direct3D 9(简称 D3D9)是微软推出的 DirectX API 的一部分,主要用于在 Windows 平台上进行 3D 图形渲染。它为开发者提供了操作图形硬件的接口,以实现复杂的 3D 图形效果。广泛应用于需要高性能图形处理的领域,如游戏开发。当然,也被很多人用于外挂开发。

D3D9绘制的基本流程:

  1. 初始化Direct3D对象: 首先,通过Direct3DCreate9函数创建IDirect3D9接口的实例,这是进行后续操作的基础。
  2. 设置显示参数: 定义D3DPRESENT_PARAMETERS结构体,设置窗口模式、后台缓冲区格式、交换效果等参数,以配置显示模式。
  3. 创建设备对象: 使用IDirect3D9CreateDevice方法创建IDirect3DDevice9接口实例,设备对象用于管理资源并执行渲染操作。
  4. 设置渲染状态: 配置渲染状态,包括光照、混合模式、深度测试等,以控制图形的渲染方式。
  5. 创建并设置顶点缓冲区: 定义顶点数据并创建顶点缓冲区,将顶点数据加载到缓冲区中。然后,设置顶点格式并将缓冲区绑定到设备。
  6. 渲染循环: 在主循环中,执行以下步骤:
    • 清除缓冲区: 使用Clear方法清除渲染目标和深度缓冲区。
    • 开始场景: 调用BeginScene方法开始绘制场景。
    • 绘制图元: 使用DrawPrimitiveDrawIndexedPrimitive方法绘制基本图元,如三角形、线条等。
    • 结束场景: 调用EndScene方法结束场景绘制。
    • 显示结果: 使用Present方法将渲染结果显示到屏幕上。
  1. 释放资源: 在程序结束时,释放所有分配的资源,包括设备、缓冲区等,以避免内存泄漏。

示例:绘制一个实心矩形

图片[1]-FPS方框透视辅助开发教学7:番外篇之D3D9方框透视绘制-游戏安全逆向社区论坛-技术社区-学技术网

#include <windows.h>
#include <d3d9.h>

#pragma comment(lib, "d3d9.lib")

// 全局变量
LPDIRECT3D9           g_pD3D = nullptr;  // Direct3D接口
LPDIRECT3DDEVICE9     g_pd3dDevice = nullptr;  // Direct3D设备
LPDIRECT3DVERTEXBUFFER9 g_pVB = nullptr;  // 顶点缓冲区

// 定义灵活顶点格式(屏幕坐标,预变换)
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)

// 定义顶点结构体
struct CUSTOMVERTEX
{
	float x, y, z, rhw; // 位置及齐次坐标
	DWORD color;        // 颜色
};

// 窗口过程
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

// 初始化 Direct3D
bool InitD3D(HWND hwnd)
{
	// 创建 Direct3D 接口
	g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (g_pD3D == nullptr)
		return false;

	// 设置呈现参数
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	d3dpp.Windowed = TRUE;                         // 窗口模式
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;       // 丢弃交换链
	d3dpp.hDeviceWindow = hwnd;                    // 指定渲染窗口

	// 创建 Direct3D 设备
	if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hwnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&g_pd3dDevice)))
	{
		return false;
	}
	return true;
}

// 初始化几何数据(顶点缓冲区),绘制一个矩形
bool InitGeometry()
{
	// 创建顶点缓冲区,包含4个顶点
	if (FAILED(g_pd3dDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX),
		0,
		CUSTOMFVF,
		D3DPOOL_MANAGED,
		&g_pVB,
		nullptr)))
	{
		return false;
	}

	// 填充顶点数据
	CUSTOMVERTEX* pVertices;
	if (FAILED(g_pVB->Lock(0, 4 * sizeof(CUSTOMVERTEX), (void**)&pVertices, 0)))
	{
		return false;
	}

	// 设置矩形四个角的坐标和颜色(使用预变换的屏幕坐标)
	// (150,50) 左上角,(450,50) 右上角,(150,350) 左下角,(450,350) 右下角
	pVertices[0] = { 150.0f,  50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 0, 0) };     // 红色
	pVertices[1] = { 450.0f,  50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 255, 0) };     // 绿色
	pVertices[2] = { 150.0f, 350.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0, 0, 255) };     // 蓝色
	pVertices[3] = { 450.0f, 350.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255, 255, 0) };   // 黄色

	g_pVB->Unlock();
	return true;
}

// 渲染场景
void Render()
{
	if (g_pd3dDevice == nullptr)
		return;

	// 清除屏幕背景,设置为黑色
	g_pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	// 开始场景
	if (SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		// 设置顶点缓冲区
		g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
		g_pd3dDevice->SetFVF(CUSTOMFVF);

		// 使用三角形带绘制矩形(绘制两个三角形构成矩形)
		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

		// 结束场景
		g_pd3dDevice->EndScene();
	}

	// 呈现渲染结果
	g_pd3dDevice->Present(nullptr, nullptr, nullptr, nullptr);
}

// 释放资源
void Cleanup()
{
	if (g_pVB != nullptr)
		g_pVB->Release();
	if (g_pd3dDevice != nullptr)
		g_pd3dDevice->Release();
	if (g_pD3D != nullptr)
		g_pD3D->Release();
}

// 程序入口
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
	// 注册窗口类
	WNDCLASSEX wc = { sizeof(WNDCLASSEX),
					  CS_CLASSDC,
					  WindowProc,
					  0,
					  0,
					  hInstance,
					  nullptr,
					  nullptr,
					  nullptr,
					  nullptr,
					  "D3D9_Rectangle_Class",
					  nullptr };
	RegisterClassEx(&wc);

	// 创建窗口
	HWND hwnd = CreateWindow("D3D9_Rectangle_Class",
		"D3D9 绘制矩形示例",
		WS_OVERLAPPEDWINDOW,
		100,
		100,
		800,
		600,
		nullptr,
		nullptr,
		hInstance,
		nullptr);

	if (hwnd == nullptr)
		return 0;

	// 初始化 Direct3D
	if (!InitD3D(hwnd))
		return 0;

	// 初始化几何数据
	if (!InitGeometry())
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	// 消息循环
	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Render();
		}
	}

	Cleanup();
	return 0;
}

以上是一个基本的框架,无论绘制什么东西,都可以遵循这个框架

示例:绘制一个透明矩形

图片[2]-FPS方框透视辅助开发教学7:番外篇之D3D9方框透视绘制-游戏安全逆向社区论坛-技术社区-学技术网

#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

LPDIRECT3D9 pD3D = nullptr;               // Direct3D 对象
LPDIRECT3DDEVICE9 pD3DDevice = nullptr;   // Direct3D 设备

// Direct3D 初始化函数
bool InitD3D(HWND hWnd) {
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (!pD3D) {
		MessageBox(hWnd, "Direct3D 初始化失败", "错误", MB_OK);
		return false;
	}

	D3DPRESENT_PARAMETERS d3dpp = {};
	d3dpp.Windowed = TRUE; // 窗口化
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 交换效果
	d3dpp.hDeviceWindow = hWnd; // 设置窗口句柄
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 后备缓冲区格式

	// 创建设备
	if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pD3DDevice))) {
		MessageBox(hWnd, "创建 Direct3D 设备失败", "错误", MB_OK);
		return false;
	}

	return true;
}

// 清理 Direct3D 资源
void Cleanup() {
	if (pD3DDevice) {
		pD3DDevice->Release();
		pD3DDevice = nullptr;
	}
	if (pD3D) {
		pD3D->Release();
		pD3D = nullptr;
	}
}

// 绘制带有外框颜色的透明矩形
void Render() {
	// 清空背景
	pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
	pD3DDevice->BeginScene();

	// 设置外框颜色为红色
	D3DCOLOR borderColor = D3DCOLOR_ARGB(255, 255, 0, 0); // 红色外框

	// 设置矩形的坐标和尺寸
	RECT rect = { 100, 100, 400, 300 };

	// 绘制矩形的外框
	struct Vertex {
		float x, y, z, rhw;
		D3DCOLOR color;
	};

	Vertex vertices[] = {
		{ 100.0f, 100.0f, 0.0f, 1.0f, borderColor }, // 左上
		{ 400.0f, 100.0f, 0.0f, 1.0f, borderColor }, // 右上
		{ 400.0f, 300.0f, 0.0f, 1.0f, borderColor }, // 右下
		{ 100.0f, 300.0f, 0.0f, 1.0f, borderColor }, // 左下
		{ 100.0f, 100.0f, 0.0f, 1.0f, borderColor }  // 返回左上,闭合矩形
	};

	// 画外框
	pD3DDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
	pD3DDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, 4, vertices, sizeof(Vertex));

	pD3DDevice->EndScene();
	pD3DDevice->Present(NULL, NULL, NULL, NULL);
}

// Windows 窗口过程函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	switch (message) {
	case WM_DESTROY:
		Cleanup();
		PostQuitMessage(0);
		return 0;
	case WM_SIZE:
		// 处理窗口大小改变时的设备重置
		if (pD3DDevice) {
			D3DPRESENT_PARAMETERS d3dpp = {};
			d3dpp.Windowed = TRUE;
			d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
			d3dpp.hDeviceWindow = hWnd;
			pD3DDevice->Reset(&d3dpp);
		}
		return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
}

// WinMain 入口函数
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, ("D3D9Demo"), NULL };
	RegisterClassEx(&wc);
	HWND hWnd = CreateWindow(wc.lpszClassName, ("透明矩形框"), WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, NULL, NULL, wc.hInstance, NULL);

	if (!InitD3D(hWnd)) {
		Cleanup();
		return 0;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	// 游戏主循环
	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while (msg.message != WM_QUIT) {
		if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else {
			Render();
		}
	}

	Cleanup();
	return 0;
}

后续流程

步骤 操作
1 初始化控制台信息
2 查找游戏窗口
3 创建透明覆盖窗口
4 初始化D3D9设备
5 启动数据采集线程
6 启动窗口位置跟踪线程
7 进入主消息循环
8 是否收到退出消息?
9 如果是,进行资源清理
10 如果否,返回第7步继续执行

透视程序编写

1. 初始化 D3D

bool InitD3D(HWND hWnd) {
    // 1. 创建D3D9接口对象
    g_pD3D = Direct3DCreate9(D3D_SDK_VERSION); 
    
    // 2. 配置呈现参数
    ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
    g_d3dpp.Windowed = TRUE;                  // 窗口模式
    g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;// 交换效果
    g_d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;// 带Alpha通道的32位格式
    g_d3dpp.EnableAutoDepthStencil = TRUE;     // 启用深度模板
    g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;// 16位深度缓冲
    
    // 3. 创建设备对象
    HRESULT result = g_pD3D->CreateDevice(
        D3DADAPTER_DEFAULT,                    // 默认显卡
        D3DDEVTYPE_HAL,                        // 硬件抽象层
        hWnd,                                  // 关联窗口
        D3DCREATE_HARDWARE_VERTEXPROCESSING,   // 硬件顶点处理
        &g_d3dpp,                              // 呈现参数
        &g_pd3dDevice                          // 输出设备指针
    );
    
    // 4. 设置混合状态(透明关键)
    g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); // 启用Alpha混合
    g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); // 源混合因子
    g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);// 目标混合因子
    
    // 5. 创建绘图工具
    D3DXCreateLine(g_pd3dDevice, &g_pLine);     // 线条绘制对象
    D3DXCreateFont(...);                       // 字体对象(省略参数)
    
    return SUCCEEDED(result);
}

2.创建透明窗口

// 窗口过程
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	switch (msg) {
	case WM_DESTROY:
		g_bRunning = false;
		PostQuitMessage(0);
		return 0;
	case WM_ERASEBKGND:
		return 1;
	case WM_PAINT:
		Render();
		return 0;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
}

HWND CreateOverlayWindow() {
    // 窗口类配置
    WNDCLASSEX wc = {
        .cbSize = sizeof(WNDCLASSEX),
        .style = CS_HREDRAW | CS_VREDRAW,      // 窗口重绘模式
        .lpfnWndProc = WndProc,                // 消息处理回调
        .hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH), // 黑色背景画刷
        .lpszClassName = "D3DOverlayClass"     // 唯一类名
    };
    
    // 注册窗口类
    RegisterClassEx(&wc);
    
    // 获取游戏窗口位置
    RECT targetRect;
    GetWindowRect(g_hTargetWnd, &targetRect);
    
    // 创建窗口关键参数:
    // WS_EX_LAYERED - 分层窗口(支持透明)
    // WS_EX_TRANSPARENT - 穿透鼠标事件
    // WS_EX_TOPMOST - 始终置顶
    HWND hWnd = CreateWindowEx(
        WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
        "D3DOverlayClass",
        "Game Overlay",
        WS_POPUP,                              // 无边框窗口
        targetRect.left,                       // 与游戏窗口对齐
        targetRect.top,
        targetRect.right - targetRect.left,    // 同游戏窗口宽度
        targetRect.bottom - targetRect.top,    // 同游戏窗口高度
        nullptr, nullptr, nullptr, nullptr
    );
    
    // 设置透明色(黑色部分透明)
    SetLayeredWindowAttributes(hWnd, RGB(0,0,0), 0, LWA_COLORKEY);
    return hWnd;
}

3. 数据采集线程工作流程

void DataThread() {
    // 1. 获取游戏进程信息
    DWORD pid = GetProcessID("hl.exe");
    DWORD moduleBase = GetModuleBase(pid, "amxmodx_mm.dll");
    
    // 2. 打开进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    
    while(running) {
        // 3. 读取本地玩家数据
        ReadProcessMemory(hProcess, (LPCVOID)characterBase, &localPlayerAddr, 4, 0);
        ReadProcessMemory(hProcess, positionAddr, &myX, 4, 0);
        
        // 4. 遍历所有实体
        for(DWORD i = 1; i < playerCount; ++i) {
            // 5. 读取敌人数据
            ReadProcessMemory(hProcess, enemyAddr + HEALTH_OFFSET, &health, 4, 0);
            
            // 6. 执行核心算法计算屏幕坐标
            float dx = enemyX - myX;
            // ...(象限判断、角度计算等)...
            
            // 7. 存储有效敌人信息
            newEnemies.push_back({screenX, screenY, ...});
        }
        
        // 8. 线程安全更新数据
        std::lock_guard<std::mutex> lock(g_dataMutex);
        g_enemies = std::move(newEnemies);
    }
}

4. 渲染管线工作流程

void Render() {
    // 1. 检查设备状态
    if(g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICELOST) {
        Sleep(100); // 设备丢失时等待恢复
        return;
    }
    
    // 2. 清空后台缓冲(使用完全透明色)
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 1.0f, 0);
    
    if(SUCCEEDED(g_pd3dDevice->BeginScene())) {
        // 3. 加锁访问共享数据
        std::lock_guard<std::mutex> lock(g_dataMutex);
        
        // 4. 遍历所有敌人进行绘制
        for(const auto& enemy : g_enemies) {
			if (enemy.inView) {

				// 绘制方框
				D3DDrawBorderBox(
					enemy.screenX - 20.0f, 
					enemy.screenY, 
					enemy.boxWidth, 
					enemy.boxHeight, 
					2, 
					D3DCOLOR_XRGB(0, 206, 209));

				// 绘制指示线
				D3DDrawLine(
					512.0f,          // 开始屏幕X坐标
					0.0f,            // 开始屏幕Y坐标
					enemy.screenX + enemy.boxWidth / 2 - 20.f,   // endX
					enemy.screenY, // endY (可调整垂直偏移)
					2.0f,            // width
					D3DCOLOR_XRGB(0, 206, 209)
				);
			}
        }
        
        // 5. 结束场景提交绘制
        g_pd3dDevice->EndScene();
    }
    
    // 6. 呈现到屏幕
    g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

5.辅助绘制:画框、画线、写字

//画框
void D3DDrawBorderBox(float x, float y, float w, float h, float thickness, D3DCOLOR color)
{
	// 顶部横线
	D3DRECT rect = { (LONG)x, (LONG)y, (LONG)(x + w), (LONG)(y + thickness) };
	g_pd3dDevice->Clear(1, &rect, D3DCLEAR_TARGET, color, 0, 0);

	// 左侧竖线
	rect = { (LONG)x, (LONG)y, (LONG)(x + thickness), (LONG)(y + h) };
	g_pd3dDevice->Clear(1, &rect, D3DCLEAR_TARGET, color, 0, 0);

	// 右侧竖线
	rect = { (LONG)(x + w - thickness), (LONG)y, (LONG)(x + w), (LONG)(y + h) };
	g_pd3dDevice->Clear(1, &rect, D3DCLEAR_TARGET, color, 0, 0);

	// 底部横线
	rect = { (LONG)x, (LONG)(y + h - thickness), (LONG)(x + w), (LONG)(y + h) };
	g_pd3dDevice->Clear(1, &rect, D3DCLEAR_TARGET, color, 0, 0);
}

//画线
void D3DDrawLine(float x1, float y1, float x2, float y2, float width, D3DCOLOR color)
{
	if (!g_pLine) return;

	D3DXVECTOR2 points[] = {
		D3DXVECTOR2(x1, y1),
		D3DXVECTOR2(x2, y2)
	};

	g_pLine->SetWidth(width);
	g_pLine->Draw(points, 2, color);
}

//画字
void D3DDrawString(float x, float y, D3DCOLOR color, const char* text)
{
	RECT rect = {
		static_cast<LONG>(x),
		static_cast<LONG>(y),
		static_cast<LONG>(x + 100),
		static_cast<LONG>(y + 20)
	};
	g_pFont->DrawTextA(NULL, text, -1, &rect, DT_LEFT | DT_NOCLIP, color);
}

6.取进程 ID 和模块句柄函数封装

//获取进程ID
DWORD GetProcessID(const char* processName) {
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	PROCESSENTRY32 entry = { sizeof(PROCESSENTRY32) };

	if (Process32First(snapshot, &entry)) {
		do {
			if (_stricmp(entry.szExeFile, processName) == 0) {
				CloseHandle(snapshot);
				return entry.th32ProcessID;
			}
		} while (Process32Next(snapshot, &entry));
	}

	CloseHandle(snapshot);
	return 0;
}

//获取模块句柄
DWORD GetModuleBase(DWORD pid, const char* moduleName) {
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
	MODULEENTRY32 entry = { sizeof(MODULEENTRY32) };

	if (Module32First(snapshot, &entry)) {
		do {
			if (_stricmp(entry.szModule, moduleName) == 0) {
				CloseHandle(snapshot);
				return (DWORD)entry.modBaseAddr;
			}
		} while (Module32Next(snapshot, &entry));
	}

	CloseHandle(snapshot);
	return 0;
}

7.透明窗口跟随游戏

HWND gameHwnd = nullptr;  // 游戏窗口句柄

// 更新窗口位置
void UpdateOverlayPosition() {
	RECT gameRect;
	while (true) {
		if (gameHwnd && GetWindowRect(gameHwnd, &gameRect)) {
			// 移动透明窗口
			SetWindowPos(g_hOverlayWnd, nullptr, gameRect.left, gameRect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
		}
		Sleep(10); // 适当降低CPU占用
	}
}

// 在创建透明窗口后调用
void StartOverlay(HWND game) {
	gameHwnd = game;
	std::thread(UpdateOverlayPosition).detach(); // 启动线程
}

8.入口函数和提示提醒

void PrintWelcomeMessage() {
	SetConsoleTitleA("《终极游戏辅助》 v1.0   微信i-xiaodi  B站:小迪xiaodi老师  学技术网:www.52xuejishu.com");


	// 获取当前时间
	std::time_t now = std::time(nullptr);
	std::tm* localTime = std::localtime(&now);

	// 打印欢迎信息
	std::cout << "**********************************************************\n";
	std::cout << "*                                                        *\n";
	std::cout << "*           欢迎使用《终极游戏辅助》 v1.0               *\n";
	std::cout << "*                                                        *\n";
	std::cout << "**********************************************************\n";
	std::cout << "\n";
	std::cout << "当前时间:"
		<< (1900 + localTime->tm_year) << "年"
		<< (1 + localTime->tm_mon) << "月"
		<< localTime->tm_mday << "日 "
		<< localTime->tm_hour << ":"
		<< localTime->tm_min << ":"
		<< localTime->tm_sec << "\n";
	std::cout << "\n";
	std::cout << "本辅助仅供娱乐使用,严禁用于非法用途。\n";
	std::cout << "功能简介:\n";
	std::cout << "1. 方框透视\n";
	std::cout << "2. 显示敌人位置\n";
	std::cout << "\n";
	std::cout << "祝您游戏愉快,玩的开心!\n";
	std::cout << "\n";
}


int main() {

    //打印辅助提醒信息
	PrintWelcomeMessage();

	// 查找目标窗口
	g_hTargetWnd = FindWindow("Valve001", "Counter-Strike");
	if (!g_hTargetWnd) {
		return 1;
	}

	// 创建覆盖窗口
	g_hOverlayWnd = CreateOverlayWindow();
	if (!g_hOverlayWnd || !InitD3D(g_hOverlayWnd)) {
		return 1;
	}

	ShowWindow(g_hOverlayWnd, SW_SHOW);

	// 启动数据线程
	std::thread dataThread(DataThread);

	// 检测窗口变动
	StartOverlay(g_hTargetWnd);

	// 主消息循环
	MSG msg;
	while (g_bRunning) {
		if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else {
			// 触发持续渲染
			InvalidateRect(g_hOverlayWnd, nullptr, FALSE);
			UpdateWindow(g_hOverlayWnd);
			Sleep(1);
		}
	}

	// 清理资源
	dataThread.join();
	if (g_pLine) g_pLine->Release();
	if (g_pFont) g_pFont->Release();
	if (g_pd3dDevice) g_pd3dDevice->Release();
	if (g_pD3D) g_pD3D->Release();

	return 0;
}

9.其他的一些声明和定义

#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <tlhelp32.h>
#include <vector>
#include <mutex>
#include <cmath>
#include <string>
#include <iostream>
#include <string>
#include <ctime>

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dwmapi.lib")

// 常量定义
constexpr DWORD PLAYER_BASE_OFFSET = 0x97030; //玩家基址模块偏移
constexpr DWORD PLAYER_COUNT_OFFSET = 0x96184;//房间人数偏移
constexpr DWORD ENTITY_LIST_OFFSET = 0x230;//人物遍历差值(偏移)
constexpr DWORD TEAM_OFFSET = 0x134;//阵营偏移
constexpr DWORD HEALTH_OFFSET = 0x1E0;//血量偏移
constexpr DWORD POSITION_OFFSET = 0x88;//坐标偏移
constexpr DWORD VIEW_ANGLE_X_OFFSET = 0x19E10C8;//鼠标X
constexpr DWORD VIEW_ANGLE_Y_OFFSET = 0x19E10C4;//鼠标Y

// 玩家信息
struct EnemyInfo {
	float screenX;
	float screenY;
	float boxWidth;
	float boxHeight;
	bool inView;
};

LPDIRECT3D9              g_pD3D = nullptr;
LPDIRECT3DDEVICE9        g_pd3dDevice = nullptr;
D3DPRESENT_PARAMETERS    g_d3dpp = {};
LPD3DXFONT               g_pFont = NULL;
ID3DXLine* g_pLine = nullptr;
HWND                     g_hTargetWnd = nullptr;
HWND                     g_hOverlayWnd = nullptr;
std::vector<EnemyInfo>   g_enemies;
std::mutex               g_dataMutex;
bool                     g_bRunning = true;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool InitD3D(HWND);
HWND CreateOverlayWindow();
void DataThread();
void Render();
DWORD GetProcessID(const char*);
DWORD GetModuleBase(DWORD, const char*);

 

结语

至此,我们就完成了一款FPS游戏的D3D方框透视

是否还有其他好玩的东西?

当然是有的,比如添加绘制的菜单,绘制血量等

菜单还可以使用第三方库比如ImGui

有很多东西等着大家去拓展,以后有时间我们再更新~

请登录后发表评论

    没有回复内容