Загрузка данных


# language: Python, file: cs2_cheat.py
import ctypes
import ctypes.wintypes as wt
import json
import math
import os
import struct
import sys
import threading
import time
import tkinter as tk
import urllib.request
from dataclasses import dataclass, field
from typing import Optional

import pymem

OFFSETS_URL = "https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/offsets.json"
CLIENT_DLL_URL = "https://raw.githubusercontent.com/a2x/cs2-dumper/main/output/client_dll.json"

@dataclass
class Offsets:
    dwEntityList: int = 0
    dwLocalPlayer: int = 0
    dwViewMatrix: int = 0
    m_iHealth: int = 0
    m_iTeamNum: int = 0
    m_vecOrigin: int = 0
    m_dwBoneMatrix: int = 0
    m_angEyeAngles: int = 0

def fetch_url(url: str) -> dict:
    try:
        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        with urllib.request.urlopen(req, timeout=10) as response:
            return json.loads(response.read().decode())
    except Exception as e:
        return {}

def load_offsets() -> Offsets:
    o = Offsets()
    print("[*] Скачиваем свежие оффсеты...")
    data_offsets = fetch_url(OFFSETS_URL)
    data_client = fetch_url(CLIENT_DLL_URL)
    
    if not data_offsets or not data_client:
        print("[!] Ошибка скачивания.")
        return o

    client = data_offsets.get("client.dll", {})
    o.dwEntityList  = client.get("dwEntityList", 0)
    o.dwLocalPlayer = client.get("dwLocalPlayer", 0)
    o.dwViewMatrix  = client.get("dwViewMatrix", 0)
    
    classes = data_client.get("client.dll", {}).get("classes", {})
    
    # Ищем нужные поля в правильных классах
    for class_name, class_data in classes.items():
        fields = class_data.get("fields", {})
        if "m_iHealth" in fields and "m_iTeamNum" in fields:
            o.m_iHealth = fields["m_iHealth"]
            o.m_iTeamNum = fields["m_iTeamNum"]
            o.m_vecOrigin = fields.get("m_vecOrigin", 0)
        if "m_dwBoneMatrix" in fields:
            o.m_dwBoneMatrix = fields["m_dwBoneMatrix"]
        if "m_angEyeAngles" in fields:
            o.m_angEyeAngles = fields["m_angEyeAngles"]

    print(f"[+] Оффсеты загружены: EntityList={hex(o.dwEntityList)}, Health={hex(o.m_iHealth)}")
    return o

@dataclass
class Vec3:
    x: float = 0.0
    y: float = 0.0
    z: float = 0.0

def v3sub(a: Vec3, b: Vec3) -> Vec3:
    return Vec3(a.x - b.x, a.y - b.y, a.z - b.z)

def calc_angle(src: Vec3, dst: Vec3) -> Vec3:
    d = v3sub(dst, src)
    hyp = math.sqrt(d.x * d.x + d.y * d.y)
    return Vec3(
        math.atan2(-d.z, hyp) * 57.29578,
        math.atan2(d.y, d.x) * 57.29578,
        0.0,
    )

def world_to_screen(w: Vec3, vm: list[float], sw: int, sh: int) -> Optional[tuple[float, float]]:
    cx = w.x * vm[0] + w.y * vm[4] + w.z * vm[8]  + vm[12]
    cy = w.x * vm[1] + w.y * vm[5] + w.z * vm[9]  + vm[13]
    cw = w.x * vm[3] + w.y * vm[7] + w.z * vm[11] + vm[15]
    if cw < 0.01:
        return None
    return ((sw * 0.5) * ((cx / cw) + 1.0), (sh * 0.5) * (1.0 - (cy / cw)))

class GameMemory:
    def __init__(self) -> None:
        self.pm: Optional[pymem.Pymem] = None
        self.client: int = 0
        self.off = Offsets()

    def attach(self) -> bool:
        try:
            self.pm = pymem.Pymem("cs2.exe")
            self.client = pymem.process.module_from_name(
                self.pm.process_handle, "client.dll"
            ).lpBaseOfDll
            self.off = load_offsets()
            return True
        except Exception as e:
            print(f"[!] Ошибка: {e}")
            return False

    def read(self, addr: int, fmt: str):
        try:
            size = struct.calcsize(fmt)
            buf = self.pm.read_bytes(addr, size)
            return struct.unpack(fmt, buf)[0]
        except Exception:
            return None

    def read_vec3(self, addr: int) -> Vec3:
        try:
            buf = self.pm.read_bytes(addr, 12)
            return Vec3(*struct.unpack("fff", buf))
        except Exception:
            return Vec3()

    def read_view_matrix(self, addr: int) -> list[float]:
        try:
            buf = self.pm.read_bytes(addr, 64)
            return list(struct.unpack("16f", buf))
        except Exception:
            return [0.0] * 16

@dataclass
class Player:
    addr: int
    health: int
    team: int
    origin: Vec3
    bones: int

@dataclass
class WorldState:
    local: int = 0
    local_origin: Vec3 = field(default_factory=Vec3)
    local_team: int = 0
    local_angles: Vec3 = field(default_factory=Vec3)
    view_matrix: list[float] = field(default_factory=lambda: [0.0] * 16)
    players: list[Player] = field(default_factory=list)

def read_world(mem: GameMemory) -> WorldState:
    ws = WorldState()
    if not mem.pm or not mem.client:
        return ws
    o = mem.off
    
    # Читаем локального игрока
    ws.local = mem.read(mem.client + o.dwLocalPlayer, "Q") or 0
    if not ws.local:
        return ws
    
    ws.local_origin = mem.read_vec3(ws.local + o.m_vecOrigin)
    ws.local_team = mem.read(ws.local + o.m_iTeamNum, "i") or 0
    ws.local_angles = mem.read_vec3(ws.local + o.m_angEyeAngles)
    ws.view_matrix = mem.read_view_matrix(mem.client + o.dwViewMatrix)

    ent_list = mem.read(mem.client + o.dwEntityList, "Q") or 0
    if not ent_list:
        return ws

    # В CS2 используется система чанков для списка сущностей
    for i in range(1, 64):
        # Читаем чанк (по 8 байт на указатель)
        chunk = mem.read(ent_list + 8 * (i >> 9) + 0x10, "Q")
        if not chunk:
            continue
        # Внутри чанка ищем сущность
        ent = mem.read(chunk + 120 * (i & 0x1FF), "Q")
        if not ent:
            continue
            
        hp = mem.read(ent + o.m_iHealth, "i")
        if hp is None or hp <= 0 or hp > 100:
            continue
            
        ws.players.append(Player(
            addr=ent,
            health=hp,
            team=mem.read(ent + o.m_iTeamNum, "i") or 0,
            origin=mem.read_vec3(ent + o.m_vecOrigin),
            bones=mem.read(ent + o.m_dwBoneMatrix, "Q") or 0,
        ))
    return ws

HEAD_BONE = 6

def bone_pos(mem: GameMemory, bones: int, bone_id: int) -> Vec3:
    if not bones:
        return Vec3()
    base = bones + bone_id * 0x20 # исправлен размер матрицы кости для CS2
    return Vec3(
        mem.read(base + 0x10, "f") or 0.0,
        mem.read(base + 0x14, "f") or 0.0,
        mem.read(base + 0x18, "f") or 0.0,
    )

class MOUSEINPUT(ctypes.Structure):
    _fields_ = [
        ("dx", wt.LONG),
        ("dy", wt.LONG),
        ("mouseData", wt.DWORD),
        ("dwFlags", wt.DWORD),
        ("time", wt.DWORD),
        ("dwExtraInfo", ctypes.POINTER(wt.ULONG)),
    ]

class INPUT(ctypes.Structure):
    class _I(ctypes.Union):
        _fields_ = [("mi", MOUSEINPUT)]
    _anonymous_ = ("i",)
    _fields_ = [("type", wt.DWORD), ("i", _I)]

INPUT_MOUSE = 0
MOUSEEVENTF_MOVE = 0x0001

def move_mouse(dx: float, dy: float) -> None:
    inp = INPUT()
    inp.type = INPUT_MOUSE
    inp.mi = MOUSEINPUT(int(dx), int(dy), 0, MOUSEEVENTF_MOVE, 0, None)
    ctypes.windll.user32.SendInput(1, ctypes.byref(inp), ctypes.sizeof(INPUT))

@dataclass
class AimConfig:
    enabled: bool = True
    fov: float = 8.0
    smooth: float = 0.35
    bone: int = HEAD_BONE
    vk: int = 0x02
    px_per_deg: float = 10.0

def do_aim(ws: WorldState, mem: GameMemory, cfg: AimConfig) -> None:
    if not cfg.enabled or not ws.local:
        return
    if not (ctypes.windll.user32.GetAsyncKeyState(cfg.vk) & 0x8000):
        return

    view = ws.local_angles
    best_ang: Optional[Vec3] = None
    best_d = cfg.fov

    for p in ws.players:
        if p.team == ws.local_team:
            continue
        target = bone_pos(mem, p.bones, cfg.bone)
        if target.x == 0.0 and target.y == 0.0 and target.z == 0.0:
            continue
        ang = calc_angle(ws.local_origin, target)
        dy = ang.y - view.y
        while dy > 180:  dy -= 360
        while dy < -180: dy += 360
        dp = ang.x - view.x
        d = math.sqrt(dy * dy + dp * dp)
        if d < best_d:
            best_d = d
            best_ang = ang

    if best_ang is None:
        return

    dy = best_ang.y - view.y
    while dy > 180:  dy -= 360
    while dy < -180: dy += 360
    dp = best_ang.x - view.x

    move_mouse(dy * cfg.px_per_deg * cfg.smooth, -dp * cfg.px_per_deg * cfg.smooth)

TRANSPARENT = "#010203"

class Overlay:
    def __init__(self, mem: GameMemory) -> None:
        self.mem = mem
        self.root = tk.Tk()
        self.root.title("overlay")
        self.root.attributes("-topmost", True)
        self.root.attributes("-fullscreen", True)
        self.root.configure(bg=TRANSPARENT)
        try:
            self.root.wm_attributes("-transparentcolor", TRANSPARENT)
        except tk.TclError:
            pass
        self.canvas = tk.Canvas(self.root, bg=TRANSPARENT, highlightthickness=0)
        self.canvas.pack(fill="both", expand=True)
        self.sw = self.root.winfo_screenwidth()
        self.sh = self.root.winfo_screenheight()
        self.root.after(10, self.tick)

    def tick(self) -> None:
        try:
            ws = read_world(self.mem)
            self.draw(ws)
        except Exception:
            pass
        self.root.after(10, self.tick)

    def draw(self, ws: WorldState) -> None:
        self.canvas.delete("all")
        if not ws.local:
            return
        for p in ws.players:
            if p.team == ws.local_team:
                continue
            head = bone_pos(self.mem, p.bones, HEAD_BONE)
            feet = Vec3(p.origin.x, p.origin.y, p.origin.z - 72.0)
            tp = world_to_screen(head, ws.view_matrix, self.sw, self.sh)
            bp = world_to_screen(feet, ws.view_matrix, self.sw, self.sh)
            if not tp or not bp:
                continue
            h = bp[1] - tp[1]
            if h <= 2 or h > self.sh:
                continue
            w = h * 0.5
            x1, x2 = tp[0] - w / 2, tp[0] + w / 2
            self.canvas.create_rectangle(x1, tp[1], x2, bp[1], outline="red", width=2)
            self.canvas.create_rectangle(x1 - 6, tp[1], x1 - 3, bp[1], fill="#333", outline="")
            hp_h = (bp[1] - tp[1]) * (p.health / 100.0)
            self.canvas.create_rectangle(x1 - 6, bp[1] - hp_h, x1 - 3, bp[1], fill="#0f0", outline="")
        self.root.update_idletasks()

    def run(self) -> None:
        self.root.mainloop()

def main() -> int:
    mem = GameMemory()
    print("[*] Ожидание запуска cs2.exe...")
    while not mem.attach():
        time.sleep(2)
    print(f"[+] Подключено. client.dll @ {hex(mem.client)}")

    cfg = AimConfig()
    overlay = Overlay(mem)

    def aim_loop() -> None:
        while True:
            try:
                ws = read_world(mem)
                do_aim(ws, mem, cfg)
            except Exception:
                pass
            time.sleep(0.002)

    threading.Thread(target=aim_loop, daemon=True).start()
    overlay.run()
    return 0

if __name__ == "__main__":
    sys.exit(main())