近日,網上驚現可以破解驗證碼的JavaScript腳本——GreaseMonkey!由「Shaun Friedle」開發的這段腳本可以輕鬆搞定Megaupload網站的CAPTCHA。如果您不相信的話,可以到HTTP://herecomethelizards.co.uk/mu_captcha/親自嘗試一下!
現在,Megaupload網站提供的CAPTCHA在上述代碼面前已經敗下陣來,說實話,這裡的驗證碼設計的不不太好。但更有趣的是:
1.HTML 5中的Canvas應用程式介面getImageData可以用來從驗證碼圖像中取得圖元資料。利用Canvas,我們不僅可以將一個圖像嵌入一個畫布中,而且之後還可以再從中重新提取出來。
2.上述的腳本中包含一個完全使用JavaScript實現的神經網路。
3.使用Canvas從圖像中提取出圖元資料後,將其送入神經網路,通過一種簡單的光學字元辨識技術來推測驗證碼中到底使用了哪些字元。
通過閱讀原始程式碼,我們不僅可以更好地理解其工作原理,也可以領會這個驗證碼究竟是如何實現的。就像前面看到的那樣,這裡使用的驗證碼不是很複雜——每個驗證碼有三個字元組成,每個字元使用一種不同的顏色,並且只使用26個字母中的字元,而所有字元都使用同一種字體。
第一步的用意很明顯,那就是把驗證碼拷貝到畫布上,並且把它轉化為灰度圖。
function convert_grey(image_data){
for (var x = 0; x < image_data.width; x++){
for (var y = 0; y < image_data.height; y++){
var i = x*4+y*4*image_data.width;
var luma = Math.floor(image_data.data[i] * 299/1000 +
image_data.data[i+1] * 587/1000 +
image_data.data[i+2] * 114/1000);
image_data.data[i] = luma;
image_data.data[i+1] = luma;
image_data.data[i+2] = luma;
image_data.data[i+3] = 255;
}
}
}
然後,將畫布分成三個單獨的圖元矩陣,每個矩陣包含一個字元。這一步實現起來非常容易,因為每個字元都使用一種單獨的顏色,所以通過顏色就可以將其區分開來。
filter(image_data[0], 105);
filter(image_data[1], 120);
filter(image_data[2], 135);
function filter(image_data, colour){
for (var x = 0; x < image_data.width; x++){
for (var y = 0; y < image_data.height; y++){
var i = x*4+y*4*image_data.width;
// Turn all the pixels of the certain colour to white
if (image_data.data[i] == colour) {
image_data.data[i] = 255;
image_data.data[i+1] = 255;
image_data.data[i+2] = 255;
// Everything else to black
} else {
image_data.data[i] = 0;
image_data.data[i+1] = 0;
image_data.data[i+2] = 0;
}
}
}
}
最終,所有無關的干擾圖元都被剔除出去。為此,可以先查找那些前面或者後面被黑色(未匹配的)圖元圍繞的白色(匹配過的)圖元,然後將匹配過的圖元刪除即可。
var i = x*4+y*4*image_data.width;
var above = x*4+(y-1)*4*image_data.width;
var below = x*4+(y+1)*4*image_data.width;
if (image_data.data[i] == 255 &&
image_data.data[above] == 0 &&
image_data.data[below] == 0) {
image_data.data[i] = 0;
image_data.data[i+1] = 0;
image_data.data[i+2] = 0;
}
現在我們已經得到了字元的大約圖形,但在將其載入神經網路之前,腳本還會進一步對它進行必要的邊緣檢測。腳本會尋找圖形最左、右、上、下方的圖元,並將其轉化為一個矩形,接著把矩形重新轉換為一個20*25圖元的矩陣。
cropped_canvas.getCoNtext("2d").fillRect(0, 0, 20, 25);
var edges = find_edges(image_data[i]);
cropped_canvas.getCoNtext("2d").drawImage(canvas, edges[0], edges[1],
edges[2]-edges[0], edges[3]-edges[1], 0, 0,
edges[2]-edges[0], edges[3]-edges[1]);
image_data[i] = cropped_canvas.getCoNtext("2d").getImageData(0, 0,
cropped_canvas.width, cropped_canvas.height);
經過上面的處理,我們得到了什麼呢? 一個20*25的矩陣,其中包含單個矩形,其中填由黑白色。真是太好了!
然後,會對這個矩形做進一步的簡化。我們策略性地從矩陣中提取一些點,作為「光感受器」,這些光感受器將輸送到神經網路。舉例而言,某個光感受器具體對應的可能是位於9*6位置圖元,有圖元或者沒有圖元。腳本會提取一系列這樣的狀態(遠少於對 20*25矩陣整個計算的次數——只提取64種狀態),並將這些狀態送入神經網路。
您可能要問,為什麼不直接對圖元進行比較?有必要使用神經網路嗎?問題的關鍵在於,我們要去掉那些模棱兩可的情況。如果您試過前面的演示就會發現,直接進行圖元比較比通過神經網路比較,更容易出錯,儘管出錯的時候不多。但我們必須承認,對於大部分使用者來說,直接的圖元比較應該已經夠用了。
下一步就是嘗試猜字母了。神經網路中導入了64個布林值(由其中的一個字元圖像獲取而來),同時包含一系列預先計算好的資料。神經網路的理念之一,就是我們希望得的結果事先就是知道的,所以我們可以針對結果對神經網路進行相關的訓練。腳本作者可以多次運行腳本,並收集了一系列最佳評分,這些評分能説明倒推出產生它們的那些值,從而幫神經網路猜出答案,除此之外,這些評分沒有任何特殊意義。
當神經網路對驗證碼中一個字母對應的64個布林值進行計算以後,和一個預先計算好的字母表相比較,然後為和每個字母的匹配都給出一個分數。(最後的結果可能類似:98%的可能是字母A,36%的可能是字母B等。)
當對驗證碼中的三個字母都經過處理以後,最終的結果也就出來了。需要注意的是,該腳本無法達到100%正確性(不知道如果在開始的時候不將字母轉換成矩形,是不是可以提高評分的精度),但這已經相當好了,至少對於當前的用途來說是這樣。而且所有的操作都是在基於標準的用戶端技術實現的瀏覽器中完成的!
補充說明一下,這個腳本應該算是一個特例吧,這項技術可能會很好的工作在在其它簡陋的驗證碼上,但對於複雜的驗證碼來說,就有點鞭長莫及了(尤其是這種基於用戶端的分析)。但願有更多人能從這個專案中受到啟發而開發出更奇妙的東西來,因為它的潛力實在是太大了
 
 
FROM:http://hi.baidu.com/zdz8207/item/ad77d13bbe01fd8bf5e4ad94

 

 
arrow
arrow
    全站熱搜

    戮克 發表在 痞客邦 留言(1) 人氣()