-
Постов
1 635 -
Зарегистрирован
-
Посещение
-
Победитель дней
55
Тип контента
Профили
Форумы
Загрузки
Блоги
Весь контент keng
-
Путей достаточно большая куча - смотря что ты подразумеваешь под этим читом. По сути, интеллект ботов сводится к здоровому циклу, который заставляет их бегать туда-сюда и реагировать на обстановку (например, если они заметят тебя). Выйти на этот цикл можно: 1. Через функцию стрельбы. 2. Через функцию нанесения урона. 3. Через функцию изменения координат при перемещении. 4. Найдя адрес здоровья врага и функцию, его читающую. И так далее. Что потом делать? Или просто писать фильтры (стрелять можешь только ты, бегать можешь только ты и так далее), или реверсить весь цикл и смотреть, что происходит. Например, можно найти такой кусок кода: if(isPlayerDetected) { StartAlarm(self); FireAtWill(Player); } А при этом когда бот умирает, то происходит вот это: if(self.Health <= 0) { self.isDead = 1; DropCurrentWeapon(self); AnimateDeath(self); } Соединяем это и: if(isPlayerDetected) //Если заметили игрока { self.isDead = 1; //Ставим себе флаг, обозначающий что мы мертвы DropCurrentWeapon(self); //Выкидываем оружие AnimateDeath(self); //Анимируемся //StartAlarm(self); //Тревогу не вызываем //FireAtWill(Player); //Стрелять не начинаем } Такое называется "medusa hack" - в честь одной из сестёр горгон греческой мифологии. Что делает? Всё просто - когда враг тебя замечает и пытается отреагировать (начать стрелять в тебя, поднять тревогу) - он просто умирает. Ещё можно просто попробовать найти нужные значения в структуре игрока - заметил он тебя или нет, поднял тревогу или нет, есть ли у него оружие или нет и так далее.
-
Привет! Всё верно, но это не совсем бессмертие. По факту, происходит такое: 1. Есть инструкция, которая постоянно (несколько раз в секунду) читает адрес здоровья (только твой или ещё чей-то - неизвестно). 2. Ты пишешь скрипт, который помимо чтения записывает именно в твой адрес здоровья (при помощи указателя) какое-то большое число. Да, с виду это будет выглядеть, как бессмертие, но бессмертие - это невозможность нанести тебе урон, а функцию нанесения урона ты не отключал, так что если ты записываешь часто-часто 100 в адрес здоровья, а игра тебя ранит на 101 - ты умрёшь. Поэтому самый верный вариант - ставить брейкпоинт на запись (тем самым ты попадёшь как раз на инструкцию, которая ранит игрока) и отключить её.
-
У тебя есть адрес начала сканирования (address base модуля), адрес конца сканирования (address base + size модуля) и адрес текущего байта для сравнения. Вот собственно этого и достаточно, чтобы прогресс бар показывал верные значения. Правда, сканирование происходит достаточно быстро (при использовании хорошего алгоритма), так что смысла в этом не много. Для начала укажи язык, на котором пишешь.
-
В любом случае, у меня эта проблема решилась запуском программы от имени администратора (т.е. с его правами).
-
Молодец! Здорово, что всё получилось.
-
Ящитаю, что ты её занопил в инстансе дллки для конкретно процесса игры, а остальные программы будут подгружать себе новую.
-
Дык а как мы тебе это проверим-то? Если у тебя работает - значит всё ок.
-
Говоришь, что если окно делает MouseLeave(), или если Rectangle окна игры не содержит координат мыши (ага), то меняешь курсор принудительно. Т.е. если винда хочет нарисовать курсор за пределами игрового окна - что-то типа SetCursor(), файл курсора можно взять прямо из ресурсов игры. Или найди событие, отвечающее за смену курсора - отладь его при переходе указателя из окна игры в рабочий стол, ну и отключи нафиг смену указателя на текущий виндовый. Правда, нафига такие костыли? Короче, хук на GetMessage, там проверка на [вот это], если она проходит - то [вот это]. Не то, чтобы офигеть, как оптимально, но просто в реализации и работать будет.
-
Имхо (не в обиду), сидеть и как обезьянка переписывать код из видеоуроков "чтобы было так же" - фиговый подход. Разберись, как работает трейнер с точки зрения логики (алгоритмически), а затем уже выясни, как реализуется та или иная часть алгоритма на выбранном тобой языке. Мы можем тебе подсказать, "как надо написать код", но вот почему именно так - мало кто станет заморачиваться.
-
Ну да, мы об одном и том же говорим, просто с разных сторон. Я стараюсь не пользоваться указателями вообще, т.к. есть вероятность, что даже если игра будет одинаковой версии - на разных компьютерах указатель может не работать. Не знаю, может просто вбилось в голову - я не выяснял.
-
Аобскан актуален для поиска функции, при чём тут id или указатели? Указатель не всегда надёжен тем, что в некоторых ситуациях он не работает, а вот id работает хотя бы в рамках текущего патча игры.
-
Суть сигнатуры в том, что она должна указывать на первый байт нужной команды. Переходишь в оле в окно кода, жмёшь ctrl+g, вбиваешь адрес инструкции и копируешь байты нужной инструкции и ниже (потому что определённая последовательность команд уникальна, в отличие от одной команды, которая может встречаться в коде много раз). PS: "Я делаю сигнатуры при помощи оли" - не совсем корректно, потому что сигнатуры делает не сама оля, а плагин для неё.
-
Есть отличная от нуля вероятность в будущем наткнуться на эту же тему и перечитывать, перечитывать, перечитывать!!!!11111
-
Так в том вся и прелесть! В игре есть функция DealDamage() - НанестиУрон(), аргументом которой служит структура "Player" - "Игрок". Вот как оно выглядит: struct Player //Структура "Игрок" { int Team; //Поле, хранящее команду игрока. 0 для союзников, 1 для врагов, к примеру float Health; //Поле, хранящее текущее здоровье игрока string Name; //Поле, хранящее имя игрока } void DealDamage(Player p) { //Функция нанесения урона. В аргументах принимает структуру Player if(p.Health > 0) { //Если здоровье игрока больше нуля p.Health = p.Health - 10; //Вычитаем из здоровья десяточку } } Теперь представь, что есть игровое поле и две команды - наша и не наша, по два игрока в каждой: Команда 0: Игрок А, Игрок Б Команда 1: Игрок В, Игрок Г А вот, какие у этих игроков будут структуры: Player { Team = 0; Health = 100; Name = "Vasya" } Player { Team = 0; Health = 100; Name = "Petya" } Player { Team = 1; Health = 100; Name = "Grisha" } Player { Team = 1; Health = 100; Name = "Dima" } Теперь представим, что Дима стреляет в Васю. Вызывается функция: DealDamage(p); Здесь p - адрес структуры Васи, потому что в него стреляют и ему наносится урон. По логике, наши от врагов отличаются только одним полем - полем Team. Вот мы берём и пишем скрипт: HackedDealDamage(Player p) { if(p.Health > 0) { //Если здоровье больше нуля if(p.Team != 0) { //И ранят игрока НЕ нашей команды (наша - 0) p.Health = p.Health - 10; //Наносим урон! } } } Вот, типа того. Функции на самом деле до лампочки, кто в кого стреляет, а мы просто берём и слегка её меняем, заставляя ранить только тех, кто не в нашей команде. Сравнивать же можно что угодно - такое вот поле Team, или какой-нибудь уникальный идентификатор игрока (ID), или же вообще адрес его здоровья (через указатель). Т.е. игра ВСЕГДА отличает игрока, его союзников и врагов - то есть ВСЕГДА будет какой-то уникальный признак, который и надо искать в структуре. Надеюсь, начинает проясняться. Ramil, главное, не надо сидеть и тыкать пальцем в небо, надеясь что оно вдруг возьмёт и заработает - лучше приводи конкретные примеры того, что именно тебе не ясно. Вопрос вида "Как мне написать скрипт?" слишком широк и абстрактен, чтобы так вот взять и ответить - не бывает универсальных решений, надо рассматривать конкретику.
-
Попробую оттолкнуться от твоих же скриншотов. Итак: 1. Ты нашёл адрес здоровья своего игрока - 0x3590632С. 2. Поставил бряк, получил инструкцию: MOV [EDI+10],EAX Что инструкция делает? Она просто кладёт в адрес здоровья ([EDI+10]) новое его значение, хранящееся в EAX. Но фишка вся в том, что при этом в EDI может быть много разных значений, т.е. это структура: struct Player { string Name; //Имя, например, "keng" float Health; //Здоровье, например, 100 } Вот и получается, считай, [Player+10], а 0x10 - смещение до поля Health в структуре. Если взять найденный тобой адрес, то получается: Health = 0x3590632С; Player = 0x3590632С - 0x10 = 0x3590631С; Вот, собственно, и выходит, что когда у тебя в регистре EDI лежит 0x3590631С, это значит что пытаются ранить твоего игрока. Пишешь скрипт: CMP EDI,0x3590631С JNE back MOV [EDI+10],EAX JMP back Что он делает, построчно: CMP EDI,0x3590631C Зная, что в EDI у нас лежит адрес начала структуры (как нашего игрока, так и врагов), а здоровье находится по смещению 0x10 от этого начала ([EDI+10]), то мы сравниваем (CMP = compare = англ. сравнить) содержимое регистра EDI и адрес начала структуры нашего игрока. После операции сравнения в процессоре устанавливается определённый флаг, сигнализирующий о том, равны ли (или нет) значения. JNE back JNE = jump if not equal = англ. прыжок, если не равно - одна из команд условного перехода. Прыжок выполняется тогда, когда последняя операция сравнения дала результат "не равно". В противном случае, процессор пропускает выполнение этой команды и послушно топает выполнять следующую. MOV [EDI+10],EAX MOV = move = англ. переместить - команда копирования из A в Б ("mov Б,А", "mov куда,что"). Банально и просто копирует значение здоровья, которое хранится в EAX, в поле структуры игрока, начало которой хранится в EDI. Получается примерно так: Player.Health = EAX; Где Player - структура (EDI), Health - поле этой структуры, хранящее здоровье ([EDI+10]). Что у нас остаётся? JMP back JMP = jump = англ. прыжок - команда безусловного перехода. Натыкаемся - управление переходит на адрес, указанный после команды. Кстати, back - это адрес команды игрового кода, следующей сразу после MOV [EDI+10],EAX. Т.е. это инъекция получается. Дык вот, к чему я это всё. Как тебе правильно подсказал ARM4ND0 в [17-м] посте, тебе надо найти разницу между твоей структурой и вражеской. Что-то типа: struct Player { int TeamID; //Идентификатор принадлежности к той или иной команде игроков string Name; float Health; } Найти такой идентификатор можно всегда, т.к. сама игра всегда знает, кто в кого стреляет и кто какой команде принадлежит. Раз это знает игра - это можно выяснить. Только вот в скрипте придётся сравнивать не EDI с адресом структуры игрока (это вообще не совсем правильно, т.к. игра может использовать DMA и адрес будет каждый раз новый), а этот самый id. Допустим, что id в структуре находится по смещению 0x14 и наш игрок имеет id = 5, а враги - id = 7, тогда вместо: CMP [EDI+10],0x3590632С Надо будет сделать: CMP [EDI+14],5 Т.е. на Си это выглядело бы примерно так: if (SomePlayer.ID == 5) { //Если id в структуре = 5 (т.е. это наш игрок) return; //Просто выходим } else { //Иначе DealDamage(SomePlayer); //Наносим урон } return; //И только после этого выходим PS: Можно писать как: CMP [EDI+10],0x3590632С Так и: CMP EDI,0x3590631С Почему именно - это будет вопросом на самостоятельное изучение.
-
Если можешь идентификатор найти - делай через него, если нет - через указатель. Это дело вкуса и умений исключительно.
-
Дополню предыдущий пост, если не найти разницу в структурах между игроком и врагом, то можно сравнивать регистр, хранящий в момент выполнения инструкции адрес здоровья того, кому наносится урон, с указателем. Это менее надёжный вариант, но более простой в реализации.