การใช้ JavaScript เพื่อถอดรหัสรหัสยืนยัน
เมื่อเร็ว ๆ นี้สคริปต์ JavaScript ที่สามารถถอดรหัสรหัสยืนยันได้ปรากฏบนอินเทอร์เน็ต - GreaseMonkey! สคริปต์นี้พัฒนาโดย "Shaun Friedle" สามารถแก้ CAPTCHA ของไซต์ Megaupload ได้อย่างง่ายดาย หากคุณไม่เชื่อคุณสามารถลองด้วยตัวเองได้ที่ http://herecomethelizards.co.uk/mu_captcha/ !
ตอนนี้ CAPTCHA ที่จัดทำโดยไซต์ Megaupload ได้พ่ายแพ้ต่อโค้ดข้างต้นแล้ว รหัสที่นี่ได้รับการออกแบบ ไม่ ไม่ค่อยดีนัก แต่สิ่งที่น่าสนใจกว่าคือ
1. อินเทอร์เฟซแอปพลิเคชัน Canvas getImageData ใน HTML 5 สามารถใช้เพื่อรับข้อมูลพิกเซลจากรูปภาพรหัสยืนยัน การใช้ Canvas เราไม่เพียงแต่สามารถฝังภาพลงในผืนผ้าใบเท่านั้น แต่ยังแยกออกมาใหม่ในภายหลังอีกด้วย
2. สคริปต์ด้านบนมีโครงข่ายประสาทเทียมที่ใช้งานใน JavaScript ทั้งหมด
3. หลังจากใช้ Canvas เพื่อดึงข้อมูลพิกเซลจากรูปภาพ ให้ส่งไปยังโครงข่ายประสาทเทียม และใช้เทคโนโลยีการรู้จำอักขระด้วยแสงอย่างง่ายเพื่อสรุปอักขระที่ใช้ในรหัสยืนยัน
ด้วยการอ่านซอร์สโค้ด เราไม่เพียงแต่สามารถเข้าใจวิธีการทำงานได้ดีขึ้น แต่ยังเข้าใจวิธีการนำรหัสยืนยันนี้ไปใช้อีกด้วย อย่างที่คุณเห็นก่อนหน้านี้ CAPTCHA ที่ใช้ในที่นี้ไม่ได้ซับซ้อนมากนัก - แต่ละ CAPTCHA ประกอบด้วยอักขระสามตัว อักขระแต่ละตัวใช้สีที่แตกต่างกัน และใช้เฉพาะอักขระจากตัวอักษร 26 ตัวอักษรเท่านั้น ในขณะที่อักขระทั้งหมดทั้งหมดใช้แบบอักษรเดียวกัน
จุดประสงค์ของขั้นตอนแรกนั้นชัดเจน นั่นคือการคัดลอกรหัสยืนยันลงบนผืนผ้าใบและแปลงเป็นภาพระดับสีเทา
ฟังก์ชั่น Convert_grey (image_data) {
สำหรับ (var x = 0; x < image_data.width; x++){
สำหรับ (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] = ลูมา;
image_data.data[i+1] = ลูมา;
image_data.data[i+2] = ลูมา;
image_data.data[i+3] = 255;
-
-
-
จากนั้น แบ่งผืนผ้าใบออกเป็นเมทริกซ์พิกเซลแยกกันสามเมทริกซ์ โดยแต่ละเมทริกซ์มีอักขระหนึ่งตัว ขั้นตอนนี้ทำได้ง่ายมาก เนื่องจากอักขระแต่ละตัวใช้สีที่แยกจากกัน จึงสามารถแยกแยะตามสีได้
ตัวกรอง (รูปภาพ_ข้อมูล [0], 105);
ตัวกรอง (รูปภาพ_ข้อมูล [1], 120);
ตัวกรอง (รูปภาพ_ข้อมูล [2], 135);
ฟังก์ชั่นตัวกรอง (image_data, สี) {
สำหรับ (var x = 0; x < image_data.width; x++){
สำหรับ (var y = 0; y < image_data.height; y++){
var i = x*4+y*4*image_data.width;
// เปลี่ยนพิกเซลทั้งหมดของสีที่ต้องการให้เป็นสีขาว
ถ้า (image_data.data[i] == สี) {
image_data.data[i] = 255;
image_data.data[i+1] = 255;
image_data.data[i+2] = 255;
// ทุกอย่างเป็นสีดำ
} อื่น {
รูปภาพ_data.data[i] = 0;
รูปภาพ_data.data[i+1] = 0;
รูปภาพ_data.data[i+2] = 0;
-
-
-
-
สุดท้าย พิกเซลรบกวนที่ไม่เกี่ยวข้องทั้งหมดจะถูกกำจัดออกไป ในการดำเนินการนี้ ขั้นแรกให้ค้นหาพิกเซลสีขาว (ตรงกัน) ที่ล้อมรอบด้วยพิกเซลสีดำ (ไม่ตรงกัน) ด้านหน้าหรือด้านหลัง จากนั้นจึงลบพิกเซลที่ตรงกันออก
var i = x*4+y*4*image_data.width;
var ด้านบน = x*4+(y-1)*4*image_data.width;
var ด้านล่าง = x*4+(y+1)*4*image_data.width;
ถ้า (image_data.data[i] == 255 &&
image_data.data[ด้านบน] == 0 &&
image_data.data[ด้านล่าง] == 0) {
รูปภาพ_data.data[i] = 0;
รูปภาพ_data.data[i+1] = 0;
รูปภาพ_data.data[i+2] = 0;
-
ตอนนี้เรามีรูปร่างโดยประมาณของตัวละครแล้ว สคริปต์จะทำการตรวจจับขอบที่จำเป็นเพิ่มเติมก่อนที่จะโหลดลงในโครงข่ายประสาทเทียม สคริปต์จะค้นหาพิกเซลซ้ายสุด ขวา บน และล่างของกราฟิก แปลงเป็นสี่เหลี่ยม แล้วแปลงสี่เหลี่ยมอีกครั้งเป็นเมทริกซ์ขนาด 20*25 พิกเซล
cropped_canvas.getContext("2d").fillRect(0, 0, 20, 25);
ขอบ var = find_edges(image_data[i]);
cropped_canvas.getContext("2d").drawImage(ผ้าใบ, ขอบ[0], ขอบ[1],
ขอบ[2]-ขอบ[0], ขอบ[3]-ขอบ[1], 0, 0,
ขอบ[2]-ขอบ[0], ขอบ[3]-ขอบ[1]);
image_data[i] = cropped_canvas.getContext("2d").getImageData(0, 0,
cropped_canvas.width, cropped_canvas.height);
หลังจากการประมวลผลข้างต้น เราจะได้อะไร เมทริกซ์ 20*25 ที่มีสี่เหลี่ยมเดียวที่เต็มไปด้วยสีดำและสีขาว เยี่ยมมาก!
จากนั้น เราจะจัดรูปสี่เหลี่ยมผืนผ้าให้ง่ายขึ้นอีก เราแยกจุดออกจากเมทริกซ์อย่างมีกลยุทธ์ในฐานะ "เซลล์รับแสง" ที่จะถูกป้อนเข้าสู่โครงข่ายประสาทเทียม ตัวอย่างเช่น เซลล์รับแสงบางตัวอาจสอดคล้องกับพิกเซลที่ขนาด 9*6 โดยมีหรือไม่มีพิกเซลก็ได้ สคริปต์จะแยกชุดของสถานะดังกล่าว (น้อยกว่าการคำนวณเมทริกซ์ 20x25 ทั้งหมด โดยแยกได้เพียง 64 สถานะเท่านั้น) และป้อนสถานะเหล่านี้เข้าสู่โครงข่ายประสาทเทียม
คุณอาจถามว่าทำไมไม่เปรียบเทียบพิกเซลโดยตรงล่ะ จำเป็นต้องใช้โครงข่ายประสาทเทียมหรือไม่ ประเด็นก็คือ เราต้องการกำจัดสถานการณ์ที่คลุมเครือเหล่านั้น หากคุณได้ลองสาธิตก่อนหน้านี้ คุณจะสังเกตเห็นว่าการเปรียบเทียบพิกเซลโดยตรงนั้นเกิดข้อผิดพลาดได้ง่ายมากกว่าการเปรียบเทียบผ่านโครงข่ายประสาทเทียม แม้ว่าจะไม่ได้เกิดขึ้นมากนักก็ตาม แต่เราต้องยอมรับว่าสำหรับผู้ใช้ส่วนใหญ่ การเปรียบเทียบพิกเซลโดยตรงก็น่าจะเพียงพอแล้ว
ขั้นตอนต่อไปคือการพยายามเดาตัวอักษร ค่าบูลีน 64 ค่า (ได้มาจากอิมเมจอักขระตัวใดตัวหนึ่ง) จะถูกนำเข้าไปยังโครงข่ายประสาทเทียม รวมถึงชุดข้อมูลที่คำนวณไว้ล่วงหน้า แนวคิดประการหนึ่งของโครงข่ายประสาทเทียมคือผลลัพธ์ที่เราต้องการได้รับจะทราบล่วงหน้า ดังนั้นเราจึงสามารถฝึกอบรมโครงข่ายประสาทเทียมตามผลลัพธ์นั้นได้ ผู้เขียนสคริปต์สามารถรันสคริปต์ได้หลายครั้งและรวบรวมชุดคะแนนที่ดีที่สุดที่สามารถช่วยให้โครงข่ายประสาทเทียมเดาคำตอบโดยการทำงานย้อนกลับจากค่าที่สร้างไว้ แต่คะแนนเหล่านี้ไม่มีความหมายพิเศษ
เมื่อโครงข่ายประสาทเทียมคำนวณค่าบูลีน 64 ค่าที่ตรงกับตัวอักษรในรหัสยืนยันเปรียบเทียบกับตัวอักษรที่คำนวณไว้ล่วงหน้าแล้วให้คะแนนการจับคู่กับตัวอักษรแต่ละตัว (ผลลัพธ์สุดท้ายอาจใกล้เคียงกัน: 98% อาจเป็นตัวอักษร A, 36% อาจเป็นตัวอักษร B เป็นต้น)
หลังจากประมวลผลตัวอักษรทั้งสามตัวในรหัสยืนยันแล้ว ผลลัพธ์สุดท้ายจะออกมา ควรสังเกตว่าสคริปต์นี้ไม่ถูกต้อง 100% (ฉันสงสัยว่าความแม่นยำของการให้คะแนนสามารถปรับปรุงได้หรือไม่หากตัวอักษรไม่ได้ถูกแปลงเป็นรูปสี่เหลี่ยมผืนผ้าในตอนเริ่มต้น) แต่ก็ค่อนข้างดี อย่างน้อยก็สำหรับวัตถุประสงค์ปัจจุบัน พูดอย่างนั้น. และการดำเนินการทั้งหมดจะเสร็จสมบูรณ์ในเบราว์เซอร์ตามเทคโนโลยีไคลเอนต์มาตรฐาน
สคริปต์นี้ควรถือเป็นกรณีพิเศษ ซึ่งอาจทำงานได้ดีกับรหัสยืนยันแบบง่ายอื่น ๆ แต่สำหรับรหัสยืนยันที่ซับซ้อน เกินขอบเขต (โดยเฉพาะการวิเคราะห์ตามลูกค้าประเภทนี้) ฉันหวังว่าผู้คนจำนวนมากจะได้รับแรงบันดาลใจจากโครงการนี้และพัฒนาสิ่งที่ยอดเยี่ยมมากขึ้น เพราะมีศักยภาพที่ยอดเยี่ยมมาก