热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

验证码识别思路

因为某些原因,最近写了个不停注册某网站账号的chrome扩展。(算外挂吗?)该网站注册时需要输入验证码,且单次有效,所以穷举不可取。(验证神马的,最讨厌了!)首先要确定验证

因为某些原因,最近写了个不停注册某网站账号的chrome扩展。(算外挂吗?)

  该网站注册时需要输入验证码,且单次有效,所以穷举不可取。(验证神马的,最讨厌了!)

================================================================

  首先要确定验证码图片是实时生成的还是只是静态图片,收集大量验证码看看是不是有大量相同的:

  最近erlang代码写得比较多,就用erlang实现了,至于存储,直接放磁盘算了。

《验证码识别思路》

-export([start/0]).
start() ->
inets:services(),
inets:start(),
S = lists:sum([get_img(X)||X<-lists:seq(1,10000)]),
io:format("~p/~p",[S,10000]).
get_img(N) ->
io:format("~p~n",[N]),
UrlPic = "http://网址就不公开了/xxx.do?yyy=zzz",
case httpc:request(UrlPic) of
{ok,{_,_H,Data}} ->
Bin = list_to_binary(Data),
<<Id:128>> = erlang:md5(Bin),
FileName = lists:flatten(io_lib:format("img/~.16b.jpg",[Id])),
case file:read_file_info(FileName) of
{ok,_} -> io:format("exists: ~p~n",[FileName]),1;
_ -> file:write_file(FileName,Bin),0
end;
Why ->
io:format("~p~n",[Why]),
get_img(N)
end.

《验证码识别思路》

  代码里对获得的图片计算了标准md5校验码作为图片文件名,判断两个图片是否完全一致的办法是看两个图片的校验码是否一致。

  测试发现,当收集了300多个图片后开始出现重复。超过5000个图片后,碰撞率变得很高。最终当我收集了1w8张验证码图片时,图片命中率高达97%。

  也许有人觉得单看验证码判断图片是否一致的方法有问题,但如果100张图片中有97张的验证码都和之前的某张的一样,但实际内容却不同,那就见鬼了。由于我好奇心比较重,为了看看有没有这种见鬼的事,我改了下上面的代码,将md5冲突的新图片保存下来人工确认,见鬼的事没有发生,内容长度确实是完全一模一样。

================================================================

  以上说明该网站的验证码就是预先一大堆静态图片,估计总数大概是2w,每次请求时随机取一张图片返回。这样做的原因估计是这么做对性能影响很小。

  这么算吧:2w张图片,人工写1000个映射关系,命中率就5%,每次请求一幅图片的时间不会超过500ms,平均不用10秒遇到一张已经知道验证码的图片。于是,于是……于是我两天晚上抽空填了3000个验证码,最后速度嘛,大概5s一个账号。

  可能有人会好奇我怎么输入3000个验证码,其实是我特地写了个小程序方便录入:

《验证码识别思路》

================================================================

  问题虽然基本解决,但我还是更倾向于用代码来识别验证码。

  感觉erlang做GUI程序不方便,还是用回C#来做这部分工作。

  从网上找了好几个.NET下的OCR引擎,识别率极低:识别出一个数字的概率大概等于瞎猫碰上死老鼠。看来靠第三方是搞不定的了,还得靠自己。

  观察验证码的特点:所有验证码都是4位0-9整数,80&#215;30像素,1.4kB左右,色调比较单一,数字都稍微扭曲了点,但不同验证码的同个数字的相似度非常高:

《验证码识别思路》

《验证码识别思路》

《验证码识别思路》

《验证码识别思路》

  我相信看到这,熟悉Matlab的同学一定乐死了。但是,我不熟悉,还是用土方法吧:对图片取灰度,截取4个小图,抽取0-9十个样本,分析时每个数字与样本匹配,相似度最高的就是对应数字。

  很不幸,这种方法识别出来的数字也不是很靠谱,四个数字通常只能识别两三个,完整识别出来的几乎没有。正当我准备对图片进行归一化调整时,我发现验证码图片中,相同位置的相同数字相似度极高,但不同位置的相同数字相似度倒是不高。

  既然规律找到了,方案自然就出来了:在取样本时,每个位置的数字的样本分开管理,下面是核心匹配代码:

《验证码识别思路》

private int parse_one(int[] hash,int n)
{
int x = 0;
int r = 0;
for (int i = 0; i <10; i++)
{
var r2 = match(hash,n,i);
if (r2 > r) { r = r2; x = i; }
}
return x;
}
private int match(int[] hash, int n, int i)
{
int sum = 0;
int o = i * H * W * 4 + n * W;
for (int x = 0; x {
for (int y = 0; y {
int g1 = cache[o + x + y * 4 * W];
int g2 = hash[x + y * W];
if (g1 > 200 && g2 > 200)
{
sum += 1000;
}
else if (g1 <50 && g2 <50)
{
sum += 5000;
}
else
{
sum += (255 - Math.Abs(g1 - g2));
}
}
}
return sum;
}

《验证码识别思路》

  最终识别率:几乎100%(试了10几张没发现哪个验证码图片识别不出,还是低调点,90%吧)

《验证码识别思路》

  后面就是写个批处理功能,把收集到的验证码转换成JS,供chrome扩展直接查表使用了,最终效果大概是2秒一个账号。至于chrome扩展怎么获取验证码图片,怎么算md5,这些都不是本文的重点,在此略过。

  这个网站的验证码方案有几点不够安全的地方:

  1. 使用静态验证码,且静态验证码总数较少(后来发现原来隔一段时间就换一次,汗);

  2. 各验证码图片的相似度太高,随机性不足,识别难度颇低;

  3. 对于短时间注册大量账号的IP没有相关应对措施。

================================================================

后记:

  昨天到别的机子运行发现这个神一样的注册机用了没多久竟然不灵了,验证码突然一个都识别不出,观察发现该网站的验证码又不一样了,暴汗,一天换一批注册码。

还好不是用人工输入的办法,打算回来继续录入样本识别,发现家里的获得的验证码的图片还是原来的,莫非这些验证码还根据IP或者网络线路发放?真是魔高一尺,道高一丈……

  我表示还是喜欢这种类型验证码,最好是还可以暴力穷举:

《验证码识别思路》


推荐阅读
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 导出功能protectedvoidbtnExport(objectsender,EventArgse){用来打开下载窗口stringfileName中 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • Python已成为全球最受欢迎的编程语言之一,然而Python程序的安全运行存在一定的风险。本文介绍了Python程序安全运行需要满足的三个条件,即系统路径上的每个条目都处于安全的位置、"主脚本"所在的目录始终位于系统路径中、若python命令使用-c和-m选项,调用程序的目录也必须是安全的。同时,文章还提出了一些预防措施,如避免将下载文件夹作为当前工作目录、使用pip所在路径而不是直接使用python命令等。对于初学Python的读者来说,这些内容将有所帮助。 ... [详细]
  • 点击上方“新机器视觉”,选择加”星标”或“置顶”重磅干货,第一时间送达很早就想总结一下前段时间学习HALCON的心得,但由于其他的事情总是抽不出时间。去年有过一段时间的集中学习,做 ... [详细]
  • CentOs 7.3中搭建RabbitMQ 3.6单机多实例服务的步骤与使用
    CentOs7.3中搭建RabbitMQ3.6单机多实例服务的步骤与使用-RabbitMQ简介RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • PatchODAX8: ... [详细]
author-avatar
HGKHGK
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有