как мы (не) вынесли sui quest 3 на миллион аккаунтов
привет, я artemm.baka, а эта статья про нашу недельную историю о sui квесте, которая началась в конце октября. время прочтения 5 минут. gl hf.
Навигация по статье:
1. начало
2. билдинг и реверс-инжиниринг
3. минт квест пассов и первые проблемы
1. начало
изначально о sui я уже успел благополучно забыть, ведь с друзьями мы сливали пачки целестии с нод по низу рынка (о чем мы не жалеем) и в целом занимались другими вещами.
однако мой коллега с ds_private яна мефе не забыл и предложил реверсить игрушку, а точнее мега кривой лаунчер worlds beyound.
для тех кто не знает что за worlds beyound и почему именно он? если кратко, во время quest 3 было много "даппок", обязательно нужно было сделать 3 из них и набрать суммарно 2500 поинтов.
мы взяли две гемблинг аппки (suilette и desuiflip) + сам wb. многие в комьюнити также софтили run legends. и там же кстати админы раньше всего заметили читеров. мы же решили эту игру скипнуть.
2. билдинг и реверс-инжиниринг
спустя еще два дня собрались мы втроем: я, яна и кису с dd dao, чтобы разделить обязанности и сделать все побыстрее. я занялся играми в wb и минтом квест пасса. яна делал казино аппки. а кису регу на лаунчер wb. и естественно все втроем занимались РеВеРс-ИнЖиНиРиНгОм.
в лаунчере было несколько игр, как офлайн, так и онлайн. проксифаером чекнули запросы во всех, везде +- одни и те же запросы, а в хедерах jwt
токен и signature
. с первым проблем нет. кстати их refresh
токен после обновления не обнулялся, что забавно. гениальные кодеры на админах.
а вот со вторым проблемы возникли и мы полезли копаться в коде лаунчера с помощью dnSpy, а потом через dotPeek. хотя они и не сильно отличаются, но второй оказался лучше в декомпиляции. короче, спасибо за детство, JetBrains.
так выглядела функция генерации сигнатуры на C#, которую мы нашли, короче просто HMACSHA256
.
private static string GenerateHash(string content) { using (MemoryStream inputStream = new MemoryStream(Encoding.ASCII.GetBytes(content))) { byte[] hash = new HMACSHA256(Encoding.ASCII.GetBytes("S0lBZsuidaidropIQ1ZCQUhEBw==")).ComputeHash((Stream) inputStream); StringBuilder stringBuilder = new StringBuilder(hash.Length * 2); foreach (byte num in hash) stringBuilder.AppendFormat("{0:x2}", (object) num); return stringBuilder.ToString(); } }
а так выглядит теперь на typescript.
const HMAC = 'S0lBZsuidaidropIQ1ZCQUhEBw=='; function generateHash(data: object): string { return CryptoJS.HmacSHA256(JSON.stringify(data), HMAC).toString(); }
что за S0lBZsuidaidropIQ1ZCQUhEBw==
думаю понятно (ключ).
но что за дата? в поисках ответа на этот вопрос я полез в ассемблер (IDA Pro), провел там пару часов, научился прикольным штукам и весело `へ´ провел время. но ответ оказался намного проще.
спустя время до нас все же дошло, что контент/дата для нужных нам запросов берется из даты этих самых запросов. спасибо C# коду и unity uploadHandler
.
кстати, все онлайн игры работали через встроенный вебсокет менеджер в unity, следовательно, девы ничего не контролировали, но мы решили сделать офлайн игры для "уменьшения рисков", хотя они и давали поменьше поинтов чем онлайн.
я перенес все нужные и ненужные запросы в софт, просчитал пинги, тайминги, правильный скор и другую хуйню, которую успели сделать недодевы в wb. на красивую обертку для бота (cli, db и т. д.) ушло многовато времени и это стало второй ошибкой в будущем. почему второй, а не первой узнаете soon.
3. минт квест пассов и первые проблемы
пока друзья доделывают регу и гемблинг, я делаю газлесс (спонсорский как на сайте) минт квест пассов.
сделать газ минт - легко, как и в любом move блокчейне (просто .moveCall
и все). сделать спонсорский минт (без газа) - чуточку сложнее. но на самом деле нужно было просто немного посидеть подумать и почитать sui доку.
со спонсорским минтом 1 аккаунт выходил 0.1$ (за прокси) + ~0.2$ в sui на другие активности = ~0.3$. с каждого акка получаем 25 sui, итого x50-x100.
4 ноября наш софт на 2к строк готов, но нас обгоняет другой софтер и регает 140к+ акков в wb - обычные юзеры это замечают, а позже и сами админы.
клейм поинтов на сайте wb перестает работать, а потом и обязательный линк sui кошелька. раньше, конечно, тоже все супер ужасно работало, но сейчас же фулл упало. плюс админы пишут, что будут перераспределять поинты.
до сих неизвестно как они будут брить, с учетом того, что админы не смогли сделать ничего нормально. ни бекенд (про RESTful вообще молчу, у них код 200 это ошибка, о чем речь), ни фронтенд.
кстати, вот так в wb выглядит пейлоад для регистрации.
{ username: 'username', email: 'email', name: 'name', password: 'password', confirmPassword: 'password', dateOfBirth: 'dateOfBirth' }
confirmPassword
- интересное и совсем не ненужное поле. и таких приколов у них очень много.
предполагаю, будет бритва либо по самым банальным критериям, либо фулл несправедливые баны даже не сибилов.
4. переобувка sui и следующая проблема
вскоре апи у суи загадочно "падает" и перестает работать спонсорский минт квест пасса, какое совпадение да? на самом деле, sui сами его отключили. ведь токены на газ на их кошельке не закончились, да и до этого их сервер прекрасно справлялся с подобными нагрузками.
конечно, можно было минтить пассы с газом. но зачем делать большое кол-во акков неправильно, если можно правильно, верно? вот и мы так подумали.
но через несколько дней sui анонсят, что больше квест пассов не будет, "минтите наши другие (платные) нфт". премного благодарю, sui team.
и чуть позже суи еще убирает лимиты по рефам у "настоящих пользователей". интересно зачем, да?
5. итоги и ошибки
что мы имеем? гениальных девов в sui играх с серверами за 5€ на contabo. wb лаунчер, который собирает бесконечность данных с твоего пк и кривым бекендом "работающем" в 1 из 100 случаев. и, конечно же, прекрасную команду sui.
- поздно начали, но на то была уважительная причина (просто оправдание)
- можно было ускорить разработку не делая лишние действия (то есть без перфекционизма)
- минт квест пассов, регу и линк в wb стоило сделать первыми или делегировать кому-то еще
да мы не сделали миллион аккаунтов, но получили интересный опыт и пару синяков под глазами.