Замена и внедрение кода. На примере игры "Europa Universalis IV" |
Находим адрес денег в игре "Europa Universalis IV". Обычным поиском точного значения, тип "целое 4 байта", умножаем на 1000. Адрес меняется при перезапуске игры, указателей нет.
Нажимаем на адресе денег, правой клавишей мыши и в меню выбираем "Найти команды, которые обращаются по адресу". Ставим доступ "Чтение/Запись" и жмём кнопку "Старт".
Далее немного поиграйте в игре, достаточно выбирать разные провинции или войска, переключаемся на ArtMoney и получаем:
Мы нашли адреса команд, который читают количество денег. Нас интересует команда, которая выполняется чаще всего (3696 раз) mov ecx,[r15+00000820]. Сразу отметим, что в регистре r15 хранится адрес структуры игрока! Однако таких адресов несколько, по количеству игроков на карте. ID игрока хранится в той же структуре по адресу [r15+00000024]. Для игры на одного ID игрока можно вообще не проверять! Для игры на несколько человек, нужно найти какой из ID наш. Запускаем многопользовательскую игру. Находим ID нашего игрока = 01000027h, его легко найти из [r15+00000024], если известно количество денег из [r15+00000820]. Далее ищем это значение 01000027h (поиск точного значения 4 байта целое). И по всем найденным адресам делаем "Найти команды, которые обращаются по адресу". В итоге только у одного адреса находим обращения. Команда cmp byte ptr [rcx+00001E46],06 сравнивает 1 байт из ID. Полный ID 4 байта находится по адресу [rcx+00001E44]. Итого у нас есть два адреса 13FBCA820, по нему мы можем получить наш ID игрока из [rcx+00001E44], и второй 1400CB525, по нему можем получить адрес структуры игрока (из регистра r15). Структура содержит все параметры игрока! Сначала объявим глобальные переменные PlayerID и PlayerStr на странице "Внедрение кода". PlayerStr это адрес структуры игрока (8 байт для 64 битного процесса). Ставим галочки "Внедрить этот код" и "Только после успешной замены". Далее добавляем в таблицу первый адрес 13FBCA820, ставим тип "Команда ассемблера" и галочку "Заменить код". Пишем код для определения PlayerID. Делаем pop/push используемых регистров. В конце кода всегда пишем оригинальную команду, которую заменяем. Далее добавляем в таблицу второй адрес 1400CB525, ставим тип "Команда ассемблера" и галочку "Заменить код". Пишем код для определения адреса структуры PlayerStr. Также в конце кода не забываем оригинальную команду, которую заменяем! Добавляем в таблицу новый адрес, выбираем тип адреса "Адрес переменной/метки". Имя переменной пишем PlayerID, адрес пишем 0 (он добавляется к адресу PlayerID если нужно). Добавляем в таблицу ещё один адрес, имя переменной пишем PlayerStr, адрес пишем 0. Далее ставим тип "указатель" (потому что, это указатель на структуру) и указываем смещение 820h. Аналогично добавляем другие параметры игрока Stability (смещение 848), Prestige (смещение 968), Manpower (смещение A08), Legitimacy (смещение CC8) и т.д. Наш код готов. Код можно внедрить по кнопке "Внедрить и заменить все коды" или автоматически. После внедрения кода, нужно зайти в игру и тогда определится PlayerID и все адреса заработают. Однако после обновления игры адреса для внедрения могут измениться. Поэтому используем сигнатуры. Создадим две сигнатуры SigResource и SigPlayerID. Желательно использовать сигнатуры длиной минимум 20 байтов. Следует отметить, что в сигнатуре следует заменять команды переходов на пропуски ??, потому что команды переходов привязывают к конкретным адресам. Так для сигнатуры SigPlayerID меняем команды переходов je и jne на пропуски! Далее открываем в таблице наши адреса 13FBCA820, 1400CB525 и выбираем у них тип адреса "Адрес сигнатуры". Получаем таблицу, которая даже будет работать после обновления игры, если не изменится структура игрока. Если вам необходимо запустить свой поток в процессе, то добавьте в нужную строку кода директиву {thread}. |