Категории: Предложка

Как я написал лаунчер и реверсил Total Immersion Racing

Как вы, наверное, помните, у нас есть предложка, куда вы можете присылать свои новости\работы\интересности. На этот раз наш подписчик @bioniclelover решил поделиться новой историей о реверс-инжиниринге в Total Immersion Racing.

Привет-привет! Надеюсь, вы еще помните меня и мою прошлую статью по поводу TiR (краткое название игры). Сейчас я немного к игре подошел с другой стороны и решил, что почему бы не вспомнить такое понятие как “реверс инжиниринг”. Статья может иметь ошибки и неточности, если гуру захотят меня поправить, то жду ваших комментариев 😉 К сожалению, некоторые моменты я уже подзабыл, поэтому прошу не бить.

Все началось с того, что я захотел сделать так, чтобы я мог через собственную dll подменить путь до путей файлов переводов (tman.dat и tlate.dat), тем самым в потенциале давая возможность использовать собственные файлы переводов (к примеру перевести на украинский). Сначала я нашел функцию, что возвращает const char * (ссылка на текст в языке С). Да, кстати, не уточнил, игра написана на C. Вернемся к функции. Вот как она выглядит.

У, страшно немного. Мне тоже. Еще страшнее было, когда у переменных названий не было, жуть. Благо я +- разобрался что где и когда. И так, мне абсолютно плевать на логику и параметры функции, не считая того факта, что возвращает функция const char *. Создал в Visual Studio проект для dll, язык C++. На форуме я нашел функцию для применения хука функции и воспользовался ею. И так, у вас наверно возник вопрос: “шо цэ такое хук функции?”

У каждой программы есть поток выполнения и он выполняет ASM-команды (команды Ассемблера, которые выполняет CPU), которые прописаны в виде байтов. У каждой такой команды есть свой неповторимый адрес и размер. Когда поток выполнения доходит до нужного адреса, dll перехватывает поток выполнения, выполняется функция в dll и происходит возврат обратно, откуда мы стырили поток выполнения, только чуть вперед (в зависимости от того какой кусок ASM-кода решили подменить), обычно на следующую ASM-команду.

В итоге я  смог подменить функцию целиком, все сработало как надо. Потом долго искал где же мне вставить подмену tman.dat файла и таки нашел.

Тут еще интереснее! Хукаем не функцию целиком, а конкретно команду под адресом 4e7e5e. Отлично!

Дальше я пытался найти место, где можно подменить папку с озвучкой. С этим как-то плохо пошло и временно забил, просто сидел и разбирался что, где и когда. Я нашел место, где грузятся заставочные анимации (в формате wmv) и как выбирается разрешение анимации.

Смотрите направо, прикольно, да?

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

Успех! Тут у нас все зависит от bool, которую получаем из функции. Дай-ка гляну… В смысле просто возвращает переменную?!

Вы только посмотрите сколько функций ее использует

И на этом моменте меня дернуло эту функцию хукнуть. Изначально там было undefined4 (функция возвращает переменную размером 4 байта), но в языке C нет bool’а. Логично предположить, что это какой-то самопал на базе того же int’а возможно. Не суть, в WinAPI есть 4-байтовый BOOL, сделаем вид, что его использовали в игре. Пишем функцию, которая бы просто возвращала значение 1 и… вуаля, красота. Привожу что было до и после.

Выбор машины до
Выбор машины после
В режиме гонки до
В режиме гонки после

Мало того, что теперь спидометр не растянут, так еще и машины в меню выбора нормальные. Красота! Потом вернулся к тому, что надо бы найти способ подменить папку с озвучкой. Целевой озвучкой стала немецкая (не знаю, просто захотелось). И я таки нашел!

Я тупо не понял, что здесь происходит. Я знал, что в этой функции происходит выбор папки, но я не понимал, что мне надо делать. Изначально я думал подменить функцию целиком, однако меня очень смущало undefined8 (const char * это 4 байта). Потом я посмотрел на ASM-код и допер, что вероятно в регистр EAX (написано, что переменная index, но анализатор вещь не идеальная) пишется адрес на текст “english” + индекс, который считается в данной функции.

Названия папок
Массив с названиями папок

Правда, я потом откопал массив, который на втором скриншоте. Вот он и используется, здесь хранятся const char *. Ну и все, подменяем команду по адресу 4afdd7 и дело в шляпе, у меня немецкая озвучка. Можно делать мод на язык. Однако dll сам ведь не подгрузится. Как говорится, здесь есть один нюанс: нужен инжектор dll. Опять-таки на просторах интернета нашел код, немного (совсем немного) переписал и моя dll подгружается и хукает функции! Инжектор я еще сделал на первых парах, его я делал не в последнюю очередь.

Однако я бы хотел еще вспомнить о том, что я делал в прошлой статье, – патчил exe для нужного соотношения сторон экрана. Я подумал “А почему бы не сделать программу, которая бы запускала игру и в ОЗУ писала необходимые значения переменных?” В своей голове я окрестил это лаунчером и погнал писать. Сначала он был очень неказистым, но я постарался сделать +- нормальную архитектуру приложения (надо бы один класс переименовать), потом занялся немного стилем и получилось это.

Лаунчер

Лаунчер все еще недоработан, надо еще сделать вывод окон с ошибкой, а мне лень пока что.

Сначала я разобрался как писать в ОЗУ нужные мне данные. В WinAPI есть для этого функция WriteProcessMemory. Замечательно. Но тут произошло самое непредвиденное. Я сломал игру. У меня во время гонки нет 3D-моделей, только UI и черный фон. Понял, что байты надо записывать задом-наперед, а не как это было в описании к видео. Я немного ошибся, когда переписывал, в итоге у меня картинка с 3D-моделями сужалась сверху и расширялась к низу и наоборот. Потом увидел опечатку, переделал и все заработало как надо.

Если хотите помочь с разработкой лаунчера, то тут исходный код. В планах теперь написать Mod API и Mod Loader, но я абсолютно не знаю, когда я это сделаю. Но когда-нибудь сделаю обязательно и напишу статью об этом. 😉

Спасибо за внимание!

Дима aka Roker2

P. S. Спасибо человеку, который меня направил в r0 Crew, там в свою очередь направили на h0x91B, а там меня тепло приняли и помогли понять суть Mod Loader’а и немного с Гидрой.

P. P. S. Ночью в процессе написания статьи я нашел этот видосик. Крут, переписал HUD (UI). Мне остается лишь копаться дальше. Я надеюсь, что все не зря.

Опубликовал
Victor Ghost