验证码多URL演示破解-安装版.rar
这个是制作的安装版。用于演示用。
验证码多URL演示破解-源码(DotNet2).rar
这个便是上面安装版的源码。
这两个附件首发于 博客园。 sban保证 博客园的版本没有病毒,请勿在其它地址下载。
这个小软件,是我06年初的时候写的,时隔两年了。那时急用,也没考虑什么面向对象,设计模式,垃圾处理等,暇疵甚多。今天把它拿出来,旨在抛砖引玉,与大家共同探讨一下C#的图文识别。
演示中的验证码的URL有的已不能用。大部分验证码图像都简单,破解尚且容易。倘若能够破解google或yahoo的验证码,那才是高手。
这是当时写的演示软件说明,其中有些话有些过了。
init(int id)
private void init(int id)

{
textBox1.Enabled = false;
button2.Enabled = false;

//
cmdUncode.CommandText = "select * from [uri] where [id] = @id";
cmdUncode.Connection = conUncode;
cmdUncode.Parameters.Clear();

cmdUncode.Parameters.Add("@id", OleDbType.Integer);
cmdUncode.Parameters["@id"].Value = id;

closeDtr();
dtrUncode = cmdUncode.ExecuteReader();

if (dtrUncode.Read())

{
uri = dtrUncode["uri"].ToString();
nCode = Convert.ToInt16(dtrUncode["nCode"]);
maxLight = Convert.ToDouble(dtrUncode["maxLt"]);
minLight = Convert.ToDouble(dtrUncode["minLt"]);
iEdge = Convert.ToInt16(dtrUncode["iEdge"]);
compairLimit = Convert.ToInt16(dtrUncode["iLmt"]);
remark = dtrUncode["remark"].ToString();
}


//uriID = 5;
//uri = "http://customer.realname.alibaba.com.cn/cap_image.php";
//nCode = 5;
//maxLight = 0.85;
//minLight = 0.55;
//iEdge = 1;
//compairLimit = 12;
//remark = "http://customer.realname.alibaba.com.cn/newapply/newwhois.htm";



linkLabel1.Text = remark;
dtrUncode.Close();

//
X0 = new int[1 + nCode*2];
Y0 = new int[1 + nCode * 2];

//
Bitmap0 = new Bitmap[3 + nCode];

CharRlt = new Char[nCode];

for (int i = 0; i < nCode; i++)

{
CharRlt[i] = ' ';
}
textBox1.Enabled = false;
button2.Enabled = false;
}
当用户点击破解的时候,首先在 GetBitmapOriginal(ref Bitmap0[0])中取出原始图像:
GetBitmapOriginal
public Bitmap GetBitmapOriginal(ref Bitmap oriBmp)

{
WebRequest webRqst = WebRequest.Create(uri);
WebResponse webRpns = webRqst.GetResponse();

Stream0 = webRpns.GetResponseStream();
oriBmp = new Bitmap(Stream0);

return oriBmp;
}
取出原始图像后,在 GetXYOfEightPoint()中取出验证码图像中每一个小图像的临界点,这将在下一步的裁图中用到:
GetXYOfEightPoint
private bool GetXYOfEightPoint()

{
int m_countX = 1;
int m_countY = 1;


bool IsBound = false;
for (X0[0] = 0; X0[0] < Bitmap0[1].Size.Width; X0[0]++)

{
IsBound = false;
for (Y0[0] = 0; Y0[0] < Bitmap0[1].Size.Height; Y0[0]++)

{
if (Bitmap0[1].GetPixel(X0[0], Y0[0]).GetBrightness() == 0)

{
IsBound = true;
continue;
}
}

if (m_countX <= nCode*2)

{
if ((m_countX % 2) == 0)

{
if (!IsBound)

{
X0[m_countX] = X0[0] - 1;
m_countX++;
}

}
else

{
if (IsBound)

{
X0[m_countX] = X0[0];
m_countX++;
}

}
}
//


}


if (m_countX < nCode*2)

{
//label1.Text = m_countX.ToString();
return false;
}

//

for (Y0[0]=0; Y0[0]<(nCode*2); Y0[0]++)

{
if ((Y0[0]%2) == 0)

{
Y0[Y0[0] + 1] = Bitmap0[1].Size.Height;
}
else

{
Y0[Y0[0] + 1] = 0;
}
}

//

for (Y0[0] = 0; Y0[0] < Bitmap0[1].Size.Height; Y0[0]++)

{
//
for (int i = 0; i < nCode * 2; i = i + 2)

{
//
for (X0[0] = X0[i + 1]; X0[0] < X0[i + 2]; X0[0]++)

{
if (Bitmap0[1].GetPixel(X0[0], Y0[0]).GetBrightness() == 0)

{
if (Y0[i + 1] > Y0[0]) Y0[i + 1] = Y0[0];
if (Y0[i + 2] < Y0[0]) Y0[i + 2] = Y0[0];
m_countY++;
}
}
//

}

}

if (m_countY < nCode*2)

{
return false;
}
return true;

}
这时候这个图像还是有躁点的,在裁图之前,必须把躁点去掉。这一步在 GetBlankWhiteBitmap()中完成:
GetBlankWhiteBitmap()
private Bitmap GetBlankWhiteBitmap()

{
int m_w, m_h;
Color m_clr = new Color();
m_w = Bitmap0[0].Size.Width;
m_h = Bitmap0[0].Size.Height;

if (m_w > Bitmap0[0].Size.Width) m_w--;
if (m_h > Bitmap0[0].Size.Height) m_h--;

Rectangle0 = new Rectangle(new Point(0, 0), new Size(m_w - iEdge, m_h - iEdge));

Bitmap0[1] = Bitmap0[0].Clone(Rectangle0, PixelFormat0);
for (X0[0] = 0; X0[0] < Bitmap0[1].Size.Width; X0[0]++)

{
for (Y0[0] = 0; Y0[0] < Bitmap0[1].Size.Height; Y0[0]++)

{
m_clr = Bitmap0[1].GetPixel(X0[0], Y0[0]);

if (m_clr.GetBrightness() <= minLight || m_clr.GetBrightness() >= maxLight)

{
Bitmap0[1].SetPixel(X0[0], Y0[0], Color.White);
}
else

{
Bitmap0[1].SetPixel(X0[0], Y0[0], Color.Black);
}
}
}

return Bitmap0[1];
}
随后在 GetSngBmp ()中拆出一个个小图像。有了临界点,又去了躁点,拆图已是相当容易。

GetSngBmp()
private void GetSngBmp()

{
for (int i = 0; i < nCode; i++)

{
Rectangle0 = new Rectangle(X0[i * 2 + 1], Y0[i * 2 + 1], X0[(i + 1) * 2] - X0[i * 2 + 1] + 1, Y0[(i + 1) * 2] - Y0[i * 2 + 1] + 1);
Bitmap0[3 + i] = Bitmap0[1].Clone(Rectangle0, PixelFormat0);
}
}
GetCharRlt()
public void GetCharRlt()

{
bool blnFinish = false;
bool HaveThisBitmap = false;
string m_codes = "";


if(DtSCode.Tables[uriID.ToString()] == null)
{

StrSql = "select * from [" + uriID.ToString() + "Code" + "]";

cmdUncode.CommandText = StrSql;
cmdUncode.Connection = conUncode;

dadUncode.SelectCommand = cmdUncode;


dadUncode.Fill(DtSCode, uriID.ToString());
}
for (int I=0; I<nCode; I++)

{
if (CharRlt[I].ToString() == " ")

{
HaveThisBitmap = false;

foreach(DataTable DT in DtSCode.Tables)
{
foreach (DataRow DR in DT.Rows)

{

MemoryStream0 = new MemoryStream();
MemoryStream0.Position = 0;
MemoryStream0 = new MemoryStream((byte[])DR["img"]);
Bitmap0[2] = new Bitmap(MemoryStream0);


if (CompareBitmap(Bitmap0[I + 3], Bitmap0[2]))

{
HaveThisBitmap = true;
CharRlt[I] = Convert.ToChar(DR["chr"]);
continue;
}
}
if (HaveThisBitmap)

{
continue;
}
}
//
//
//
if (HaveThisBitmap)

{
textBox1.Enabled = false;
button2.Enabled = false;
}
else

{
MessageBox.Show("Input a char correspond to " + (I + 1).ToString() + " code");
label1.Text = "Input a char correspond to " + (I + 1).ToString() + " code";
textBox1.Enabled = true;
button2.Enabled = true;
textBox1.Focus();
I = nCode + 1;
break;
}
}

}

blnFinish = true;
for (int m_fi = 0; m_fi < nCode; m_fi++)

{
if (CharRlt[m_fi].ToString() == " ")

{
blnFinish = false;
break;
}

}
if (blnFinish)

{
for (int i = 0; i < nCode; i++)

{
m_codes += CharRlt[i].ToString();
}
MessageBox.Show(m_codes, "code");
label1.Text = "The codes is " + m_codes;
button1.Enabled = true;
button1.Focus();
}

}
这个是制作的安装版。用于演示用。
验证码多URL演示破解-源码(DotNet2).rar
这个便是上面安装版的源码。
这两个附件首发于 博客园。 sban保证 博客园的版本没有病毒,请勿在其它地址下载。
这个小软件,是我06年初的时候写的,时隔两年了。那时急用,也没考虑什么面向对象,设计模式,垃圾处理等,暇疵甚多。今天把它拿出来,旨在抛砖引玉,与大家共同探讨一下C#的图文识别。
演示中的验证码的URL有的已不能用。大部分验证码图像都简单,破解尚且容易。倘若能够破解google或yahoo的验证码,那才是高手。
这是当时写的演示软件说明,其中有些话有些过了。
◇ 本软件为验证码破解示例软件. 纯绿色,可完全卸载,不含任何插件、恶意代码。
◇ 支持不同色彩,不同大小,不同个数,不同亮度.
◇ 支持不同格式,不同形式,不同方法.
◇ 由于是针对大众验证码的演示软件,准确率以及破解速度远不及针对单一验证码的破解.
◇ 关于设置URI等参数的功能,由于对于不同的验证码参数是不定的,需要调试得出,所以没有列出. ◇ 凡是小软件,应力求功能简单,效率与实用性才能提高.一个无所不能的软件也就是一个什么也不能的软件.
◇ 支持不同色彩,不同大小,不同个数,不同亮度.
◇ 支持不同格式,不同形式,不同方法.
◇ 由于是针对大众验证码的演示软件,准确率以及破解速度远不及针对单一验证码的破解.
◇ 关于设置URI等参数的功能,由于对于不同的验证码参数是不定的,需要调试得出,所以没有列出. ◇ 凡是小软件,应力求功能简单,效率与实用性才能提高.一个无所不能的软件也就是一个什么也不能的软件.
好了,且看源码。
源码中有一个Access数据库[suncode06.mdb]。
这个表用于存储验证码的地址及破解配置信息。其中,maxLt与minLt是躁点取舍范围。nCode是验证码的个数。
如图所示,这个表便存储了验证码的图片信息。
这个小软件破解验证码的原理,是记忆性破解。读取验证码图片,分成一个个小图片,如果库中有记录,则返回它的验证码字符;如果不存在,则插入新记录。对于没有记忆过的验证码图片,它是识别不出来的。这个破解方法只可用于验证码字符范围固定的验证码。对于不固定范围的,如QQ的注册验证则不能破解。
其中,所有破解代码都在Form1中,form2可以不看。
在Form1中,首先init读取当前要破解的验证码的url及破解参数:


































































当用户点击破解的时候,首先在 GetBitmapOriginal(ref Bitmap0[0])中取出原始图像:














取出原始图像后,在 GetXYOfEightPoint()中取出验证码图像中每一个小图像的临界点,这将在下一步的裁图中用到:








































































































































这时候这个图像还是有躁点的,在裁图之前,必须把躁点去掉。这一步在 GetBlankWhiteBitmap()中完成:












































随后在 GetSngBmp ()中拆出一个个小图像。有了临界点,又去了躁点,拆图已是相当容易。














最后在GetCharRlt()计算验证码字符,如果库中没有,则提示输入并存储,并进入下一个验证码字符破解。


























































































































代码质量不高,坏味实足,各位多多包涵。