Перейти к содержанию

[GTA Vice City] Простой спавн машин


Рекомендуемые сообщения

Всем привет.

Сегодня я расскажу о том, как создавать нужный автомобиль с помощью CE в GTA Vice City.

Как и говорил partoftheworlD, это очень просто, но раз возникают вопросы, я решил написать небольшой гайд.

 

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

Поэтому выйдя на функцию обработки чита - мы найдем функции для создания автомобиля. Приступим.

 

Для начала вспомним несколько читов для создания автомобилей.

Я выбрал чит-код создания катафалка - THELASTRIDE , но так же можно использовать наш любимый чит создания танка - PANZER.

 

Собственно ввод кодов - это операция по сохранению текущего введенного символа в строку и последующая проверка получившейся строки на соответствие.

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

 

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

 

Выйдем в меню игры, введем чит-код THELASTRIDE и попробуем поискать подстроку TSALEHT (не забываем переворачивать чит-код) в игре:

Spoiler

P1.thumb.png.37bb0683b0f54fad934bbcc0412

 

Ура, мы нашли текст по адресу 00A0F94F. Не будем его запоминать, он нам не пригодится, а сразу посмотрим, что же творится в памяти.

Нажмем на адрес правой кнопкой мыши и выбираем Browse this memory Region.

Spoiler

P2.thumb.png.42815bada58dad30680497a38f2

 

В памяти сразу поднимемся на пару строк вверх, обычно строки длиннее чем мы искали:

Spoiler

P3.thumb.png.23caf0e48a82fad41a881ebfc64

 

Ура, видим часть введенного нами кода. Так же могут присутствовать и другие куски текста, например на скришоте я немного побегал перед вводом чит-кода.

Теперь мы видим, что в реальности строка ввода чит-кода больше чем мы ожидали, а её начало находится там, где присутсвуют первые символы DW DIRTSAL, т.е. по адресу 00A0F94A. Добавим этот адрес в табличку (размер строки вычислен эмпирическим путем - посчитал не нулевые байты):

Spoiler

P4.thumb.png.6d1ab64b9e78933bfca169a445b

 

P5.png.4513c8c2e4a3a233dc46696b00f60c67.

 

Теперь если в игре мы побегаем или введем другие чит-коды, увидим как они укладываются в памяти. 

 

Посмотрим же, что использует этот буфер - попросим CE найти всех, кто использует данный адрес при вводе чит-кода

Сначала жмем ПКМ на адресе в главном окне CE и выбираем Find out what accesses this address:

Spoiler

P6.thumb.png.3ecb741dd5b9fa98bec1e27e165

 

 

Теперь переключимся в игру и введем любое слово, например HELLOGHL. Этим мы отсеим инструкции, которые используют наш адрес при обычном вводе. В окне появились следующие инструкции, мы будем их игнорировать:

Spoiler

P8.png.530d681785c6192145cb334badd1cdd4.

 

Теперь введем чит-код на создание автомобиля - THELASTRIDE. Внимательно следим за окном с инструкциями, т.к. в процессе ввода у меня появились еще несколько инструкций, которые используют адрес, но не влияют на появление машины. После ввода последней буквы видим следующую картину:

Spoiler

P9.thumb.png.8e5684919d3da16feec9a18a6cb

 

Уже можно заметить несколько функций, выполняющихся один раз. Для того, чтобы отсеять лишние инструкции, попробуем ввести другой чит-код, не относящийся к созданию автомобилей, например LEAVEMEALONE:

Spoiler

P10.thumb.png.74f5b245595a506a5c10353594

 

Ура, из предыдущих инструкций у нас осталось одна - инструкция mov byte ptr [00A0F94A] по адресу 004AC84A. Давайте выделим её и нажмем Show disassembler, чтобы увидеть, где она выполняется:

Spoiler

P11.thumb.png.bd128596e8f18b2ba9932fecf5

 

Собственно мы видим некое условие, после которого в наш буфер записывает 0x20, он же 32 он же пробел и вызывается некая функция gta-vc.exe+AE7C0 с аргументом AC. Заочно можно нас поздравить, потому что мы нашли нужную нам функцию, осталось только убедиться в этом.

 

Попробуйте тем же способом найти чит-функцию для создания танка. Я её уже нашел, давайте посмотрим:

Spoiler

P12.thumb.png.d96a6f6ce880e4bba3448185cd

 

Видно, что функция находится немного в другом месте, но отличие состоит только в том, какой аргумент передается в функцию - push записывает в стек A2 , вместо AC. В остальном код условия идентичен и я предлагаю попробовать просто вызывать функцию gta-vc.exe+AE7C0 с разными параметрами.

 

Для вызова функции мы будем использовать AutoAssembe и функцию createthread.

Зайдем в AutoAssembler (откроем Memory Viewer, меню Tools - AutoAssemble) и набросаем следующий скрипт:

Spoiler

[ENABLE]
// код, который выполнится при включении скрипта

// выделяем память под нашу функцию, хватит и 64 байта
alloc(our_func, 64)

// начало нашей функции
// фактически просто копируем код из игры
our_func:
// записываем в стек AC, он же 172
push 000000AC
// вызываем некую функцию
call gta-vc.exe+AE7C0
// убираем из стека наш AC
pop ecx
// конец функции
ret


// создаем поток, который прыгнет на нашу our_func и выполнит код
createthread(our_func)

[DISABLE]
// код, который выполнится при выключении скрипта

// просто освобождаем память от нашей функции
dealloc(our_func)

 

 

Добавим его в таблицу через File - Assign to current cheat table и можно закрывать окно Auto assemble.

Скрипт выделяет в памяти игры 64 байта для себя, после чего записывает туда инструкции, которые мы скопировали из оригинальной игры и просит createthread выполнить их.

 

Обратите внимание, что аргументы в данную функцию передаются как push AC. В оригинальной игре после call мы можем заметить инструкцию pop ecx. Это значит, что функция не трогает стек и мы сам должны двигать его за ним (т.е. откатить push AC). Поэтому после функции выполняется pop и мы обязательно должны его скопировать, иначе ret будет пытаться вернуть поток не куда-то по адресу 0xAA123456, а по адресу 0x000000AC. Почему pop использует ecx? В данном случае - потому что левая пятка компилятора так решила и это ни на что не влияет (ecx спокойно можно заменить на eax и другие регистры).

 

Ура, скрипт в нашей таблице, давайте же активируем его! Смотрим на результат и...:

Spoiler

P13.thumb.png.075cdb4a7aac2fae6375e20a09

 

Наш скрипт вызвал чит-функцию создания катафалка! Наверное вы уже догадались, что если мы заменим push AC на push A2 мы увидим заспаунившися танк?

Spoiler

P14.thumb.png.2b903763a6c9e338b14c802ada

 

Получается, что AC - это катафалк, а A2 - танк. Поискав GTA Vice City Vehicle IDs, мы найдем, что действительно, A2 = 162 - это Vehicle ID танка, а AC = 172 - катафалк. Попробуем указать свой ID, один из списка, например 168 (такси). Передача аргумента превратится в push #168:

Spoiler

P15.thumb.png.8ee5ba5d10c662ea6ca3ad09e4

 

Можно сказать, что наш скрипт работает! Осталось вынести ID модели как переменную:

Spoiler

[ENABLE]
// код, который выполнится при включении скрипта

// выделяем память под нашу функцию, хватит и 64 байта
alloc(our_func, 64)
// выделяем память под переменную
alloc(our_vehicle_id, 4)

// объявляем нашу our_func как переменную,
// чтобы можно было вызывать createthread из другого скрипта
registersymbol(our_func)

// объявляем нашу our_vehicle_id как переменную,
// чтобы можно было обращаться из таблицы
registersymbol(our_vehicle_id)

// записываем начальное занчение
our_vehicle_id:
// sabre turbo
dd #206

// начало нашей функции
// фактически просто копируем код из игры
our_func:
// записываем в стек наш ID машины
push [our_vehicle_id]
// вызываем некую функцию
call gta-vc.exe+AE7C0
// убираем из стека наш AC
pop ecx
// конец функции
ret

[DISABLE]
// код, который выполнится при выключении скрипта

// удаляем информацию о функции
dealloc(our_func)
unregistersymbol(our_func)

// удаляем информацию о переменной
dealloc(our_vehicle_id)
unregistersymbol(our_vehicle_id)

 

 

Я удалил из скрипта функцию вызова потока, чтобы переместить её в отдельный скрипт:

Spoiler

[ENABLE]
createthread(our_func)

[DISABLE]

 

 

Теперь можно добавить в таблицу адрес our_vehicle_id, в который после записи скрипта будет записано число 206 (ID наикрутейшего Sabre Turbo).

Это число отвечает за то, что мы передаем в чит-функцию и меня его мы будем менять ID заспаунившегося автомобиля:

Spoiler

P16.png.983d25bd00d54824447b896b015d72f0

 

Результат:

Spoiler

P17.thumb.png.fee85d7b679c07fcea0f81a33f

 

И о проблемах :)

 

Скрипт фактически вызывает чит-код, поэтому мы начинаем слыть читерами, рейтинг в игре уменьшается и т.д. Это довольно легко обходится, т.к. если мы провалимся в функцию gta-vc.exe+AE7C0, перед самым ret есть две инструкции - add [gta-vc.exe+5B4F94],000003E8 и mov byte ptr [gta-vc.exe+60FB37],01 . Первая накидывает очки читерства (они хранятся отдельно) и устанавливает флаг - "этот парень использовал коды". Если их занопить - игра никогда не узнает о ваших проделках.

 

И вновь, потому что мы просто вызываем функцию чит-кода, она спаунит машины только на дорогу. Она находит ближайшую RoadPoint, прибавляет по оси Z несколько метров и спаунит авто. Поэтому создать авто прямо перед игроком так просто не получится.

 

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

Spoiler

P18.thumb.png.05628c7a7c78f64a8b9408bc74

 

О том, как обойти эти проблемы и вызывать уже конструкторы классов мы узнаем в следующем уроке :)

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

 

 

  • Понравилось 1
  • Плюс 13
Ссылка на комментарий
Поделиться на другие сайты

Спавн через Lua как-то так

Скрытый текст
Скрытый текст


function SpawnGameObject(id, name)
	autoAssemble([[
		globalalloc(spawnFunction1, $1000)
		spawnFunction1:
			push ]]..id..[[
			call gta-vc.exe+AE7C0
			pop ecx
			ret
		createthread(spawnFunction1)]])
	speak(name)
end

 

В консоли Lua ввести, что-то типа


SpawnGameObject(206, "Sabre Turbo ")

 

Я бы не сразу догадался искать перевернутый текст и не сразу бы догадался об инструкциях

add [gta-vc.exe+5B4F94],000003E8 и mov byte ptr [gta-vc.exe+60FB37],01

 

Интуиция мне подсказывает, что createthread() вызывать не всегда безопасно, например, когда другой поток выполняет код в той же области памяти. Я могу ошибаться, надо будет про потоки почитать. 

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

  • 2 недели спустя...
В 27.02.2017в17:17, MasterGH сказал:

Интуиция мне подсказывает, что createthread() вызывать не всегда безопасно, например, когда другой поток выполняет код в той же области памяти. Я могу ошибаться, надо будет про потоки почитать. 

Небезопасно только при использовании общих данных, не более: когда один поток читает, а другой пишет в ту же ячейку, но тут это вроде как не грозит, потому что инструкции сразу меняют значения, даже не считывая их.

Ссылка на комментарий
Поделиться на другие сайты

  • 1 месяц спустя...

У меня крашится;(

Автор, почему именно такой адрес? У меня на его месте байты XOR [адрес], eax это точно тот адрес? 

Почему номер машины кладется в стек, а в функции вызывается из esi ?

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, Trix said:

Автор, почему именно такой адрес?


Привет. Если внимать читательнее - мы выходим на адрес функции через ввод чит-кода.

Как только введеный чит-код совпадает с одним из списка - в строку ввода чит-кода записывается завершающий символ и вызывается нужная нам функция (её можно определить по передаваемому параметру A2).

Собственно тебе нужно выйти на следующие инструкции, там же ты и найдешь адрес функции:

Spoiler

P11.png

 

Если тебе нужно найти саму функцию в игре, но ты не хочешь ориентироваться на адрес модуля - провались внутрь самой функции (ПКМ на call - далее Follow) и через aobscan найди её в игре, после так же вызывай через call.

 

1 hour ago, Trix said:

Почему номер машины кладется в стек

 

Увы, под руками сейчас нет игры, но если ты провалишься в функцию, что увидишь, что она берет данные из стека и записывает их в esi.

По типу mov esi, [esp+4]

Изменено пользователем srg91
Ссылка на комментарий
Поделиться на другие сайты

1 час назад, srg91 сказал:

Привет. Если внимать читательнее - мы выходим на адрес функции через ввод чит-кода.

так понимаю, у нас разные версии игры, что меня затруднило((( 

 

У  меня затруднения с Find out what accesses this address:

получается вот такой список функций, пробовал неоднократно

 

Скрытый текст

13812243.png

Найти функцию, как у вас (которая сравнивает строку, как я понял) не удалось... Или она все же есть? Ибо в регионе памяти не удалось найти похожее сравнение 

 

 

 

1 час назад, srg91 сказал:

Если тебе нужно найти саму функцию в игре, но ты не хочешь ориентироваться на адрес модуля - провались внутрь самой функции (ПКМ на call - далее Follow) и через aobscan найди её в игре, после так же вызывай через call.

В общем, а если есть сам адрес функции, могу ли я обратно узнать кто его вызывает? 

 

 

 

 

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

Но у меня получилось найти его вручную отмотав достаточно приличный кусок кода, так что будет интересно узнать, почему у автора есть функция, а у меня ее нет) 

И да, гуглил, гуглил, а найти номера всех машин не удалось даже на сайтах разработчиков модов. Нет ли у кого ссылки?)
Спасибо за статью)

 

 

Изменено пользователем Trix
UPD
Ссылка на комментарий
Поделиться на другие сайты

36 минут назад, Trix сказал:

В общем, а если есть сам адрес функции, могу ли я обратно узнать кто его вызывает? 

 

Угу ставишь бряк и смотришь на вершину стека.

 

36 минут назад, Trix сказал:

И да, гуглил, гуглил, а найти номера всех машин не удалось даже на сайтах разработчиков модов. Нет ли у кого ссылки?)

Плюс в статье уже все есть.

В 26.02.2017 в 16:12, srg91 сказал:

Поискав GTA Vice City Vehicle IDs

 

Видимо гуглить не умеешь, первая ссылка в гугле http://www.gtamodding.com/wiki/List_of_vehicles_(VC)

 

 

Изменено пользователем partoftheworlD
Ссылка на комментарий
Поделиться на другие сайты

7 minutes ago, partoftheworlD said:

Плюс в статье уже все есть

 

спасибо, как раз об этом писал )

 

42 minutes ago, Trix said:

Найти функцию, как у вас

 

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

43 minutes ago, Trix said:

В общем, а если есть сам адрес функции, могу ли я обратно узнать кто его вызывает? 

 

Можешь, как написали выше. Но я так понимаю в твоем случае тебе это не нужно же? Я так понимаю ты хочешь просто вызвать эту функцию из своего проекта?

Если так - в своем проекте ты можешь искать функцию через маску байтов по типу aobscan или, если сложно, то ты можешь просто взять смещение модуля 'gta-vc.exe', прибавить к нему смещение функции (те самые +AE7C0 в моем случае) и делать call по этому адресу. Но смещение не будет работать на других версиях игры.

Поправьте, пожалуйста, если не прав.

Ссылка на комментарий
Поделиться на другие сайты

3 минуты назад, srg91 сказал:

Можешь, как написали выше. Но я так понимаю в твоем случае тебе это не нужно же? Я так понимаю ты хочешь просто вызвать эту функцию из своего проекта?

да, хотел бы вызвать функцию из проекта ради теста) 

Переписал инъектируемые байты, вышло вот это 

Скрытый текст

            byte[] asm = new byte[] {
            0x68, 0xB1, 0x00, 0x00, 0x00 , //          - push 000000B1 { 177 }
            0xE8, 0xE6, 0xE8, 0x5D, 0xFF,  //          - call gta-vc.exe+AE8F0
            0x59,                          //          - pop ecx
            0xC3                           //          - ret 
};

Однако, игра все так же крашится, в чем я мог допустить ошибку?

Ссылка на комментарий
Поделиться на другие сайты

  • 7 месяцев спустя...

Здравствуйте, а как выйти через активацию кода в игре на адрес\инструкцию в другой игре, коды через стрелочки на клаве...

Пример:

Скрытый текст

Коды на машины:
1) → → ↓ ←
2)→ ↑ → ↑
3) ← ← ← →
4) → → ← ←
5) ↓ ↓ → ←
6) → → → →
Код на персонажей:
7) ↓ ↓ ↓ ←

Коды отключаются только после перезапуска игры, и вводятся один раз за сессию, после перезапуска вводить по новой.

Изменено пользователем DieVis
Ссылка на комментарий
Поделиться на другие сайты

56 минут назад, DieVis сказал:

Коды отключаются только после перезапуска игры, и вводятся один раз за сессию, после перезапуска вводить по новой.

Обработчик событий клавиатуры возможно.

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

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

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