淘寶滑動驗證碼研究
引言
悠閒的時候,總會去找些事做做。前些天在登入淘寶的時候,發現了滑動驗證碼,雖然已經不是什麼新事物,但還是產生了很大的興趣。
傳統的字元輸入驗證碼,變為了滑動驗證碼,這一看就是產品大師的手筆啊,不知道申請專利沒有。
這種“情感化”的驗證碼設計,可破解度高不高呢?如果是可破解度高,那就真是驗證碼的一次革命變新了。還是讓我先了解一下滑動驗證碼的資料吧!
沒有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,自動好評。