Usando JavaScript para quebrar códigos de verificação
Recentemente, apareceu na Internet um script JavaScript que pode quebrar códigos de verificação - GreaseMonkey. Este script desenvolvido por "Shaun Friedle" pode resolver facilmente o CAPTCHA do site Megaupload! Se você não acredita, você pode tentar em http://herecomethelizards.co.uk/mu_captcha/
Agora, o CAPTCHA fornecido pelo site Megaupload foi derrotado pelo código acima. o código aqui foi projetado Não, não é muito bom. Mas o que é mais interessante é:
1. A interface do aplicativo Canvas getImageData em HTML 5 pode ser usada para obter dados de pixel da imagem do código de verificação. Usando o Canvas, podemos não apenas incorporar uma imagem em uma tela, mas também extraí-la novamente posteriormente.
2. O script acima contém uma rede neural implementada inteiramente em JavaScript.
3. Depois de usar o Canvas para extrair dados de pixel da imagem, envie-os para a rede neural e use uma tecnologia simples de reconhecimento óptico de caracteres para inferir quais caracteres são usados no código de verificação.
Ao ler o código-fonte, podemos não apenas entender melhor como ele funciona, mas também entender como esse código de verificação é implementado. Como você viu anteriormente, os CAPTCHAs usados aqui não são muito complexos - cada CAPTCHA consiste em três caracteres, cada caractere usa uma cor diferente e usa apenas caracteres do alfabeto de 26 letras, enquanto todos os caracteres usam a mesma fonte.
O objetivo da primeira etapa é óbvio: copiar o código de verificação para a tela e convertê-lo em uma imagem em tons de cinza.
função convert_grey(dados_da_imagem){
for (var x = 0; x <image_data.width; x++){
for (var y = 0; y < image_data.height; y++){
var i = x*4+y*4*image_data.width;
var luma = Math.floor(image_data.data[i] * 299/1000 +
dados_imagem.data[i+1] * 587/1000 +
dados_imagem.data[i+2] * 114/1000);
imagem_data.data[i] = luma;
dados_imagem.data[i+1] = luma;
dados_imagem.data[i+2] = luma;
dados_imagem.data[i+3] = 255;
}
}
}
Em seguida, divida a tela em três matrizes de pixels separadas, cada uma contendo um caractere. Esta etapa é muito fácil de realizar porque cada personagem usa uma cor separada, para que possa ser distinguido pela cor.
filtro(dados_imagem[0], 105);
filtro(dados_imagem[1], 120);
filtro(dados_imagem[2], 135);
filtro de função(dados_da_imagem, cor){
for (var x = 0; x <image_data.width; x++){
for (var y = 0; y < image_data.height; y++){
var i = x*4+y*4*image_data.width;
//Transforma todos os pixels de uma determinada cor em branco
if (image_data.data[i] == cor) {
dados_imagem.data[i] = 255;
dados_imagem.data[i+1] = 255;
dados_imagem.data[i+2] = 255;
// Todo o resto fica preto
} outro {
dados_imagem.data[i] = 0;
dados_imagem.data[i+1] = 0;
dados_imagem.data[i+2] = 0;
}
}
}
}
Finalmente, todos os pixels interferentes irrelevantes são eliminados. Para fazer isso, você pode primeiro encontrar os pixels brancos (correspondentes) cercados por pixels pretos (não correspondentes) na frente ou atrás e, em seguida, excluir os pixels correspondentes.
var i = x*4+y*4*image_data.width;
var acima = x*4+(y-1)*4*image_data.width;
var abaixo = x*4+(y+1)*4*image_data.width;
if (image_data.data[i] == 255 &&
image_data.data[acima] == 0 &&
image_data.data[abaixo] == 0) {
dados_imagem.data[i] = 0;
dados_imagem.data[i+1] = 0;
dados_imagem.data[i+2] = 0;
}
Agora que temos uma forma aproximada do personagem, o script executa ainda a detecção de borda necessária nele antes de carregá-lo na rede neural. O script procurará os pixels mais à esquerda, à direita, superior e inferior do gráfico, converterá-os em um retângulo e, em seguida, converterá novamente o retângulo em uma matriz de 20*25 pixels.
cropped_canvas.getContext("2d").fillRect(0, 0, 20, 25);
var bordas = find_edges(image_data[i]);
cropped_canvas.getContext("2d").drawImage(canvas, bordas[0], bordas[1],
arestas[2]-arestas[0], arestas[3]-arestas[1], 0, 0,
arestas[2]-arestas[0], arestas[3]-arestas[1]);
image_data[i] = cropped_canvas.getContext("2d").getImageData(0, 0,
cropped_canvas.width, cropped_canvas.height);
Após o processamento acima, o que obtemos? Uma matriz 20*25 contendo um único retângulo preenchido com preto e branco. Isso é ótimo!
Então, simplificaremos ainda mais o retângulo. Extraímos estrategicamente pontos da matriz como “fotorreceptores” que serão alimentados na rede neural. Por exemplo, um determinado fotorreceptor pode corresponder a um pixel localizado em 9*6, com ou sem pixels. O script extrai uma série desses estados (muito menos do que todo o cálculo da matriz 20x25 - apenas 64 estados são extraídos) e alimenta esses estados na rede neural.
Você pode perguntar: por que não comparar os pixels diretamente? É necessário usar uma rede neural? A questão é: queremos nos livrar dessas situações ambíguas? Se você tentou a demonstração anterior, notará que comparar pixels diretamente é mais sujeito a erros do que comparar por meio de uma rede neural, embora isso não aconteça muito. Mas temos que admitir que, para a maioria dos usuários, a comparação direta de pixels deve ser suficiente.
O próximo passo é tentar adivinhar as letras. 64 valores booleanos (obtidos de uma das imagens dos personagens) são importados para a rede neural, bem como uma série de dados pré-calculados. Um dos conceitos das redes neurais é que os resultados que queremos obter são conhecidos antecipadamente, para que possamos treinar a rede neural adequadamente com base nos resultados. O autor do script pode executar o script várias vezes e coletar uma série de melhores pontuações que podem ajudar a rede neural a adivinhar a resposta trabalhando de trás para frente a partir dos valores que as produziram, mas essas pontuações não têm nenhum significado especial.
Quando a rede neural calcula os 64 valores booleanos correspondentes a uma letra no código de verificação, compara-os com um alfabeto pré-calculado e, em seguida, dá uma pontuação pela correspondência com cada letra. (O resultado final pode ser semelhante: 98% pode ser a letra A, 36% pode ser a letra B, etc.)
Depois que todas as três letras do código de verificação forem processadas, o resultado final será exibido. Deve-se notar que este script não está 100% correto (me pergunto se a precisão da pontuação pode ser melhorada se as letras não forem convertidas em retângulos no início), mas é muito bom, pelo menos para o propósito atual. Diga isso. E todas as operações são concluídas no navegador com base na tecnologia de cliente padrão.
Como complemento, esse script deve ser considerado um caso especial. Essa tecnologia pode funcionar bem em outros códigos de verificação simples, mas para códigos de verificação complexos, é um pouco. fora do alcance (especialmente este tipo de análise baseada no cliente). Espero que mais pessoas possam se inspirar neste projeto e desenvolver mais coisas maravilhosas, pois seu potencial é muito grande