Search
Write a publication
Pull to refresh

Ломаем капчу

Гуляя по просторам интернета, зашёл на один высокопосещаемый древний сайт рунета. Для того, чтобы скачать файлик с этого сайта, нужно угадать вот такую капчу:
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:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.