【C++】从零开始的CS:GO逆向分析3——写出一个透视

news/2024/5/20 14:16:28/文章来源:https://www.cnblogs.com/water-wells/p/16782843.html

【C++】从零开始的CS:GO逆向分析3——写出一个透视

 

本篇内容包括:

  1. 透视实现的方法介绍

  2. 通过进程名获取进程id和进程句柄

  3. 通过进程id获取进程中的模块信息(模块大小,模块地址,模块句柄)

  4. 读取游戏内存(人物ViewMatrix,敌人坐标,敌人生命值,敌人阵营)

  5. 三维坐标转二维坐标(游戏内人物坐标转换成屏幕上的坐标)

  6. glfw+imgui 在屏幕上的绘制直线

请先依据前两篇,对偏移、基址有基本了解,并且配置好了glfw+imgui的环境,在上篇创建好的工程中创建CPP文件和同名.h文件

 实现效果:

 


透视实现的方法介绍

  一般有两种方式,一种是外挂,一种是内挂,外挂是在创建一个透明窗口,在透明窗口上画线,让鼠标事件透过窗口,透明窗口覆盖在游戏窗口上。内挂是通过DLL注入,HOOK游戏中的绘制函数,在游戏绘制人物的时候绘制自己的线。还剩一种比较少用,但也可以实现,找到人物模型ID,在渲染到人物模型的时候关掉渲染缓冲(应该是叫这个?),使人物模型在墙模型前面渲染,导致可以直接看到人物。本篇文章采用的是外挂的形式,根据上篇文章已经可以创建出一个覆盖在屏幕上的透明窗口。


先把需要用到的全局变量声明一下(GetImformation.cpp)

变量名起的挺明白的,就不写注释了

DWORD g_process_id = NULL;
HANDLE g_process_handle = NULL;
UINT_PTR g_local_player = NULL;
UINT_PTR g_player_list_address = NULL;
UINT_PTR g_matrix_address = NULL;
UINT_PTR g_angle_address = NULL;
HWND g_game_hwnd = NULL;
module_information engine_module;
module_information client_module;
module_information server_module;
float g_client_width;
float g_client_height;

把需要用到的偏移也声明一下

#define dwViewMatrix 0x4DCF254
#define dwLocalPlayer 0xDC14CC
#define dwClientState 0x58CFDC
#define dwEntityList 0x4DDD93C
#define dwClientState_ViewAngles 0x4D90#define m_vecOrigin 0x138
#define m_bDormant 0xED
#define m_lifeState 0x25F
#define m_iHealth 0x100
#define m_iTeamNum 0xF4

再把需要使用到的函数先声明和实现(GetImformation.cpp),实现思路写在后面

获取屏幕大小,保存到全局变量

void GetWindowSize()
{HDC hdc = GetDC(nullptr);g_client_width = GetDeviceCaps(hdc, DESKTOPHORZRES);g_client_height = GetDeviceCaps(hdc, DESKTOPVERTRES);ReleaseDC(nullptr, hdc);
}

 


 

先写一个错误获取函数,以方便获取出错的信息

void error(const char*text)
{MessageBoxA(nullptr, text, nullptr, MB_OK);exit(-1);
}
bool is_error()
{return GetLastError() != 0;
}

 


 

通过进程名获取进程id和进程句柄

使用CreateToolhelp32Snapshot函数,创建进程快照,遍历系统快照中的进程名,遍历到process_name,则返回该进程的进程ID

DWORD get_process_id(const char*process_name)
{HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (is_error()) error("CreateToolhelp32Snapshot失败");PROCESSENTRY32 process_info;ZeroMemory(&process_info, sizeof(process_info));process_info.dwSize = sizeof(process_info);char target[1024];ZeroMemory(target, 1024);strncpy_s(target, process_name, strlen(process_name));_strupr(target);bool state = Process32First(snap, &process_info);while (state){if (strncmp(_strupr(process_info.szExeFile), target, strlen(target)) == 0){return process_info.th32ProcessID;}state = Process32Next(snap, &process_info);}CloseHandle(snap);return 0;
}

通过进程ID获取进程句柄

HANDLE get_process_handle(DWORD process_id)
{HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id);if (is_error())error("get_process_handle失败");
return process_handle;
}

 


 

通过进程id获取进程中的模块信息(模块大小,模块地址,模块句柄)

可以发现偏移都是由 client.dll+xxxxx 此种形式构成,所以需要获取模块的地址

先创建一个模块结构体,需要获取模块的模块大小,模块地址,模块句柄

class module_information
{
public:HANDLE module_handle;char module_name[1024];char *module_data;UINT_PTR module_address;int module_size;void alloc(int size){module_size = size;module_data = (char *)VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);if (is_error())error("申请内存失败");}void release(){if (module_data)VirtualFree(module_data, 0, MEM_RELEASE);module_data = nullptr;}
};

传入进程ID和需要获取的模块名,CreateToolhelp32Snapshot创建模块快照,遍历快照,比对模块名,获取模块信息

void get_moduel_info(DWORD process_id, const char *name, OUT module_information&info)
{HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process_id);if (is_error())error("创建快照错误");MODULEENTRY32 module_info;ZeroMemory(&module_info, sizeof(module_info));module_info.dwSize = sizeof(module_info);char target[1024];ZeroMemory(target, 1024);strncpy(target, name, strlen(name));_strupr(target);bool status = Module32First(snap, &module_info);while (status){if (strncmp(_strupr(module_info.szModule), target, sizeof(target)) == 0){info.module_address = (UINT_PTR)module_info.modBaseAddr;info.module_handle = module_info.hModule;info.alloc(module_info.modBaseSize);
            DWORD size = read_memory(g_process_handle, info.module_address, info.module_data, info.module_size);//TODO
            CloseHandle(snap);return;}status = Module32Next(snap, &module_info);}error("未找到模块");return;
}

 


 

读取游戏内存函数

例如之前得到 上下角度 = [[engine.dll+58CFDC]+00004D90]则可以 

ReadProcessMemory(g_process_handle, (LPVOID)(engine.dll+58CFDC), recv, size, &readsize);

ReadProcessMemory(g_process_handle, (LPVOID)recv, recv, size, &readsize);

函数的使用方法:ReadProcessMemory(句柄,地址,读到哪里,读多少,具体读了多少);

则可以读到上下角度

通过ReadProcessMemory函数读取内存,对这个函数进行打包,方便使用(好吧,我承认这个打包的很烂,几乎没有方便使用)

DWORD read_memory(HANDLE process, DWORD address, void *recv, int size)
{DWORD readsize;ReadProcessMemory(process, (LPVOID)address, recv, size, &readsize);return readsize;if (is_error())error("读取内存失败");
}

重写了一个我觉得比较好用的,各位可以酌情对其进行改写

template<class T>
T ReadMem(HANDLE ProcessHandle, UINT_PTR Address, int size)
{T Reader;ReadProcessMemory(ProcessHandle, (LPVOID)Address, &Reader, size, NULL);return Reader;
}

 


三维坐标转二维坐标

创建两个结构体来储存二维坐标,一个用来储存三维坐标

struct Vec2
{
public:float x, y; }; struct Vec3 { public:float x, y, z; };

传入一个三维坐标和视角矩阵,算出人物在屏幕上的坐标 VecScreen

bool WorldToScreen(const Vec3& VecOrgin, Vec2& VecScreen, float* Matrix)
{VecScreen.x = VecOrgin.x *Matrix[0] + VecOrgin.y*Matrix[1] + VecOrgin.z*Matrix[2] + Matrix[3];VecScreen.y = VecOrgin.x *Matrix[4] + VecOrgin.y*Matrix[5] + VecOrgin.z*Matrix[6] + Matrix[7];float w = VecOrgin.x*Matrix[12] + VecOrgin.y*Matrix[13] + VecOrgin.z*Matrix[14] + Matrix[15];if (w < 0.01f){return false;}Vec2 NDC;NDC.x = VecScreen.x / w;NDC.y = VecScreen.y / w;VecScreen.x = (g_client_width / 2 * NDC.x) + (NDC.x + g_client_width / 2);VecScreen.y = (g_client_height / 2 * NDC.y) + (NDC.y + g_client_height / 2);ConvertToRange(VecScreen);return true;
}
void ConvertToRange(Vec2 &Point)
{Point.x /= g_client_width;Point.x *= 2.0f;Point.x -= 1.0f;Point.y /= g_client_height;Point.y *= 2.0f;Point.y -= 1.0f;
}

 GLFW画线

使用glVertex2f函数,第一个glVertex2f是开始的位置,第二个glVertex2f是结束的位置

void DrawLine(Vec2& start, Vec2& end)
{glLineWidth(1.2);glBegin(GL_LINES);glColor4f(255, 255, 255, 100);glVertex2f(start.x, start.y);glVertex2f(end.x, end.y);glEnd();
}

 

写一个init函数,实现初始化

void init_address(const char*process_name)
{std::cout << "请先启动游戏"<< std::endl;DWORD process_id = get_process_id(process_name);HANDLE process_handle = get_process_handle(process_id);g_process_id = process_id; //将pid保存到全局变量g_process_handle = process_handle;//将process_handle保存到全局变量//获取模块信息get_moduel_info(process_id, "engine.dll", engine_module);get_moduel_info(process_id, "client.dll", client_module);get_moduel_info(process_id, "server.dll", server_module);UINT_PTR temp_address;float Matrix[16];UINT_PTR matrix_address = client_module.module_address + dwViewMatrix; //获取视角矩阵地址g_matrix_address = matrix_address; //将视角矩阵地址保存到全局变量//获取人物视角地址ReadProcessMemory(g_process_handle, (LPVOID)(engine_module.module_address + 0x58CFDC), &temp_address, 4, NULL);//[engine.dll + 58CFDC]+00004D90g_angle_address = temp_address + dwClientState_ViewAngles;//获取本地人物地址 [client.dll+0xDC04CC]+100 = 生命值ReadProcessMemory(g_process_handle, (LPVOID)(client_module.module_address + dwLocalPlayer), &temp_address, 4, NULL);g_local_player = temp_address; //[g_local_player+100] = 生命值//获得ENtitylist地址  [client.dll+0x4DDC90C + i *0x10]+100 = 敌人生命值g_player_list_address = client_module.module_address + dwEntityList;
}

 


 先说一下整体的思路:

 

 通过进程名(csgo.exe)获取进程ID

  ↓

 通过进程ID获取进程句柄、client.dll模块的信息

  ↓

 通过进程句柄读取人物视角矩阵地址、本地人物对象地址、敌人对象地址 并保存到全局变量(初始化完成)

  ↓

 获得屏幕大小储存在全局变量、创建透明窗口

  ↓

 循环遍历敌人对象,通过地址读取到人物的视角矩阵、敌人的位置

  ↓

 在循环中将敌人的位置结合矩阵,转换成2D坐标

  ↓

 再循环中在透明窗口上把算出来的坐标画出来

 


 

再写一段伪代码出来帮助理解,代码贴在后面

int main
{获取视角矩阵地址、获取本地人物地址、获取敌人对象地址获取屏幕分辨率根据屏幕分辨率创建窗口while1)消息循环{
    清除画的线获得视角矩阵,因为会变,所以需要不停的获取
for(int i=0;i<64;i++)因为游戏人数最大为64{获得自己的阵营获取当前敌人对象根据对象获取人物血量、阵营、生存状态、敌人是否有效如果敌人血量<=0 或者 敌人阵营=自己阵营 或者 无效 或者 敌人对象为空 或者 敌人生存状态
        则遍历下一个对象获得敌人的位置将敌人的坐标转换为2D坐标画线}} }

 

 

代码部分

GetImformation.h

#pragma once
struct Vec2
{public:float x, y;};
struct Vec3
{
public:float x, y, z;};
bool is_error();
void error(const char*text);
class module_information
{
public:HANDLE module_handle;char module_name[1024];char *module_data;UINT_PTR module_address;int module_size;void alloc(int size){module_size = size;module_data = (char *)VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);if (is_error())error("申请内存失败");}void release(){if (module_data)VirtualFree(module_data, 0, MEM_RELEASE);module_data = nullptr;}
};
void init_address(const char*process_name);
DWORD get_process_id(const char*process_name);HANDLE get_process_handle(DWORD process_id);void ConvertToRange(Vec2 &Point);
bool WorldToScreen(const Vec3& VecOrgin, Vec2& VecScreen, float* Matrix);
void get_moduel_info(DWORD process_id, const char *name, OUT module_information&info);
DWORD read_memory(HANDLE process, DWORD address, void *recv, int size);template<class T>
T ReadMem(HANDLE ProcessHandle, UINT_PTR Address, int size)
{T Reader;ReadProcessMemory(ProcessHandle, (LPVOID)Address, &Reader, size, NULL);return Reader;
}

 

GetImformation.cpp

#include<Windows.h>
#include<TlHelp32.h>
#include"GetIMformation.h"DWORD g_process_id = NULL;
HANDLE g_process_handle = NULL;
UINT_PTR g_local_player = NULL;
UINT_PTR g_player_list_address = NULL;
UINT_PTR g_matrix_address = NULL;
UINT_PTR g_angle_address = NULL;
HWND g_game_hwnd = NULL;
module_information engine_module;
module_information client_module;
module_information server_module;
float g_client_width;
float g_client_height;#define dwViewMatrix 0x4DCF254
#define dwLocalPlayer 0xDC14CC
#define dwClientState 0x58CFDC
#define dwEntityList 0x4DDD93C
#define dwClientState_ViewAngles 0x4D90#define m_vecOrigin 0x138
#define m_bDormant 0xED
#define m_lifeState 0x25F
#define m_iHealth 0x100
#define m_iTeamNum 0xF4
//获取模块信息
void get_moduel_info(DWORD process_id, const char *name, OUT module_information&info)
{HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process_id);if (is_error())error("创建快照错误");MODULEENTRY32 module_info;ZeroMemory(&module_info, sizeof(module_info));module_info.dwSize = sizeof(module_info);char target[1024];ZeroMemory(target, 1024);strncpy(target, name, strlen(name));_strupr(target);bool status = Module32First(snap, &module_info);while (status){if (strncmp(_strupr(module_info.szModule), target, sizeof(target)) == 0){info.module_address = (UINT_PTR)module_info.modBaseAddr;info.module_handle = module_info.hModule;info.alloc(module_info.modBaseSize);//DWORD size = read_memory(g_process_handle, info.module_address);//TODODWORD size = read_memory(g_process_handle, info.module_address, info.module_data, info.module_size);//TODO
            CloseHandle(snap);return;}status = Module32Next(snap, &module_info);}error("未找到模块");return;
}
void error(const char*text)
{MessageBoxA(nullptr, text, nullptr, MB_OK);exit(-1);
}
bool is_error()
{return GetLastError() != 0;
}
DWORD read_memory(HANDLE process, DWORD address, void *recv, int size)
{DWORD readsize;ReadProcessMemory(process, (LPVOID)address, recv, size, &readsize);return readsize;if (is_error())error("读取内存失败");
}HANDLE get_process_handle(DWORD process_id)
{HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id);if (is_error())error("get_process_handle失败");std::cout << "进程句柄为:" << std::hex << process_handle << std::endl;return process_handle;
}
DWORD get_process_id(const char*process_name)
{HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (is_error()) error("CreateToolhelp32Snapshot失败");PROCESSENTRY32 process_info;ZeroMemory(&process_info, sizeof(process_info));process_info.dwSize = sizeof(process_info);char target[1024];ZeroMemory(target, 1024);strncpy_s(target, process_name, strlen(process_name));_strupr(target);bool state = Process32First(snap, &process_info);while (state){if (strncmp(_strupr(process_info.szExeFile), target, strlen(target)) == 0){CloseHandle(snap);return process_info.th32ProcessID;}state = Process32Next(snap, &process_info);}CloseHandle(snap);MessageBoxA(NULL, "查找进程id失败", "提示", MB_OK);return 0;
}
void GetWindowSize()
{HDC hdc = GetDC(nullptr);g_client_width = GetDeviceCaps(hdc, DESKTOPHORZRES);g_client_height = GetDeviceCaps(hdc, DESKTOPVERTRES);ReleaseDC(nullptr, hdc);
}void init_address(const char*process_name)
{std::cout << "请先启动游戏"<< std::endl;DWORD process_id = get_process_id(process_name);HANDLE process_handle = get_process_handle(process_id);g_process_id = process_id;//获取模块信息g_process_handle = process_handle;get_moduel_info(process_id, "engine.dll", engine_module);get_moduel_info(process_id, "client.dll", client_module);get_moduel_info(process_id, "server.dll", server_module);//TODO 要写一个特征码寻址,获取视角矩阵信息
    UINT_PTR temp_address;float Matrix[16];UINT_PTR matrix_address = client_module.module_address + dwViewMatrix;g_matrix_address = matrix_address;//获取 人物视角地址ReadProcessMemory(g_process_handle, (LPVOID)(engine_module.module_address + 0x58CFDC), &temp_address, 4, NULL);//[engine.dll + 58CFDC]+00004D90g_angle_address = temp_address + 0x00004D90;//获取本地人物地址 [client.dll+0xDC04CC]+100 = 生命值ReadProcessMemory(g_process_handle, (LPVOID)(client_module.module_address + dwLocalPlayer), &temp_address, 4, NULL);g_local_player = temp_address; //[g_local_player+100] = 生命值temp_address = 0;//获得ENtitylist地址  [client.dll+0x4DDC90C + i *0x10]+100 = 敌人生命值g_player_list_address = client_module.module_address + dwEntityList;
}bool WorldToScreen(const Vec3& VecOrgin, Vec2& VecScreen, float* Matrix)
{VecScreen.x = VecOrgin.x *Matrix[0] + VecOrgin.y*Matrix[1] + VecOrgin.z*Matrix[2] + Matrix[3];VecScreen.y = VecOrgin.x *Matrix[4] + VecOrgin.y*Matrix[5] + VecOrgin.z*Matrix[6] + Matrix[7];float w = VecOrgin.x*Matrix[12] + VecOrgin.y*Matrix[13] + VecOrgin.z*Matrix[14] + Matrix[15];if (w < 0.01f){return false;}Vec2 NDC;NDC.x = VecScreen.x / w;NDC.y = VecScreen.y / w;VecScreen.x = (g_client_width / 2 * NDC.x) + (NDC.x + g_client_width / 2);VecScreen.y = (g_client_height / 2 * NDC.y) + (NDC.y + g_client_height / 2);ConvertToRange(VecScreen);return true;
}
void ConvertToRange(Vec2 &Point)
{Point.x /= g_client_width;Point.x *= 2.0f;Point.x -= 1.0f;Point.y /= g_client_height;Point.y *= 2.0f;Point.y -= 1.0f;
}

 

main.cpp

#include <stdio.h>
#include<cstdlib>
#include<Windows.h>
#include<iostream>
#include<cmath>#include <GLFW/glfw3.h>
#include "imgui/imgui.h"
#include "imgui/imgui_impl_glfw.h"
#include "imgui/imgui_impl_opengl3.h"#include "GetIMformation/GetIMformation.h"//声明外部变量
extern DWORD g_process_id;
extern HANDLE g_process_handle;
extern UINT_PTR g_local_player;
extern UINT_PTR g_player_list_address;
extern UINT_PTR g_matrix_address;
extern UINT_PTR g_angle_address;
extern HWND g_game_hwnd;
extern module_information engine_module;
extern module_information client_module;
extern module_information server_module;
extern float g_client_width;
extern float g_client_height;void DrawLine(Vec2& start, Vec2& end)
{glLineWidth(1.2);glBegin(GL_LINES);glColor4f(255, 255, 255, 100);glVertex2f(start.x, start.y);glVertex2f(end.x, end.y);glEnd();
}
void ShowMenu(GLFWwindow* Window)
{glfwSetWindowAttrib(Window, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
}void HideMenu(GLFWwindow* Window)
{glfwSetWindowAttrib(Window, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
}static void glfw_error_callback(int error, const char* description)
{fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}void GetWindowSize()
{HDC hdc = GetDC(nullptr);g_client_width = GetDeviceCaps(hdc, DESKTOPHORZRES);g_client_height = GetDeviceCaps(hdc, DESKTOPVERTRES);ReleaseDC(nullptr, hdc);
}int main(int, char**)
{/////////////////////////功能性代码////////////////////////////////////////////////////////////////////////////////////////////
    GetWindowSize();init_address("csgo.exe");UINT_PTR temp_address;/////////////////////////功能性代码////////////////////////////////////////////////////////////////////////////////////////////// Setup window
    glfwSetErrorCallback(glfw_error_callback);if (!glfwInit())return 1;GLFWmonitor* monitor = glfwGetPrimaryMonitor();//###########################设置窗口###########################auto glsl_version = "#version 130";int Height = glfwGetVideoMode(monitor)->height;int Width = glfwGetVideoMode(monitor)->width;glfwWindowHint(GLFW_FLOATING, true);glfwWindowHint(GLFW_RESIZABLE, false);glfwWindowHint(GLFW_MAXIMIZED, true);glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, true);//###########################设置窗口###########################
GLFWwindow* window = glfwCreateWindow(Width, Height, "titile", nullptr, nullptr);if (window == nullptr)return 1;glfwSetWindowAttrib(window, GLFW_DECORATED, false); //设置没有标题栏
    ShowWindow(GetConsoleWindow(), SW_HIDE);glfwMakeContextCurrent(window);glfwSwapInterval(1);IMGUI_CHECKVERSION();ImGui::CreateContext();ImGuiIO& io = ImGui::GetIO();(void)io;ImGui::StyleColorsDark();ImGui_ImplGlfw_InitForOpenGL(window, true);ImGui_ImplOpenGL3_Init(glsl_version);bool bMenuVisible = true;bool Dormant;int EntityTeamNum;int lifestate;int blood;int iTeamNum;float temp_pos[3];float Matrix[16];Vec2 LineOrigin;Vec2 ScreenCoord;Vec3 EntityLocation;LineOrigin.x = 0.0f;LineOrigin.y = -1.0f;UINT_PTR Entity;while (!glfwWindowShouldClose(window)){glfwPollEvents();glClear(GL_COLOR_BUFFER_BIT);ImGui_ImplOpenGL3_NewFrame();ImGui_ImplGlfw_NewFrame();ImGui::NewFrame();if (GetAsyncKeyState(VK_F11) & 1){bMenuVisible = !bMenuVisible;if (bMenuVisible)ShowMenu(window);elseHideMenu(window);}//界面设计if (bMenuVisible){ImGui::Text("USE F11 TO Hiden/Show");ImGui::Text("");if (ImGui::Button("exit")) return 0;}ReadProcessMemory(g_process_handle, (LPVOID)(client_module.module_address + dwLocalPlayer),&g_local_player, 4, nullptr);if(g_local_player!=0){ScreenCoord.x = 0.0f;ScreenCoord.y = -1.0f;g_angle_address = ReadMem<UINT_PTR>(g_process_handle, (engine_module.module_address + dwClientState), 4)+ dwClientState_ViewAngles;ReadProcessMemory(g_process_handle, (LPCVOID)(client_module.module_address + dwViewMatrix), Matrix,sizeof(float) * 16, nullptr);for (short int i = 0; i < 64; ++i){ReadProcessMemory(g_process_handle, (LPVOID)(client_module.module_address + dwLocalPlayer),&g_local_player, 4, nullptr);ReadProcessMemory(g_process_handle, (LPCVOID)(g_local_player + m_iTeamNum), &iTeamNum, 4, nullptr);//获取敌人实体ReadProcessMemory(g_process_handle, (LPCVOID)(client_module.module_address + dwEntityList + i * 0x10),&Entity, sizeof(float), nullptr);ReadProcessMemory(g_process_handle, (LPVOID)(Entity + m_bDormant), &Dormant, sizeof(bool), nullptr);ReadProcessMemory(g_process_handle, (LPVOID)(Entity + m_lifeState), &lifestate, 4, nullptr);ReadProcessMemory(g_process_handle, (LPCVOID)(Entity + m_iTeamNum), &EntityTeamNum, 4, nullptr);ReadProcessMemory(g_process_handle, (LPCVOID)(Entity + m_iHealth), &blood, 4, nullptr);if ((Entity == NULL) || (Entity == g_local_player) || (EntityTeamNum == iTeamNum) || (blood <= 0) ||lifestate || Dormant)continue;ReadProcessMemory(g_process_handle, (LPVOID)(Entity + m_vecOrigin), &temp_pos, 12, nullptr);EntityLocation.x = temp_pos[0], EntityLocation.y = temp_pos[1], EntityLocation.z = temp_pos[2];if (!WorldToScreen(EntityLocation, ScreenCoord, Matrix))continue;if (true){DrawLine(LineOrigin, ScreenCoord);}}}// Rendering
        ImGui::Render();int display_w, display_h;glfwGetFramebufferSize(window, &display_w, &display_h);glViewport(0, 0, display_w, display_h);ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());glfwSwapBuffers(window);}// Cleanup
    ImGui_ImplOpenGL3_Shutdown();ImGui_ImplGlfw_Shutdown();ImGui::DestroyContext();glfwDestroyWindow(window);glfwTerminate();return 0;
}

至此一个简单的透视就写完了,本系列也完结力....

 

后记:

  感觉有些地方逻辑讲的不是很清晰,有问题可以在评论区里提

  里面写的偏移全都是写死的,等CSGO一更新就不能用了,解决这个问题的方法,就是写一个特征码查找,但不能保证所有人都是来学思路和方法的,对于直接copy代码的,起码偏移要自己找一下。

  方框、自瞄、防闪其实也写了,但感觉不是很适合在这里发,如果后面想发了,再写一个补充篇吧

  因为是从一堆功能中抽出一个小透,所以可能报错,少点什么东西,能自己补的自己补一下,不能的评论区说一下,我来补

  

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_589156.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java项目本地部署搭建实战SpringBoot高校宿舍管理系统源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套Java开发的SpringBoot高校宿舍管理系统源码。 技术架构 技术框架&#xff1a;SpringBoot2.0.0 Mybatis1.3.2 Mysql5.7 layui运行环境&#xff1a;jdk8 IntelliJ IDEA maven3 宝塔面板 …

触摸屏分类和触摸屏校准原理

一、触摸屏分类 常用触摸屏分两种 1、电阻触摸屏校正原理&#xff1a;导电ITO层及整个电路电阻值会随时间电压等轻微偏移&#xff0c;为了更精确与LCD显示屏上的功能图案相对应&#xff0c;重新校正计算标准位置。不校正可能会线性偏移&#xff0c;好的触摸屏一般无需校正&am…

【面经】360大数据开发面经

30 分钟&#xff0c;不做题。 欢迎点击此处关注公众号&#xff0c;每天分享大数据开发面经 介绍实习项目 会涉及平台开发吗 平时常用的语言 回答了 Java。 Python 用过吗 Java 实现一个单例要注意什么 懒汉式&#xff1a; public class Singleton {private static Sing…

钢铁行业经销商商城系统:完善钢材管控方案,轻松实现控价和防伪

钢铁工业是全球经济发展的核心&#xff0c;也是现代社会可持续发展的核心。根据数据显示&#xff0c;2020年中国钢材产量为13.25亿吨&#xff0c;同比增长9.96%;生铁产量为8.88亿吨&#xff0c;同比增长9.77%;粗钢产量为10.53亿吨&#xff0c;同比增长5.72%。 图片来源&#xf…

网络编程之TCP模型

1. TCP模型 2. socket 最早的socket和消息队列、共享内存、管道一致&#xff0c;只能实现一台主机多个进程间通信&#xff0c;后期加入了tcp/ip协议&#xff0c;使得支持不同主机的进程间通信 socket本质上是一个编程接口给&#xff08;API&#xff09;,是对TCP/IP协议的封装…

利用表面肌电信号对手部抓取动作分类的新型卷积网络模型

利用表面肌电信号对手部抓取动作分类的新型卷积网络模型 文章目录利用表面肌电信号对手部抓取动作分类的新型卷积网络模型一.相关研究二.材料和方法2.1 数据集2.2 数据预处理2.3 1D-1D-CNN三.实验结果分析四.相关研究对比参考文献一.相关研究 肌电信号号代表肌肉功能的特征&…

ReentrantLock可重入、可打断、锁超时实现原理

述 前面讲解了ReentrantLock加锁和解锁的原理实现&#xff0c;但是没有阐述它的可重入、可打断以及超时获取锁失败的原理&#xff0c;本文就重点讲解这三种情况。 可重入 可重入是指一个线程如果获取了锁&#xff0c;那么它就是锁的主人&#xff0c;那么它可以再次获取这把锁…

神经网络损失函数不下降,神经网络参数优化算法

1、matlab支持向量机预测数据怎么减小相对误差 采用网格搜索法。基于长短时记忆神经网络算法的支持向量机的预测方法&#xff0c;为了保证支持向量机预测结果的准确性减小相对误差&#xff0c;选用网格搜索法对支持向量机参数进行优化处理。为了减小在预测算法中&#xff0c;由…

如何快速制作一个自己心目中的可视化大屏?

从来没有接触过可视化的软件,也没有什么基础,我应该怎么开始学习可视化呢?遇到过不少朋友问:我从来没有接触过可视化的软件,也没有什么基础,我应该怎么开始学习可视化呢? 其实很简单,现在市面上有很多公司研发的可视化软件/编辑网站已经不再像过去一样要求使用者是专业…

linux下挂载新的磁盘

1、前提条件 虚拟机上已经新增了新的磁盘。 物理机上已经接好了新的硬盘。 2、挂载步骤 查看系统磁盘情况。使用以下命令&#xff1a;&#xff08;如果没出现新增磁盘&#xff0c;重启系统&#xff09; fdisk -l可以看到新增的磁盘/dev/sdb下还没有进行分区。 对新增的磁…

我终于读懂了设计模式的七大原则。。。

文章目录&#x1f4a5;&#x1f412;设计模式的目的&#x1f434;什么叫单一职责原则&#xff1f;&#x1f424;什么叫接口隔离原则&#xff1f;&#x1f42b;什么叫做依赖倒转原则&#xff1f;&#x1f411;什么是里氏替换原则&#xff1f;&#x1f418;什么叫开闭原则&#x…

拒绝项目经理沟通崩溃瞬间,驾驭项目复杂性

如何一句话终结和项目经理的聊天&#xff1f;这还需要凭实力&#xff1f;这不是信手拈来的事&#xff0c;分分钟让项目经理怒气值加满、停止沟通。来整两句&#xff1a;  紧急需要不停歇——深夜10点&#xff0c;客户&#xff1a;“这个新需求明天必须上。”  方案最后都是…

多测师肖sir_高级讲师_第2个月第27讲解jmeter性能硬件指标

jmeter性能硬件指标 一、采集硬件指标的工具nmon 1、基本介绍 nmon&#xff0c;帮助在一个屏幕上显示所有重要的性能优化信息&#xff0c;并动态地对其进行更新。 2、收集那些数据&#xff1a; nmon 工具可以为 AIX 和 Linux 性能专家提供监视和分析性能数据的功能&#xff0c…

枚举

目录枚举枚举的定义枚举的使用枚举的常用方法枚举的构造方法枚举的优缺点枚举与反射用反射能拿到枚举的实例对象吗&#xff1f;为什么枚举实现的单例模式是安全的&#xff1f;(面试问题)枚举 枚举的定义 枚举是在JDK1.5以后引入的。主要用途是&#xff1a;将一组常量组织起来…

TRC丨艾美捷TRC N-去羟乙基达沙替尼说明书

艾美捷TRC N-去羟乙基达沙替尼&#xff1a;达沙替尼的代谢产物。用于治疗癌症和免疫疾病。 艾美捷TRC N-去羟乙基达沙替尼化学性质&#xff1a; 目录号D290000 化学名称N-去羟乙基达沙替尼 同义词N-(2-氯-6-甲基苯基)-2-[[2-甲基-6-(1-哌嗪基)-4-嘧啶基]氨基]-5-噻唑甲酰胺&…

【漏洞复现-骑士cms-代码执行】vulfocus/骑士cms_cve_2020_35339

目录 一、靶场环境 1.1、平台&#xff1a; 1.2、知识: 1.3、描述&#xff1a; 二、漏洞验证 2.1、分析 2.4、解题&#xff1a; 一、靶场环境 1.1、平台&#xff1a; Vulfocus 漏洞威胁分析平台 123.58.224.8:57171 123.58.224.8:36168 ​ 123.58.224.8:36168 ​ 1.2、知…

多线程——synchronized详解

多线程——synchronized详解 “当多个线程同时访问一个对象时&#xff0c;如果不用考虑这些线程在运行时环境下 的调度和交替执行&#xff0c;也不需要进行额外的同步&#xff0c;或者在调用方进行任何其他的协调操作&#xff0c;调用这个对象的行为都可以获得正确的结果&…

2023年中德(CSC-DAAD)博士后奖学金项目开始申报

10月9日&#xff0c;国家留学基金委&#xff08;CSC&#xff09;发布了《2023年中德&#xff08;CSC-DAAD&#xff09;博士后奖学金项目遴选工作启动》的通知。该项目提供50个博士后奖学金名额&#xff0c;申请受理时间为2022年11月1-30日。知识人网小编将CSC的申报指南全文转载…

osgEarth 三维坐标系和地理坐标系

目录 三维坐标系 地理坐标系 投影坐标系 坐标转换 三维坐标系 三维坐标系以地球球心为原点&#xff0c;三维世界坐标系 x轴正方向由地心指向本初子午线与赤道的交点&#xff0c;y轴正方向由地心指向东经 90 与赤道交点&#xff0c;z轴正方向由地心指向正北。 地理坐标系 地理…

如何在AFO里将一个特性的key和text显示为两列,且显示列名

把一个特性按key 和 text来展示成两列的话&#xff0c;第二列就没有列名了。 本篇是个讨论篇&#xff0c;没有完全解决方案&#xff0c;希望有知道的小伙伴一起讨论下。 如果我给它convert to formula是可以看到了的。但是这样就丢失了所有的下钻功能。 而且不能随query保存啊…