1. 程式人生 > >破解需驗證碼登入網站~ing

破解需驗證碼登入網站~ing

何謂驗證碼?

驗證碼就是以圖片格式將文字、數字、符號表示出來,在登入網站、發表評論時,同時將這些資訊輸入,以防止某些程式惡意登入、刷貼等,但也影響了某些情況下的正常程式訪問。這些符號人眼很容易識別,但對計算機來說卻非常不易,從而達到防範惡意程式的目的。

驗證碼的原理

驗證碼無非就是根據某些資訊產生符號集,然後將這些符號集轉換成圖片。早期的驗證碼基本上都是數字加英文字母,而且生成的圖片背景也比較乾淨,這就為一些OCR軟體提供了可乘之機,通過專業的OCR軟體就能輕易識別出驗證碼的文字資訊。但從現在的應用來看,不僅背景上添加了許多雜色,而且符號也開始不工整,甚至採用了漢字,大大增加了OCR識別的難度。

實現驗證碼有兩種主要的方式:
1. 訪問頁面時由jsp,aspx等指令碼生成驗證碼圖片,同時將驗證碼資訊寫入本地cookies, 可用函式加密,當頁面提交時就會在本地判斷cookies.code是否與你輸入的驗證碼相等,或者與f(cookies.code)做比較,即生成的驗證碼是cookies的一個函式值。要破解這種方式,幾乎不需要動用OCR,只要正確輸入一次驗證碼,把這個正確的驗證碼及cookies記錄下來,不斷地用正確的cookies去替換新cookies,就可以不斷的提交頁面。

2, session控制。session控制與第1種的不同之處在於,對照碼放在一個session變數裡,提交時會將你輸入的驗證碼與這個session變數或其函式值做比較,由於session變數是取不到的,所以破解的難度也大大增加。

以下主要針對第2種情況進行分析。

準備工作

先了解驗驗碼的生成原理

在需要驗證碼的頁面放如下程式碼,即一個輸驗證碼的文字框和一個驗證碼圖片,(注意是由asp指令碼生成的)

<input type="text" name="validatecode" size="20"><img src="validatecode.asp"></p>

假如該頁要提交到view.asp,

在view.asp中寫如下程式碼:(sas_validatecode是任意命名的,只要與下文validatecode.asp中保持一致即可)

if(Trim(request.form("validatecode"))=Empty or trim(session("sessionname_validatecode

"))<>Trim(request.form("validatecode"))) then
response.write("請輸入正確驗正碼")
else
response.write("you are right!" & request.form("validatecode"))
end if

%>

再看一下validatecode.asp的程式碼:

<%
Option Explicit
Response.Buffer = True
Response.Expires = -1
Response.AddHeader "Pragma","no-cache"
Response.AddHeader "cache-ctrol","no-cache"
Dim RndNum,ImgFileContent
Randomize Timer
RndNum = Cint(7999*Rnd+1000)
Session("sas_ValidateCode") = Cstr(RndNum)
ImgFileContent=NumCode(RndNum)
Response.ContentType = "image/BMP"
Response.BinaryWrite ImgFileContent

Function NumCode(NumS)
    Dim NumI,NumJ
    Dim AdoM,AdoN
    Dim Arr_Img(4),NStr
        NStr=Cstr(NumS)
        For NumI=0 To 3
            Arr_Img(NumI)=Cint(Mid(NStr,NumI+1,1))
        Next
    Dim Position
    Set AdoM=Server.CreateObject("Adodb.Stream")
        AdoM.Mode=3
        AdoM.Type=1
        AdoM.Open
        Set AdoN=Server.CreateObject("Adodb.Stream")
        AdoN.Mode=3
        AdoN.Type=1
        AdoN.Open
        AdoM.LoadFromFile(Server.Mappath("validatebody.fix"))
        AdoN.Write AdoM.Read(1280)
        For NumI=0 To 3
            AdoM.Position=(9-Arr_Img(NumI))*320
            AdoN.Position=NumI*320
            AdoN.Write AdoM.Read(320)
        Next   
        AdoM.LoadFromFile(Server.Mappath("validatehead.fix"))
        Position=Lenb(AdoM.Read())
        AdoM.Position=Position
        For NumI=0 To 9 Step 1
            For NumJ=0 To 3
                AdoN.Position=NumI*32+NumJ*320
                AdoM.Position=Position+30*NumJ+NumI*120
                AdoM.Write AdoN.Read(30)
            Next
        Next
        AdoM.Position = 0
        NumCode = AdoM.Read()
        AdoM.Close:Set AdoM=Nothing
        AdoN.Close:Set AdoN=Nothing
End Function
%>

這段程式碼就是隨機生成數字,然後去控制兩個檔案,validatebody.fix和validatehead.fix,它其實是BMP圖片的兩部分,head是BMP檔案的通用頭,即前54個位元組,body就是驗證碼的主體了。生成驗證碼之後將這兩部分合在一起生成一個可顯示出來的BMP圖片。注意看這句話:Response.ContentType = "image/BMP"

下一步的工作需要首先獲取這個圖片,然後才能OCR,到temporary internet files目錄下,找到相應網站對應的檔案,仔細查詢這個圖片,把它拖到“開始-》執行”對話方塊裡可以看到在檔案系統中的名字叫validatecode[1].bmp,多刷幾次網頁,以確認驗證碼就是這個圖片。同時你也會發現這個圖片的完整路徑,

C:/documents and settings/user/local settings/temporary internet files/content.IE5/OU786VF/validatecode[1].bmp

需要注意的是,content.IE5下面的子目錄名稱是經常變化的,每重新整理一次就會不同。給獲取圖片增加了一定難度。

但我們還是有辦法,遍歷content.IE5下的每個資料夾,包括檔案,去搜索驗證碼圖片,程式碼如下:

因為我重新整理temporary internet files,因些不能用TIdHTTP元件,它沒有表示層,必須使用TCppWebBrowser元件,

CppWebBrowser1->Navigate(WideString("http://192.168.0.3/login.asp"));

Navigate之後,驗證碼圖片就會更新,於是用下面的程式獲得該圖片

//------------------------------------------------------------------------

TSearchRec sr;
String asFileName,extension;
extension="*.*";
String startpath="C://Documents and Settings//user//Local Settings//Temporary Internet Files//Content.IE5//";
if(!FindFirst(startpath+extension,faAnyFile,sr))
{
do
  {
  if (sr.Name != "." && sr.Name != "..")
   asFileName=FileSearch("validatecode[1].bmp",startpath+sr.Name);
   Memo1->Lines->Add(startpath+sr.Name);
   if(!asFileName.IsEmpty())
   Edit1->Text=OCR(startpath+sr.Name+"
//validatecode[1].bmp",-1);
  //Memo1->Lines->Add(sr.Name);
  }
while(!FindNext(sr));

}

FindClose(sr);

//---------------------------------------------------------------------------------------------------

把識別的結果存到Edit1裡面。OCR(string,int)是一個OCR函式,來自aspriseOCR.dll的demo版。具體呼叫不再敘述。

然後把識別碼資訊寫到你的Post資訊裡,用IdHTTP post出去。

TStringStream *ResponseData=new TStringStream("");
TStringList *PostData = new TStringList;
String URL="http://192.168.0.3/view.asp" ;
String PostStr;

PostStr="validatecode="+Edit1->Text;
PostData->Add(PostStr);
try
{
  Form1->IdHTTP1->Post(URL,PostData,ResponseData) ;
  Form1->Memo1->Clear();
  Form1->Memo1->Text=ResponseData->DataString;
}
   catch ( ... )
   {
   // handler for any C++ exception
   ShowMessage( "A C++ exception was thrown.,由於網路原因程式中斷");

   }

//-------程式執行到此處已解決大部分問題,但post動作會新建一個session,(經常會get得到圖片和要post的頁面還不一致,如本例,get圖片需要訪問login.asp,卻又需要post到view.asp) session變數會被重新整理,導致與你OCR出來的驗證碼不一致,問題就出在這裡,等等繼續研究解答。