Перейти к содержанию
  • записей
    98
  • комментариев
    109
  • просмотра
    6404

История о том, как я для юнити писал автосплитер

Авторизация  
partoftheworlD

263 просмотра

Начнем с того, что теперь я ненавижу юнити, так, что моей ненавистью можно питать пару крупных городов еще и останется.


Проблема возникла с тем, что у игры есть свои значения проверяющие загружена игра или нет, но получить к ним доступ через указатель оказалось невозможным. Перепробовав около 50 разных способов и потратив 1.5 недели, решил залезть в управление памятью юнити, возможно что-то интересно окажется там. Доков и исходников нет и поэтому - Реверсим, реврсим, вертим крутим и делаемся всякие непотребства с памятью и...

 

Бам, оказалось( возможно это чистое совпадение), но UnityPlayer использует статические адреса для "работы" с CFG.
CFG/CF это Control Flow Guard -  механизм защиты Windows, нацеленный на усложнения процесса эксплуатации бинарных уязвимостей в пользовательских и ядреных приложения.

 

Сам механизма проводит валидацию неявных вызовов, предотвращающая перехват потока исполнения, например переписывая таблицы виртуальных функций. Именно этим мы и воспользуемся, но для начала найдем максимум информации о CFG и его внутреннем устройстве.

 

Итак, когда игра не загружена то, адреса должны указывать на статические данные внутри UnityPlayer.dll, но после загрузки игры выделяться, например в куче. Зная это, можем приступать к поиску.

В итоге нашелся статический адрес указывающий на старшую часть указателя, который работает с CFG, когда игра находится в меню или загружается, то старшая часть равна 7FFX( X - значение от 0 до F), но когда игра загружена, то значение меняется на адрес кучи. Что-то типа:

Static - 7FFFDEADBEEF
Heap   - 01EFDEADBEEF

 

Значит берем старшую часть, уменьшаем её для более простого сравнения используя:
 

value & 0xFFF

В итоге, получаем значение которое можем засунуть для проверки в автосплитере, если игра не загружена, то значение равно от 4080 до 4095, но если игра загружена, то значение меньше 600, но на всякий случай, я указал:

 

value < 4080

 

И на этом все, на все про все у меня ушло где-то 2.5-3 недели, просто чтобы узнать состояние игры. В общем, было интересно и стало более понятно как юнити работает с памятью. 
Желаю всем подобных заданий, это ведь интересней, чем патрончики накручивать.

  • Плюс 2
Авторизация  


5 Комментариев


Рекомендуемые комментарии

Хм, интересно,  а можно ли таким макаром задетектить динамическую загрузку какой-либо сборки в C#... Надо будет потестить, спасибо за наводку.

Поделиться этим комментарием


Ссылка на комментарий

Если не секрет, что за игра на Unity и зачем узнавать состояние загрузки игры? Игра встроена в браузер или stand alone. Билд под mono или под il2cpp?

Для проверки состояния игры можно написать  очень простой скрипт из этого примера и внедрить его в готовый билд. Можно и скрипт чуть посложнее написать с проверкой загруженного индекса сцены и на нем уже активировать читы цепляя скрипты на gameObjects из иерархии или подгружая свои AssetBundle локально или удаленно

Поделиться этим комментарием


Ссылка на комментарий
8 часов назад, MasterGH сказал:

Если не секрет, что за игра на Unity и зачем узнавать состояние загрузки игры?

 

My Friend Pedro, состояние игры нужно, чтобы правильно работал внешний таймер, а именно удалял время между загрузками уровней.

 

8 часов назад, MasterGH сказал:

Билд под mono или под il2cpp?

ll2cpp

 

8 часов назад, MasterGH сказал:

внедрить его в готовый билд

Внедрять ничего нельзя, это одна из проблем, игра должна оставаться чистой, только чтение значений из памяти допускается.

 

8 часов назад, MasterGH сказал:

с проверкой загруженного индекса сцены

Делал такую проверку, при переходе между уровнями появляется загрузочный экран, который делится на 3 части, затемнение экрана, загрузка уровня, затемнение экрана. Флаг загрузки уровня нашел, а вот с затемнением такое не работает из-за чего возникает разница во времени, а на 50+ уровнях это очень сильно заметно.(+2-3 минуты)

Поделиться этим комментарием


Ссылка на комментарий
16 часов назад, partoftheworlD сказал:

Внедрять ничего нельзя, это одна из проблем, игра должна оставаться чистой, только чтение значений из памяти допускается.

 

Как вариант для Unity игр или для подобных движков. Разработчики то и дело пользуются подгрузкой ассетов - набором игровых файлов. Либо загрузка из локальной папки, либо по url. А это значит, что можно подгрузить свой ассет со своими сбилженными скриптами с собранной dll сборке, которая  вроде как может делать все, что хочешь в игре. Например, показать всю иерархию игровых объектов и название классов на основным объектах. А там уже и дело за малым. Создать еще один ассет и подгрузить его с читами. Не думаю, что тут античиты заработают, хотя все может быть.

 

Еще одна мысль это использовать софт для распознавания изображения и реакции на него. Sikulix, OpenCV... Например, увидели темный экран и потом он пропал, значит игра загрузилась... как-то так.

Поделиться этим комментарием


Ссылка на комментарий
12 минут назад, MasterGH сказал:

для распознавания изображения и реакции на него. Sikulix, OpenCV

 

Для этого нужно будет использовать OpenCV на чем-то компилируемом, иначе обработка в 15-20 кадров не подойдет.

 

14 минут назад, MasterGH сказал:

что можно подгрузить свой ассет со своими сбилженными скриптами с собранной dll сборке

А для этого надо знать C#

 

Единственный вариант остался, это найти все статические переменные в UnityPlayer в надежде, что какой-нибудь из них является индикатором загрузки уровней/передачи управления гг.

Поделиться этим комментарием


Ссылка на комментарий

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
×

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.