Ебём весь Geetest без сервисов и нейронок (bypass free).
Сегодня разберемся как решать все гитесты с этой странички https://www.geetest.com/en/adaptive-captcha-demo
Для начала накидаем на эмуляции, а потом посмотрим запросеки.. Похуярили!
Slide (эмуляция)
Разумеется, на много пизже работает на контурах, как я делал до этого.
Но для разнообразия, накидаю попсовым вариантом, как было в статье на хабре, с заготовкой фоной. Это ещё пригодится для последней, клик капчи)
Генерация фонов
Сначала нужно как-то получить фоны. Руками мне лепить их лень, потому я сделал генератор. Напарсил фоны, а потом замерджил по phash. phash выбрал чисто потому, что оно по имени сортируется в папке, выглядит красиво)
А еще, хеш - готовая строка, поэтому сравнение картинок по схожести по нему будет работать сильно быстрее, чем каждую картинку друг с другом сравнивать.
Парсинг в общую папку. Хотя на скринах я уже паршу тесты, но суть та же.
В ответе и запросе есть колбек "geetest_" + Date.now(), так как эт фикса по длине, по ней я ответ и подрезал через slice.
Итак, напарсил чуток фонов с дыркой. Все картинки, кстати, с шумами, но как будет видно позже, это не проблема)
Сортировку делал отдельно по hash, как в скрипте по seosprint.
В результате получаем фон с дыркой в разных местах. Остается только мердж.
А мердж довольно простой и логичный.
Мы у всех сортированных картинок из папки берем пиксель по индексу, сейвим в массив, а потом голосованием выбираем какой это пиксель. Если 1 и 2 вариант одинаковы по количеству голосов, берем случайно либо 1, либо 2, чтобы разнообразить шумы.
Да, массив RGBA я сохраняю как строку, чтобы проще сравнивать схожесть.
Решение
Так как при мердже часть фонов вышла с мусором, я их ручками удалил. Всеравно ведь удалить пару картинок проще, чем сидеть и собирать их по частям)
Имея базу "чистых" фонов, берем картинку капчи и ищем какой фон имеет наибольшую схожесть с нашей используя нативный метод баса "поиск картинки в картинке".
А потом удаляем все лишнее с картинки либой pixelmatch, как делалось в статье с хабра или материале на форуме зенки.
Благодаря либе, шумы, которые есть на каждом фоне, в итоге отсутствуют на нашем итоговом изображении.
Имея позицию по Y и фон, найдем позицию скриптом Sadzurami (с парой строк моего говнокода) для тестов. Как я сказал ранее, подход не самый удачный, но для эмуляции решил поэкспериментировать. Для запросов сделал уже нормально.
Ну и оно работает, что не удивительно, ищет дырку по пазлу.
Эмуляция
Ну а тут будут причины почему мне не нравится эмуляция.
1) Я запускаю сайт и он грузится, а капча не успевает прогрузиться. Хорошо, я ставлю ждать полной загрузки. В итоге выбивает ошибку ожидания загрузки, ведь ждало больше минуты, но что-то вот как-то не пошло. Ну окей, и чего мне тогда делать? Мне нужна обычная, самая обычная, нормальная загрузка страницы и нужно просто ее дождаться. Но нет, мне приходится городить какие-то костыли.. Поэтому я убрал ожидание загрузки страницы и добавил ожидание именно капчи.
Но проблемы на этом не заканчиваются, они только начинаются.
2) При решении слайдера мне нужно зажать кнопочку и переместить по координатам. И вот я беру и... вместо правильного движения мышка резко улетает куда-то в ебеня. Это наверное не проблема баса, а сайта, но мне такие приколы не нравятся.
Более того, сайт еще имеет и горизонтальный, сука, скрол.
Поэтому я ручками пошукал, сделал удаление стилей, которые делали эту хуйню. Тем самым сломав верстку нахуй.
Только вот это нихуя не помогло. Оно опять кликало не туда и мышка улетала в ебеня. Костыльным решением, которое спасло ситуацию, стал юз режима капчи попап.
Еще, зачем-то пришлось добавить сдвиг в 10 пикселей к позиции ответа.
3) Картинки дергал через кеш, с этим проблем не возникло. Хотя нет, возникло блять. Капча без задачек автоматически решалась при загрузке страницы, поэтому в кеш попадала хуйня. Чтоб этого небыло, пришлось добавить ожидание перед переключением режима капчи, тк именно при переключении режима оно сразу дергает получение задания на капчу. Хотя, можно было фильтр кеша делать по типу задания, он ведь тоже в урле.
Но хотя бы теперь я смог протестить, что все работает правильно. Слайдер есть слайдер, потому не удивительно, что оно пиздато решается. Вообще, я применил поиск картинки в картинке для определения позиции, но тк у нас и тк есть онли пазл, можно было дернуть через маску, тк наша картинка по сути маска готовая. Но даже так, за все время тестирования вроде всего 1 ошибка была.
IconCrush (эмуляция)
Эта капча очень простая и решается чисто математикой. Я не очень умный, по-этому сделал так как смог.
Тем более, задачка прилетает просто массивом
Решение
По сути, наша задача найти какие-то 2 картинки, флип которых даст линию из 3х совпадающих элементов, причем если флип горизонтальный, линия - решение получится вертикальной и наоборот. Например, мы флипаем 2 красных квадратика, а решение получится в одном из зеленых столбцов.
Я не знаю как это решается по нормальному, но раз нужно найти какую-то пару, которая приведет к решению, я просто возьму и забручу все варианты решения нахуй. Возьму и выполню все варианты перестановок и сделаю прочек получилась линия или нет. Тем более перестановок выйдет около нихуя. Чтобы небыло баги перезаписи значений, опять пришлось добавлять клонирование через сериализацию.
Эмуляция
Тут все обошлось без приколов. Есть классы, где в нейминге указаны позиции. Я передал туда ответы и кликал сразу куда нужно.
Само задание просто парсил из кеша
Все максимально просто и логично
В итоге решало 100 из 100 на эмуляции.
Gobang (эмуляция)
Наверняка, мой код говно и можно сделать проще (любители литкода, ваш выход), но я сделал как сделал и оно работает.
Как и в случае с прошлой капчей, тут нам прилетает массив
Решение
Для начала чекаем какие у нас вообще есть цвета. После, проходимся по горизонтали, вертикали и диагоналям, собирая статку по цветам в каждом типе линий (BOARD) через функцию подсчета checker. Далее чекаем какой именно тип линий - решение и на какой позиции, сейвим в task_type и value.
А после, шукаем конкретную позицию дырки и камня желаемого цвета, исключая при поиске нашу линию - решение. Все довольно топорно. Куча циклов, но проблем по скорости вроде нету, поэтому меня всё устраивает.
Эмуляция
В процессе тестов я нашел багу. Если варианта ответа 2, хуйня как на скрине ниже. Изначально я это не предусмотрел и оно лажало, решая 90%. Но ведь это можно просто взять и фиксануть.
В итоге я её просто взял и захардкодил. У нас в чекере идет подсчет цветов, а дырку мы выкидываем. Получается, у нас всегда остается объект, где всего 1 цвет.
Задачку, как и в прошлой капче, дергаем через кеш.
Клик по элементам решил сделать через выбор класса полоски и её элемента.
В итоге все работает, теперь решает 100 из 100.
Icon (эмуляция)
А вот с этой штукой я уже чуток намучался. Задачка прилетает, как и со слайдером.
Решение
Ну окей, ищем и удаляем фон, всё как у слайдера. Фоны я ранее чисто под эту капчу парсил и мерджил, ровно как и со слайдером.
Картинка получается не очень чистая, но в целом сойдет. Все таки нам важно сохранить иконки и похерить шум.
А теперь самое интересное, че же делать дальше?
А дальше надо по любому дергать эти иконки. Только вот хуйня вся в том, что мини иконки и их версии на картинке чуть отличаются.
Поэтому я решил дергать внешний контур иконки. Я получаю фон, а потом дергаю все что не фон)
Да, выглядит он немного ебано, но задачу свою полностью выполняет. Всетаки прям в пиздатом качестве иконки в данной капче не вытянешь, даже при наличии фона.
Дополнительно добавляю сортировку. В чем смысол решения станет понятно чуть позже.
Ну и мини иконки тож дергаю. Тк они сразу чб, то всё чуток проще.
На выходе получаем подобную хуеверть.
Ну а теперь перейдем к сути решения.
Берём 2 массива, массив иконок с картинки и мини иконок.
Далее нам нужно как-то их сопоставить. Для этого оба массива сортируем по ключу, какому-то хитрому значению параметров, которое специфично для каждой картинки, но при этом не зависит от размера. На выходе получим пары.
Так как у массива мини иконок был порядковый идентификатор, раз пары у нас есть, соберем новый массив с индексом от второго и координатами от первого, а потом отсортируем по порядковому индексу.
Однако, для сравнения нужен какой-то хитрый параметр. Да, в сортировках выше уже и так видно как я порешал, но представим что ни кто этого не заметил.
Чтобы его подобрать, я просто взял и провел тесты со всеми алгоритмами и значениями. Для тестов заготовил 10 картинок и чекал какой метод решения лучше. Вообще, у роя много всяких параметров и методов, но я почекал чисто базу.
И решением по итогу стал старый советский...
Кароче, я поделил площадь на периметр и определил это значение в качестве кэфа: e.coeff=e.d.mbrSurface/e.d.perimeter
И по итогу получим правильное решение.
Чтобы это все добавить на картинку, я просто выполнил цикл.
Ну и добавил текст. Все довольно просто.
Берём фон и картинку. Делаем маску. По маске получаем картинку из роя, причем с параметрами. Считаем каждой картинке отношение периметра к площади, а также сейвим координаты XY. Потом сортировка.
Получаем инфу по площади и периметру для мини иконок. Их тоже сортируем? но при этом сейвим их индексы.
Далее еще она сортировка, но итогового массива.
Так как мини иконки без фона, отдельно делал функцию добавления оного
Эмуляция
Ну тут все совсем просто. Парсим положение картинки, а потом эти координаты докидываем к ответу.
В целом, на тестах статка выходила в 60% успеха, что неплохо для такой капчи, при том без использования нейронок.
Space
Помимо описанных ранее капч, у гитеста ещё есть вот такая поебеть, которую можно чекнуть на другой демо страничке https://www.geetest.com/en/demo
Но как её решать я не смог придумать, не затащил.
Типо кликни на маленький зеленый рядом с большим еще чем-то. Я хуй знает как это решать без нейронок и распознавания объектов. Поэтому её скрипаем.
Реверс и запросеки
Напоминаю, наша демо страничка.
Проведем поверхностный ресерч. Все параметры и так есть в задачке капчи или еще где-то, а вот W. Её нам и надо будет разгадать.
Опять чекаем стек вызовов, опять чекаем каждый вызов..
Находим воть и потом разматываем дальше
И приходим вот сюды. И шо мы тут видим? А видим мы, что было тело с решением, а потом мы его как-то пошифровали, получив на выход 2 какие-то строки.
Шагаем еще чуть назад и видим, что создаются 2 функции, AES(cbc) и RSA. Тогда все становится на свои места. Мы генерим рандом ключ, им шифруем тело через AES, а потом шифруем ключ через RSA, тем самым юзаем плюсы обоих крипто методов.
Теперь нужно понять че мы шифруем. Для слайдера это позиция + какой-то пов + пара дефолт данных. В целом, вроде ничего сложного.
Такс, ну ключик RSA у нас статичный, поэтому пиздим его из памяти.
Все оказалось довольно просто, поэтому я решил почекать другие варианты гитеста (старый вид). Чекнул на демо страничке от кап гуру. Код такой же практически, алгоритмы те же..
И нашел я там.. такой же ключ RSA. Типо, ровно тот же.
00C1E3934D1614465B33053E7F48EE4EC87B14B95EF88947713D25EECBFF7E74C7977D02DC1D9451F79DD5D1C10C29ACB6A9B4D6FB7D0A0279B6719E1772565F09AF627715919221AEF91899CAE08C0D686D748B20A3603BE2318CA6BC2B59706592A9219D0BF05C9F65023A21D2330807252AE0066D59CEEFA5F2748EA80BAB81
А потом я подумал: выглядит гига изично, но мне так лень писать код.
Поэтому по ключу я посерчил на гите и нашел сразу готовые решения.
Какбэ да, можно было б и самому пореверсить, но нахуя, а главное зочем, если это ровно тот же код, что я получил бы и сам, но часа через 3.
Из всех реп для меня примечательна стала именно эта, тк код на ноде.
Забегая вперед скажу, что китаец молодец и написал отличный рабочий код. Желаю ему получить мискарис и кошкажена от партия.
Также, чуток погуглил и нашел много заметок прям с разбором реверса от других китайцев, поэтому не вижу смысла расписывать это тут.
Хорошие заметки, все подробно и четко расписано, со стрелочками даже.
А тут даже есть подробный видео гайд, помимо статьи.
Вот тоже интересная заметка по реверсу гитеста. Тут даже целый форум, точнее ветка на форуме.
Вот например реверс протобуфа. Чел показал, как собрал данные и шаблон, а потом через питончик отправить запрос.
IconCrush (запросы)
Такс, раз шифрование у нас есть, соберем решалку на самой простой задачке и почекаем. Общая схема скрипта такая.
В процессе подготовки к тестам, я обратил внимание, что в прод коде капчи, в отличие от китайского есть 2 новых значения:
Чуть потыкал стек вызовов и нашел biht.
Тут оно дергало из гига массива файла по индексу нейм biht.
Значение мы всегда получаем одно и то же - 1426265548. А значение это - контрольная сумма функции от самой себя. Возможно это какой-то контроль версий файла капчи.
А вот чтобы найти второй параметр, пришлось чуть похитрить. И нет, это не рандом. Оказалось он тянется из файла капчи и ставится как window._lib
Я поставил на декод логический брек, который стопал когда видел слово _lib. И нашел от куда оно берется.
Оказалось, в коде есть гига массив с данными, по индексу от туда и берется значение. Первая часть имени есть в файле, вторая в массиве. И получается это какбэ привязка к файлу, типо ключи.. можно и наверное нужно сделать парсер, но для тестов я просто их дернул как есть и фсе. Хотя парсинг написать изи, пример скрин ниже.
По итоге код шифрования стал выглядеть так
Теперь перейдем к самой решалке.
Чисто визуально массив повернут, но на самом деле нет и ничего делать не нужно.
Почекаем че мы шифруем для этой капчи. Вроде вся та же хуйня, что я собрал ранее. Можно тестить.
Запрашиваем капчу, дергаем ответ и пару данных для запроса ответа. Получаем ответ, шифруем и шлем на решение.
Интересная тут только подготовка тела капчи. Я докинул параметров, которые нужны в запросе и добавил енкод для тела, чтобы сразу из JSON получить uri данные.
И оно в итоге работает, решает 100 из 100 на запросах)
А значит нужно переходить к остальным капчам.
Gobang (запросы)
И в отличие от прошлой капчи, тут поменялся только тип таска и блок решалки перекочевал из скрипта с эмуляцией.
Icon (запросы)
У клик капчи данные были странноватые.
Но оказалось, что они просто в процентах.
Тоесть, в отличие от предыдущей капчи, помимо переноса решалки, в эту потребовалось докинуть еще функцию перевода координат в проценты.
В итоге, около 60% валид решения, как и в случае с эмуляцией.
Slide (запросы)
А вот у слайдера есть пара своих отличий.
Как и в ориг репе китайца, в теле решения этой капчи нужны были параметры setLeft и userresponse.
{
"setLeft": 216,
"passtime": 1003,
"userresponse": 216.72311322005146
}
Там я и спиздил кусок userresponse: distance / (.8876 * 340 / 300)
Для запросов решалку я поставил уже нормальную, на контурах, как и у бинанса.