Pull to refresh

Ломаем капчу

Reading time 3 min
Views 80K
Гуляя по просторам интернета, зашёл на один высокопосещаемый древний сайт рунета. Для того, чтобы скачать файлик с этого сайта, нужно угадать вот такую капчу:
image
В очередной раз видя картинку с цифрами — решился. В голове уже давно проносились мысли, сломать какую-нибудь капчу :)

Ставлю себе задачу: Написать скрипт, который будет расшифровывать показанную капчу и выплевывать драгоценные циферки.

Название сайта специально не привожу — сами догадаетесь :)

Итак, поехали!



Анализируем картинку


Для начала надо просмотреть как можно больше таких капч, чтобы выявить сходства/различия, какие-то закономерности. Для этих целей я скачал порядка 50 капч. Среди них можно выбрать основные, которые содержат максимум различий:

image    image    image    image    image

Вообще люблю всматриваться в числа, так как в своё время много времени посвятил изучению математики :)

Рассматриваем, и понимаем:
  • картинка черно-белая, в формате gif
  • размер картинки может меняться, но цифры всегда стоят по центру (правда вертикально они выравнены не очень по центру)
  • используется градиент, его направление может меняться в 2 стороны
  • кроме градиента есть, "угловой градиент" (так я его обозвал, не пинайте :) ), тот который идёт из угла под углом 45 (ещё раз не пинайте :) ) это просто линия-диагональ, в моём понимании
  • всего я выявил 6 разных шрифтов написания (точнее 3, другие 3 являются их наклонными версиями)
  • пиксели всех цифр не темнее цвета #606060, но не одного цвета
  • цифр 3-5 в капче, высотой не выше 14px

Ищем решение


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

Пришёл к такому решению:
  • заводим массив с отпечатками
  • обрезаем картинку со всех сторон, лишнее надо выбросить
  • удаляем лишние цвета — это градиент и угловой градиент
  • проходим по всем пикселям слева-направо сверху-вниз, и если цвет пикселя соответствует цвету цифры (>= #606060), то сверяем с отпечатками, со всеми по порядку

Реализация


  1. Готовим отпечатки
    Всего их получается 6 * 10 = 60 штук, их помещаем в массив. Отпечатки я делал по цифрам из капч, для каждого шрифта. Это просто массив строчек, где в каждой строчке буквой "x" отмечен пиксель цифры.

    Например, вот так выглядит цифра 2 первого шрифта:
    image
  2. Открываем картинку
    Это делается просто, через imagecreatefromgif($filename);

  3. Определяем направление градиента
    Надо определить, в какую сторону смотрит градиент, это потребуется в следующих пунктах.
    Это сделать просто, достаточно определить цвет первого пикселя (0, 0)
    $color = imagecolorat($image, 0, 0) < 0x20 ? 'black' : 'white' ;

  4. Вычищаем угловые градиенты
    Здесь нужно почистить угловые линии-градиенты, причём это лучше cделать до обрезания капчи.
    Вот тут как раз нам нужно знать направление градиента, чтобы вычистить с нужной стороны.
    Путём анализа выявляем, что перепад цвета с пикселя (1, 1) на (2, 2) и т.д. не может быть больше #202020.
    Вычистить — это значит закрасить черным цветом, т.к. все цифры у нас не ниже цвета #606060.

    Получаем такую картинку:
    image
    php-код вы можете просмотреть в аттаче (см. ссылку ниже)

  5. Режем капчу
    На этом этапе отрезаем слева и справа по 12px.
    Т.к. высота цифры не выше 14px, то снизу и сверху обрезаем лишнее, в зависимости от высоты всей капчи.

    Получаем:
    image
  6. Чистим градиент
    Со всех сторон всё же остаются лишние полоски градиента. Их надо так же вычистить.
    Проходим сперва сверху-вниз, потом слева-направо, берём цвет полоски, и если она сплошная (длина > 10px) и одного цвета — то считаем что это полоска градиента, и вычищаем её.

    Итого получаем:
    image
    Но в некоторых случаях (~ 5%) всё же могут оставаться вот такие шумы:
    image    image
    Правда они нам всё равно не помешают :) Т.к. их цвет уже не подходит под цвет цифр.

  7. Сверяем с отпечатками
    Проходим по всем пикселям сверху-вниз слева-направо, цвет которых подходит под цвет цифр и сверяем со всеми отпечатками по-порядочку.

Результаты


image

Тестирование


Для тестирования я скачал 200 таких капч, на моём домашнем ПК скрипт разобрал их ~ за 19 секунд.
Это примерно 10 капч в секунду.

Из этих 200 не было выявлено ни одной ошибки, скрипт отлично отработал :)

Итоги


Я написал класс CapCrack, который разбирает капчу.

Если есть желание более подробно разобраться в алгоритме, или протестировать на своём ПК, можете взглянуть на код: cap_crack.zip

На этом успехе я не остановился и решил попробовать написать скрипт для скачки файлов с сайта, в автоматическом режиме, но это уже совсем другая история :) достойная отдельной статьи…

P.S. Это мой первый пост на Хабре, так что прошу строго не судить :)
Tags:
Hubs:
+282
Comments 144
Comments Comments 144

Articles