Вам необходимо обновить браузер или попробовать использовать другой.
-
Главная -
Форумы
-
Программирование и Дизайн
-
Языки программирования
-
C++ / C# / .NET
- Дней с нами
- 709
- Розыгрыши
- 0
- Сообщения
- 31
- Репутация
+/- -
0
- Реакции
- 4
-
6 Апр 2021
-
#1
Похожие темы
-
Главная -
Форумы
-
Программирование и Дизайн
-
Языки программирования
-
C++ / C# / .NET
- Mipped.com Milk
- Russian (RU)
- Обратная связь
- Условия и правила
- Политика конфиденциальности
- Помощь
- Главная
- RSS
-
#include «hVector.h»
-
#include <Windows.h>
-
#include «hProcess.h»
-
#include <algorithm>
-
#include <math.h>
-
using namespace std;
-
#include <iostream>
-
#include <Windows.h>
-
#include <dwmapi.h>
-
HWND TargetWnd; // handles to our game and overlay
-
RECT WindowRect, ClientRect; // Rect, coordinates basically
-
char TargetWndName[256] = «Counter-Strike: Global Offensive»;
-
int windowHeight, windowWidth; // size of window
-
//AIM
-
bool smooth = false;
-
//IClientEntity* PlayerToAim;
-
float AimFOV;
-
bool isaimbotting;
-
//Hard Coded Made when TroubleShooting.
-
int ScreenCenterX = 960;
-
int ScreenCenterY = 540;
-
/*
-
extern IDirect3D9Ex* dx_Object;
-
extern IDirect3DDevice9Ex* dx_Device;
-
extern D3DPRESENT_PARAMETERS dx_Params;
-
extern ID3DXLine* dx_Line;
-
extern ID3DXFont* dx_Font;
-
*/
-
float Get3dDistance(float * myCoords, float * enemyCoords);
-
void CalcAngle(float *src, float *dst, float *angles);
-
bool WorldToScreen(float * from, float * to);
-
void GetNumberOfPlayers();
-
void ESP(int x, int y, int distance, int hp, int team, int dorm);
-
void Aimbot();
-
void keyState();
-
int Render();
-
extern int windowWidth; // Game window width
-
extern int windowHeight; // Game window height
-
extern char lWindowName[256]; // Overlay window name (our overlay window name)
-
extern HWND hWnd; // Handle to our window
-
extern char tWindowName[256]; // Target window name (our game window name)
-
extern HWND TargetWnd; // Our target window handle
-
extern RECT WindowRect, ClientRect; // Rectangles, coordinates
-
extern MSG Message; // Queue message..
-
LRESULT CALLBACK Proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
-
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
-
extern int NumOfPlayers;
-
const DWORD dw_playerbase = 0xA7094C; // Player Data Structure // DWORD = 4 bytes long aka 32 bits
-
const DWORD dw_entitybase = 0x4A13264; // Entity Base (list of players, which in this case includes you)
-
const DWORD dw_entity_loop_distance = 0x10; // The distance between each player data structure
-
const DWORD dw_mouse_x = 0x4CE0; // Engine.dll X, Y coordinates ingame… SetCursor
-
const DWORD dw_numofplayers = 0x5C817C; // How many players are in the game
-
const DWORD dw_health_offset = 0xFC; // Health
-
const DWORD dw_team_offset = 0xF0; // Team 1 — Spec, 2 — T, 3 — CT
-
const DWORD dw_position_offset = 0x134; // Position
-
const DWORD dw_flags_offset = 0x100; // Flags?
-
const DWORD dw_bone_offset = 0xA78; // Bone Offset
-
const DWORD dw_fov_offset = 0x158C; // FOV
-
const DWORD dw_activeweapon = 0x12C0; // Active
-
const DWORD dw_weaponid = 0x1684; // Weapon ID
-
const DWORD dw_crosshair_offset = 0x23F8; // We can use this as a triggerbot
-
const DWORD dw_engine_pointer = 0x55B434;
-
const DWORD dw_vmatrix = 0x4A087A4; // View Matrix
-
CHackProcess fProcess;
-
int NumOfPlayers = 32;
-
#define PI 3.14159265
-
int mfov;
-
int bonetarget = 10;
-
#define M_PI 3.14159265359
-
typedef struct
-
{
-
float rawflMatrix[5][4];
-
}WorldToScreenMatrix_t;
-
struct MyPlayer_t
-
{
-
DWORD CLocalPlayer;
-
int Team;
-
int Health;
-
WorldToScreenMatrix_t WorldToScreenMatrix;
-
float Position[3];
-
float CurrentAng[3];
-
float ViewAngle[3];
-
int Flags;
-
int CrosshairID;
-
int flickerCheck, flickerCheck2, flickerCheck3, flickerCheck4;
-
float Vecview[3];
-
void ReadInformation()
-
{
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordClient + dw_playerbase), &CLocalPlayer, sizeof(DWORD), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CLocalPlayer + dw_health_offset), &Health, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CLocalPlayer + dw_team_offset), &Team, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CLocalPlayer + dw_position_offset), &Position, sizeof(float[3]), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CLocalPlayer + dw_flags_offset), &Flags, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CLocalPlayer + dw_crosshair_offset), &CrosshairID, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordEngine + dw_mouse_x), &CurrentAng, sizeof(float[3]), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordEngine + dw_vmatrix), &ViewAngle, sizeof(float[3]), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CLocalPlayer + 0x104), &Vecview, sizeof(float[3]), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordClient + dw_vmatrix), &WorldToScreenMatrix, sizeof(WorldToScreenMatrix), 0);
-
}
-
}MyPlayer;
-
struct TargetList_t
-
{
-
DWORD CLocalPlayer;
-
float Distance;
-
float AimAngle[3];
-
TargetList_t() { }
-
TargetList_t(float MyCoords[], float EnemyCoords[], float aimAngle[])
-
{
-
Distance = Get3dDistance(MyCoords, EnemyCoords);
-
AimAngle[0] = aimAngle[0];
-
AimAngle[1] = aimAngle[1];
-
AimAngle[2] = aimAngle[2];
-
}
-
}TargetList;
-
struct PlayerList_t
-
{
-
DWORD CBaseEntity;
-
int Team;
-
int Health;
-
int Dorm;
-
int Flags;
-
DWORD Bones;
-
float Position[3];
-
float BonePosition[3];
-
float AimAngle[3]; // ?
-
float Distance; // ?
-
void ReadInformation(int player, int iBone)
-
{
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordClient + dw_entitybase + (player * dw_entity_loop_distance)), &CBaseEntity, sizeof(DWORD), 0); // CBaseEntity
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CBaseEntity + dw_health_offset), &Health, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CBaseEntity + dw_team_offset), &Team, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CBaseEntity + dw_position_offset), &Position, sizeof(float[3]), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CBaseEntity + dw_flags_offset), &Flags, sizeof(int), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CBaseEntity + dw_bone_offset), &Bones, sizeof(DWORD), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PVOID)(Bones + 0x30 * bonetarget + 0xC), &BonePosition[0], sizeof(float), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PVOID)(Bones + 0x30 * bonetarget + 0x1C), &BonePosition[1], sizeof(float), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PVOID)(Bones + 0x30 * bonetarget + 0x2C), &BonePosition[2], sizeof(float), 0);
-
BonePosition[2] —= 60;
-
}
-
}PlayerList[32];
-
void SetAngles(float* Angles)
-
{
-
DWORD cviewptr;
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordEngine + dw_engine_pointer), &cviewptr, sizeof(DWORD), NULL);
-
if (cviewptr){
-
WriteProcessMemory(fProcess.__HandleProcess, (PBYTE*)(cviewptr + dw_mouse_x), Angles, sizeof(float[3]), 0);
-
}
-
}
-
void GetAngles(float* Angles)
-
{
-
DWORD AnglePointer;
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordEngine + dw_engine_pointer), &AnglePointer, sizeof(DWORD), NULL);
-
if (AnglePointer)
-
{
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(AnglePointer + dw_mouse_x), &Angles, sizeof(float[3]), 0);
-
}
-
}
-
void AngleNormalize(float* angle)
-
{
-
if (angle[0] > 89.0f && angle[0] <= 180.0f)
-
{
-
angle[0] = 89.0f;
-
}
-
if (angle[0] > 180.f)
-
{
-
angle[0] —= 360.f;
-
}
-
if (angle[0] < —89.0f)
-
{
-
angle[0] = —89.0f;
-
}
-
if (angle[1] > 180.f)
-
{
-
angle[1] —= 360.f;
-
}
-
if (angle[1] < —180.f)
-
{
-
angle[1] += 360.f;
-
}
-
if (angle[2] != 0.0f)
-
{
-
angle[2] = 0.0f;
-
}
-
}
-
void SmoothAngleSet(float* dest, float* orig)
-
{
-
float SmoothAngles[3];
-
SmoothAngles[0] = dest[0] — orig[0];
-
SmoothAngles[1] = dest[1] — orig[1];
-
SmoothAngles[2] = 0.0f;
-
AngleNormalize(SmoothAngles);
-
SmoothAngles[0] = orig[0] + SmoothAngles[0] / 100.0f * 20;
-
SmoothAngles[1] = orig[1] + SmoothAngles[1] / 100.0f * 20;
-
SmoothAngles[2] = 0.0f;
-
AngleNormalize(SmoothAngles);
-
SetAngles(SmoothAngles);
-
Sleep(1);
-
}
-
void VelocityComp(int PlayerNumber, float* EnemyPos)
-
{
-
int smoothamount = 10;
-
float EnemyVelocity[3];
-
float MyVelocity[3];
-
EnemyPos[0] = EnemyPos[0] + (EnemyVelocity[0] / 100.f) * (40.f / smoothamount); //not sure why 40 works. I tried a lot of different values and 40 seems to scale perfectly
-
EnemyPos[1] = EnemyPos[1] + (EnemyVelocity[1] / 100.f) * (40.f / smoothamount);
-
EnemyPos[2] = EnemyPos[2] + (EnemyVelocity[2] / 100.f) * (40.f / smoothamount);
-
EnemyPos[0] = EnemyPos[0] — (MyVelocity[0] / 100.f) * (40.f / smoothamount);
-
EnemyPos[1] = EnemyPos[1] — (MyVelocity[1] / 100.f) * (40.f / smoothamount);
-
EnemyPos[2] = EnemyPos[2] — (MyVelocity[2] / 100.f) * (40.f / smoothamount);
-
}
-
bool inFOV(float* destination, float* MyAngle)
-
{
-
float myX = MyAngle[0];
-
float myY = MyAngle[1];
-
float toX = destination[0];
-
float toY = destination[1];
-
if (toX >= (myX — 10) &&
-
toX <= (myX + 10) &&
-
toY >= (myY — 10) &&
-
toY <= (myY + 10))
-
return true;
-
return false;
-
}
-
DWORD GetPlayerBase()
-
{
-
return ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordClient + dw_playerbase), &GetPlayerBase, sizeof(DWORD), 0);
-
}
-
void GetVelocity(float* Buffer)
-
{
-
DWORD PlayerBase = GetPlayerBase();
-
if (PlayerBase)
-
{
-
// Mem.R<float*>(PlayerBase + DwVecVelocity, true, 3, Buffer);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(PlayerBase + 0x110), &Buffer, sizeof(float[3]), 0);
-
}
-
}
-
/*
-
float GetViewOrigin()
-
{
-
DWORD PlayerBase = GetPlayerBase();
-
if (PlayerBase)
-
{
-
float Vecview[3];
-
//Mem.R<float*>(PlayerBase + DwVecViewOrigin, true, 3, Vecview);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(PlayerBase + 0x104), &Vecview, sizeof(float[3]), 0);
-
return Vecview[2];
-
}
-
} */
-
void GetPosition(float* Position)
-
{
-
DWORD PlayerBase = GetPlayerBase();
-
if (PlayerBase)
-
{
-
//Mem.R<float*>(PlayerBase + DwVecOrigin, true, 3, Position);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(PlayerBase + 0x134), &Position, sizeof(float[3]), 0);
-
}
-
}
-
void MakeVector(float *angle, float *vector)
-
{
-
float pitch = float(angle[0] * M_PI / 180);
-
float yaw = float(angle[1] * M_PI / 180);
-
float tmp = float(cos(pitch));
-
vector[0] = float(—tmp * —cos(yaw));
-
vector[1] = float(sin(yaw)*tmp);
-
vector[2] = float(—sin(pitch));
-
}
-
void CalcAngle(float *src, float *dst, float *angles)
-
{
-
double delta[3] = { (src[0] — dst[0]), (src[1] — dst[1]), (src[2] — dst[2]) };
-
double hyp = sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
-
angles[0] = atan(delta[2] / hyp) * 180.0 / PI;
-
angles[1] = (float)(atanf(delta[1] / delta[0]) * 57.295779513082f);
-
angles[2] = 0.0f;
-
if (delta[0] >= 0.0)
-
{
-
angles[1] += 180.0f;
-
}
-
}
-
float GetFOV(float *Angles, float *Source, float *Dst)
-
{
-
float ang[3], aim[3];
-
float fov;
-
CalcAngle(Source, Dst, ang);
-
MakeVector(Angles, aim);
-
MakeVector(ang, ang);
-
float mag_s = sqrt((aim[0] * aim[0]) + (aim[1] * aim[1]) + (aim[2] * aim[2]));
-
float mag_d = sqrt((aim[0] * aim[0]) + (aim[1] * aim[1]) + (aim[2] * aim[2]));
-
float u_dot_v = aim[0] * ang[0] + aim[1] * ang[1] + aim[2] * ang[2];
-
fov = acos(u_dot_v / (mag_s*mag_d)) * (180.0 / 3.14159265358979323846);
-
return fov;
-
}
-
struct CompareTargetArray
-
{
-
bool operator () (TargetList_t & lhs, TargetList_t & rhs)
-
{
-
int x = lhs.Distance;
-
int y = rhs.Distance;
-
return x < y;
-
}
-
};
-
float Get3dDistance(float * myCoords, float * enemyCoords)
-
{
-
return sqrt(
-
pow(double(enemyCoords[0] — myCoords[0]), 2.0) +
-
pow(double(enemyCoords[1] — myCoords[1]), 2.0) +
-
pow(double(enemyCoords[2] — myCoords[2]), 2.0));
-
}
-
float m_vecStoreboneData[3][4];
-
void GetBonePosition(int BoneNumber, float *FloatArray){
-
DWORD Bones;
-
DWORD CBaseEntity;
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordClient + dw_entitybase + (32* dw_entity_loop_distance)), &CBaseEntity, sizeof(DWORD), 0);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(CBaseEntity + dw_bone_offset), &Bones, sizeof(DWORD), 0);
-
ReadProcessMemory(fProcess.__HandleProcess,(PBYTE*)(Bones + BoneNumber * 0x30), &m_vecStoreboneData, sizeof(m_vecStoreboneData), NULL);
-
FloatArray[0] = m_vecStoreboneData[0][3];
-
}
-
void Aimbot()
-
{
-
TargetList_t * TargetList = new TargetList_t[NumOfPlayers];
-
int targetLoop = 0;
-
float EnemyXY[3];
-
float _x = 500;
-
float _y = 450;
-
int enemydistance;
-
float Fov;
-
int AimFov;
-
for (int i = 1; i < NumOfPlayers; i++)
-
{
-
PlayerList[i].ReadInformation(i, 14);
-
if (PlayerList[i].Health < 2)
-
{
-
continue;
-
}
-
else
-
{
-
CalcAngle(MyPlayer.Position, PlayerList[i].BonePosition, PlayerList[i].AimAngle);
-
int distanceX = Get3dDistance(MyPlayer.Position, PlayerList[i].Position);
-
enemydistance = distanceX;
-
if (PlayerList[i].Team != MyPlayer.Team)
-
{
-
TargetList[targetLoop] = TargetList_t(MyPlayer.Position, PlayerList[i].BonePosition, PlayerList[i].AimAngle);
-
targetLoop++;
-
}
-
}
-
}
-
//(GetKeyState(0x01)) & 0x80
-
if ((targetLoop > 0) && (GetAsyncKeyState(0x05)))
-
{
-
std::sort(TargetList, TargetList + targetLoop, CompareTargetArray());
-
float Head[3];
-
GetBonePosition(10, Head);
-
MyPlayer.ReadInformation();
-
Fov = GetFOV(MyPlayer.ViewAngle, MyPlayer.Vecview, Head);
-
cout << Fov << endl;
-
// if (Fov < 10)
-
// {
-
SetAngles(TargetList[0].AimAngle);
-
// }
-
}
-
targetLoop = 0;
-
delete[] TargetList;
-
}
-
struct Player {
-
DWORD dwBase;
-
int team;
-
Vector m_vecPunch;
-
Vector oldPunch;
-
int m_iShotsFired;
-
};
-
void RecoilControlSystem()
-
{
-
bool activated = false;
-
Player me;
-
me.oldPunch.x = 0;
-
me.oldPunch.y = 0;
-
while (true)
-
{
-
if (GetAsyncKeyState(VK_NUMPAD1) & 0x8000) {
-
activated = !activated;
-
std::cout << «RCS «;
-
if (activated) {
-
std::cout << «enabled»;
-
}
-
else {
-
std::cout << «disabled»;
-
}
-
std::cout << «n«;
-
Sleep(200);
-
}
-
// if (RCSWeapon){
-
DWORD dwPlayer;
-
DWORD dwEngine;// = mem.Read<DWORD>(modClient.dwBase + LocalPlayer_offset);
-
// = mem.Read<DWORD>(modEngine.dwBase + EnginePointer_offset);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordClient + dw_playerbase), &dwPlayer, sizeof(DWORD), NULL);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(fProcess.__dwordEngine + dw_engine_pointer), &dwEngine, sizeof(DWORD), NULL);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(dwPlayer + 0x13DC), &me.m_vecPunch, sizeof(Vector), NULL);
-
//me.m_vecPunch = mem.Read<Vector>(dwPlayer + VecPunch_offset);
-
me.m_vecPunch.x *= 2.0f;
-
me.m_vecPunch.y *= 2.0f;
-
//me.m_iShotsFired = mem.Read<int>(dwPlayer + iShotsFired_offset);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(dwPlayer + 0x1D58), &me.m_iShotsFired, sizeof(int), 0);
-
if (me.m_iShotsFired > 1 && activated) {
-
Vector currentAngles; // = mem.Read<Vector>(dwEngine + SetViewAngle_offset);
-
ReadProcessMemory(fProcess.__HandleProcess, (PBYTE*)(dwPlayer + 0x4ce0), ¤tAngles, sizeof(Vector), NULL);
-
Vector modifier = me.m_vecPunch;
-
modifier.x —= me.oldPunch.x;
-
modifier.y —= me.oldPunch.y;
-
currentAngles.x —= modifier.x;
-
currentAngles.y —= modifier.y;
-
// mem.Write<Vector>(dwEngine + SetViewAngle_offset, currentAngles);
-
WriteProcessMemory(fProcess.__HandleProcess, (PBYTE*)(dwEngine + dw_mouse_x), ¤tAngles, sizeof(Vector), 0);
-
}
-
me.oldPunch = me.m_vecPunch;
-
// }
-
Sleep(1);
-
}
-
}
-
int main()
-
{
-
HANDLE thread_GlowESP, thread_RCSystem, thread_RCSWeapon, thread_bhop, thread_ReadInfoTriggerBot;
-
DWORD ThreadID;
-
//thread_rcs = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)rcs, NULL, NULL, &ThreadID);
-
fProcess.RunProcess();
-
cout << «Aimbot on!» << endl;
-
while (true)
-
{
-
MyPlayer.ReadInformation();
-
Aimbot();
-
Sleep(1);
-
}
-
return 0;
-
}
|
Authenticator Code |
Thread Tools |
CSGO — Simple Aimbot, example code |
|
#1 |
|||||||||||
botlsmmmm Junior Member Join Date: Jan 2018
Reputation: 1649 Points: 4,278, Level: 6 Level up: 76%, 222 Points needed Activity: 3.1% Last Achievements |
here is my aimbot, you can use it as an example, its deliberately simple altho it uses some Modern c++ e.i. std::thread std:ptional std::remainderf full source code in github Code: #include "pch.h" #include "utils.h" constexpr float M_PI = 3.1415927f; constexpr DWORD MaxPlayers = 20; constexpr DWORD dwClientState_ViewAngles = 0x4D88; void clampAngle(vec3& angle) { std::clamp(angle.x,-89.f,89.f); std::clamp(angle.y,-180.f,180.f); angle.z = 0.0f; } void normalise(vec3& angle) { if (angle.x > 89.0f) angle.x -= 180.0f; if (angle.x < -89.0f) angle.x += 180.0f; angle.y = std::remainderf(angle.y, 360.0f); } vec3 calcAngle(const vec3& source, const vec3& destination){ vec3 retAngle; vec3 delta = source - destination; float hyp = sqrtf(delta.x * delta.x + delta.y * delta.y); retAngle.x = (float)(atan(delta.z / hyp) * (180.0f / M_PI)); retAngle.y = (float)(atan(delta.y / delta.x) * (180.0f / M_PI)); retAngle.z = 0.f; if (delta.x >= 0.f) retAngle.y += 180.f; return retAngle; } float getDistance(const vec3& point1,const vec3& point2) { vec3 delta = point1 - point2; normalise(delta); float temp = (delta.x*delta.x) + (delta.y*delta.y) + (delta.z*delta.z); return sqrtf(temp); } vec3 getBone(const DWORD boneaddy, const int id) { vec3 bone; bone.x = *(float*)((boneaddy + 0x30 * id + 0x0C)); bone.y = *(float*)((boneaddy + 0x30 * id + 0x1C)); bone.z = *(float*)((boneaddy + 0x30 * id + 0x2C)); return bone; } [[noreturn]] void main() { using namespace std::string_literals; // to stop null termination DWORD entityListAddress = *(DWORD*)(findPattern("client_panorama.dll", "xBB????x83xFFx01x0Fx8C????x3BxF8"s) + 1); DWORD clientState = **(DWORD**)(findPattern("engine.dll", "xA1????x33xD2x6Ax00x6Ax00x33xC9x89xB0"s) + 1); DWORD localPlayerAddress = ((*(DWORD*)(findPattern("client_panorama.dll", "x8Dx34x85????x89x15????x8Bx41x08x8Bx48x04x83xF9xFF"s) + 3)) + 4); vec3* myViewAngle = (vec3*)(clientState + dwClientState_ViewAngles); PlayerClass* localPlayer = *(PlayerClass**)localPlayerAddress; while (1) { std::this_thread::sleep_for(std::chrono::nanoseconds(1)); if (GetAsyncKeyState(VK_LBUTTON)) { std::pair<std::optional<float>, vec3> closestTarget{ std::nullopt,{0,0,0} }; for (int i = 1; i < MaxPlayers; i++) { PlayerClass* entity = *(PlayerClass**)(entityListAddress + (i) * 0x10); if (!entity) continue; if (entity->m_iTeamNum == localPlayer->m_iTeamNum) continue; if (*(char*)((DWORD)entity + 0xED) == 1) continue; // dormant cheak if (entity->m_lifeState != 0) continue; if (entity->m_iHealth <= 0) continue; vec3 localHeadPos = localPlayer->m_vecViewOffset + localPlayer->m_vecOrigin; vec3 enHeadPos = getBone(entity->m_dwBoneMatrix, 8); vec3 AimAngle = calcAngle(localHeadPos, enHeadPos); float distance = getDistance(localPlayer->m_vec3ViewAngle,AimAngle); if (distance < closestTarget.first || !closestTarget.first.has_value()) { closestTarget.first = distance; closestTarget.second = AimAngle; } } if (closestTarget.first.has_value()) { normalise(closestTarget.second); vec3 AimPunch = localPlayer->m_aimPunchAngle; AimPunch *= 2.f; closestTarget.second -= AimPunch; normalise(closestTarget.second); clampAngle(closestTarget.second); *myViewAngle = closestTarget.second; } } if (GetAsyncKeyState(VK_F1)) break; } } BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){ if(ul_reason_for_call == DLL_PROCESS_ATTACH){ std::thread main(main); main.detach(); } return TRUE; }
|
|||||||||||
botlsmmmm is offline |
|
#2 |
|||||||||||
boboibob123 Junior Member Join Date: Jul 2019
Reputation: 175 Points: 1,323, Level: 2 Level up: 85%, 77 Points needed Activity: 1.8% Last Achievements |
thanks for the upload i will use that __________________
|
|||||||||||
boboibob123 is offline |
|
#3 |
|||||||||||
laxol Join Date: Dec 2018
Reputation: 27387 Points: 31,135, Level: 26 Level up: 38%, 1,065 Points needed Activity: 5.5% Last Achievements |
https://github.com/MrLiamMcQ/CSGO_Ai…imbot.cpp#L120 Zero error-handling is performed and there is no way to eject the DLL from the target process. Also, I recommend looking up what switch cases are used for. https://github.com/MrLiamMcQ/CSGO_Ai…Aimbot.cpp#L55 You are within the address space of the process, a proper internal should be hooking the relevant game-functions and not doing stuff like this on it’s own thread. https://github.com/MrLiamMcQ/CSGO_Ai…Aimbot.cpp#L72 This has zero reason being an optional, all you are doing here is adding extra overhead. You actually have functions in your utilities header that could actually return an optional. https://github.com/MrLiamMcQ/CSGO_Ai…Aimbot.cpp#L80 The AND and OR operators exist. https://github.com/MrLiamMcQ/CSGO_Ai…imbot.cpp#L124 Never do this. (for obvious reasons). https://github.com/MrLiamMcQ/CSGO_Ai…Aimbot.cpp#L59 There is nothing windows specific about this, why on earth are you using the windows headers typedefs? https://github.com/MrLiamMcQ/CSGO_Ai…Aimbot.cpp#L49 Why are you performing c-style casts? they will not be checked for compatibility at compile-time. If you are implementing little STL containers such as optional in your code why on earth would you not do something as simple as C++ type casting? https://github.com/MrLiamMcQ/CSGO_Ai…_Aimbot.cpp#L6 Never use macros for constants when writing C++ code, instead you can use the constexpr keyword with caps variable name. Also this has zero reason being a DWORD. https://github.com/MrLiamMcQ/CSGO_Ai…_Aimbot.cpp#L7 Can also be constexpr. https://github.com/MrLiamMcQ/CSGO_Ai…_Aimbot.cpp#L9 Use std::clamp. https://github.com/MrLiamMcQ/CSGO_Ai…Aimbot.cpp#L73 Never do this. https://github.com/MrLiamMcQ/CSGO_Ai…nly/utils.h#L4 Why on earth is this a union?
|
|||||||||||
laxol is offline |
|
#4 |
|||||||||||
botlsmmmm Junior Member
Join Date: Jan 2018
Reputation: 1649 Points: 4,278, Level: 6 Level up: 76%, 222 Points needed Activity: 3.1% Last Achievements |
Quote:
Originally Posted by laxol . your good comments: stop using a switch statement for one case — good idea your opinions that i disagree with: stop using DWORD — i like it, so sue me parts i think you are wrong: Zero reason for std:ptional ???? are you high, its so i can do closestTarget.first.has_value() TO SEE IF THERE IS A CLOSES ENEMY the rest: Why on earth is vec3 a union? — its a union so i could do .data[0] and stuff not needed now, but might be useful and doesn’t remove functionality.
|
|||||||||||
botlsmmmm is offline |
|
#5 |
|||||||||||
GDPR_Anonymous MVP Join Date: Sep 2005
Reputation: 425882 Points: 1, Level: 1 Level up: 0%, 1 Points needed Activity: 0% |
Quote:
Originally Posted by botlsmmmm Zero reason for std:ptional ???? are you high, its so i can do closestTarget.first.has_value() TO SEE IF THERE IS A CLOSES ENEMY Never do «bool firstTime =1» — ?? do you know a better way??? what should i instead compare the distance to some arbitrary large number to begin with?? what he is trying to get at is probably that a simple nullptr check will suffice in this case, which is understandable. however, this would also invalidate his other point in which he recommends you should use optional in your findpattern function, which is nonsense as well. yes, because the distances in csgo have a set limit and never go above it. |
|||||||||||
GDPR_Anonymous is offline |
|
#6 |
|||||||||||
laxol Join Date: Dec 2018
Reputation: 27387 Points: 31,135, Level: 26 Level up: 38%, 1,065 Points needed Activity: 5.5% Last Achievements |
Quote:
Originally Posted by botlsmmmm your good comments: Zero reason for std:ptional ???? are you high, its so i can do closestTarget.first.has_value() TO SEE IF THERE IS A CLOSES ENEMY Error handling is always required, just because it works for you, doesn’t mean it will work for everybody using your code. This is incredibly basic stuff, a proper DLL module should handle all potential errors and invoke some sort of emergency ejection function. Also, what is the point of creating a console if nothing useful is even printed onto it? No, they are not «ugly», seeing a bunch of if statements is in fact ugly and redundant. AND and OR operator exists for a reason. «dont use c-style casts — they work and using reinterpret_cast is ugly» This is the equivalent of saying something along the lines of «I don’t use smart-pointers because the container names are ugly». As for the «bool = 1» the proper tags designed for boolean usage. Also same thing for your while-loops. Quote:
Originally Posted by DucaRii what he is trying to get at is probably that a simple nullptr check will suffice in this case, which is understandable. however, this would also invalidate his other point in which he recommends you should use optional in your findpattern function, which is nonsense as well. yes, because the distances in csgo have a set limit and never go above it. The function I was talking about returns a plain DWORD, however given this context a simple if ! check may suffice. Moreover, the optional is of type float.
|
|||||||||||
laxol is offline |
|
#7 |
|||||||||||
botlsmmmm Junior Member
Join Date: Jan 2018
Reputation: 1649 Points: 4,278, Level: 6 Level up: 76%, 222 Points needed Activity: 3.1% Last Achievements |
Quote:
Originally Posted by laxol «dont use c-style casts — they work and using reinterpret_cast is ugly» This is the equivalent of saying something along the lines of «I don’t use smart-pointers because the container names are ugly». not at all. smart pointers add something, reinterpret_cast adds a compiler warning. Quote:
Originally Posted by laxol Error handling is always required, just because it works for you, doesn’t mean it will work for everybody using your code. This is incredibly basic stuff, a proper DLL module should handle all potential errors and invoke some sort of emergency ejection function. what are the errors that you have encountered, please tell me, i have not seen ANY ERRORS EVER when attaching a dll using my injector. so keep bloating up your code. Quote:
Originally Posted by laxol Also, what is the point of creating a console if nothing useful is even printed onto it? so am not allowed to create a console now? if its not being used i can use it. Quote:
Originally Posted by laxol No, they are not «ugly», seeing a bunch of if statements is in fact ugly and redundant. AND and OR operator exists for a reason. Code: if(!entity || (entity->m_iTeamNum == localPlayer->m_iTeamNum) || (*(char*)((DWORD)entity + 0xED) == 1) || entity->m_iHealth > 100 || entity->m_lifeState != 0 || entity->m_iHealth <= 0) continue; yea thats very elegant, one big line across my screen |
|||||||||||
botlsmmmm is offline |
|
#8 |
|||||||||||
iDatFuuzy I Own Everyone Join Date: May 2014 Location: kyoto
Reputation: 44052 Recognitions (2) Points: 55,755, Level: 35 Level up: 21%, 2,945 Points needed Activity: 2.2% Last Achievements |
1. you need error handling as laxol said Code: if (entity->m_iHealth > 100) { continue; }; 5. pretty sure dangerzone allows entity hp to be over 100. you shouldn’t be concerned about checking if hp is *over* a value anyway. laxol said pretty much everything so i won’t repeat his criticism. __________________ source engine: csgo cheat devs be like «yea i made it» |
|||||||||||
iDatFuuzy is offline |
|
#9 |
|||||||||||
botlsmmmm Junior Member
Join Date: Jan 2018
Reputation: 1649 Points: 4,278, Level: 6 Level up: 76%, 222 Points needed Activity: 3.1% Last Achievements |
Quote:
Originally Posted by iDatFuuzy why are you using so many c-style casts? Quote:
Originally Posted by laxol Why are you performing c-style casts? they will not be checked for compatibility at compile-time. IN GAME HACKING IT WILL LITERALLY ALWAYS BE REINTERPRET_CAST !! so why the should i constantly write boilerplate code? that will literally be turned into a c-style cast when compiled, if yous love boilerplate code SO MUTCH go write some java. you know i rewrote all my code to have reinterpret_cast then i thought about it, and that i did that just because some people on unknowncheats told me there way is better. i only have two hard coded offsets and they haven’t changed in years. @iDatFuuzy your suggestion to take off the >= 100 health was good thanks. |
|||||||||||
botlsmmmm is offline |
|
#10 |
|||||||||||
1337Nexo UC Supporter Join Date: Aug 2018
Reputation: 5974 Points: 17,964, Level: 18 Level up: 11%, 1,336 Points needed Activity: 4.5% Last Achievements |
the code is very ugly in my opinion and there are so many «errors».. but good release. __________________ Vanguard sucks. |
|||||||||||
1337Nexo is offline |
|
#11 |
|||||||||||
wasturlife ~xorstr~ Join Date: Jun 2018 Location: some where!
Reputation: 2230 Points: 6,349, Level: 8 Level up: 87%, 151 Points needed Activity: 2.6% Last Achievements |
not bad thanks for sharing __________________ |
|||||||||||
wasturlife is offline |
Similar Threads |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
[Information] Example of simple aimbot. | Dimp | Programming for Beginners | 25 | 10th April 2018 07:31 AM |
[Coding] Code Redirection Example (JMP Detour) | System! | Anti-Cheat Bypass | 5 | 14th November 2013 08:24 PM |
[Detected] Combat arms GameDevice Pointer Example Code | Gellin | Combat Arms | 9 | 4th December 2009 07:55 PM |
[Help] Can anyone give me an example of a hack? (the code) | christian_jayr7 | C and C++ | 4 | 2nd November 2009 10:11 PM |
[Coding] How to add «Snippets» to a base (Example code) | PR0C3SS-1337 | Programming for Beginners | 8 | 11th October 2009 05:36 AM |
Tags |
vec3, angle.x, continue;, angle.y, dword, 89.0f, float, return, source, 0x30 |
«
Previous Thread
|
Next Thread
»
Forum Jump |
All times are GMT. The time now is 02:49 AM.
Contact Us —
Toggle Dark Theme
Terms of Use Information Privacy Policy Information
Copyright ©2000-2023, Unknowncheats� UKCS #312436
no new posts
1 / 1 / 0 Регистрация: 31.07.2013 Сообщений: 31 |
|
1 |
|
Как писать аимботы (читы) для шутеров?17.10.2016, 14:26. Показов 31931. Ответов 10
прошёл две книги по языку программированию с++, синтаксис знаю, но до сих пор ума не представляю как писать мне программы которые я хочу, где искать нужные библиотеки а если их нет, Как мне их писать? мне просто читать уже надоело книги по с++, практики в них мало, а читать уже задалбывает, хочется кодить а не читать как кодить, на практике же я даже не знаю что мне написать, а то что хочу я не могу. з.ы в интернете полно задач на математическую тематику, но они же такие скучные, их вообще не в кайф делать, просто засыпаю моментально.
__________________
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
17.10.2016, 14:26 |
Ответы с готовыми решениями: Боты для 3D шутеров — рили? Как создаются читы для игр? Видеокарта для шутеров Читы для игр 10 |
Любитель чаепитий 3734 / 1793 / 563 Регистрация: 24.08.2014 Сообщений: 5,998 Записей в блоге: 1 |
|
17.10.2016, 14:30 |
2 |
go100gi,
5.7. Запрещено создание и распространение вредоносного ПО, вирусов, кряков и взлома лицензионного софта, а также публикация ссылок для их скачивания.
0 |
Selot |
17.10.2016, 14:35
|
Не по теме: хорошо, что ты не можешь научиться, я рад, искренне. Вот такой я злой, угу. Задолбали читеры в ксго, что ни игра в мм, то обязательно с читером
0 |
obivan |
17.10.2016, 14:38
|
Не по теме:
хорошо, что ты не можешь научиться, я рад, искренне. Вот такой я злой, угу. Задолбали читеры в ксго, что ни игра в мм, то обязательно с читером с точки зрения игрока это плохо, но по фатку если смотреть на это глазами программиста, то очень сложная и трудная тема
0 |
13 / 13 / 9 Регистрация: 24.09.2016 Сообщений: 74 |
|
17.10.2016, 14:39 |
5 |
Надеюсь у тебя ничего не получится.
0 |
Selot |
17.10.2016, 14:49
|
Не по теме:
с точки зрения игрока это плохо, но по фатку если смотреть на это глазами программиста, то очень сложная и трудная тема Точка зрения программиста в данном случае не рассматривается, т.к налицо корыстные цели, а не стремление познать тонкости работы с памятью, процессами итд. средствами крестов
0 |
Администратор 9365 / 4648 / 757 Регистрация: 17.04.2012 Сообщений: 9,496 Записей в блоге: 14 |
|
17.10.2016, 15:04 |
7 |
GbaLog-, как бы мы не «любили» читеров, читы и боты взломом на форуме не считаются.
0 |
1 / 1 / 0 Регистрация: 31.07.2013 Сообщений: 31 |
|
17.10.2016, 15:57 [ТС] |
8 |
ну я всего 5 месяцев учусь, думаю научится, а как научусь , обязательно выложу в открытый доступ, просто я не люблю Гейба. Да и вообще читерить люблю Просто я не знаю с чего обучение начать, скачал Source SDK, хотел в коде поковырятся но скомпилить не могу, потому что нужна 10 студия, думал еще в ядре мангоса для знаний поковырятся , но там 12 студия нужна, какая то елда с этим программированием. Каждый раз когда я найду какой то исходник мне нужно перекачивать студию нужной версии?
0 |
Любитель чаепитий 3734 / 1793 / 563 Регистрация: 24.08.2014 Сообщений: 5,998 Записей в блоге: 1 |
|
17.10.2016, 16:24 |
9 |
Не по теме:
с точки зрения игрока это плохо, но по фатку если смотреть на это глазами программиста, то очень сложная и трудная тема Тут я согласен с Selot, если хочется научиться работать с памятью и процессами в run-time, то иди взламывать одиночки, а в онлайн нечего лезть.
как бы мы не «любили» читеров, читы и боты взломом на форуме не считаются. Очень-очень жаль.
1 |
1379 / 406 / 144 Регистрация: 22.10.2014 Сообщений: 872 |
|
17.10.2016, 17:10 |
10 |
Очень-очень жаль. Ну что вы, давайте научим человека go100gi, Значит так, есть два варианта, один — относительно простой и все пользуются им, другой очень сложный.
0 |
Selot |
17.10.2016, 18:41
|
Не по теме:
обязательно выложу в открытый доступ, просто я не люблю Гейба Ну Гейб то уж точно за сердце схватится от такого
0 |
Я не буду объяснять, как создавать проекты в VisualStudio и тому подобное, будем считать, что те, кто читают этот гайд, хотя бы немного разбираются в том, как создавать и работать с проектами в визуалке.
1)Первым делом нужно скачать библиотеку на GitHub:NativeManager
2)Скомпилируйте эту библиотеку у себя на компьютере
3)Создайте свой проект с будущим читом
4)Через ссылки добавьте NativeManager в свой проект
5)Приступаем к разработке!!!!
————————————————————————————————————————————————————————————————————————————
Чит мы будем создавать на примере игры CS:GO
1)После того как мы создали проект с читом, нам нужно добавить ссылки на пространства имен нашего NativeManager’a
using System.MemoryInteraction;
2)В NativeManager есть 2 класса для работы с памятью
- SimpleMemoryManager
- MemoryManager(Производный класс от SimpleMemoryManager)
Мы будем использовать класс MemoryManager, так как в нем реализованы методы, которые позволяют нам без дополнительных усилий прочитать данные из памяти процесса.
3)Пишем код для присоединения к процессу игры
ВАЖНО!!!
Игра должна быть запущена раньше чита, иначе мы словим исключение, что такого процесса не существует!
Process process = Process.GetProcessesByName("csgo")[0];
MemoryManager memory = process.GetMemoryManager();
В первой строчке кода мы указали, что нам нужен процесс с именем «CSGO».
Во второй строчке кода мы указали, что нам нужно получить экземпляр MemoryManager для работы с виртуальной памятью процесса.
4)Следующим этапом нам нужно получить модули процесса, с которыми нам нужно работать, что бы прочитать нужные нам данные
IntPtr client = process.GetModule("client.dll").BaseAddress;
5)Создаем бесконечный цикл для того, что бы наш чит постоянно читал данные из игры и мог так же в нее записывать.
6)Теперь нам нужно получить локального игрока из игры. Для этого в цикле нам нужно написать вот такой код
IntPtr localPlayer = memory.Read<IntPtr>(client + 0xD3FC5C);
Число 0xD3FC5C может меняться с каждым обновлением игры. Следить за обновлением оффсетов можно на GitHub по этой ссылке:hazedumper
7)Мы получили локального игрока, теперь нам нужно получить его флаг. С помощью него мы будем понимать в прыжке он или нет
int flag = memory.Read<int>(localPlayer + 0x104);
8)Для начала сделаем проверку на нажатие кнопки пробела
Этот код нужно добавить в любой из классов
[DllImport("user32.dll")]
static extern bool GetAsyncKeyState(int vKey);
А этот код в наш цикл после получения флага
if (GetAsyncKeyState(32))
{
}
9)Теперь нам нужно сделать проверку, находится игрок в воздухе или на земле. Для этого нужно добавить этот код в условие проверки нажатия клавиши пробел
if(flag == 256 || flag == 262)
{
}
10)В этом условии нам нужно сделать запись в память игры, что бы делать прыжок, когда мы оказываемся на земле
if (flag == 256 || flag == 262)
{
memory.Write(client + 0x51FE22C, 4);
}
else
{
memory.Write(client + 0x51FE22C, 5);
}
На этом все. Мы написали такой маленький и легкий код, с помощью которого наш персонаж может прыгать без остановок.
Надеюсь, я объяснил все доходчиво и понятно. Если будут какие то вопросы, то с удовольствием отвечу вам на них в комментариях.
А вот подарок тем, кто не хочет копировать код по частям.
Process process = Process.GetProcessesByName("csgo")[0];
MemoryManager memory = process.GetMemoryManager();
IntPtr client = process.GetModule("client.dll").BaseAddress;
while(true)
{
IntPtr localPlayer = memory.Read<IntPtr>(client + 0xD3FC5C);
int flag = memory.Read<int>(localPlayer + 0x104);
if (GetAsyncKeyState(32))
{
if (flag == 256 || flag == 262)
{
memory.Write(client + 0x51FE22C, 4);
}
else
{
memory.Write(client + 0x51FE22C, 5);
}
}
Thread.Sleep(1);
}
Время на прочтение
11 мин
Количество просмотров 13K
В этом посте мы расскажем о процессе создания aimbot — программы, автоматически прицеливающейся во врагов в игре жанра «шутер от первого лица» (FPS). Создавать будем aimbot для игры Half-Life 2, работающей на движке Source. Aimbot будет работать внутри процесса игры и использовать для своей работы внутренние функции игры, подвергнутые реверс-инжинирингу (в отличие от других систем, работающих снаружи игры и сканирующих экран).
Для начала изучим Source SDK и используем его как руководство для реверс-инжиниринга исполняемого файла Half-Life 2. Затем мы применим полученные данные, для создания бота. К концу статьи у нас будет написан aimbot, привязывающий прицел игрока к ближайшему врагу.
▍ Реверс-инжиниринг и Source SDK
Давайте рассмотрим, как выполнить реверс-инжиниринг исполняемого файла, чтобы найти нужную нам информацию. Для создания кода, который будет автоматически прицеливаться в мишень, нужно знать следующее:
- Позицию глаз игрока
- Позицию глаз ближайшего врага
- Вектор от глаза игрока к глазу врага (получаемый по двум предыдущим пунктам)
- Способ изменения положения камеры игрока так, чтобы глаз игрока смотрел по вектору к глазу врага
Для всего, кроме третьего пункта, требуется получать информацию от состояния запущенной игры. Эту информацию получают реверс-инжинирингом игры для поиска классов, содержащих соответствующие поля. Обычно это оказывается чрезвычайно трудоёмкой задачей со множеством проб и ошибок; однако в данном случае у нас есть доступ к Source SDK, который мы используем в качестве руководства.
Начнём поиск с нахождения ссылок на позицию глаз в репозитории. Изучив несколько страниц с результатами поиска, мы выйдем на огромный класс CBaseEntity. Внутри этого класса есть две функции:
virtual Vector EyePosition(void);
virtual const QAngle &EyeAngles(void);
Так как CBaseEntity является базовым классом, от которого происходят все сущности (entity) игры, и он содержит члены для позиции глаза и углов камеры, то похоже, именно с ним нам и нужно работать. Дальше нам нужно посмотреть, откуда ссылаются на эти функции. Снова немного поискав на GitHub Source SDK, мы находим интерфейс IServerTools, у которого есть несколько весьма многообещающих функций:
virtual IServerEntity *GetIServerEntity(IClientEntity *pClientEntity) = 0;
virtual bool SnapPlayerToPosition(const Vector &org, const QAngle &ang, IClientEntity *pClientPlayer = NULL) = 0;
virtual bool GetPlayerPosition(Vector &org, QAngle &ang, IClientEntity *pClientPlayer = NULL) = 0;
// ...
virtual CBaseEntity *FirstEntity(void) = 0;
virtual CBaseEntity *NextEntity(CBaseEntity *pEntity) = 0;
В этом интерфейсе очень удобно то, что он предоставляет доступ к позиции локального игрока, что позволяет привязать игрока к другой позиции и углу обзора, а также обеспечивает возможность итеративно обходить сущности. К тому же его экземпляр создаётся глобально и привязан к жёстко прописанной в коде строке.
#define VSERVERTOOLS_INTERFACE_VERSION_1 "VSERVERTOOLS001"
#define VSERVERTOOLS_INTERFACE_VERSION_2 "VSERVERTOOLS002"
#define VSERVERTOOLS_INTERFACE_VERSION "VSERVERTOOLS003"
#define VSERVERTOOLS_INTERFACE_VERSION_INT 3
// ...
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerTools, IServerTools001, VSERVERTOOLS_INTERFACE_VERSION_1, g_ServerTools);
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerTools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION, g_ServerTools);
Можем начать разработку aimbot с поиска этого класса в памяти. Запустив Half-Life 2 и подключив к нему отладчик, поищем строковые ссылки на VSERVERTOOLS.
Мы видим, откуда на них ссылаются:
7BCAB090 | 68 88FA1F7C | push server.7C1FFA88 | 7C1FFA88:"VSERVERTOOLS001"
7BCAB095 | 68 00C4087C | push server.7C08C400 |
7BCAB09A | B9 B02A337C | mov ecx,server.7C332AB0 |
7BCAB09F | E8 8CCA3F00 | call server.7C0A7B30 |
7BCAB0A4 | C3 | ret |
7BCAB0A5 | CC | int3 |
7BCAB0A6 | CC | int3 |
7BCAB0A7 | CC | int3 |
7BCAB0A8 | CC | int3 |
7BCAB0A9 | CC | int3 |
7BCAB0AA | CC | int3 |
7BCAB0AB | CC | int3 |
7BCAB0AC | CC | int3 |
7BCAB0AD | CC | int3 |
7BCAB0AE | CC | int3 |
7BCAB0AF | CC | int3 |
7BCAB0B0 | 68 98FA1F7C | push server.7C1FFA98 | 7C1FFA98:"VSERVERTOOLS002"
7BCAB0B5 | 68 00C4087C | push server.7C08C400 |
7BCAB0BA | B9 BC2A337C | mov ecx,server.7C332ABC |
7BCAB0BF | E8 6CCA3F00 | call server.7C0A7B30 |
7BCAB0C4 | C3 | ret |
В ассемблерном листинге видно, что функция-член server.7C0A7B30 вызывается в server.7C332AB0 и server.7C332ABC. Эта функция получает два аргумента, один из которых — это имя-строка интерфейса. После изучения отладчика становится понятно, что второй параметр — это статический экземпляр чего-то.
Посмотрев на то, что делает в коде макрос EXPOSE_SINGLE_INTERFACE_GLOBALVAR, становится понятнее, что это синглтон CServerTools, предоставленный как глобальный интерфейс. Зная это, мы легко сможем получить указатель на этот синглтон в среде исполнения: мы просто берём адрес этой псевдофункции, перемещающей указатель в EAX, и вызываем её напрямую. Чтобы сделать это, можно написать следующий дженерик-код, который мы продолжим применять для нового использования других функций:
template <typename T>
T GetFunctionPointer(const std::string moduleName, const DWORD_PTR offset) {
auto moduleBaseAddress{ GetModuleHandleA(moduleName.c_str()) };
if (moduleBaseAddress == nullptr) {
std::cerr << "Could not get base address of " << moduleName
<< std::endl;
std::abort();
}
return reinterpret_cast<T>(
reinterpret_cast<DWORD_PTR>(moduleBaseAddress) + offset);
}
IServerTools* GetServerTools() {
constexpr auto globalServerToolsOffset{ 0x3FC400 };
static GetServerToolsFnc getServerToolsFnc{ GetFunctionPointer<GetServerToolsFnc>(
"server.dll", globalServerToolsOffset) };
return getServerToolsFnc();
}
Здесь мы берём базовый адрес, в который загружена server.dll, добавляем смещение, чтобы попасть туда, откуда можно получить доступ к синглтону CServerTools, и возвращаем его как указатель вызывающей функции. Благодаря этому мы сможем вызывать нужные нам функции в интерфейсе и игра будет реагировать соответствующим образом. Нас интересуют две функции: GetPlayerPosition и SnapPlayerToPosition.
Внутри GetPlayerPosition при помощи вызова UTIL_GetLocalPlayer получается класс локального игрока, а также вызываются EyePosition и EyeAngles; внутри SnapPlayerToPosition при помощи SnapEyeAngles корректируются углы обзора игрока. Всё вместе это даёт нам то, что необходимо для получения позиций и углов обзора сущностей, благодаря чему можно выполнить соответствующие вычисления нового вектора и угла обзора, привязывающихся к глазам врагов.
Давайте разбираться по порядку, начнём с GetPlayerPosition. Так как мы можем получить указатель на IServerTools и имеем определение интерфейса, можно выполнить явный вызов GetPlayerPosition и пошагово пройтись по вызову при помощи отладчика. При этом мы попадём сюда:
7C08BEF0 | 55 | push ebp |
7C08BEF1 | 8BEC | mov ebp,esp |
7C08BEF3 | 8B01 | mov eax,dword ptr ds:[ecx] |
7C08BEF5 | 83EC 0C | sub esp,C |
7C08BEF8 | 56 | push esi |
7C08BEF9 | FF75 10 | push dword ptr ss:[ebp+10] |
7C08BEFC | FF50 04 | call dword ptr ds:[eax+4] |
7C08BEFF | 8BF0 | mov esi,eax |
7C08BF01 | 85F6 | test esi,esi |
7C08BF03 | 75 14 | jne server.7C08BF19 |
7C08BF05 | E8 E616E7FF | call server.7BEFD5F0 |
7C08BF0A | 8BF0 | mov esi,eax |
7C08BF0C | 85F6 | test esi,esi |
7C08BF0E | 75 09 | jne server.7C08BF19 |
7C08BF10 | 32C0 | xor al,al |
7C08BF12 | 5E | pop esi |
7C08BF13 | 8BE5 | mov esp,ebp |
7C08BF15 | 5D | pop ebp |
7C08BF16 | C2 0C00 | ret C |
7C08BF19 | 8B06 | mov eax,dword ptr ds:[esi] |
7C08BF1B | 8D4D F4 | lea ecx,dword ptr ss:[ebp-C] |
7C08BF1E | 51 | push ecx |
7C08BF1F | 8BCE | mov ecx,esi |
7C08BF21 | FF90 08020000 | call dword ptr ds:[eax+208] |
7C08BF27 | 8B4D 08 | mov ecx,dword ptr ss:[ebp+8] |
7C08BF2A | D900 | fld st(0),dword ptr ds:[eax] |
7C08BF2C | D919 | fstp dword ptr ds:[ecx],st(0) |
7C08BF2E | D940 04 | fld st(0),dword ptr ds:[eax+4] |
7C08BF31 | D959 04 | fstp dword ptr ds:[ecx+4],st(0) |
7C08BF34 | D940 08 | fld st(0),dword ptr ds:[eax+8] |
7C08BF37 | 8B06 | mov eax,dword ptr ds:[esi] |
7C08BF39 | D959 08 | fstp dword ptr ds:[ecx+8],st(0) |
7C08BF3C | 8BCE | mov ecx,esi |
7C08BF3E | FF90 0C020000 | call dword ptr ds:[eax+20C] |
7C08BF44 | 8B4D 0C | mov ecx,dword ptr ss:[ebp+C] |
7C08BF47 | 5E | pop esi |
7C08BF48 | D900 | fld st(0),dword ptr ds:[eax] |
7C08BF4A | D919 | fstp dword ptr ds:[ecx],st(0) |
7C08BF4C | D940 04 | fld st(0),dword ptr ds:[eax+4] |
7C08BF4F | D959 04 | fstp dword ptr ds:[ecx+4],st(0) |
7C08BF52 | D940 08 | fld st(0),dword ptr ds:[eax+8] |
7C08BF55 | B0 01 | mov al,1 |
7C08BF57 | D959 08 | fstp dword ptr ds:[ecx+8],st(0) |
7C08BF5A | 8BE5 | mov esp,ebp |
7C08BF5C | 5D | pop ebp |
7C08BF5D | C2 0C00 | ret C |
Разбираться в этом довольно долго, однако в виде графа потока управления всё выглядит довольно просто:
Если построчно сопоставить дизассемблированную программу с кодом, то мы достаточно быстро найдём необходимое. Код вызывает функцию UTIL_GetLocalPlayer только тогда, когда переданный параметр pClientEntity равен null
. Эта логика проверяется в блоке первой функции графа. Если существует действительная клиентская сущность, код переходит к получению позиции и углов глаза для неё, а в противном случае получает сущность локального игрока. Этот вызов происходит при исполнении команды call server.7BEFD5F0 по адресу server.7C08BF05. Как и ранее, мы можем создать указатель функции на UTIL_GetLocalPlayer и вызывать её напрямую.
CBasePlayer* GetLocalPlayer() {
constexpr auto globalGetLocalPlayerOffset{ 0x26D5F0 };
static GetLocalPlayerFnc getLocalPlayerFnc{ GetFunctionPointer<GetLocalPlayerFnc>(
"server.dll", globalGetLocalPlayerOffset) };
return getLocalPlayerFnc();
}
Следующими в дизассемблированном коде идут вызовы функций EyePosition и EyeAngles. Нас интересует только получение позиций глаза, поэтому важен только первый вызов. Для получения адреса функции мы можем пошагово пройти по вызову, пока не вызовем адрес, находящийся в [EAX+0x208]. После исполнения этой команды мы перейдём на server.dll+0x119D00, таким образом узнав, где находится функция.
Vector GetEyePosition(CBaseEntity* entity) {
constexpr auto globalGetEyePositionOffset{ 0x119D00 };
static GetEyePositionFnc getEyePositionFnc{ GetFunctionPointer<GetEyePositionFnc>(
"server.dll", globalGetEyePositionOffset) };
return getEyePositionFnc(entity);
}
И это всё, что нам нужно от GetPlayerPosition; теперь у нас есть возможность получения указателя локальной сущности игрока и получения позиции глаза сущности. Последнее, что нам потребуется — возможность задания угла обзора игрока. Как говорилось выше, это можно сделать, вызвав функцию SnapPlayerToPosition и посмотрев, где находится функция SnapEyeAngles. Дизассемблированный код SnapEyeAngles выглядит следующим образом:
7C08C360 | 55 | push ebp |
7C08C361 | 8BEC | mov ebp,esp |
7C08C363 | 8B01 | mov eax,dword ptr ds:[ecx] |
7C08C365 | 83EC 0C | sub esp,C |
7C08C368 | 56 | push esi |
7C08C369 | FF75 10 | push dword ptr ss:[ebp+10] |
7C08C36C | FF50 04 | call dword ptr ds:[eax+4] |
7C08C36F | 8BF0 | mov esi,eax |
7C08C371 | 85F6 | test esi,esi |
7C08C373 | 75 14 | jne server.7C08C389 |
7C08C375 | E8 7612E7FF | call server.7BEFD5F0 |
7C08C37A | 8BF0 | mov esi,eax |
7C08C37C | 85F6 | test esi,esi |
7C08C37E | 75 09 | jne server.7C08C389 |
7C08C380 | 32C0 | xor al,al |
7C08C382 | 5E | pop esi |
7C08C383 | 8BE5 | mov esp,ebp |
7C08C385 | 5D | pop ebp |
7C08C386 | C2 0C00 | ret C |
7C08C389 | 8B06 | mov eax,dword ptr ds:[esi] |
7C08C38B | 8BCE | mov ecx,esi |
7C08C38D | FF90 24020000 | call dword ptr ds:[eax+224] |
7C08C393 | 8B4D 08 | mov ecx,dword ptr ss:[ebp+8] |
7C08C396 | F3:0F1001 | movss xmm0,dword ptr ds:[ecx] |
7C08C39A | F3:0F5C00 | subss xmm0,dword ptr ds:[eax] |
7C08C39E | F3:0F1145 F4 | movss dword ptr ss:[ebp-C],xmm0 |
7C08C3A3 | F3:0F1041 04 | movss xmm0,dword ptr ds:[ecx+4] |
7C08C3A8 | F3:0F5C40 04 | subss xmm0,dword ptr ds:[eax+4] |
7C08C3AD | F3:0F1145 F8 | movss dword ptr ss:[ebp-8],xmm0 |
7C08C3B2 | F3:0F1041 08 | movss xmm0,dword ptr ds:[ecx+8] |
7C08C3B7 | 8BCE | mov ecx,esi |
7C08C3B9 | F3:0F5C40 08 | subss xmm0,dword ptr ds:[eax+8] |
7C08C3BE | 8D45 F4 | lea eax,dword ptr ss:[ebp-C] |
7C08C3C1 | 50 | push eax |
7C08C3C2 | F3:0F1145 FC | movss dword ptr ss:[ebp-4],xmm0 |
7C08C3C7 | E8 14CFD0FF | call server.7BD992E0 |
7C08C3CC | FF75 0C | push dword ptr ss:[ebp+C] |
7C08C3CF | 8BCE | mov ecx,esi |
7C08C3D1 | E8 4A0FE0FF | call server.7BE8D320 |
7C08C3D6 | 8B06 | mov eax,dword ptr ds:[esi] |
7C08C3D8 | 8BCE | mov ecx,esi |
7C08C3DA | 6A FF | push FFFFFFFF |
7C08C3DC | 6A 00 | push 0 |
7C08C3DE | FF90 88000000 | call dword ptr ds:[eax+88] |
7C08C3E4 | B0 01 | mov al,1 |
7C08C3E6 | 5E | pop esi |
7C08C3E7 | 8BE5 | mov esp,ebp |
7C08C3E9 | 5D | pop ebp |
7C08C3EA | C2 0C00 | ret C |
Повторив уже описанный выше процесс, мы выясним, что команда call server.7BE8D320 является вызовом SnapEyeAngles. Мы можем определить следующую функцию:
void SnapEyeAngles(CBasePlayer* player, const QAngle& angles)
{
constexpr auto globalSnapEyeAnglesOffset{ 0x1FD320 };
static SnapEyeAnglesFnc snapEyeAnglesFnc{ GetFunctionPointer<SnapEyeAnglesFnc>(
"server.dll", globalSnapEyeAnglesOffset) };
return snapEyeAnglesFnc(player, angles);
}
Итак, теперь у нас есть всё необходимое.
▍ Создание aimbot
Для создания aimbot нам нужно следующее:
- Итеративно обойти сущности
- Если сущность является врагом, то найти расстояние между сущностью и игроком
- Отслеживать ближайшую сущность
- Вычислить вектор «глаз-глаз» между игроком и ближайшим врагом
- Корректировать углы глаза игрока так, чтобы он следовал за этим вектором
Ранее мы узнали, что для получения позиции игрока можно вызвать GetPlayerPosition. Для циклического обхода списка сущностей можно вызвать FirstEntity и NextEntity, которые возвращают указатель на экземпляр CBaseEntity. Чтобы понять, является ли сущность врагом, можно сравнить имя сущности со множеством имён враждебных NPC-сущностей. Если мы получили сущность врага, то вычисляем расстояние между игроком и сущностью и сохраняем позицию сущности, если она ближайшая из всех, пока найденных нами.
После итеративного обхода всего списка сущностей мы получаем ближайшего врага, вычисляем вектор «глаз-глаз» и корректируем углы глаза игрока при помощи функции VectorAngles.
В виде кода получим следующее:
auto* serverEntity{ reinterpret_cast<IServerEntity*>(
GetServerTools()->FirstEntity()) };
if (serverEntity != nullptr) {
do {
if (serverEntity == GetServerTools()->FirstEntity()) {
SetPlayerEyeAnglesToPosition(closestEnemyVector);
closestEnemyDistance = std::numeric_limits<float>::max();
closestEnemyVector = GetFurthestVector();
}
auto* modelName{ serverEntity->GetModelName().ToCStr() };
if (modelName != nullptr) {
auto entityName{ std::string{GetEntityName(serverEntity)} };
if (IsEntityEnemy(entityName)) {
Vector eyePosition{};
QAngle eyeAngles{};
GetServerTools()->GetPlayerPosition(eyePosition, eyeAngles);
auto enemyEyePosition{ GetEyePosition(serverEntity) };
auto distance{ VectorDistance(enemyEyePosition, eyePosition) };
if (distance <= closestEnemyDistance) {
closestEnemyDistance = distance;
closestEnemyVector = enemyEyePosition;
}
}
}
serverEntity = reinterpret_cast<IServerEntity*>(
GetServerTools()->NextEntity(serverEntity));
} while (serverEntity != nullptr);
}
В коде есть несколько вспомогательных функций, которые мы ранее не рассматривали: функция GetFurthestVector возвращает вектор с максимальными значениями float в полях x, y и z; GetEntityName возвращает имя сущности в виде строки, получая член m_iName экземпляра CBaseEntity; а IsEntityEnemy просто сверяет имя сущности со множеством враждебных NPC.
Векторные вычисления и расчёт нового угла обзора происходят в показанной ниже SetPlayerEyeAnglesToPosition:
void SetPlayerEyeAnglesToPosition(const Vector& enemyEyePosition) {
Vector eyePosition{};
QAngle eyeAngles{};
GetServerTools()->GetPlayerPosition(eyePosition, eyeAngles);
Vector forwardVector{ enemyEyePosition.x - eyePosition.x,
enemyEyePosition.y - eyePosition.y,
enemyEyePosition.z - eyePosition.z
};
VectorNormalize(forwardVector);
QAngle newEyeAngles{};
VectorAngles(forwardVector, newEyeAngles);
SnapEyeAngles(GetLocalPlayer(), newEyeAngles);
}
Эта функция вычисляет вектор «глаз-глаз», вычитая из вектора позиции глаза врага вектор позиции глаза игрока. Затем этот новый вектор нормализуется и передаётся функции VectorAngles для вычисления новых углов обзора. Затем углы глаза игрока корректируются под эти новые углы, что должно создавать эффект слежения за сущностью.
Как это выглядит в действии?
Вы видите почти прозрачный прицел, следующий за головой идущего по комнате NPC. Когда NPC отходит достаточно далеко, код выполняет привязку к более близкому NPC. Всё работает!
▍ Заключение
Описанные в статье методики в общем случае применимы к любой игре жанра FPS. Способ получения позиций и углов может различаться в разных игровых движках, однако векторные вычисления для создания угла обзора из вектора расстояния применимы в любом случае.
Реверс-инжиниринг Half-Life 2 был сильно упрощён открытостью Source SDK. Возможность сопоставления кода и структур данных с ассемблерным кодом существенно упростила отладку, однако обычно такого везения не бывает! Надеюсь, эта статья помогла вам понять, как работают aimbot и показала, что создавать их не очень сложно.
Полный исходный код aimbot выложен на GitHub, можете свободно с ним экспериментировать.