Jump to content
vladiii

Cum sa spargem un captcha simplu

Recommended Posts

cap1.pngcap2.png

cap3.pngcap4.png

In acest tutorial vom invata sa spargem acest tip de captcha. In ce consta el ?

- culoarea backgroundului este random

- culoarea cifrelor este mereu aceeasi

- pozitia cifrelor difera pe X

- pozitia cifrelor ramane neschimbata pe Y

Ce inseamna sa "spargem un captcha" ? Practic, trebuie sa afisam in format text cifrele din fiecare imagine (evident, sunt random). Sa vedem in continuare codul .php care genereaza imaginile:


<?php
header('Content-type: image/png');
$img = imagecreate(239, 25);

$r = rand(1, 255);
$g = rand(1, 255);
$b = rand(1, 255);
$l1 = rand(0, 4);
$l2 = rand(0, 4);
$l3 = rand(0, 4);
$l4 = rand(0, 4);
$l5 = rand(0, 4);
$poz1 = rand(0, 48);
$poz2 = $poz1 + rand(9, 48);
$poz3 = $poz2 + rand(9, 48);
$poz4 = $poz3 + rand(9, 48);
$poz5 = $poz4 + rand(9, 48);

$background = imagecolorallocate($img, $r, $g, $;
$culoare = imagecolorallocate($img, 100, 100, 100);

imagechar($img, 7, $poz1, 6, $l1, $culoare);
imagechar($img, 7, $poz2, 6, $l2, $culoare);
imagechar($img, 7, $poz3, 6, $l3, $culoare);
imagechar($img, 7, $poz4, 6, $l4, $culoare);
imagechar($img, 7, $poz5, 6, $l5, $culoare);

imagepng($img);
?>

1) Background - alb, cifre - negru.

Primul pas consta in eliminarea culorilor. Backgroundul imaginii va deveni alb, iar cifrele vor avea culoarea neagra. Sa vedem codul php:


$img = imagecreatefrompng("http://site.com/captcha/cap1.png");

$alb = imagecolorallocate($img, 255, 255, 255);
$negru = imagecolorallocate($img, 0, 0, 0);

//Simplificarea imaginii
//Background alb
//Scris de culoare neagra
for ($i=0; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixel = imagecolorat($img, $i, $j);
$rgb = imagecolorsforindex($img, $pixel);
if ($rgb['red']!=100 && $rgb['green']!=100 && $rgb['blue']!=100)
{
imagesetpixel($img, $i, $j, $alb);
}
else
{
imagesetpixel($img, $i, $j, $negru);
}
}
}
//Finished simplificare

cap1.png reprezinta imaginea care urmeaza sa fie "sparta". Se observa din cod ca cifrele (care au r, g, b = 100) sunt setate la culoarea neagra, iar restul pixelilor la alb. Acum imaginea este alb-negru.

2) Gasire dreptunghiuri cifre.

Cum am spus, cifrele sunt plasate random pe axa oX. Ideea este ca noi trebuie sa impartim imaginea initiala (cea mare/cap1.png) in 5 imagini mai mici, fiecare continand doar o cifra ! Un amanunt foarte important este ca fontul default folosit la functia imagechar() este monospaced (courier din cate stiu), iar orice cifra "scrisa" cu font size=7 poate fi incadrata intr-un dreptunghi de lungime 9.

Deci spre exemplu, ca sa gasesc prima cifra, trebuie sa gasesc primul pixel de culoare neagra (cautarea pornind de la stanga la dreapta) si sa ii retin X'ul. Apoi extrag dreptunghiul de la X pana la X+8. Codul PHP:


//Gasire dreptunghi prima cifra
for ($i=0; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixel = imagecolorat($img, $i, $j);
$rgb = imagecolorsforindex($img, $pixel);
if ($rgb['red']==0 && $rgb['green']==0 && $rgb['blue']==0)
{
$istart = $i; $ifinal = $i+8; break 2;
}
}
}

//Gasire dreptunghi a 2-a cifra
for ($i=$ifinal+1; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixel = imagecolorat($img, $i, $j);
$rgb = imagecolorsforindex($img, $pixel);
if ($rgb['red']==0 && $rgb['green']==0 && $rgb['blue']==0)
{
$iistart = $i; $iifinal = $i+8; break 2;
}
}
}

//Gasire dreptunghi a 3-a cifra
for ($i=$iifinal+1; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixel = imagecolorat($img, $i, $j);
$rgb = imagecolorsforindex($img, $pixel);
if ($rgb['red']==0 && $rgb['green']==0 && $rgb['blue']==0)
{
$iiistart = $i; $iiifinal = $i+8; break 2;
}
}
}

//Gasire dreptunghi a 4-a cifra
for ($i=$iiifinal+1; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixel = imagecolorat($img, $i, $j);
$rgb = imagecolorsforindex($img, $pixel);
if ($rgb['red']==0 && $rgb['green']==0 && $rgb['blue']==0)
{
$ivstart = $i; $ivfinal = $i+8; break 2;
}
}
}

//Gasire dreptunghi a 5-a cifra
for ($i=$ivfinal+1; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixel = imagecolorat($img, $i, $j);
$rgb = imagecolorsforindex($img, $pixel);
if ($rgb['red']==0 && $rgb['green']==0 && $rgb['blue']==0)
{
$vstart = $i; $vfinal = $i+8; break 2;
}
}
}
//Finished gasire dreptunghiuri

Am gasit ceea ce aveam nevoie (valorile sunt retinute in variabilele $istart, $iistart, $iiistart, $ivstart, $vstart). Acum trebuie sa dam crop la imaginea initiala pentru a extrage exact aceste cifre (pt. asta folosim functia imagecopyresampled -> http://www.php.net/manual/en/function.imagecopyresampled.php ):


//Impartire in 5 imagini
//Cropuire de la stanga la dreapta
$img1=imagecreate(9, 25);
$img2=imagecreate(9, 25);
$img3=imagecreate(9, 25);
$img4=imagecreate(9, 25);
$img5=imagecreate(9, 25);
imagecopyresampled ($img1, $img, 0, 0, $istart, 0,9, 25, 9, 25);
imagecopyresampled ($img2, $img, 0, 0, $iistart, 0,9, 25, 9, 25);
imagecopyresampled ($img3, $img, 0, 0, $iiistart, 0,9, 25, 9, 25);
imagecopyresampled ($img4, $img, 0, 0, $ivstart, 0,9, 25, 9, 25);
imagecopyresampled ($img5, $img, 0, 0, $vstart, 0,9, 25, 9, 25);
//Finished cropuire de la stanga la dreapta

Din ceea ce se vede mai sus, cifrele sunt salvate in imagini de 9x25. Sa le vedem:

0.png1.png2.png3.png4.png

3) Compararea imaginilor.

Acum ca am obtinuit imaginile care contin cifrele (0, 1, 2, 3, 4), le salvam pe server pentru a face comparatii mai tarziu. Ca sa le putem folosi in scriptul php, trebuie sa folosim urmatorul cod:


$cif[0] = imagecreatefrompng("cifre/0.png");
$cif[1] = imagecreatefrompng("cifre/1.png");
$cif[2] = imagecreatefrompng("cifre/2.png");
$cif[3] = imagecreatefrompng("cifre/3.png");
$cif[4] = imagecreatefrompng("cifre/4.png");

Ce ne mai ramane de facut ? Sa comparam pixelii lui $img1, $img2, $img3, $img4, $img5 cu fiecare dintre $cif[0], $cif[1], $cif[2], $cif[3], $cif[4], pe rand. Daca $img1 coincide cu $cif[2], atunci cifra corespunzatoare este 2.


//Functie comparare imagini
function comparare($imagine12, $cifra12)
{
$true = 0;
for ($i=0; $i<239; $i++)
{
for ($j=0; $j<25; $j++)
{
$pixelx = imagecolorat($imagine12, $i, $j);
$pixely = imagecolorat($cifra12, $i, $j);
if ($pixelx != $pixely)
{
//Difera un pixel
$true = 1; break 2;
}
}
}

return $true;
}
//End functie

//Comparari imagini & stuff
//Daca returneaza 0, imaginile sunt identice
//Daca returneaza 1, imaginile sunt diferite
//Si trecem sa comparam cu urmatoarea
for ($x=0; $x<=4; $x++)
{
$value=comparare($img1, $cif[$x]);
if ($value==0) { echo $x."\r\n"; break; }
}
for ($x=0; $x<=4; $x++)
{
$value=comparare($img2, $cif[$x]);
if ($value==0) { echo $x."\r\n"; break; }
}
for ($x=0; $x<=4; $x++)
{
$value=comparare($img3, $cif[$x]);
if ($value==0) { echo $x."\r\n"; break; }
}
for ($x=0; $x<=4; $x++)
{
$value=comparare($img4, $cif[$x]);
if ($value==0) { echo $x."\r\n"; break; }
}
for ($x=0; $x<=4; $x++)
{
$value=comparare($img5, $cif[$x]);
if ($value==0) { echo $x."\r\n"; break; }
}

Asta e tot. Ati reusit sa spargeti un captcha ! Felicitari :)

Link to comment
Share on other sites

vladiii, acuma macar sunt sigur ca am vb cu tine pe mess (eram 90% da mi se intampla sa ma mai faca friend cate un kenpaki din cand in cand...).

Ma gandeam ca de la punctul 2 incolo, la tipul asta de captcha: se poate folosi ceva gen dictionar, iei cifrele din captcha fara sa te intereseze fontul si le pui deoparte, apoi le compari. Pentru optimizarea algoritmului, dorind sa obtii doar un text cu numerele, nu te mai intereseaza sa corespunda 100% cu imaginea, nu faci OCR pe ea. Gasesti doar cateva pozitii ale unor pixeli pentru fiecare cifra in parte si le cauti doar in imaginea din captcha. Ceva cum e LCD-ul: 1 inseamna 2 liniute, restul zero, intelegi! Si in caz ca nu am observat (nu pot citi cod la ora asta): comparatia se face ">culoare fundal" sau "<culoare fundal" si nu "==culoare fixa"

Link to comment
Share on other sites

^ Inclin sa cred ca in acest caz metoda care am folosit-o eu este cea mai buna. Nu avea rost sa ma complic pt. un captcha care nu este foarte greu de spart.

Metoda aleasa de tine se foloseste si poate avea rezultate bune, insa in cazul unor captcha'uri mai complicate. Bafta !

Link to comment
Share on other sites

chiar e bine ca s-a creat un astfel de tutorial.

pentru spargerea unui captcha trebuie destul de mult efort investit.

de la analizarea imaginilor, a tipurilor de caractere, gasirea punctelor comune, si daca e nevoie puse pe categorii punctele comune (de exemplu 3 tipuri de fonturi), alegerea metodei de recunoastere a caracterelor, si implementarea propriu-zisa... uneori si teste exhaustive sau antrenarea retelelor neuronale ( :lol: )

kewl

Link to comment
Share on other sites

^ Inclin sa cred ca in acest caz metoda care am folosit-o eu este cea mai buna. Nu avea rost sa ma complic pt. un captcha care nu este foarte greu de spart.

Metoda aleasa de tine se foloseste si poate avea rezultate bune, insa in cazul unor captcha'uri mai complicate. Bafta !

Nu ziceam de captcha complicate. Desi... cred ca ai dreptate. Comparatia cu LCD este doar de a nu compara intreaga imagine ci partial. E doar o optimizare, dar deoarece scopul scuza mijloacele, e mai complicat si inutil sa creez optimizarea asta (ma complic singur).

Luat un caz de cifre si gandit:

- care pixeli exista marcati la cifra 0 si care nu

- ... cifra 1...

La litere e cam pierdere de timp. Bine e cum am zis, o optimizare prea complicata, ca timp de executie este insesizabila.

Is curios de un algoritm de vanat matzele de pe rapidshare (totusi se pare ca se lauda cu un update pe viitor)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...