-
Автор темы
- #1
Приветствую !
В этом гайде я расскажу как сделать рабочий External на путончике пока что только zoomhack + weather changer.
Полагаю что у каждого есть опыт с Cheat Engine, и в этом гайде я не буду углубляться в его изучение.
И так в доте есть уже встроенные команды для реализации Zoomhack, но в матче конечно мы их менять не можем, но можем писать в адреса значений этих команд.
Нам понадобиться найти несколько адресов:
r_farz (Грубо говоря это лимит как бы на обзор , он должен увеличиваться пропорционально с дистанцией камеры чтобы не было черных нон-рендер зон)
dota_camera_distance (сама команда для изменение дальности камеры) - Кстати адрес дальности камеры статична, с этим заморачиваться не будем.
fog_enable (Включение/Выключение тумана, в >1400 дистанции камеры уже туман будет сильно мешать, а >2000 уже все будет покрыто под белый туман и поэтому надо его автоматически отключить при запуске)
cl_weather 0-9 (на выбор 10 погод, так же легко меняется через запись в память)
В итоге получаем 4 адреса которые нам надо заполучить.
Начинаем по порядку - r_farz:
Заходим в пробу героя, смотрим r_farz, в начале он всегда -1 но так как значений -1 много чтобы не крашнуло CE ставим другое желаемое
например 100000 и потом резко отсеиваем до 1 чтобы отсеять весь прочий мусор. И да r_farz это float не ошибайтесь.
Как только мы нашли нужный адрес смотрим, пробуем его менять через CE, попробуйте изменять его на 0, если обзор пропадет то значит все ок!
Дальше мы делаем Pointerscan на найденный нами адрес, клацаем по Pointerscan of this address и выставляем желаемые значения от 3 до 7. Желательно 3, больше и не надо, подождите пару минут и в результате сканирования выберите адрес с минимальным количеством смещений, для удобства.
Выходим из игры - Заходим обратно, открываем еще раз дотку на CEшке и заново ищем r_farz , найденный адрес вбиваем в результат сканирования, нажимаете
Pointer scanner - Rescan Memory removes pointers not pointing to the right address.
В появившемся окне на поле ввода адреса вставляем новый адрес r_farz и отсеиваем по новой.
В новых результатах ищем стабильный адрес желательно с одним смещением .И обязательно модуль должен быть client.dll для всех адресов которые мы будем искать, вам могут попастьсяtier0.dll, engine2.dll, server.dll -их не трогаем они опасны или не стабильны.
После того как нашли записывайте себе в конфиги чита (например у меня offsets.json):
[client.dll, базовый адрес, смещение] .
Принцип поиска для остальных такой же, ищете в консоли команду - меняется, отсеиваете находите адрес делаете Pointerscan, перезаходите и еще раз так по кругу и записываем в конфиги свои. Только учтите что у cl_weather не float а integer (4 bytes).
а у fog_enabled (0, 1) - byte
Приступим к коду
Ну код у каждого может быть индивидуальным но я приведу базовый пример. После такого как мы нашли адреса и смещения нам надо написать код для грамотной записи в память и еще один для нашей гуишки (интерфейса).
Начнем с самого главного - запись в память:
Записывать будем через библиотеку Pymem.
Код для записи вы будете реализовывать в интерфейсе ну если вы не ленивые можно ин на отдельном файле. В коде я привел пример использования.
События могут так же быть разные - прокрутка мыши, ползунка , по нажатии кнопки и т.п, но принцип одинаковый:
Event >mm.write_memory(cam_distance_address, cam_distance, "float")
если mm.read_memory(fog_enable_address, "byte") == 1: mm.write_memory(fog_enable_address, 0, "byte")
Event >mm.write_memory(r_farz_address, cam_distance*2, "float") - r_farz должен быть выше дистанции
Вам не обязательно копировать весь мой код, все можно сделать гораздо компактнее, но все то сделано для удобства, вы же можете игнорировать методы как calculate_pointer, read_pointer они вам вряд ли понадобиться . Ну окошко думаю тут уже по вашему вкусу, можете на tkinter, можете на PyQt5. Тут уже исходя только от вашей фантазии. Ну если вы прям хотите вы скажите и я вам отправлю код моей гуишки.
На этом все. Конечный результат выглядит так:
В этом гайде я расскажу как сделать рабочий External на путончике пока что только zoomhack + weather changer.
Полагаю что у каждого есть опыт с Cheat Engine, и в этом гайде я не буду углубляться в его изучение.
И так в доте есть уже встроенные команды для реализации Zoomhack, но в матче конечно мы их менять не можем, но можем писать в адреса значений этих команд.
Нам понадобиться найти несколько адресов:
r_farz (Грубо говоря это лимит как бы на обзор , он должен увеличиваться пропорционально с дистанцией камеры чтобы не было черных нон-рендер зон)
dota_camera_distance (сама команда для изменение дальности камеры) - Кстати адрес дальности камеры статична, с этим заморачиваться не будем.
fog_enable (Включение/Выключение тумана, в >1400 дистанции камеры уже туман будет сильно мешать, а >2000 уже все будет покрыто под белый туман и поэтому надо его автоматически отключить при запуске)
cl_weather 0-9 (на выбор 10 погод, так же легко меняется через запись в память)
В итоге получаем 4 адреса которые нам надо заполучить.
Начинаем по порядку - r_farz:
Заходим в пробу героя, смотрим r_farz, в начале он всегда -1 но так как значений -1 много чтобы не крашнуло CE ставим другое желаемое
например 100000 и потом резко отсеиваем до 1 чтобы отсеять весь прочий мусор. И да r_farz это float не ошибайтесь.
Как только мы нашли нужный адрес смотрим, пробуем его менять через CE, попробуйте изменять его на 0, если обзор пропадет то значит все ок!
Дальше мы делаем Pointerscan на найденный нами адрес, клацаем по Pointerscan of this address и выставляем желаемые значения от 3 до 7. Желательно 3, больше и не надо, подождите пару минут и в результате сканирования выберите адрес с минимальным количеством смещений, для удобства.
Выходим из игры - Заходим обратно, открываем еще раз дотку на CEшке и заново ищем r_farz , найденный адрес вбиваем в результат сканирования, нажимаете
Pointer scanner - Rescan Memory removes pointers not pointing to the right address.
В появившемся окне на поле ввода адреса вставляем новый адрес r_farz и отсеиваем по новой.
В новых результатах ищем стабильный адрес желательно с одним смещением .И обязательно модуль должен быть client.dll для всех адресов которые мы будем искать, вам могут попасться
После того как нашли записывайте себе в конфиги чита (например у меня offsets.json):
[client.dll, базовый адрес, смещение] .
Принцип поиска для остальных такой же, ищете в консоли команду - меняется, отсеиваете находите адрес делаете Pointerscan, перезаходите и еще раз так по кругу и записываем в конфиги свои. Только учтите что у cl_weather не float а integer (4 bytes).
а у fog_enabled (0, 1) - byte
Приступим к коду
Ну код у каждого может быть индивидуальным но я приведу базовый пример. После такого как мы нашли адреса и смещения нам надо написать код для грамотной записи в память и еще один для нашей гуишки (интерфейса).
Начнем с самого главного - запись в память:
Записывать будем через библиотеку Pymem.
memory_manager.py:
# Импортируем необходимые модули
import ctypes # Для работы с Windows API (чтение/запись памяти)
import psutil # Для получения информации о процессах
import struct # Для упаковки/распаковки данных
# Класс для управления процессом и памятью
class MemoryManager:
# Константа для полного доступа к процессу
PROCESS_ALL_ACCESS = 0x1F0FFF
def [B]init[/B](self, process_name):
# Сохраняем имя процесса
self.process_name = process_name
# Получаем PID процесса по его имени
self.pid = self.get_pid_by_name(process_name)
# Если процесс не найден — кидаем исключение
if not self.pid:
raise Exception(f"Процесс '{process_name}' не найден!")
print(f"[INFO] PID процесса '{process_name}': {self.pid}")
# Открываем процесс с полным доступом
self.process = ctypes.windll.kernel32.OpenProcess(self.PROCESS_ALL_ACCESS, False, self.pid)
if not self.process:
raise Exception("Не удалось открыть процесс!")
@staticmethod
def get_pid_by_name(name):
"""
Ищет PID процесса по его имени.
"""
for proc in psutil.process_iter(['pid', 'name']):
if proc.info['name'].lower() == name.lower():
return proc.info['pid']
return None
def list_modules(self):
"""
Возвращает список модулей (DLL) загруженных процессом.
"""
h_module_snap = ctypes.windll.kernel32.CreateToolhelp32Snapshot(0x00000008, self.pid)
if h_module_snap == -1:
raise Exception("Ошибка создания снимка модулей!")
# Структура для хранения информации о модуле
class MODULEENTRY32(ctypes.Structure):
[I]fields[/I] = [
("dwSize", ctypes.c_ulong),
("th32ModuleID", ctypes.c_ulong),
("th32ProcessID", ctypes.c_ulong),
("GlblcntUsage", ctypes.c_ulong),
("ProccntUsage", ctypes.c_ulong),
("modBaseAddr", ctypes.POINTER(ctypes.c_ubyte)),
("modBaseSize", ctypes.c_ulong),
("hModule", ctypes.c_void_p),
("szModule", ctypes.c_char * 256),
("szExePath", ctypes.c_char * 260)
]
# Создаем экземпляр структуры и устанавливаем ее размер
me32 = MODULEENTRY32()
me32.dwSize = ctypes.sizeof(MODULEENTRY32)
modules = []
# Перебираем модули процесса
if ctypes.windll.kernel32.Module32First(h_module_snap, ctypes.byref(me32)):
while True:
module_name = me32.szModule.decode()
module_base = ctypes.addressof(me32.modBaseAddr.contents)
modules.append((module_name, module_base))
if not ctypes.windll.kernel32.Module32Next(h_module_snap, ctypes.byref(me32)):
break
# Закрываем снимок модулей
ctypes.windll.kernel32.CloseHandle(h_module_snap)
return modules
def read_pointer(self, address):
"""
Чтение указателя по адресу.
"""
buffer = ctypes.create_string_buffer(8)
bytes_read = ctypes.c_size_t()
if ctypes.windll.kernel32.ReadProcessMemory(self.process, ctypes.c_void_p(address), buffer, 8, ctypes.byref(bytes_read)):
return int.from_bytes(buffer.raw, "little")
return None
def calculate_pointer(self, base_address, offsets):
"""
Рассчитываем адрес с учетом цепочки указателей.
"""
address = base_address
for offset in offsets:
address = self.read_pointer(address)
if address is None:
raise Exception("Ошибка чтения указателя")
address += offset
return address
def read_memory(self, address, data_type):
"""
Чтение значения из памяти по адресу.
"""
size = {"byte": 1, "int": 4, "float": 4, "double": 8, "str": 256}.get(data_type, 4)
buffer = ctypes.create_string_buffer(size)
bytes_read = ctypes.c_size_t()
if ctypes.windll.kernel32.ReadProcessMemory(self.process, ctypes.c_void_p(address), buffer, size, ctypes.byref(bytes_read)):
if data_type == "byte":
return buffer.raw[0]
elif data_type == "int":
return int.from_bytes(buffer.raw, "little")
elif data_type == "float":
return struct.unpack('f', buffer.raw[:4])[0]
elif data_type == "double":
return struct.unpack('d', buffer.raw[:8])[0]
elif data_type == "str":
return buffer.raw.decode(errors="ignore").rstrip('\x00')
return None
def close(self):
"""
Закрываем хендл процесса.
"""
ctypes.windll.kernel32.CloseHandle(self.process)
print(f"[INFO] Процесс '{self.process_name}' закрыт.")
# Пример использования с поддержкой смещения
if [B]name[/B] == "[B]main[/B]":
try:
# Создаем менеджер памяти для процесса notepad.exe
mm = MemoryManager("dota2.exe")
# Получаем список модулей и находим базовый адрес модуля notepad.exe
modules = mm.list_modules()
base_address = None
for module_name, module_base in modules:
if "dota2.exe" in module_name.lower():
base_address = module_base
print(f"[INFO] Модуль '{module_name}' найден по базовому адресу: {hex(base_address)}")
break
if not base_address:
raise Exception("Базовый адрес модуля не найден!")
#Оффсеты (пример, замени на свой) Так же можешь из конфига своего загрузить
offset = 0x10
final_address = base_address + offset
print(f"[INFO] Конечный адрес после смещения: {hex(final_address)}")
value = mm.read_memory(final_address, "float")
print(f"[INFO] Значение по адресу {hex(final_address)}: {value}")
# Закрываем процесс
mm.close()
except Exception as e:
print(f"[ERROR] {str(e)}")
События могут так же быть разные - прокрутка мыши, ползунка , по нажатии кнопки и т.п, но принцип одинаковый:
Event >mm.write_memory(cam_distance_address, cam_distance, "float")
если mm.read_memory(fog_enable_address, "byte") == 1: mm.write_memory(fog_enable_address, 0, "byte")
Event >mm.write_memory(r_farz_address, cam_distance*2, "float") - r_farz должен быть выше дистанции
Вам не обязательно копировать весь мой код, все можно сделать гораздо компактнее, но все то сделано для удобства, вы же можете игнорировать методы как calculate_pointer, read_pointer они вам вряд ли понадобиться . Ну окошко думаю тут уже по вашему вкусу, можете на tkinter, можете на PyQt5. Тут уже исходя только от вашей фантазии. Ну если вы прям хотите вы скажите и я вам отправлю код моей гуишки.
На этом все. Конечный результат выглядит так: