PDA

Просмотр полной версии : Декодирование капчи


4nob1oz
27.02.2008, 14:49
Рыскав по инету я заменил, что опять какой то барыга продаёт кучу софта и в ней был хрумер 4. Я почитал описалово, прифигел и опять задумался над тем как же декодят эти капчи. Как то раз я уже пытался задекодить самую простую но ничего не вышло и я забил на это дело. В этот раз я наконец то написал скрипт который декодит одну из самых простейцих капч чему очень рад(ура я не такой тупой =)). В капче присутствует эффект шума и ничего более.

Вот пример капчи:
http://img99.imageshack.us/img99/522/01od6.png

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

Итак обо всём попорядку.

Переводим капчу в монохромное(чёрно-белое) изображение.
---------------------------------------------------------------------------

Унас есть капча(пример выше). В чём её слабость. Ну первое что бросается в глаза это то, что все символы написаны белым. Так за это и нужно зацепиться. Алгоритм перевода в монохромное изображение будет таков, что все пикселы кроме белого мы переводим в белый, а белые пикселы в чёрный.

//Цикл перевода капчи в монохромное изображение
for($i=0;$i<$width;$i++)
{
for($j=0;$j<$height;$j++)
{
// Получаем RGB пикселя по координате
$color=imageColorAt($im,$i,$j);
// Разбиваем RGB на Red,Green,Blue и записываем каждую составляющую в свою переменную
list($r,$g,$b)=array_values(imageColorsForIndex($i m,$color));
//Сравнение белого ли цвета пиксель
if($r==255 && $g=255 && $b==255)
{
imagesetpixel($im,$i,$j,$black); // Установка пикселя в чёрный
} else {
imagesetpixel($im,$i,$j,$white); // Установка пикселя в белый
}
}
}

После этого капча станет такого вида.

http://img84.imageshack.us/img84/729/monoeq8.png

Далее нам нужно отсекать по каждому символу в капче. Разберём код

for($i=0;$i<$width;$i++)
{
for($j=0;$j<$height;$j++)
{
// Получаем RGB пикселя по координате
$color=imageColorAt($im,$i,$j);
// Разбиваем RGB на Red,Green,Blue и записываем каждую составляющую в свою переменную
list($r,$g,$b)=array_values(imageColorsForIndex($i m,$color));
// Сравнение на чёрный пиксел
if($r==0 && $g==0 && $b==0 && $left==0)
{
$left=1;
$black_pix++;
}
// Сравнение на чёрный пиксел и левую границу символа
else if($r==0 && $g==0 && $b==0 && $left==1)
{
$black_pix++;
}
// То же самое только ещё добавлна проверка на кол-во чёрных пикселов
else if($r==0 && $g==0 && $b==0 && $left==1 && $black_pix==0)
{
$left=0;
$black_pix=0;
}
}


Уже в монохромной капче мы ищем первый чёрный пиксел. Если это первый чёрный пиксе и флаг левой границы не установлен, то мы утсанавливаем этот флаг и увеличиваем переменную $black_pix которая отвечает за кол-во символов в данном столбце пикселов. Далее если флаг границы установлен, то мы просто увеличиваем переменную $black_pix, а вот если флаг границы утсановлен и переменная $black_pix равна нулю то значит мы достигли гонца первого символа и можем начать сравнеие по шаблонам предварительно обнулив переменную $black_pix и флаг $left.Каждый раз после подсчёта чёрных пикселов мы добавляли в переменную $char значение переменной $black_pix. Как это сделано можно посмотреть в коде декодера, здесь я этот момент затрагивать не стану.

Идём дальше по коду.

Сравниваем сомвол с шаблонами.
-----------------------------------------

Перед тем как делать сравнение я подготовил шаблоны для всех цифр которы есть в капче.

//Цикл сравнения цифры из капчи с каждой цифрой по шаблонам
for($x=0;$x<count($templates);$x++)
{
for($y=0;$y<count($templates[$x]);$y++)
{
//Если равно кол-во чёрных пикселов то увеличиваем переменную OK
if($char[$y]==$templates[$x][$y])
{
//Увеличили совпадения
$ok++;
//Если кол-во совпадений больше либо равно 8 то нашли цифру
if($ok>=8)
{
$out .= $x;
break;
}
}
}
//Обнуляем переменную совпадений
$ok=0;
}
//Обнуляем переменную символа
$char='';
}

После того как мы отсекли первый символ мы можем начать сравнение. Как я уже говорил выше в переменной $char содержится количество символов в каждом стобце пикселов для данной отсечённой цифоы из капчи. Там будет чтото вроде 23433343. Это значит, что в ширина символа всего 8 пикселов и в первом столбце чёрных пиксела 2, во втором 3 ну итд.
Исключение составляет только цифра 4, ширина то у неё тоже 8 пикселов, но кол-во чёрных пикселов в некоторых столбцах равно 10, а вот сравнение идёт побайтово и шаблон для цифры 4 был сделано из 10 символов. Ну и теперь можно сравнивать побайтово переменную $char с каждым шаблоном и если например первое байт из шаблона совпадает с первым байтом из переменной $char, то мы увеличиваем переменную $ok, ну а если кол-во совпадений становится 8 и больше то мы просто прерывааем цикли так как нашли цифру. В переменную $out записываем переменную $x так как символы расположены по порядку в массиве $templates то $x будет соответствовать искомой цифре.

Капчи были взяты с сайта http://dign.narod.ru/, но там нет готового решения, я решил написать и от что получилось :)

Архив с капчами
--------------------

Link: http://webfile.ru/1769225

Полный код
---------------

Captcha(very_easy).php
<?
$image = "01.png"; // Сама капча

$black_pix=0; // Кол-во чёрных пикселей по высоте
$left=0; // Левая граница каждой цифры
$ok=0; // Кол-во совпадений

//Шаблоны цифр
$zero = array(4,6,4,4,4,4,6,4);
$one = array(2,3,1,0,1,0,1,1);
$two = array(2,4,5,4,4,5,5,3);
$three = array(2,4,2,3,3,7,7,3);
$four = array(2,3,3,3,3,1,0,1,0,1);
$five = array(6,7,4,3,3,5,6,3);
$six = array(6,8,5,3,3,6,6,2);
$seven = array(3,4,3,3,3,3,4,3);
$eigth = array(3,7,7,3,3,7,7,3);
$nine = array(2,6,6,3,3,5,8,6);

//Большой массив который содержит все шаблоны
$templates = array($zero,$one,$two,$three,$four,$five,$six,$sev en,$eigth,$nine);

//Ширина и высота капчи
list($width,$height) = getimagesize($image);

//Получаем хендл капчи
$im = imagecreatefrompng($image);

//определяем чёрный и белые цвета
$white = imagecolorallocate($im,255,255,255);
$black = imagecolorallocate($im, 0, 0, 0);

//Цикл перевода капчи в монохромное изображение
for($i=0;$i<$width;$i++)
{
for($j=0;$j<$height;$j++)
{
// Получаем RGB пикселя по координате
$color=imageColorAt($im,$i,$j);
// Разбиваем RGB на Red,Green,Blue и записываем каждую составляющую в свою переменную
list($r,$g,$b)=array_values(imageColorsForIndex($i m,$color));
//Сравнение белого ли цвета пиксель
if($r==255 && $g=255 && $b==255)
{
imagesetpixel($im,$i,$j,$black); // Установка пикселя в чёрный
} else {
imagesetpixel($im,$i,$j,$white); // Установка пикселя в белый
}
}
}

// Цикл декодирования монохромной капчи
for($i=0;$i<$width;$i++)
{
for($j=0;$j<$height;$j++)
{
// Получаем RGB пикселя по координате
$color=imageColorAt($im,$i,$j);
// Разбиваем RGB на Red,Green,Blue и записываем каждую составляющую в свою переменную
list($r,$g,$b)=array_values(imageColorsForIndex($i m,$color));
// Сравнение на чёрный пиксел
if($r==0 && $g==0 && $b==0 && $left==0)
{
$left=1;
$black_pix++;
}
// Сравнение на чёрный пиксел и левую границу символа
else if($r==0 && $g==0 && $b==0 && $left==1)
{
$black_pix++;
}
// То же самое только ещё добавлна проверка на кол-во чёрных пикселов
else if($r==0 && $g==0 && $b==0 && $left==1 && $black_pix==0)
{
$left=0;
$black_pix=0;
}
}
//Проверка равено ли кол-во чёрных пикселов в столбце 0
if($black_pix!=0)
{
$char .= $black_pix;
} else {
//Цикл сравнения цифры с каждой цифрой по шаблонам
for($x=0;$x<count($templates);$x++)
{
for($y=0;$y<count($templates[$x]);$y++)
{
//Если равно кол-во чёрных пикселов то увеличиваем переменную OK
if($char[$y]==$templates[$x][$y])
{
//Увеличили совпадения
$ok++;
//Если кол-во совпадений больше либо равно 8 то нашли цифру
if($ok>=8)
{
$out .= $x;
break;
}
}
}
//Обнуляем переменную совпадений
$ok=0;
}
//Обнуляем переменную символа
$char='';
}
//Обнуляем переменную кол-ва чёрных пикселов
$black_pix=0;
}

//Вывод капчи и прочей информации
print("<font color=grey>--------------------------<br>");
print("Sample captcha decode:<br>");
print("--------------------------</font><br>");
print("<img src=".$image."> <b><---></b> <font color=red><b>".$out."</b></font>");
print("<br>(c)Coded by <b>perdimonokl aka 4nob1oz</b> just for fun");

//Закрываем хендл капчи
imagedestroy($im);
?>

Если чтото для вас стало сложно или непонятно, если есть какие то предложение или замечания, пишите в ПМ, пишите здесь, пишите в асю или жабер(если знаете конечно).

Вот и всё...

©Coded by perdimonokl aka 4nob1oz just for fun

diehard
27.02.2008, 15:03
простая капча - простой алгоритм. Насколько я помню для распознавания письма на изображениях используются обучаемые алгоритмы на основе нейронных сетей

Isis
27.02.2008, 15:12
Была статья от Nomer1, там код реализован короче и лучше..

+ только за то что способ твой(если он твой)

Conquerstador
27.02.2008, 15:37
это все конечно хорошо и + конечно но вот бы скрипт чтобы с капчи автоматом прописывалась вот это было бы реал, хотя фантазия но все равно )))

KEZ
27.02.2008, 15:46
еголд попробуйте распознать

4nob1oz
28.02.2008, 12:21
На еголде :) Там жесть вообще :)

+toxa+
28.02.2008, 14:34
4nob1oz
на mail.ru посмотри новую)

Хозяин
28.02.2008, 15:14
+toxa+, рвется она уже )))

ProTeuS
28.02.2008, 15:38
статья боян, сорцов аналоги4ных тулх давно пруд пруди, и на основе нейросетей. инетерсно было бы 4итать разве4то реализацию алго выделения изображений, переворота и горизонального\вертикальн го проэцирования

ElteRUS
28.02.2008, 15:59
Про распознавание примитивных капчей уже писали ТУТ (http://forum.antichat.ru/threadnav51141-1-10.html) и ТУТ (http://forum.antichat.ru/thread60049-%EA%E0%EF%F7%E0.html) . Да и вобще нету особых проблем в том, что бы распознать такие капчи. Лучше б написали что-то об методах фильтрации шумов, проведении сегментации и распознавании искаженных символов (блин, забыл термин, такой прикольный... которым обозначают искажение символов )))

4nob1oz
28.02.2008, 22:44
Пипец заглянул на mail.ru, вот это капча так капча :) А про распознование искажённых символов вред ли тебе ктото расскажет и тем более покажет, я видел только одну статью и там просто рассказывалось про алгоритм.

А тем кто тут пишет что типа боян и что кодов и алгов, а конкретнее я говорю про тебя ProTeuS, что от вас я вообще не видел ни одной статьи, ни одного релиза, ни одного сплоита даже ДоС, такие как ты позорят расскую сцену и гнут свои пальцы но сами из себя ничего не представляют. Ты 0 ты никто тебя никто не знает ты пустое место и мне твоё мнение не важно, я послушаю прислушаюсь к мнению Great, Сталина, Кеза, Электа, Краша, +Тохи+ и ещё многих других сильных в тех плане парней но не твоё...

NOmeR1
28.02.2008, 23:39
Мне понравилась статья. Мой способ менее автоматизирован, да и продуман не сильно.

_Great_
29.02.2008, 00:25
А тем кто тут пишет что типа боян и что кодов и алгов, а конкретнее я говорю про тебя ProTeuS, что от вас я вообще не видел ни одной статьи, ни одного релиза, ни одного сплоита даже ДоС, такие как ты позорят расскую сцену и гнут свои пальцы но сами из себя ничего не представляют. Ты 0 ты никто тебя никто не знает ты пустое место и мне твоё мнение не важно, я послушаю прислушаюсь к мнению Great, Сталина, Кеза, Электа, Краша, +Тохи+ и ещё многих других сильных в тех плане парней но не твоё...
Прислушайся: закрой рот. И не открывай больше

ЗЫ. А статья, действительно, боян

ElteRUS
29.02.2008, 00:32
А про распознование искажённых символов вред ли тебе ктото расскажет и тем более покажет, я видел только одну статью и там просто рассказывалось про алгоритм.


Ну вот, если ты видел алгоритм, то почему б было не написать по нему скрипт\статью ? Многие тебе были б благодарны - это действительно интересно и актуально и не боян.

Если не жалко, дай ссылку на ту статью.

4nob1oz
29.02.2008, 00:37
Дак найти бы ещё её эту статью. Пороюсь может и найду, но написать точно не напишу там вообще нереально для моего понимания :)

fucker"ok
29.02.2008, 01:09
даешь нейросети!

lsass.exe
29.02.2008, 20:55
http://dign.narod.ru/
Имхо взято отсюда, тока переписано на пхп ;)

orcismylife
01.03.2008, 01:35
Вообще-то у него в статье ссылка на этот сайт и есть.
А так - понравилось.

//Автор, не выёбывайся только с вашей помойкой-tgbr и любимых ваших высказываниях, как кто-то позорит русскую хак сцену. Сам же в начале повествуешь, что твой алгоритм для нубских капчей. Да и вообще, сомневаюсь, что итальянский хекер будет читать этот топик в онлайн переводчике и своим тиммейтам рассказывать, какой в России народ.

Что-то я разошёлся.

Constantine
01.03.2008, 02:33
боян, тема сисек не раскрыта. автор хам

vadim399
01.03.2008, 19:29
Щас на рапиде капча с кошками и собаками идет О_о

vvs777
04.03.2008, 18:59
Щас на рапиде капча с кошками и собаками идет О_о
Ммать, это как?
принцип "тыкни мышкой туда где у болонки нос иначе мышка вонять будет"?

Dr. Livesey
08.04.2008, 17:13
отпишитесь в пм пожалуйста кто умеет писать распознавалки несложных капчей (ну или сделать на базе gocr или еще чего-то такого).

платно, разумеется.

Johan
17.04.2008, 17:32
Автору спасибо, на основе его и Nomer'овского кода решил свои маленькие проблемы с одним надоедливым сервисом. :)

Распознает капчу из букв и цифр типа http://i013.radikal.ru/0804/38/abd2a1864683.jpg

<?

//coded by rikki

function pwntcha($image) {

define("LETTERS" , "...##.....####...##..##.##....####....####....#### ########....####....####....########..##...##.##.. ..####...##.######..##...##.##....####....####...# #.######....#####..##...####.....###......##...... ##......##......##.....#.##...##..#####.######..## ...##.##....####....####....####....####....####.. ..####...##.######..#######.##......##......##.... ..######..##......##......##......##......#######. ##########......##......##......######..##......## ......##......##......##........#####..##...####.. ....##......##......##...#####....####....##.##... ##..#####.##....####....####....####....########## ##....####....####....####....####....############ ################################################## ####################...####......##......##......# #......##......##......##..#...##..##.##....###... ##....####...##.##..##..##.##...####....####....## .##...##..##..##...##.##....####......##......##.. ....##......##......##......##......##......##.... ..#######.##....#####..#############.##.####.##.## ##.##.####....####....####....####....####....#### #...######..######..####.##.####.##.####..######.. .#####...#####....##.............................. .................................................. #######.##....####....####....#########.##......## ......##......##......##........####...##..##.##.. ..####....####....####....####.##.####..####.##..# #...####.########.##....####....####....#########. #####...##..##..##...##.##....####....##.######.## ....####......##.......######.......##......##.... ..####....##.######.########...##......##......##. .....##......##......##......##......##......##... ##....####....####....####....####....####....#### ....####....##.##..##...####..##....####....####.. ..##.##..##..##..##..##..##...####....####.....##. .....##...##....####....####....####....####.##.## ##.##.####.##.#############..#####....####....#### ....##.##..##...####.....##......##.....####...##. .##.##....####....####....####....##.##..##...#### .....##......##......##......##......##......##... #######......##......##.....##.....##.....##.....# #.....##......##......#######...####...##..##.##.. ..##......##.....##.....##.....##.....##.....##... ..########.#####..##...##.......##.....##....###.. .....##.......##......####...##..#####.......##... ..###....####...##.##..##..##.##...##.########.... .##......##......##.#######.##......##......##.### ..###..##.......##......####....##.##..##...####.. ..####...##..##.##....#.##......##.###..###..##.## ....####....##.##..##...####..########......##.... ..##.....##.....##.....##.....##.....##.....##.... ..##........####...##..##.##....##.##..##...####.. .##..##.##....####....##.##..##...####....####...# #..##.##....####....##.##..###..###.##......##.#.. ..##.##..##...####..
");

define("CSE", rand(1,10)>5?65:97); //randomly define CASE of captcha value at runtime. Don't wanna leave a pattern.



$tempname = tempnam("./", "cap");

$temp = fopen($tempname, "w");
fwrite($temp, $image);
fclose($temp);

$src = imagecreatefromjpeg($tempname);
$im = imagecreatetruecolor(53, 10);
imagecopy($im, $src, 0, 0, 5, 11, 53, 10);
$bl = imagecreatetruecolor(8, 10);

$txtNum = '';

for($n = 0; $n<48; $n += 9) {

imagecopy($bl, $im, 0, 0, $n, 0, 8, 10);
$txtNum .= charcode($bl);

}

unlink($tempname);
return $txtNum;

}

function charcode($cell) {

$white = imagecolorallocate($cell, 255, 255, 255); //$cell must be truecolor, otherwise OOL
$black = imagecolorallocate($cell, 0, 0, 0); //-/- applies :P

$linear='';

for($j=0;$j<10;$j++)
{

for($i=0;$i<8;$i++)
{
$color=imageColorAt($cell,$i,$j);
list($r,$g,$b) = array_values(imageColorsForIndex($cell,$color));
if($r>40 && $g>40 && $b>40)
{
imagesetpixel($cell,$i,$j,$white); //what we do here is we map the image pixel by pixel onto a string
$linear .= '.';//echo "."; //with binary values of # == "I am a pixel that's part of a letter" and . == "I am useless and irrelevant"
} else {
imagesetpixel($cell,$i,$j,$black);
$linear .= '#';//echo "#";
}
}
//echo "\n\r";
}

$char = strpos(LETTERS, $linear);

if ($char < 2075) {return(chr(CSE + $char/80));}
else {return(chr(50 + ($char/80)-26 ));}



}

?>