清閒的時候,總會去找些事作作。前些天在登陸淘寶的時候,發現了滑動驗證碼,雖然已經不是什麼新事物,但仍是產生了很大的興趣。javascript
傳統的字符輸入驗證碼,變爲了滑動驗證碼,這一看就是產品大師的手筆啊,不知道申請專利沒有。html
這種「情感化」的驗證碼設計,可破解度高不高呢?若是是可破解度高,那就真是驗證碼的一次革命變新了。仍是讓我先了解一下滑動驗證碼的資料吧!java
沒有Google就百度,搜一搜,讓我很震驚,通常搜技術的東西,大多數來源於csdn,blogs.cn,更牛批一點的是來源於stackoverflow,此次竟然來自於知乎,這顛覆了我對知乎的見解。web
https://www.zhihu.com/question/32209043/answer/55252171ajax
http://www.zhihu.com/question/35538123c#
特別是第二個連接裏有一個評論,對我有很重要的啓示,原話爲瀏覽器
響應時間,拖拽速度,時間,位置,軌跡,重試次數等。
這些因素可以構成一個採樣結果或者辨識特性。緩存
這下算是知道了,要破解這種驗證碼,就要用鼠標去模擬滑動。我再來分析淘寶驗證碼時,發現淘寶的登陸驗證碼是隨機的,而且有一個很明顯的延遲加載。網絡
爲破解淘寶的滑動驗證碼,我梳理了一個整個過程。測試
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,自動好評。