Pull to refresh

Первый опыт взлома капчи

Lumber room
Awaiting invitation

Почему мне это понадобилось?


Недавно, блуждаю по сайту фриланса, наткнулся на интересное задание — нужно было скачать около 65000 файлов. Скачивание ограничивалось вводом капчи, состоящей из четырех цифр. Сначала хотел использовать сервис antigate.com, о чем прямо сообщил заказчику, но мое желание сэкономить любопытство заставило меня взяться за написание скрипта, который бы разгадывал капчу автоматически.

Немного о коде


Я программирую на PHP недолго, поэтому код у меня еще не качественный, сильно не бейте.

Пример капчи


image

Поехали взламывать


Для начала загружаем изображение в скрипт, определяем его высоту и ширину и устанавливаем для него белый и черный цвет.
    $image = imagecreatefrompng($img);
    $width = imagesx($image);
    $height = imagesy($image);
    $white = imagecolorallocate($image,255,255,255);
    $black = imagecolorallocate($image,0,0,0);

Внимательно изучив картинку под фотошопом микроскопом, понял, что фоновый шум всегда состоит из одного цвета RGB(216,216,216), причем в цифрах этот цвет не встречается. Поэтому очищаем изображение от этого цвета, заменив его на белый:
for ($x=0;$x<$width;$x++) {
    for($y=0;$y<$height;$y++) {
        $color_index = imagecolorat($image,$x,$y);
        $color_back = imagecolorsforindex($image,$color_index);
        if ($color_back['red'] == 216 && $color_back['green'] == 216 && $color_back['blue'] == 216) {
            imagesetpixel($image,$x,$y,$white);
        }
    }
}

Затем перекрашиваем все цифры в черный цвет, исходя из того, что любой цвет, кроме белого, принадлежит цифрам:
for ($x=0;$x<$width;$x++) {
    for($y=0;$y<$height;$y++) {
        $color_index = imagecolorat($image,$x,$y);
        $color_back = imagecolorsforindex($image,$color_index);
        if ($color_back['red'] + $color_back['green'] + $color_back['blue'] != 765) {
            imagesetpixel($image,$x,$y,$black);
        }
    }
}

Далее снова взялся за фотошом микроскоп. Проанализировав цифры, понял, что все они имеют размеры 8х10 рх и располагаются строго по одной вертикали (первая цифра от 15 до 22 пикселя, вторая — 25 — 32 пиксель и т. д.). Причем цифры не искажаются, то есть состоят из строго определенного набора пикселей. Еще раз посмотрев на цифры, я составил для каждой из них что-то типа матрицы. К примеру для семерки:
11111111
00000011
00000011
00000110
00001100
00011000
00110000
01100000
11000000
11000000

Где 0 — это белый пиксель, а 1 — черный. Чтобы было меньше кода для сравнивания цифр, я преобразовал матрицы цифр в строку. Все та же семерка:
11111111000000110000001100000110000011000001100000110000011000001100000011000000
Далее анализируем нужный нам квадрат с цифрой, указывая, что белый пиксель равен нулю, а черный — единице. Для первой цифры:
	for ($x=15;$x<=22;$x++) {
		for($y=0;$y<$height;$y++) {
			$color_index = imagecolorat($image,$x,$y);
			$color_back = imagecolorsforindex($image,$color_index);
			if ($color_back['red'] + $color_back['green'] + $color_back['blue'] == 0) {
				$temp[$y][] = 1;
			} else {
				$temp[$y][] = 0;
			}
		}
	}

Для второй — четвертой цифр аналогично.
Получается двухмерный массив, превращаем его в одномерный:
	for ($i=0;$i<count($temp);$i++) {
		$temp[$i] = implode('',$temp[$i]);
	}

Далее из получившегося массива удаляем чистые ряды, то есть ряды, содержащие только '00000000'
	foreach ($temp as $value) {
		if ($value != '00000000') {
			$digit1[] = $value;
		}
	}

Получившийся массив $digit1 объединяем в строку:
$digit1 = implode('',$digit1);
.
И сравниваем получившееся значение с имеющимися матрицами цифр с помощью небольшой самописной функции:
	function compare($digit) {
		$one 	= file_get_contents('1.txt');
		$two 	= file_get_contents('2.txt');
		$three 	= file_get_contents('3.txt');
		$four 	= file_get_contents('4.txt');
		$five 	= file_get_contents('5.txt');
		$six 	= file_get_contents('6.txt');
		$seven 	= file_get_contents('7.txt');
		$eight 	= file_get_contents('8.txt');
		$nine 	= file_get_contents('9.txt');
		$zero 	= file_get_contents('0.txt');
		if ($digit === $one) $value = '1';
		if ($digit === $two) $value = '2';		
		if ($digit === $three) $value = '3';
		if ($digit === $four) $value = '4';
		if ($digit === $five) $value = '5';
		if ($digit === $six) $value = '6';
		if ($digit === $seven) $value = '7';
		if ($digit === $eight) $value = '8';
		if ($digit === $nine) $value = '9';
		if ($digit === $zero) $value = '0';
		return $value;

	}

Результат сразу для четырех цифр:
    $result = compare($digit1) . compare($digit2) . compare($digit3) . compare($digit4);
    return $result;

Результаты

  1. Написано всего 150 строк кода за 3 часа.
  2. Приобретен опыт взлома капчи.
  3. Получен огромный выигрыш во времени (antigate разгадывает капчу за 10-20 секунд, скрипт за 1-2).
  4. Сэкономлено почти $100.
Tags: phpкапчавзлом
Hubs: Lumber room
You can’t comment this post 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.