geek Игры story 

Как взломать вампира или История одного нубохака

Пролог

Пару лет назад на просторах интернета столкнулся с многообещающей игрой с фурри-проном в вампирской тематике. Игра называлась (и называется) “Vampire Life”. Вампирскую тематику я люблю, рпг уважаю, название намекает на некий симулятор, что тоже неплохо, а вот фурри прон мне заходит ситуативно, т.к многие автора плохо видят границу с зооеблей. Пожалуй, решающим аргументом в пользу скачивания стала необычная рисовка: мультяшная, будто рисовали кисточкой, без нарочитого нарушения пропорций тел и черт лица, чем нынче грешат (грешили и будут грешить) многие ленивые художники называя это “авторским стилем”. В описании на торрентах создатель честно предупредил что в игре присутствует гринд… нет, не так - много гринда, и это несколько настораживало, но я все же решил рискнуть, в конце концов - гринд гринду рознь, и как показало время страхи были не беспочвенными.

Часть 1: Суть игры и мотивация к взлому

Сама игра выполнена на (в?) рпгмэйкере, управление интуитивное, уже в то время (пару лет назад)  в игре большинство стоковых ассетов было заменено, что делало визуал более свежим, приятным и приближало его к сеттингу. Сам протагонист - вампир, который проснулся в своем “логове” (на деле - грязной пещере), будучи голым, нищим и потерявшим всю свою силу, навыки и память (если таковые были) за время сна. Клише конечно, но, будем откровенны, большинство сюжетных ходов было изобретено еще в античные времена, так что на данный момент все зависит главным образом от авторской подачи. Вампир знакомится со своей верной, но бестолковой слугой, с жителями поселения которое находится на выходе из логова и решает зарабатывать на жизнь отловом и продажей в рабство/на опыты фурри-розбійників (называемых в игре морфами), что в обилии обитают в тамошних местах, параллельно поебывая тех самых фурри, по возможности не обходя стороной и обычных неписей.Игра обладает множеством механик: потребности (еда, вода, сон, иммунитет), шмотки и оружие, их заточка, крафт, отстройка логова, отношение с неписями, прокачка навыков, зелья, артефакты и т.д., что, хоть и может крепко увлечь на первых порах, в дальнейшем становится рутиной и источником необходимости гриндить для получения новых элементов прогрессии  все больше и больше (в оффлайн игре!).С первых секунд игры появляется ощущения что тебя троллят.., нет - откровенно издеваются. Причем не как над персонажем, а как над игроком, и в дальнейшем эти ощущения только усиливаются. Регулярно возникают игровые ситуации, которые требуют значительной прокачки (явно больше чем может иметь игрок попавший в них на старте) или метаинформации, и в случае провала значительно тормозят прогресс игры (еще больше гринда). Самого гринда много: мало лута, мобы имеют рандомные статы, требования по ресурсам для прогрессии значительные. И по мере самой прогрессии только растут. При таких вводных очевидно, что накрутить себе нужных параметров условным артмани становится удобным решением для пропуска дрочи (в плохом смысле), и переходу непосредственно к новой порции контента. И тут меня ждал сюрприз: разработчик озаботился защитой от желающих срезать углы.

Часть 2:  Взлом начинается

Так как никакие попытки найти нужные мне значения с использованием тулзов проде читэнжина или артмани не увенчались успехом (и я позже поясню почему), была предпринята попытка модификации сейв файла. Благо что движок популярный - онлайн эдиторы присутствуют, а сам сейв должен являть собой сырой JSON (в теории). В реальности, меня в этот раз постигла неудача - онлайн тулза для модификации сохранений упорно рапортовала об ошибке чтения. Решил заглянуть в сам файл и поглядеть что там не так, и таки что я там вижу? Строка из букв разных кейсов, крайне похожая на нечто заэнкоженное в Base64. Но увы, походить не значит являться (АУФ!) - снова неудача. К тому моменту мной уже плотно овладел азарт, мне было пофиг на геймплей, я хотел решить этот пазл, и очевидно низкий технический уровень разработчика, который просматривался сквозь декорации игры давал надежду что у меня получится. Не можем прочитать сейв? Тогда бы почему не открыть сам проект?Ищу в стиме Rpgmaker MZ, смотрю на цену, вспоминаю что я далеко не самый состоятельный человек в нищей восточноевропейской стране, и отправляюсь в зеленый стим. Ставлю и вылечиваю Мэйкер, создаю новый проект и копирую в него ресурсы из игры. Чуда не произошло - ресурсы не читаются. Открываю файлы ресурсов - там те же закодированные строки заместо джейсонов, как и в сейвах. Т.к чудес очевидно не бывает, и игра все-же должна как-то уметь читать свои же ресурсы, то она явно хранит в себе некий декриптор или декодер который превращает буквенное месиво в джейсон. Пришла пора лезть в код.

1
|YobwRAlgJiTiBcYBcCmBnBYA0YDu0EAs4AGLfJCAc33VhMSQA8EBlCALyTgEYA2LAIwCGAYwDWFAE4B7AK4A7GLAAsWAGZS5CAGIj08AEpaA+gGkJg;>	2 * v
s£jIA2SCUflIKlwRMz0mcMAB0vw4ACYAXQAVVAQfPyJArzkIOXUAQh8IYABnQLdkJn9PCICQsLyomLjE5LSMrAgUAFlBORlBKlYOOFUmlCQAXwxwaE9kNBysXCgCYlJyKho6LJZ2PS4VMCExSVkFOGXlTRlhPQarKyw5;>

Как выглядели ресурсы игры 


Часть 3: Пора кодить

Как в любом приличном проекте на рпгмэйкере , в файлах игры лежит движок, написанный на JS, и который, как я подозревал, был модифицирован автором игры для защиты от взлома и модификации. Хоть я и большую часть времени я пишу на Java, в моей жизни было два года, когда я работал на проекте где приходилось совмещать 50/50 джаву с Node JS. Научившись в свое время отличать асинк от авэйта, промис от колбэка, и запомнив все 6 (или 7?) типов которые существуют в JS я подходил к разбору кода со сдержанным оптимизмом. Который чуть было не иссяк стоило мне увидеть код. ВСЕ было написано на прототипах, на которых писал еще мой прадед в перерывах между охотой на мамонтовую фауну и наскальной живописью. Было ли то результатом некой компиляции из typescript либо невозможностью (или нежеланием, что по сути одно и то же) разработчиков движка добавить в него поддержку es6 я не знал, да и к сути задачи оно не относилось. Через непродолжительное время копания в коде, мною было обнаружено что весь кастомный код содержится в папке /plugins, что весьма логично, в коде есть захардкоженный список ресурсов которые енкриптятся особо, а искомый декриптор, очевидно кастомный, созданный автором игры, хранится в PKD_Protector.js. 

(function (_0xl970dd, _0x59c80l) {
Var _0X54646C function (_0X480£/95) { if ('LoesR' _0xfal0('0x4€')) {
if (_0x403l(_0xfal0('0x20')) _0xfal0('0x4f')) { if (_0xfal0('0x50') _0xfal0('0x51')) {
(_0X27b4(_0x4031(_0xfal0('0X35')))	_0X4031(_0xfal0('0x4c'))) {
_0x59e20b
Фрагмент того самого обфусцированного протектора

К слову, в процессе перебора исходников пришло понимание почему в артмани не работает поиск: каждая переменная в памяти игры хранится в двух полях. Условно А и Б. Истинное_значение = A - Б, где Б генерируется случайно при каждом изменении переменной. Таким образом, для поиска условного артмани обе цифры в памяти меняются как-бы случайным образом. Или не меняются, т.к рандом может и совпасть.


И как всегда ложка дегтя: код декриптора был обфусцирован (переписан с сохранением синтаксиса языка, но в нечитабельной для человека форме). Это уже успех - запустив этот скрипт можно получить чистые исходники ресурсов для последующего их открытия в Rpgmaker MZ. В теории. Но на практике посмотреть и изменить ресурсы и скрипты игрового процесса мало - нужно еще вложить их на старое место предварительно зашифровав обратно. А для этого нужен был алгоритм шифрования. Обфусцированного кода всего 300 строк, что очень немного. Расставляю брейкпоинты, запускаю дебаггер помечаю используемые строчки кода и значения. Спустя полчаса алгоритм дешифрования найден и переписан в явном виде (всего в 20 строк). Еще 3 минуты на написание и проверку обратного алгоритма. Запустил сразу на все содержимое папки /data, и получил исходники ресурсов. Теперь (наконец-то!) можно переходить в Rpgmaker MZ и насладится творчеством разработчика.

function parseCinputString) {
try {
var keyStn = "DataManager" var result = "; var keyShift = 0;
for (var b = 0; b <| inputstring.length; ++b) { result += String.fromCharCodeC
codes: inputstring.charCodeAt(b) - keyStr.charCodeAt(keyShift)); keyShift++;
!if (keyShift === keyStr.length) {

 Как было оно было задумано разработчиком (логика сохранен)


Часть 4: Глубже в кроличью нору

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

Variable Selector
X
Variables
[	1821	1840	]
[	1841	1860	]
[	1861	1880	]
[	1881	1900	]
[	1901	1920	]
[	1921	1940	]
[	1941	I960	]
[	1961	1980	]
[	1981	2000	]
[	2001	2020	]
[	2021	2040	]
[	2041	2060	]
[	2061	2080	]
[	2081	2100	]
[	2101	2120	]
[	2121	■ 2140	]
[	2141	■ 2160	]
[	2161

[
"Klesi",
0.15|
],
[
"Торог",
0.15
],
[
"0tmi4ka"
0.25
],
[
"Nary4nik
[...i,
0.2
],,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,Игры,Истории

♦Label : нач
♦If : ЛевелПостоянный = 1 ♦If : ПлохТрейтДефицитВнимания = 1 ♦if : уровеньСчет > 6000
♦Control Variables : #2152 ОпытРезервация = уровеньСчет ♦Control Variables : #2152 ОпытРезервация -= 6000 ♦Control Variables : #0261 ЛевелПостоянный = 2 ♦Control Variables : #0301 ОчкиУровня += 2

♦If : ЛевелПостоянный = 72 ♦If : ПлохТрейтДефицитВнимания = 1 ♦if : уровеньСчет 2 9999999
♦Control Variables : #2152 ОпытРезервация = уровеньСчет ♦Control Variables : #2152 ОпытРезервация -= 9999999 ♦Control Variables : #0261 ЛевелПостоянный = 73 ♦Control Variables : #0301 ОчкиУровня += 1 ♦Jump


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

Часть 5: Выводы

Мне очень понравилась концепция заложенная в игру “Vampire Life”, у проекта хорошие интенции, и мне жаль что местами проект портит неуместный йумор и баланс настроенный на гринд. Сам проект висит на патроне уже б-г знает сколько и как по мне, разработчику пока остановится с новым контентом, потратить время на починку старого, выправить баланс и релизится с чистой совестью. На полноценную игру контента хватит с головой, хватит сосать из патронов шекели. Удачи разрабу во всем, надеюсь мой пост будет компенсацией за то, что поиграл в версию с разблокированными возможностями так и не занеся ему денег

P.S. Этот пост должен был выйти в день моей днюхи, но слегка запоздал. Не являясь активным участником срачей или контентмейкером реактора я посчитал нужным вместо фотки кота, торта и монитора (у меня и кота то нет), что было бы крайне неуместно и нагло с моей стороны, угостить честной люд вкусным контентом - так будет правильно

Развернуть