- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 505
- Реакции
- 12
Здарова, реверсеры. Глянул тут одну любопытную поделку на питоне, которую позиционируют как «vibecoded» триггер. По факту — это сборная солянка из нормальных наработок, которую не стыдно поковырять, если вы устали от детектных методов захвата экрана и палевного эмулятора мыши.
Основной сок тут в двух вещах:
Техническая начинка:
Важный нюанс по Vanguard:
Автор пишет, что сам не тестил на основе, и это правильно. Сигнатуры этого кода в паблике уже наверняка засвечены. Если будете юзать — меняйте логику работы с памятью или хотя бы перепишите структуры. В текущем виде это отличная база для обучения или создания своего приватного билда «для своих».
В целом, связка OBS Hook + GHUB Driver — это классика легитного читинга в Валоранте. Если прикрутить сюда нормальную рандомизацию таймингов и кастомный драйвер, можно жить довольно долго.
Интересно, как сейчас Vanguard триггерится на такие хуки захвата кадра, если dll не подписана валидным сертом.
Основной сок тут в двух вещах:
- Юзается ghub_device.dll для кликов. Это kernel-драйвер от логитеков, который Vanguard кушает гораздо охотнее, чем обычный SendInput. Шанс отлететь за «искусственный ввод» значительно ниже.
- Захват через GameCapture.dll. По сути, это хук в стиле OBS, который тянет кадры напрямую из процесса. Работает в эксклюзивном фулскрине и обходит многие стандартные проверки на скринкапчу.
Техническая начинка:
- Детекция по HSV (Hue, Saturation, Value). Есть ползунки для настройки под любой цвет обводки (пурпурный в приоритете).
- Обработка через OpenCV (если установлен) — это дает буст к скорости. Если нет, костылит через colorsys, но это для мазохистов.
- Настраиваемый FOV (радиус сканирования вокруг центра экрана).
- Reaction Delay — можно выставить задержку, чтобы не выглядеть как робот с реакцией 0 мс.
- Интерфейс на DearPyGui. Выглядит опрятно, не грузит систему.
Для тех, кто решит завести это чудо, не забудьте накатить либы:
Также рядом со скриптом должны лежать ghub_device.dll и GameCapture.dll, иначе магии не будет.
Код:
pip install mss keyboard pyautogui opencv-python numpy dearpygui
Важный нюанс по Vanguard:
Автор пишет, что сам не тестил на основе, и это правильно. Сигнатуры этого кода в паблике уже наверняка засвечены. Если будете юзать — меняйте логику работы с памятью или хотя бы перепишите структуры. В текущем виде это отличная база для обучения или создания своего приватного билда «для своих».
Код:
import os, sys, time, threading, colorsys, ctypes
from ctypes import *
import numpy as np
import dearpygui.dearpygui as dpg
# Optional imports with availability flags
try:
import cv2; HAS_CV2 = True
except ImportError: HAS_CV2 = False
try:
import win32api; HAS_WIN32 = True
except ImportError: HAS_WIN32 = False
try:
import win32gui; HAS_WIN32GUI = True
except ImportError: HAS_WIN32GUI = False
try:
import mss as mss_lib; HAS_MSS = True
except ImportError: HAS_MSS = False
try:
import keyboard as kb; HAS_KEYBOARD = True
except ImportError: HAS_KEYBOARD = False
try:
import pyautogui
pyautogui.PAUSE = 0
pyautogui.FAILSAFE = False
HAS_PYAUTOGUI = True
except ImportError: HAS_PYAUTOGUI = False
# Windows high-precision timer
try: ctypes.windll.winmm.timeBeginPeriod(1)
except: pass
# Screen center cached at startup
_user32 = ctypes.windll.user32
CENTER_X = _user32.GetSystemMetrics(0) // 2
CENTER_Y = _user32.GetSystemMetrics(1) // 2
SCREEN_W = _user32.GetSystemMetrics(0)
SCREEN_H = _user32.GetSystemMetrics(1)
# ─────────────────────────────────────────────
# GHUB KERNEL MOUSE DRIVER
# Drop ghub_device.dll next to this script.
# Much harder to detect than SendInput.
# ─────────────────────────────────────────────
class GHUBMouse:
def __init__(self):
self.found = False
dll_path = os.path.abspath("ghub_device.dll")
if not os.path.exists(dll_path):
print("[GHUB] ghub_device.dll not found — skipping.")
return
try:
self.lib = ctypes.CDLL(dll_path)
self.lib.device_open.restype = ctypes.c_int
self.lib.moveR.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_bool]
self.lib.moveR.restype = ctypes.c_int
if self.lib.device_open() == 0:
print("[GHUB] device_open() failed — is GHUB running?")
return
# Some builds expose mouse_up, some don't
self.has_mouse_up = False
try: _ = self.lib.mouse_up; self.has_mouse_up = True
except: pass
self.found = True
print("[GHUB] Kernel driver loaded.")
except Exception as e:
print(f"[GHUB] Load failed: {e}")
def click(self):
if not self.found: return False
try:
if self.has_mouse_up:
self.lib.mouse_down(1); time.sleep(0.01); self.lib.mouse_up(1)
else:
self.lib.mouse_down(1); time.sleep(0.01); self.lib.mouse_down(0)
return True
except Exception as e:
print(f"[GHUB] Click error: {e}"); return False
# ─────────────────────────────────────────────
# OBS GAME CAPTURE
# Drop GameCapture.dll next to this script.
# Works in exclusive fullscreen — hooks the
# game process directly like OBS does.
# Requires cv2.
# ─────────────────────────────────────────────
class GCImage(Structure):
_fields_ = [("width", c_int32),
("height", c_int32),
("pitch", c_int32),
("data", POINTER(c_uint8))]
class OBSCapture:
def __init__(self, window_name):
self.found = False
self.frame = None
dll_path = os.path.abspath("GameCapture.dll")
if not os.path.exists(dll_path):
print("[OBS] GameCapture.dll not found — falling back to mss.")
return
if not HAS_CV2:
print("[OBS] cv2 required for OBS capture — falling back to mss.")
return
if not HAS_WIN32GUI:
print("[OBS] pywin32 required for OBS capture.")
return
try:
self.lib = ctypes.WinDLL(dll_path)
self.lib.gc_create.argtypes = [c_int32, c_int32, c_int32, c_int32, c_char_p]
self.lib.gc_create.restype = c_void_p
self.lib.gc_get_frame.argtypes = [c_void_p, POINTER(GCImage)]
self.lib.gc_get_frame.restype = c_int32
self._img = GCImage()
hwnd = win32gui.FindWindow(None, window_name)
if hwnd == 0:
print(f"[OBS] Window '{window_name}' not found.")
return
self.handle = self.lib.gc_create(
SCREEN_W, SCREEN_H, SCREEN_W, SCREEN_H,
window_name.encode("utf-8")
)
if not self.handle:
print("[OBS] gc_create() failed.")
return
self.found = True
print("[OBS] Game capture online.")
except Exception as e:
print(f"[OBS] Init failed: {e}")
def get_frame(self):
"""Returns full BGRA numpy frame or None."""
if not self.found: return None
ok = self.lib.gc_get_frame(self.handle, byref(self._img))
if not ok or not self._img.data: return None
size = self._img.height * self._img.pitch
raw = string_at(self._img.data, size)
buf = np.frombuffer(raw, dtype=np.uint8).reshape((self._img.height, self._img.pitch))
return buf[:, :(self._img.width * 4)].reshape((self._img.height, self._img.width, 4))
# ─────────────────────────────────────────────
# SHARED STATE
# All config the GUI writes to, bot reads from.
# ─────────────────────────────────────────────
state = {
"running": False,
"fov_radius": 150, # pixels from center to edge of scan circle
"reaction_ms": 0, # artificial delay before firing (ms)
"trigger_key": "space", # keyboard key OR "MOUSE1"
"cooldown": 0.05, # min seconds between triggers
"hue_low": 277.0, # degrees 0-360
"hue_high": 320.0,
"sat_low": 0.320, # 0.0-1.0
"sat_high": 0.700,
"val_low": 106.0, # 0-255
"val_high": 255.0,
"use_ghub": False, # set True automatically if DLL found
"use_obs": False,
"obs_window": "",
"log": "Ready.",
}
state_lock = threading.Lock()
stop_event = threading.Event()
# Hardware singletons
ghub = GHUBMouse()
obs_capture: OBSCapture = None # created when obs_window is set
if ghub.found:
with state_lock:
state["use_ghub"] = True
# ─────────────────────────────────────────────
# INPUT FIRE
# Handles MOUSE1 vs keyboard keys,
# GHUB vs fallback backends.
# ─────────────────────────────────────────────
def fire_trigger():
with state_lock:
key = state["trigger_key"]
use_ghub = state["use_ghub"]
if key.upper() == "MOUSE1":
if use_ghub and ghub.found:
ghub.click()
elif HAS_WIN32:
# win32api fallback
win32api.mouse_event(0x0002, 0, 0) # MOUSEEVENTF_LEFTDOWN
time.sleep(0.01)
win32api.mouse_event(0x0004, 0, 0) # MOUSEEVENTF_LEFTUP
elif HAS_PYAUTOGUI:
pyautogui.click()
else:
if HAS_KEYBOARD:
kb.send(key)
elif HAS_PYAUTOGUI:
pyautogui.press(key)
# ─────────────────────────────────────────────
# BOT LOOP
# Runs on background thread.
# Captures FOV region, checks HSV circle mask,
# applies reaction delay, fires.
# ─────────────────────────────────────────────
def bot_loop():
last_trigger = 0.0
cached_fov = -1
circle_mask = None
with mss_lib.mss() as sct:
while not stop_event.is_set():
# Read state once per frame
with state_lock:
running = state["running"]
cooldown = state["cooldown"]
reaction_ms = state["reaction_ms"]
fov_r = state["fov_radius"]
use_obs = state["use_obs"]
hl = state["hue_low"] / 360.0
hh = state["hue_high"] / 360.0
sl = state["sat_low"]
sh = state["sat_high"]
vl = state["val_low"] / 255.0
vh = state["val_high"] / 255.0
if not running:
time.sleep(0.01)
continue
# Recompute circular mask only when FOV radius changes
if fov_r != cached_fov:
size = fov_r * 2
Y, X = np.ogrid[:size, :size]
circle_mask = (np.sqrt((X - fov_r)**2 + (Y - fov_r)**2) <= fov_r)
cached_fov = fov_r
size = fov_r * 2
# ── Capture ──────────────────────────────────────
img = None
if use_obs and obs_capture and obs_capture.found:
# OBS path: full frame, slice FOV region from center
full = obs_capture.get_frame()
if full is not None:
y1 = max(0, CENTER_Y - fov_r)
x1 = max(0, CENTER_X - fov_r)
img = full[y1:y1+size, x1:x1+size]
if img is None:
# mss fallback (borderless/windowed fullscreen)
region = {
"top": CENTER_Y - fov_r,
"left": CENTER_X - fov_r,
"width": size,
"height": size,
}
try:
shot = sct.grab(region)
img = np.frombuffer(shot.bgra, dtype=np.uint8).reshape((size, size, 4))
except Exception as e:
set_log(f"Capture error: {e}")
time.sleep(0.1)
continue
# ── Color detection ───────────────────────────────
# img is always BGRA shaped (H, W, 4)
detected = False
if HAS_CV2:
# Fast path: vectorised HSV conversion via cv2
# cv2 HSV: H→0-180, S→0-255, V→0-255
bgr = img[:, :, :3]
hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
lo = np.array([hl * 180, sl * 255, vl * 255], dtype=np.uint8)
hi = np.array([hh * 180, sh * 255, vh * 255], dtype=np.uint8)
cmask = cv2.inRange(hsv, lo, hi)
detected = bool(np.any(circle_mask & (cmask > 0)))
else:
# Slow path: per-pixel colorsys (no cv2 installed)
rgb = img[:, :, [2, 1, 0]] # BGRA → RGB
pixels = np.argwhere(circle_mask)
for (py, px) in pixels:
r, g, b = rgb[py, px] / 255.0
h, s, v = colorsys.rgb_to_hsv(r, g, b)
if hl <= h <= hh and sl <= s <= sh and vl <= v <= vh:
detected = True
break
# ── Fire ─────────────────────────────────────────
now = time.perf_counter()
if detected and (now - last_trigger >= cooldown):
if reaction_ms > 0:
time.sleep(reaction_ms / 1000.0)
fire_trigger()
last_trigger = time.perf_counter()
set_log(f"Triggered at {time.strftime('%H:%M:%S')}")
def set_log(msg):
with state_lock:
state["log"] = msg
try:
dpg.set_value("log_text", msg)
except: pass
# ─────────────────────────────────────────────
# GUI CALLBACKS
# ─────────────────────────────────────────────
def toggle_bot():
with state_lock:
state["running"] = not state["running"]
is_on = state["running"]
dpg.set_value("status_text", "● ACTIVE" if is_on else "● INACTIVE")
dpg.configure_item("status_text", color=[0, 220, 80] if is_on else [220, 60, 60])
dpg.set_item_label("toggle_btn", "Stop Bot" if is_on else "Start Bot")
def update_state(sender, app_data, user_data):
with state_lock:
state[user_data] = app_data
def on_hsv_change(sender, app_data, user_data):
update_state(sender, app_data, user_data)
update_preview()
def update_preview():
with state_lock:
h = ((state["hue_low"] + state["hue_high"]) / 2.0) / 360.0
s = (state["sat_low"] + state["sat_high"]) / 2.0
v = (state["val_low"] + state["val_high"]) / 2.0 / 255.0
r, g, b = colorsys.hsv_to_rgb(h, s, v)
dpg.set_value("color_preview", [int(r*255), int(g*255), int(b*255), 255])
def apply_obs_window(sender, app_data, user_data):
global obs_capture
window_name = app_data.strip()
with state_lock:
state["obs_window"] = window_name
if window_name:
obs_capture = OBSCapture(window_name)
with state_lock:
state["use_obs"] = obs_capture.found
dpg.set_value("obs_status",
"[✓] OBS capture active" if obs_capture.found
else "[✗] Window not found — using mss")
dpg.configure_item("obs_status",
color=[0,200,80] if obs_capture.found else [200,100,60])
# ─────────────────────────────────────────────
# GUI BUILD
# ─────────────────────────────────────────────
def build_gui():
dpg.create_context()
dpg.create_viewport(title="Triggerbot", width=450, height=680, resizable=False)
dpg.setup_dearpygui()
with dpg.theme() as global_theme:
with dpg.theme_component(dpg.mvAll):
dpg.add_theme_color(dpg.mvThemeCol_WindowBg, [18, 20, 28])
dpg.add_theme_color(dpg.mvThemeCol_FrameBg, [30, 33, 45])
dpg.add_theme_color(dpg.mvThemeCol_FrameBgHovered, [40, 44, 60])
dpg.add_theme_color(dpg.mvThemeCol_SliderGrab, [90, 150, 255])
dpg.add_theme_color(dpg.mvThemeCol_Button, [50, 80, 160])
dpg.add_theme_color(dpg.mvThemeCol_ButtonHovered, [70, 110, 210])
dpg.add_theme_color(dpg.mvThemeCol_Header, [40, 60, 120])
dpg.add_theme_color(dpg.mvThemeCol_HeaderHovered, [55, 80, 150])
dpg.add_theme_color(dpg.mvThemeCol_Text, [210, 215, 230])
dpg.add_theme_color(dpg.mvThemeCol_CheckMark, [90, 150, 255])
dpg.add_theme_style(dpg.mvStyleVar_FrameRounding, 6)
dpg.add_theme_style(dpg.mvStyleVar_GrabRounding, 4)
dpg.add_theme_style(dpg.mvStyleVar_WindowPadding, 12, 12)
dpg.add_theme_style(dpg.mvStyleVar_ItemSpacing, 8, 6)
dpg.bind_theme(global_theme)
with dpg.window(label="Triggerbot", tag="main_window",
no_close=True, no_move=True, no_resize=True,
width=450, height=680, pos=[0, 0]):
# ── Status ───────────────────────────────────────────
with dpg.group(horizontal=True):
dpg.add_text("● INACTIVE", tag="status_text", color=[220, 60, 60])
dpg.add_spacer(width=10)
dpg.add_text("Ready.", tag="log_text", color=[120, 125, 140])
dpg.add_separator()
dpg.add_spacer(height=4)
dpg.add_button(label="Start Bot", tag="toggle_btn",
callback=toggle_bot, width=-1, height=36)
dpg.add_spacer(height=6)
# ── Detection ────────────────────────────────────────
with dpg.collapsing_header(label="Detection", default_open=True):
dpg.add_spacer(height=2)
dpg.add_text(f"Screen center: ({CENTER_X}, {CENTER_Y})",
color=[120, 125, 140])
dpg.add_slider_int(
label="FOV Radius (px)",
default_value=state["fov_radius"],
min_value=5, max_value=600, width=220,
callback=update_state, user_data="fov_radius")
dpg.add_slider_int(
label="Reaction Delay (ms)",
default_value=state["reaction_ms"],
min_value=0, max_value=500, width=220,
callback=update_state, user_data="reaction_ms",
format="%d ms")
dpg.add_spacer(height=4)
# ── Trigger ──────────────────────────────────────────
with dpg.collapsing_header(label="Trigger", default_open=True):
dpg.add_spacer(height=2)
dpg.add_text("Key options: 'space', 'f', 'MOUSE1', 'ctrl', etc.",
color=[120, 125, 140])
dpg.add_input_text(
label="Trigger Key",
default_value=state["trigger_key"], width=130,
callback=update_state, user_data="trigger_key")
dpg.add_slider_float(
label="Cooldown (s)",
default_value=state["cooldown"],
min_value=0.01, max_value=2.0, width=220,
callback=update_state, user_data="cooldown",
format="%.3f s")
dpg.add_spacer(height=4)
# ── Hardware ─────────────────────────────────────────
with dpg.collapsing_header(label="Hardware", default_open=True):
dpg.add_spacer(height=2)
# GHUB
ghub_ok = ghub.found
ghub_label = "[✓] ghub_device.dll loaded" if ghub_ok else "[✗] ghub_device.dll not found"
dpg.add_text(ghub_label, color=[0,200,80] if ghub_ok else [180,60,60])
dpg.add_checkbox(
label="Use GHUB driver for MOUSE1",
default_value=ghub_ok,
callback=update_state, user_data="use_ghub")
dpg.add_spacer(height=6)
# OBS
obs_dll_ok = os.path.exists("GameCapture.dll")
obs_label = "[✓] GameCapture.dll found" if obs_dll_ok else "[✗] GameCapture.dll not found"
dpg.add_text(obs_label, color=[0,200,80] if obs_dll_ok else [180,60,60])
dpg.add_text("Enter game window title to enable OBS capture:",
color=[150,155,170])
dpg.add_input_text(
label="Window Name", hint="e.g. Counter-Strike 2",
default_value=state["obs_window"], width=240,
callback=apply_obs_window, user_data="obs_window",
on_enter=True)
dpg.add_text("[mss fallback active]", tag="obs_status",
color=[120,125,140])
dpg.add_spacer(height=4)
# ── HSV Color Range ──────────────────────────────────
with dpg.collapsing_header(label="HSV Color Range", default_open=True):
dpg.add_spacer(height=2)
dpg.add_text("Hue (0 – 360°)")
with dpg.group(horizontal=True):
dpg.add_slider_float(label="Low ##h",
default_value=state["hue_low"],
min_value=0, max_value=360, width=155,
callback=on_hsv_change, user_data="hue_low", format="%.1f°")
dpg.add_slider_float(label="High##h",
default_value=state["hue_high"],
min_value=0, max_value=360, width=155,
callback=on_hsv_change, user_data="hue_high", format="%.1f°")
dpg.add_text("Sat (0.0 – 1.0)")
with dpg.group(horizontal=True):
dpg.add_slider_float(label="Low ##s",
default_value=state["sat_low"],
min_value=0.0, max_value=1.0, width=155,
callback=on_hsv_change, user_data="sat_low", format="%.3f")
dpg.add_slider_float(label="High##s",
default_value=state["sat_high"],
min_value=0.0, max_value=1.0, width=155,
callback=on_hsv_change, user_data="sat_high", format="%.3f")
dpg.add_text("Val (0 – 255)")
with dpg.group(horizontal=True):
dpg.add_slider_float(label="Low ##v",
default_value=state["val_low"],
min_value=0, max_value=255, width=155,
callback=on_hsv_change, user_data="val_low", format="%.0f")
dpg.add_slider_float(label="High##v",
default_value=state["val_high"],
min_value=0, max_value=255, width=155,
callback=on_hsv_change, user_data="val_high", format="%.0f")
dpg.add_spacer(height=6)
with dpg.group(horizontal=True):
dpg.add_text("Preview (HSV midpoint):")
dpg.add_color_button(tag="color_preview",
default_value=[128, 0, 200, 255],
width=24, height=24)
update_preview()
dpg.add_spacer(height=4)
dpg.set_primary_window("main_window", True)
# ─────────────────────────────────────────────
# ENTRY
# ─────────────────────────────────────────────
if __name__ == "__main__":
missing = []
if not HAS_MSS: missing.append("mss")
if not HAS_KEYBOARD: missing.append("keyboard")
if missing:
print(f"[ERROR] Missing packages: {', '.join(missing)}")
print(f"Run: pip install {' '.join(missing)}")
sys.exit(1)
if not HAS_CV2:
print("[WARN] cv2 not installed — color detection will be slower.")
print(" Install with: pip install opencv-python")
threading.Thread(target=bot_loop, daemon=True).start()
build_gui()
dpg.show_viewport()
dpg.start_dearpygui()
stop_event.set()
dpg.destroy_context()
В целом, связка OBS Hook + GHUB Driver — это классика легитного читинга в Валоранте. Если прикрутить сюда нормальную рандомизацию таймингов и кастомный драйвер, можно жить довольно долго.
Интересно, как сейчас Vanguard триггерится на такие хуки захвата кадра, если dll не подписана валидным сертом.