1. 程式人生 > >淘寶滑動驗證碼研究

淘寶滑動驗證碼研究

引言

悠閒的時候,總會去找些事做做。前些天在登入淘寶的時候,發現了滑動驗證碼,雖然已經不是什麼新事物,但還是產生了很大的興趣。

 

傳統的字元輸入驗證碼,變為了滑動驗證碼,這一看就是產品大師的手筆啊,不知道申請專利沒有。

這種“情感化”的驗證碼設計,可破解度高不高呢?如果是可破解度高,那就真是驗證碼的一次革命變新了。還是讓我先了解一下滑動驗證碼的資料吧!

沒有Google就百度,搜一搜,讓我很震驚,一般搜技術的東西,大多數來源於csdn,blogs.cn,更牛批一點的是來源於stackoverflow,這次居然來自於知乎,這顛覆了我對知乎的看法。

特別是第二個連結裡有一個評論,對我有很重要的啟示,原話為

響應時間,拖拽速度,時間,位置,軌跡,重試次數等。
這些因素能夠構成一個取樣結果或者辨識特性。

這下算是知道了,要破解這種驗證碼,就要用滑鼠去模擬滑動。我再來分析淘寶驗證碼時,發現淘寶的登入驗證碼是隨機的,並且有一個很明顯的延遲載入。

為破解淘寶的滑動驗證碼,我梳理了一個整個過程。

1,判斷驗證碼在什麼時候出現。

2,驗證碼出現時,判斷何時載入完成。

3,確定驗證碼的位置。

4,用滑鼠模擬拖動驗證碼。

5,檢驗本次操作是否成功。

下文,就是我針對這5個步驟,一步一步的去實現淘寶驗證碼的破解。

 一:判斷驗證碼在什麼時候出現

 要想知道滑動驗證碼在什麼時候出現,就顯得非常簡單了,用firefox一看,只要會點html的人,一下就明白了。

經過換電腦,換瀏覽器,清快取的反覆驗證,發現:有驗證碼時候與有沒驗證碼時,HTML的區別在於

<!--無驗證碼-->
<div id=imgCaptcha></div>

<!--有驗證碼-->
 <div id=imgCaptcha style="HEIGHT: 339px; MIN-HEIGHT: 0px; TOP: -202px"></div>

我在寫程式的時候,就是根據這兩行程式碼的區別來分辨本次登入是否需要驗證碼。

二:驗證碼出現時,判斷何時載入完成

        這個問題最先是困擾著我的,這個驗證碼是通過ajax載入的,一個外部程式去判斷一個網頁的ajax請求是否載入完成,顯然是有難度的,我搜了些資料,沒找到一個合適的方法。

        隨後我變了一種思路,我發現正在載入驗證碼的時候,span標籤裡的文字是‘載入中’,載入成功後,span的文字變為了 ‘請按住滑塊,拖動到最右邊’。所以我通過這個區別很輕鬆的判斷了驗證碼是否已經載入完成了。

        換個思路,問題就簡單了。

三:確定驗證碼的位置

        判斷驗證碼的位置,這是一個真正的難點,且聽我娓娓道來。

        驗證碼X軸 = 瀏覽器在電腦屏上的X軸  +  驗證碼在瀏覽器中的X軸

        驗證碼Y軸 = 瀏覽器在電腦屏上的Y軸  +  驗證碼在瀏覽器中的Y軸

        我體會到了計算機與數學的關係,雖然只是小學數學。

1,驗證碼在網頁中的位置

        驗證碼是在網頁中的,要先確定驗證碼在網頁中的位置,這時,會javascript的同學就笑了。但是你的javascript要怎樣才能註冊到淘寶的網頁中去呢?顯然不太容易,後來我用HtmlDocument物件來確定網頁的位置,具體程式碼如下。

        後來,我發現往淘寶網頁註冊javascript也是可行的,但還是用第一種吧!解決這個問題我只用一種方法就行了。

複製程式碼
/// <summary>
/// 獲取驗證碼的位置
/// </summary>
/// <returns></returns>
private System.Windows.Point GetCaptchaPosition(System.Windows.Forms.HtmlDocument paraHtmlDoc)
{
    System.Windows.Point webControlPoint = default(System.Windows.Point);

    //獲取當前控制元件的所有父控制元件  Example  html -> body -> form -> div
    List<KeyValuePair<String, HtmlElement>> allElement = new List<KeyValuePair<string, HtmlElement>>();
    HtmlElement currentElement = paraHtmlDoc.GetElementById("TPL_username");
    while (currentElement != null)
    {
        allElement.Insert(0, new KeyValuePair<String, HtmlElement>(currentElement.TagName, currentElement));
        currentElement = currentElement.Parent;
    }

    int webControlX = 0;
    int webControlY = 0;
    for (int i = 0; i < allElement.Count; i++)
    {
        webControlX += allElement[i].Value.OffsetRectangle.X;
        webControlY += allElement[i].Value.OffsetRectangle.Y;
    }
    webControlPoint = new Point(webControlX, webControlY);
    return webControlPoint;
}
複製程式碼

2,整個網頁在電腦中的位置:

    這個相對於第1點來說,技術上沒那麼難,但是考慮的問題要多些,螢幕的大小,解析度的改變,最小化,最大化視窗時,都要去考慮一下。

四:用滑鼠模擬拖動驗證碼      

在c#中模擬滑鼠的拖動,我呼叫了Windows自身的類庫,註釋我也寫的比較詳細了,如果實在是有不懂的,也可以互相研究哈!

複製程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
//using Microsoft.Win32;

namespace TaoBao.ClientWPFApp
{
    public class Win32Mouse
    {
        //滑鼠移動
        //dX和dy保留移動的資訊。給出的資訊是絕對或相對整數值。
        public static readonly int MOUSEEVENTF_MOVE = 0x0001;
        //絕對位置
        //則dX和dy含有標準化的絕對座標,其值在0到65535之間。
        //事件程式將此座標對映到顯示錶面。
        //座標(0,0)對映到顯示錶面的左上角,(65535,65535)對映到右下角
        //如果沒指定MOUSEEVENTF_ABSOLUTE,dX和dy表示相對於上次滑鼠事件產生的位置(即上次報告的位置)的移動。
        //正值表示滑鼠向右(或下)移動;負值表示滑鼠向左(或上)移動。
        public static readonly int MOUSEEVENTF_ABSOLUTE = 0x8000;
        public static readonly int MOUSEEVENTF_LEFTDOWN = 0x0002;//左鍵按下
        public static readonly int MOUSEEVENTF_LEFTUP = 0x0004;//左鍵擡起
        public static readonly int MOUSEEVENTF_RIGHTDOWN = 0x0008; //右鍵按下 
        public static readonly int MOUSEEVENTF_RIGHTUP = 0x0010; //右鍵擡起 
        public static readonly int MOUSEEVENTF_MIDDLEDOWN = 0x0020; //中鍵按下 
        public static readonly int MOUSEEVENTF_MIDDLEUP = 0x0040;// 中鍵擡起 

        /// <summary>
        /// 得到游標的位置
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(out System.Windows.Point pt);

        /// <summary>
        /// 移動游標的位置
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        [DllImport("user32.dll")]
        public static extern void SetCursorPos(int x, int y);

        /// <summary>
        /// 第2個引數應該是為,
        /// </summary>
        /// <param name="dwFlags"></param>
        /// <param name="dx">DX=需要移動的X*65536/取螢幕寬度 ()+1</param>
        /// <param name="dy">DY=需要移動的Y*65536/取螢幕高度 ()+1</param>
        /// <param name="cButtons"></param>
        /// <param name="dwExtraInfo"></param>
        /// <returns></returns>
        [DllImport("user32")]
        public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
    }
}
複製程式碼

 五:檢驗本次操作是否成功

 這個和第一點“判斷驗證碼在什麼時候出現”類似,主要比較HTML的差異。如果發現滑鼠模擬拖動不成功,就得檢驗驗證碼的位置是否正確,以及再模擬拖動滑鼠。

 經過反覆修改測試,淘寶滑動驗證碼的破解成功率在100%。最後補一張效果圖,有點遺憾的是,我想截圖的時候,刷了好幾次驗證碼都沒有出來。

後記:

朋友開了網店,在網路裡下載些刷單軟體經常被騙,聽說後我義憤填膺啊,為了公道,必須得開發一個牛批的軟體來打擊這些騙子。前期功能就實現以下幾點:

1,實現自動輸入使用者名稱,密碼,自動拖拉驗證碼,實現全自動化淘寶登入。

2,提取淘寶使用者的資訊,比如等級,收貨資訊,已購物的訂單詳情。

3,實現自動搜尋商品。

4,實現自動貨比三家,新增收藏夾。

5,實現自動網頁旺旺聊天。

6,實現自動提交訂單。

7,實現付款。

8,自動好評。