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

【C++】从零开始的CS:GO逆向分析3——写出一个透视本篇内容包括:
1. 透视实现的方法介绍
2. 通过进程名获取进程id和进程句柄
3. 通过进程id获取进程中的模块信息(模块大小 , 模块地址 , 模块句柄)
4. 读取游戏内存(人物ViewMatrix , 敌人坐标,敌人生命值,敌人阵营)
5. 三维坐标转二维坐标(游戏内人物坐标转换成屏幕上的坐标)
6. glfw+imgui 在屏幕上的绘制直线
请先依据前两篇,对偏移、基址有基本了解 , 并且配置好了glfw+imgui的环境,在上篇创建好的工程中创建CPP文件和同名.h文件

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

文章插图
实现效果:
【C++】从零开始的CS:GO逆向分析3——写出一个透视

文章插图
透视实现的方法介绍一般有两种方式,一种是外挂,一种是内挂,外挂是在创建一个透明窗口,在透明窗口上画线,让鼠标事件透过窗口,透明窗口覆盖在游戏窗口上 。内挂是通过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),实现思路写在后面获取屏幕大?。4娴饺直淞?/h2>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获取进程中的模块信息(模块大?。?榈刂?nbsp;, 模块句柄)可以发现偏移都是由 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 = https://www.huyubaike.com/biancheng/(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 = https://www.huyubaike.com/biancheng/nullptr;}};传入进程ID和需要获取的模块名,CreateToolhelp32Snapshot创建模块快照,遍历快照,比对模块名,获取模块信息

推荐阅读