. Авторизуйся картинкой наоборот или отгадай три цифры
Авторизуйся картинкой наоборот или отгадай три цифры

Авторизуйся картинкой наоборот или отгадай три цифры

Прочитав статью "Авторизуйся картинкой" я подумал, что многим будет интереснее обратная статья о том, как эту напасть обойти.

На многих сайтах при регистрации, отправке SMS и т.п. ты наверняка встречал форму с картинкой для авторизации, типа защита от роботов. Хитрые и злые дядьки веб-мастеры стали использовать их в целях защиты от нас с вами. Ничто не мешает написать программу, а еще лучше скрипт, который будет, к примеру, создавать почтовые ящики, и запустить его на серваке с хорошим каналом. В результате таких действий атакуемый сервер может просто накрыться. Дело упирается в эту самую картинку. Но и ]i[ack-прогресс на месте не стоит. Пишутся программы для распознавания таких картинок, усложняются и картинки, увеличивается количество мусора в них. Из этой статьи ты узнаешь, как написать свою несложную программу для анализа таких изображений.

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

  • Очень маленький размер картинки. Тот же FineReader на таком клочке просто не может ничего увидеть.
  • Нестандартные шрифты.
  • "Пляска" символов, в то время как предполагается, что они должны находиться на одном уровне.
  • И много чего другого.

По этим причинам придется писать свою прогу для анализа изображений и нахождения в ней символов. Это будет узкоспециализированный алгоритм, написанный для распознавания только одного вида картинок. Попытка написать универсальную программу к успеху не привела, так как ничего универсального не существует. Но программу легко изменить для многих видов картинок, кроме разве что тех, что выводятся при регистрации на Yahoo, например. Там такая абра-катабра, что с первого раза и не разберешь, что написано.

  • Скачиваем картинку.
  • Отделяем символы от фона.
  • Очищаем от мусора.
  • Загружаем шаблоны символов (маски).
  • "Прикладываем" маски и перемещаем их по картинке, запоминая максимальный процент наложения для каждого символа на картинке.
  • Анализируем варианты совпадений для всех масок и выбираем наилучшие, запоминая номер маски.
  • Получаем результат - последовательность из номеров шаблонов, которая соответствует символам, нарисованным на картинке.

Сразу хочу предупредить - этот алгоритм не идеален. У него есть и существенные недостатки, а именно:

  • В нем не учитывается вращение символов, так как при этом алгоритм бы заметно усложнился. Но и это можно реализовать. Достаточно во время каждого "прикладывания" к картинке вращать маску в заданном интервале.
  • Предполагается, что цвет символов или фона не меняется. Это тоже устранимо. Например, можно попробовать перевести картинку в черно-белый цвет (2 бита на пиксель) и получить четкую границу между символами и фоном.
  • Количество символов, а также примерные места их размещения должны быть заранее известны, в противном случае алгоритм заметно усложняется. Пришлось бы находить положение первого символа, отступать от него определенное расстояние (средняя ширина символа), находить второй и т.д.
  • Размер картинки в нем постоянен, что, практически всегда, так и есть.
  • Требуются маски - не зашумленные и не искаженные образцы символов. Этот недостаток неустраним, поскольку мы не можем найти и распознать символ, не зная как он выглядит.

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

Писать прогу будем на Delphi. В качестве примера, ниже представлена простая программа. Форма состоит из двух кнопок, двух картинок и одной метки. По нажатию на кнопку Button1 происходит открытие картинки. Button2 запускает алгоритм распознавания и выводит результат. Маски цифр загружаются из черно-белых bmp-файлов.

procedure TForm1.Button1Click(Sender: TObject); begin < Запускаем диалог иоткрываем картинку > If OpenPicture.Execute then Image_IN.Picture.LoadFromFile(OpenPicture.FileName); end; procedure TForm1.Button2Click(Sender: TObject); const mask_height=10; < Высотамаски > mask_width=8; < Ширинамаски > pic_height=20; < Высотакартинки > pic_width=48; < Ширинакартинки > fig_width=round(pic_width/3); < Третьячасть картинки (для трех цифр) > type mask=array[0..mask_width-1,0..mask_height-1] of byte; < Типмассива для маски > var masks:array[0..9] of mask; < Массивмасок > masks_pix:array[0..9] of integer; < Массивдля хранения кол-ва белых пикселей для каждой маски > pic:array[0..pic_width-1,0..pic_height-1] of byte; < Массив длякартинки > i,x,y,x_,y_,dx,max,prob:integer; dig,s,pos_x,pos_y:array[0..9] of byte; < вспомогательныемассивы > < Функцияопределения номера максимально совпавшей маски > function Getmax(dig:array of byte):byte; < dig - числосовпавших точек для каждой маски > var i,i_:byte; a,b:real; begin a:=0; i:=0; for i_:=0 to 9 do begin < Вычисляемвероятность совпадения > b:=dig[i_]/masks_pix[i_]; if a<b then begin a:=b; i:=i_; end; end; result:=i; end; begin < Загружаеммаски в массивы > for i:=0 to 9 do begin masks_pix[i]:=0;

Temp.Picture.LoadFromFile(ExtractFilePath(Application.Exename)+'MASKS\'+InttoStr(i)+'.bmp'); for x:=0 to mask_width-1 do for y:=0 to mask_height-1 do if Temp.Canvas.Pixels[x,y]=clwhite then begin masks[i][x,y]:=1; masks_pix[i]:=masks_pix[i]+1; end else masks[i][x,y]:=0; end; < Загружаем картинкув массив > for x:=0 to pic_width-1 do for y:=0 to pic_height-1 do begin if Image_IN.Canvas.Pixels[x,y]=clwhite then pic[x,y]:=1 else pic[x,y]:=0; end; < ПодготовкаImage_OUT > Image_OUT.Picture.Bitmap.Width:=pic_width; Image_OUT.Picture.Bitmap.Height:=pic_height; < Очищаем картинкуот мусора

> < Мусор в данномслучае - точки того же цвета, что и цифры > for x:=0 to pic_width-1 do for y:=0 to pic_height-1 do if pic[x,y]=1 then begin x_:=x; y_:=y; if x<=-1 then x_:=1; if y<=-1 then y_:=1; < Если нет соседнихточек или точка лежит на краях картинки то убираем ее > < Здесь может быть икакой-нибудь другой признак: различие по цвету, например > if (pic[x_+1,y_]<>1) and (pic[x_-1,y_]<>1) and (pic[x_,y_+1]<>1) and (pic[x_,y_-1]<>1) and (pic[x_+1,y_+1]<>1) and (pic[x_-1,y_-1]<>1) and (pic[x_-1,y_+1]<>1) and (pic[x_+1,y_-1]<>1) then pic[x_,y_]:=0; end; dx:=0; < Смещение погоризонтали > prob:=100; < Начальноезначение вероятности успешного распознавания(в %) > label1.Caption:=''; < В этой части ипроисходит распознавание > repeat < Обнуляем всемассивы > for i:=0 to 9 do begin dig[i]:=0; s[i]:=0; pos_x[i]:=0; pos_y[i]:=0; end; for x:=dx to dx+mask_width-1 do for y:=0 to 9 do < Определеннаяобласть на картинке > begin for i:=0 to 9 do s[i]:=0; for x_:=0 to mask_width-1 do for y_:=0 to mask_height-1 do < Беремпо очереди все точки из маски > begin for i:=0 to 9 do begin < Подставляемвсе маски по очереди > if (pic[x_+x,y_+y]=masks[i][x_,y_]) and (masks[i][x_,y_]=1) then s[i]:=s[i]+1; < Присовпадении увеличиваем элемент массива на 1 > < Запоминаеммаксимальное число совпавших точек для конкретной маски > if s[i]>dig[i] then begin dig[i]:=s[i];pos_x[i]:=x;pos_y[i]:=y; end; end; end; end; max:=getmax(dig); < Агде же у нас совпало лучше всех? > < Следующие строкидо комментария "!" можно выкинуть > < Здесь для понтарисуются цифры по маскам, в тех позициях, где они были на картинках > for x:=dx to dx+fig_width do for y:=0 to pic_height-1 do image_out.Picture.Bitmap.Canvas.Pixels[x,y]:=clblack; for x:=0 to mask_width-1 do for y:=0 to mask_height-1 do if masks[max][x,y]=1 then

image_out.Picture.Bitmap.Canvas.Pixels[x+pos_x[max],y+pos_y[max]]:=$00AAFFAA; < Запоминаем самуюменьшую вероятность совпадения > if round(100*dig[max]/masks_pix[max])<PROB then

prob:=round(100*dig[max]/masks_pix[max]); label1.Caption:=Label1.Caption+inttostr(max); dx:=dx+fig_width; < Сдвигаемсявправо для следующей цифры > until dx>=pic_width; label1.Caption:=Label1.Caption+' ('+inttostr(prob)+'%)'; end;

Программу после переделки и добавления в нее некоторых функций (работа с сокетами, преобразование картинки в BMP или JPEG) можно использовать, например, в качестве робота для рассылки СМС.

Рассмотренный алгоритм является примерным. Возможно, что он тебе не подойдет, но поможет написать свой анализатор.

📎📎📎📎📎📎📎📎📎📎