diff --git a/deadlock/aimbot.py b/deadlock/aimbot.py index ee216ec..996fba8 100644 --- a/deadlock/aimbot.py +++ b/deadlock/aimbot.py @@ -89,6 +89,9 @@ class AimbotSettings: headshot_on_acquire: bool = True #: force headshots for 0.4s when locking on after a 2s gap + glow_override: bool = False + #: if ``True`` NOP the in-game glow check + class Aimbot: """Basic aimbot controller.""" diff --git a/deadlock/aimbot_gui.py b/deadlock/aimbot_gui.py index 39bcffa..68398fc 100644 --- a/deadlock/aimbot_gui.py +++ b/deadlock/aimbot_gui.py @@ -184,6 +184,13 @@ def _build_settings_frame(self, parent: ttk.Frame) -> None: ttk.Entry(hero_frame, textvariable=self.paradox_e_key, width=3).grid(row=hero_row, column=2, sticky="w") hero_row += 1 row += 1 + self.glow_override_var = tk.BooleanVar(value=self.settings.glow_override) + ttk.Checkbutton( + frame, + text="Bypass glow check", + variable=self.glow_override_var, + ).grid(row=row, column=0, columnspan=2, sticky="w") + row += 1 control_frame = ttk.Frame(frame) control_frame.grid(row=row, column=0, columnspan=2, pady=10, sticky="ew") self.start_button = ttk.Button(control_frame, text="Start", command=self.start) @@ -278,6 +285,8 @@ def _apply_widget_values(self) -> None: if self.paradox_e_key.get(): self.settings.paradox_e_key = ord(self.paradox_e_key.get().upper()[0]) + self.settings.glow_override = self.glow_override_var.get() + def start(self) -> None: """Start the aimbot.""" if self.is_running: @@ -321,6 +330,11 @@ def _initialise_and_run(self) -> None: """Initialise memory and run the aimbot.""" try: mem = DeadlockMemory() + if self.settings.glow_override: + try: + mem.toggle_glow_override(True) + except Exception as exc: + self.log_queue.put(f"Glow override failed: {exc}") self.bot = Aimbot(mem, self.settings) self.log_queue.put("Aimbot started successfully.") self.root.after(0, lambda: ( @@ -380,6 +394,11 @@ def stop(self) -> None: return if self.bot: + if self.settings.glow_override: + try: + self.bot.mem.toggle_glow_override(False) + except Exception as e: + self.log_queue.put(f"Error disabling glow override: {str(e)}") self.bot.stop() self.is_running = False diff --git a/deadlock/memory.py b/deadlock/memory.py index 7da9799..a2431a4 100644 --- a/deadlock/memory.py +++ b/deadlock/memory.py @@ -3,7 +3,7 @@ """Thin wrapper over :mod:`pymem` for reading Deadlock game memory.""" from dataclasses import dataclass -from typing import Dict, Tuple +from typing import Dict, Tuple, Optional import pymem @@ -12,6 +12,14 @@ from . import mem_offsets as mo import offset_finder +# Pattern to locate the glow check conditional in client.dll +GLOW_PATTERN = bytes.fromhex( + "0F 85 70 02 00 00 44 0F 11 54 24 58 C7 44 24 68 FF FF 7F FF " + "48 8B CB C7 44 24 6C FF FF 7F FF 48" +) +GLOW_PATCH = b"\x90" * 6 +GLOW_ORIGINAL = bytes.fromhex("0F 85 70 02 00 00") + @dataclass class Offsets: @@ -34,6 +42,8 @@ def __init__(self, process: str = "deadlock.exe") -> None: self.pm.process_handle, "client.dll" ).lpBaseOfDll self.offsets = self._read_offsets() + self._glow_addr: Optional[int] = None + self._glow_original: bytes | None = None def _read_offsets(self) -> Offsets: """Read offsets via :mod:`offset_finder`.""" @@ -144,3 +154,32 @@ def read_entity(self, index: int) -> Dict: "hero": hero_id, "aim_angle": aim_angle, } + + # Glow override ----------------------------------------------------- + def _find_glow_address(self) -> Optional[int]: + module = pymem.process.module_from_name( + self.pm.process_handle, "client.dll" + ) + data = self.pm.read_bytes(module.lpBaseOfDll, module.SizeOfImage) + idx = data.find(GLOW_PATTERN) + if idx == -1: + return None + return module.lpBaseOfDll + idx + + def toggle_glow_override(self, enable: bool) -> bool: + """Enable or disable the glow check NOP patch.""" + + if self._glow_addr is None: + self._glow_addr = self._find_glow_address() + if self._glow_addr is None: + return False + + if self._glow_original is None: + try: + self._glow_original = self.pm.read_bytes(self._glow_addr, len(GLOW_PATCH)) + except pymem.exception.MemoryReadError as e: + print(f"Failed to read glow bytes: {e}") + self._glow_original = None + patch = GLOW_PATCH if enable else self._glow_original + self.pm.write_bytes(self._glow_addr, patch, len(patch)) + return True