百度贴吧验证码识别技术
[ 2009-11-10 21:41:13 | 作者: admin ]
百度贴吧验证码识别技术前言:
下面这篇文章算是比较老了,针对的是很早以前的百度贴吧的验证码识别,当然现在早已不能用了。不过其中的思路,技术还是有值得借鉴的。所以一并贴出来了。
相信大家都有在论坛灌水的经历吧?但是如果你连续发表统一内容的东西在论坛中,不久论坛的整个板块就全是你发表的信息了,其他信息全被挤在了后面。假设你发表的信息够多,版主都删不完时,那么这个论坛基本就报废了!其他的商业论坛也意识到了防止恶意灌水的重要性,纷纷使用了一些防止恶意灌水的措施,有发贴间隔时间的限制、同一IP地址的发贴数限制、内容不能重复等,但是这些都不是今天的重点,由于百度使用的是一个公用发贴表单,允许匿名发帖,需要突破唯一的难点是验证码。(为了防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试或是防止不断提交某网络信息而采用的一种网络通行方式。随机生成字符信息放入图片中,防止计算机直接识别。比如招商银行的网上个人银行,腾讯的QQ社区等等)
这时验证码在整个系统中就扮演了了一个至关重要的角色。如果我们能突破它,写一个自动发布的程序,那么我们来算一算:假设每两秒程序post一次,一分钟就是30次、 一小时就有30×60=1800次、 一天就有1800×24=43200次!如果我们把发贴程序或是密码穷举程序挂在很多肉鸡上,进行同时工作,那么结果可想而知!笔者曾亲目睹过国内某著名安全论坛就是验证码被人破解,导致被人恶意灌水,最后完全崩溃!当然还有某网络银行也因此类原因导致用户密码被盗等众多事件。笔者也作如下声明:下文介绍的方法并不是有意针某公司或是某机构,只是作为技术交流,如果部分读者利用本文介绍的方法进行破坏或是穷举他人密码,这已经违法了法律,那么责任由他自己承担,与笔者无关!
好了,我们可以进入正题了(以下出现的代码为delphi写的部分源码,为了防止任意利用,我以介绍方法为主,如果读者感兴趣,可以自己组合编写完整,在本文附带的程序中,笔者提供了一个验证码参数确定程序(附源码))。验证码分为如下几类:数字型、字符型、符号型、综合型。
我们看了看百度贴吧的验证码如图: 是属于数字型的!不过其图片中生成了不少彩色和黑白的噪音点(指验证图片上的斑点)。那么我们应该怎么去识别呢?传统的验证码识别方式很简单,由于数字的位置是固定的,所以我们只需要提取每一幅数字的图片(没有噪音点的)然后把每一个特殊数字独有的象素位置记录下来,然后在网络上提取需要破解的特征码,祛除噪音点,对其位置和记录位置进行比对,那就是么就能确定相应的数字了。
总结一下传统的就是:
1.先分析验证码,前景颜色是否不定
2.然后把验证码的宽度/验证码文字个数,比如一验证码下载后宽度为60,有4个数字,那么就60/4=15,然后保存每个字,如果只有数字保存0-9数字到位图文件,如果英文那更麻烦点,0-9,A-Z都要保存到位图,位图的前景色都不变,保持一种颜色,背景随便你改不改
3.如果前景要变则将文字统一为同种颜色,每个数字0-9的点阵都有个公共点,取该公共点颜色然后把前景全部统一成一种颜色,比如白色{255,255,255},位图的结构是BGR,而不是RGB
4.然后进行比较,如果验证码的一点为白色,第2步保存的位图同一点也是白色,那么频率增加1
5.最后频率最高的就是验证码了!
可是这种传统的识别方法却遇到了挑战!如果图片数字的位置也是随机出现,大小也是随机出现,那么这种识别方法也就失效了,百度贴吧的就是这样的验证码。
笔者这里向大家引入一个专有名词:“hough变换”也许学习计算机图像学的朋友知道,笔者还是简要介绍一下:
直线hough变换:直线Hough变换利用图像空间和Hough参数空间的点-线对偶性,把图像空间中的检测问题转换到参数空间。通过在参数空间里进行简单的累加统计,然后在Hough参数空间寻找累加器峰值的方法检测直线。例如,图1(a)中的九条线段对应于如图1(b)所示的其Hough参数空间的九个累加器峰值。图1(b)中,Hough参数空间的横纵坐标分别为直线极坐标方程:ρ=x×cos(θ) + y×sin(θ) 的两个参数ρ和θ。九个峰值的ρ和θ值唯一的确定其对应线段所在直线的两个参数。并且线段的长度决定坐标(ρ,θ)处的累加值的大小。
1(a)
1(b)
没有明白的读者可以多读两遍(数学啊数学!),还是比较好理解。其实讲通俗一点,就是我们只要利用这个方程ρ=x×cos(θ) + y×sin(θ)统计出ρ出现的次数,就可以确定一条直线,比如说图片中我们计算出了某个方向(θ的大小)的ρ出现次数的最大值,那么这就是这个方向最长的直线了!
好了,知道了hough变换检测直线的原理,那么我们就来写段代码
var
p: PByteArray;
Gray, x, y,i1,i2: Integer;
Bmp: TBitmap;
begin
listbox1.Clear;
listbox2.Clear;
Bmp := TBitmap.Create;
Bmp.Assign(Image2.Picture.Bitmap);
//设置为24位真彩色
Bmp.PixelFormat := pf24Bit;
randomize;
for y := 0 to Bmp.Height - 1 do
begin
p := Bmp.scanline[y];
for x := 0 to Bmp.Width - 1 do
begin
//一个象素点三个字节
Gray := Round(p[x * 3 + 2] * 0.3 + p[x * 3 + 1] * 0.59 + p[x
* 3] * 0.11);
if gray > 128 then //全局阀值128
begin
end
else
begin
i1:=x;//表示检测的θ为0度
i2:=y; //表示检测的θ为90度
ListBox1.Items.Add(inttostr(i1));//用于日后算出现的次数,当然也可以用数组!
ListBox2.Items.Add(inttostr(i2));
end;
end;
end;
Image2.Picture.Bitmap.Assign(Bmp);
Bmp.Free;
这段代码的意思就是检测图片0度和90度的直线。
现在我们就说说具体操作了。先得到一幅验证码图片,这个得到的方法有很多,我建议用屏幕指定位置抓图来实现,然后保存成BMP格式,进行图像的二值化处理。二值化处理就是把图片转换成两种颜色,不过需要设置一个适当的阀值(由于24位图的一个点是由RGB3个颜色分量来控制,那么我们得到这3个分量的值后除以3就是阀值了),这样才能起到祛除部分噪音的效果。我们假设阀值为128 现在我们看看这段代码
var
p: PByteArray;
Gray, x, y: Integer;
Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
Bmp.Assign(Image1.Picture.Bitmap);
//设置为24位真彩色
Bmp.PixelFormat := pf24Bit;
randomize;
for y := 0 to Bmp.Height - 1 do
begin
p := Bmp.scanline[y];
for x := 0 to Bmp.Width - 1 do
begin
//一个象素点三个字节
Gray := Round(p[x * 3 + 2] * 0.3 + p[x * 3 + 1] * 0.59 + p[x
* 3] * 0.11);
if gray > 128 then //全局阀值128
begin
p[x * 3] := 255;
p[x * 3 + 1] := 255;
p[x * 3 + 2] := 255;
end
else
begin
p[x * 3] := 0;
p[x * 3 + 1] := 0;
p[x * 3 + 2] := 0;
end;
end;
end;
Image2.Picture.Bitmap.Assign(Bmp);
Bmp.Free;
这样我们就得到了一幅二值化的BMP。
得到这副图后,我们需要对图像进行分割,就是把它变成4个小位图,分别装入4个数字。分割算法很简单,因为验证码的数字位置左右跳动幅度不大,源代码就不再给出。
然后我们要做的就是把这副图进行几个方向的hough变换检测,由控制θ的角度来实现,比如说这个 这是数字3 我们可以看到它有什么特征没有?它横着由三横组成,竖着由2竖组成!我们就规定 如果横着有3条直线,竖着有两条直线,那么这个数就是3了!所以我们只要用hough算子检测 0 & 90 度就能确定横竖有多少直线了,再看这个 这是数字1 我们就规定竖有一条最长的直线,然而横的直线如果不超过竖直线长的1/2那么就是1了。其他数以此类推!
当然实际操作当然没有这么简单,因为还是有部分噪音点没有祛除干净,但是这的确说明了我们的思想!所以每个数有需要准备几套特征编码,如果出现多个数,就看使用编码数最多的数就是我们要识别的数了。最后就是统计了,统计函数我们现在给出
function Repeatcount(s:string;d:string):integer;
var i:integer;
begin
i:=0;
while pos(d,s)>0 do
begin
i:=i+1;
delete(s,pos(d,s),length(d));
end;
result:=i;
end;
利用这个函数,我们就可以确定出现最多的p的次数以及使用编码最多的次数了!笔者随文附送了一个检测0度和90度的检测器,读者可以多试几次就明白了!(如图)
当然只有这两度检测是远远不够的,实际应用中,可以使用0~90度中任意一度检测,比如说7,它的竖由于不是90度的(直的)所以要用其他的度数来检测! 这里也总结一下,任意数字,只要我们能得到相应的特征,那么我们就可以对它进行识别!
总结一下创新的:
1、 获得图片,进行二值化的变换、祛除噪音。
2、 分割图像,保存成相应的BMP文件。
3、 对其进行几个方向的HOUGH变换检测,根据相应的验证码来定!
(你也可以做更多的检测,比如有英文字母就需用到其他算法了!)
4、 对特征进行统计,得出识别结果。
接下来要做的就是做个post程序了,这个太简单了,代码你就自己写吧!不过也要做到如下细节:做成多线程程序进行发贴,不然程序会失去响应的。最好是可以导入大量的代理IP的,然后就是发贴的内容最后加上几个随机字符,这样可以防止重复贴的过滤!最重要的,只是做测试,发贴量不要太多、不要乱发广告贴!
所以说再安全的验证码也有软肋,我们只要发现就可以找出其中的漏洞!当然不只是针对百度,其他论坛的特征码同样能识别!当然网络安全技术也是双刃剑,我这里再次强调!这种方法的确能识别很多重要的部门的一些关键验证码,但是读者如果使用其方法进行破坏,那已经违反了中华人民共和国的相关法律,是要付刑事责任的!并且与笔者无关!
其实上述方法已经不是只是对验证码进行识别了,完全可以用到现实生活中去,比如说手写体识别、车牌识别等等,但是现实生活中我们还要进行更多的加工,比如说圆形检测,多边形检测等等。所以说从网络安全技术中,也有很多东西能造福社会,还等待我们继续创造!
下面这篇文章算是比较老了,针对的是很早以前的百度贴吧的验证码识别,当然现在早已不能用了。不过其中的思路,技术还是有值得借鉴的。所以一并贴出来了。
相信大家都有在论坛灌水的经历吧?但是如果你连续发表统一内容的东西在论坛中,不久论坛的整个板块就全是你发表的信息了,其他信息全被挤在了后面。假设你发表的信息够多,版主都删不完时,那么这个论坛基本就报废了!其他的商业论坛也意识到了防止恶意灌水的重要性,纷纷使用了一些防止恶意灌水的措施,有发贴间隔时间的限制、同一IP地址的发贴数限制、内容不能重复等,但是这些都不是今天的重点,由于百度使用的是一个公用发贴表单,允许匿名发帖,需要突破唯一的难点是验证码。(为了防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试或是防止不断提交某网络信息而采用的一种网络通行方式。随机生成字符信息放入图片中,防止计算机直接识别。比如招商银行的网上个人银行,腾讯的QQ社区等等)
这时验证码在整个系统中就扮演了了一个至关重要的角色。如果我们能突破它,写一个自动发布的程序,那么我们来算一算:假设每两秒程序post一次,一分钟就是30次、 一小时就有30×60=1800次、 一天就有1800×24=43200次!如果我们把发贴程序或是密码穷举程序挂在很多肉鸡上,进行同时工作,那么结果可想而知!笔者曾亲目睹过国内某著名安全论坛就是验证码被人破解,导致被人恶意灌水,最后完全崩溃!当然还有某网络银行也因此类原因导致用户密码被盗等众多事件。笔者也作如下声明:下文介绍的方法并不是有意针某公司或是某机构,只是作为技术交流,如果部分读者利用本文介绍的方法进行破坏或是穷举他人密码,这已经违法了法律,那么责任由他自己承担,与笔者无关!
好了,我们可以进入正题了(以下出现的代码为delphi写的部分源码,为了防止任意利用,我以介绍方法为主,如果读者感兴趣,可以自己组合编写完整,在本文附带的程序中,笔者提供了一个验证码参数确定程序(附源码))。验证码分为如下几类:数字型、字符型、符号型、综合型。
我们看了看百度贴吧的验证码如图: 是属于数字型的!不过其图片中生成了不少彩色和黑白的噪音点(指验证图片上的斑点)。那么我们应该怎么去识别呢?传统的验证码识别方式很简单,由于数字的位置是固定的,所以我们只需要提取每一幅数字的图片(没有噪音点的)然后把每一个特殊数字独有的象素位置记录下来,然后在网络上提取需要破解的特征码,祛除噪音点,对其位置和记录位置进行比对,那就是么就能确定相应的数字了。
总结一下传统的就是:
1.先分析验证码,前景颜色是否不定
2.然后把验证码的宽度/验证码文字个数,比如一验证码下载后宽度为60,有4个数字,那么就60/4=15,然后保存每个字,如果只有数字保存0-9数字到位图文件,如果英文那更麻烦点,0-9,A-Z都要保存到位图,位图的前景色都不变,保持一种颜色,背景随便你改不改
3.如果前景要变则将文字统一为同种颜色,每个数字0-9的点阵都有个公共点,取该公共点颜色然后把前景全部统一成一种颜色,比如白色{255,255,255},位图的结构是BGR,而不是RGB
4.然后进行比较,如果验证码的一点为白色,第2步保存的位图同一点也是白色,那么频率增加1
5.最后频率最高的就是验证码了!
可是这种传统的识别方法却遇到了挑战!如果图片数字的位置也是随机出现,大小也是随机出现,那么这种识别方法也就失效了,百度贴吧的就是这样的验证码。
笔者这里向大家引入一个专有名词:“hough变换”也许学习计算机图像学的朋友知道,笔者还是简要介绍一下:
直线hough变换:直线Hough变换利用图像空间和Hough参数空间的点-线对偶性,把图像空间中的检测问题转换到参数空间。通过在参数空间里进行简单的累加统计,然后在Hough参数空间寻找累加器峰值的方法检测直线。例如,图1(a)中的九条线段对应于如图1(b)所示的其Hough参数空间的九个累加器峰值。图1(b)中,Hough参数空间的横纵坐标分别为直线极坐标方程:ρ=x×cos(θ) + y×sin(θ) 的两个参数ρ和θ。九个峰值的ρ和θ值唯一的确定其对应线段所在直线的两个参数。并且线段的长度决定坐标(ρ,θ)处的累加值的大小。
1(a)
1(b)
没有明白的读者可以多读两遍(数学啊数学!),还是比较好理解。其实讲通俗一点,就是我们只要利用这个方程ρ=x×cos(θ) + y×sin(θ)统计出ρ出现的次数,就可以确定一条直线,比如说图片中我们计算出了某个方向(θ的大小)的ρ出现次数的最大值,那么这就是这个方向最长的直线了!
好了,知道了hough变换检测直线的原理,那么我们就来写段代码
var
p: PByteArray;
Gray, x, y,i1,i2: Integer;
Bmp: TBitmap;
begin
listbox1.Clear;
listbox2.Clear;
Bmp := TBitmap.Create;
Bmp.Assign(Image2.Picture.Bitmap);
//设置为24位真彩色
Bmp.PixelFormat := pf24Bit;
randomize;
for y := 0 to Bmp.Height - 1 do
begin
p := Bmp.scanline[y];
for x := 0 to Bmp.Width - 1 do
begin
//一个象素点三个字节
Gray := Round(p[x * 3 + 2] * 0.3 + p[x * 3 + 1] * 0.59 + p[x
* 3] * 0.11);
if gray > 128 then //全局阀值128
begin
end
else
begin
i1:=x;//表示检测的θ为0度
i2:=y; //表示检测的θ为90度
ListBox1.Items.Add(inttostr(i1));//用于日后算出现的次数,当然也可以用数组!
ListBox2.Items.Add(inttostr(i2));
end;
end;
end;
Image2.Picture.Bitmap.Assign(Bmp);
Bmp.Free;
这段代码的意思就是检测图片0度和90度的直线。
现在我们就说说具体操作了。先得到一幅验证码图片,这个得到的方法有很多,我建议用屏幕指定位置抓图来实现,然后保存成BMP格式,进行图像的二值化处理。二值化处理就是把图片转换成两种颜色,不过需要设置一个适当的阀值(由于24位图的一个点是由RGB3个颜色分量来控制,那么我们得到这3个分量的值后除以3就是阀值了),这样才能起到祛除部分噪音的效果。我们假设阀值为128 现在我们看看这段代码
var
p: PByteArray;
Gray, x, y: Integer;
Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
Bmp.Assign(Image1.Picture.Bitmap);
//设置为24位真彩色
Bmp.PixelFormat := pf24Bit;
randomize;
for y := 0 to Bmp.Height - 1 do
begin
p := Bmp.scanline[y];
for x := 0 to Bmp.Width - 1 do
begin
//一个象素点三个字节
Gray := Round(p[x * 3 + 2] * 0.3 + p[x * 3 + 1] * 0.59 + p[x
* 3] * 0.11);
if gray > 128 then //全局阀值128
begin
p[x * 3] := 255;
p[x * 3 + 1] := 255;
p[x * 3 + 2] := 255;
end
else
begin
p[x * 3] := 0;
p[x * 3 + 1] := 0;
p[x * 3 + 2] := 0;
end;
end;
end;
Image2.Picture.Bitmap.Assign(Bmp);
Bmp.Free;
这样我们就得到了一幅二值化的BMP。
得到这副图后,我们需要对图像进行分割,就是把它变成4个小位图,分别装入4个数字。分割算法很简单,因为验证码的数字位置左右跳动幅度不大,源代码就不再给出。
然后我们要做的就是把这副图进行几个方向的hough变换检测,由控制θ的角度来实现,比如说这个 这是数字3 我们可以看到它有什么特征没有?它横着由三横组成,竖着由2竖组成!我们就规定 如果横着有3条直线,竖着有两条直线,那么这个数就是3了!所以我们只要用hough算子检测 0 & 90 度就能确定横竖有多少直线了,再看这个 这是数字1 我们就规定竖有一条最长的直线,然而横的直线如果不超过竖直线长的1/2那么就是1了。其他数以此类推!
当然实际操作当然没有这么简单,因为还是有部分噪音点没有祛除干净,但是这的确说明了我们的思想!所以每个数有需要准备几套特征编码,如果出现多个数,就看使用编码数最多的数就是我们要识别的数了。最后就是统计了,统计函数我们现在给出
function Repeatcount(s:string;d:string):integer;
var i:integer;
begin
i:=0;
while pos(d,s)>0 do
begin
i:=i+1;
delete(s,pos(d,s),length(d));
end;
result:=i;
end;
利用这个函数,我们就可以确定出现最多的p的次数以及使用编码最多的次数了!笔者随文附送了一个检测0度和90度的检测器,读者可以多试几次就明白了!(如图)
当然只有这两度检测是远远不够的,实际应用中,可以使用0~90度中任意一度检测,比如说7,它的竖由于不是90度的(直的)所以要用其他的度数来检测! 这里也总结一下,任意数字,只要我们能得到相应的特征,那么我们就可以对它进行识别!
总结一下创新的:
1、 获得图片,进行二值化的变换、祛除噪音。
2、 分割图像,保存成相应的BMP文件。
3、 对其进行几个方向的HOUGH变换检测,根据相应的验证码来定!
(你也可以做更多的检测,比如有英文字母就需用到其他算法了!)
4、 对特征进行统计,得出识别结果。
接下来要做的就是做个post程序了,这个太简单了,代码你就自己写吧!不过也要做到如下细节:做成多线程程序进行发贴,不然程序会失去响应的。最好是可以导入大量的代理IP的,然后就是发贴的内容最后加上几个随机字符,这样可以防止重复贴的过滤!最重要的,只是做测试,发贴量不要太多、不要乱发广告贴!
所以说再安全的验证码也有软肋,我们只要发现就可以找出其中的漏洞!当然不只是针对百度,其他论坛的特征码同样能识别!当然网络安全技术也是双刃剑,我这里再次强调!这种方法的确能识别很多重要的部门的一些关键验证码,但是读者如果使用其方法进行破坏,那已经违反了中华人民共和国的相关法律,是要付刑事责任的!并且与笔者无关!
其实上述方法已经不是只是对验证码进行识别了,完全可以用到现实生活中去,比如说手写体识别、车牌识别等等,但是现实生活中我们还要进行更多的加工,比如说圆形检测,多边形检测等等。所以说从网络安全技术中,也有很多东西能造福社会,还等待我们继续创造!
评论Feed: http://blog.xg98.com/feed.asp?q=comment&id=1313
这篇日志没有评论。
此日志不可发表评论。