聲明
本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用,不用于其他任何目的移层,不提供完整代碼启摄,抓包內(nèi)容、敏感網(wǎng)址幽钢、數(shù)據(jù)接口等均已做脫敏處理歉备,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無(wú)關(guān)匪燕!
本文章未經(jīng)許可禁止轉(zhuǎn)載蕾羊,禁止任何修改后二次傳播,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外帽驯,作者均不負(fù)責(zé)龟再,若有侵權(quán),請(qǐng)?jiān)诠娞?hào)【K哥爬蟲】聯(lián)系作者立即刪除尼变!
逆向目標(biāo)
- 目標(biāo):百度滑塊驗(yàn)證碼利凑、點(diǎn)選驗(yàn)證碼浆劲、旋轉(zhuǎn)驗(yàn)證碼,v1哀澈、v2 逆向分析
- v1 旋轉(zhuǎn)驗(yàn)證碼:
aHR0cHM6Ly93YXBwYXNzLmJhaWR1LmNvbS9zdGF0aWMvY2FwdGNoYS90dXhpbmcuaHRtbD9haz0zM2M0ODg4NGI3ZGY4M2Q0MjMwZTA3Y2JjZDBkMDdmZCZiYWNrdXJsPWh0dHBzJTNBJTJGJTJGYWlxaWNoYS5iYWlkdS5jb20mdGltZXN0YW1wPTE2MzE0MzQ0MjUmc2lnbmF0dXJlPWM2ODRhODJiNzk4MjAyOTg3NWJmZDhlMGE2NjBiNzdm
- v2 旋轉(zhuǎn)驗(yàn)證碼:
aHR0cHM6Ly93YXBwYXNzLmJhaWR1LmNvbS9zdGF0aWMvY2FwdGNoYS90dXhpbmcuaHRtbD8mYWs9YzI3YmJjODlhZmNhMDQ2MzY1MGFjOWJkZTY4ZWJlMDY=
- v2 滑塊驗(yàn)證碼:
aHR0cHM6Ly93YXBwYXNzLmJhaWR1LmNvbS9zdGF0aWMvY2FwdGNoYS90dXhpbmcuaHRtbD8mYW1wO2FrPWMyN2JiYzg5YWZjYTA0NjM2NTBhYzliZGU2OGViZTA2
- v2 點(diǎn)選驗(yàn)證碼:
aHR0cHM6Ly93YXBwYXNzLmJhaWR1LmNvbS92Ni9nZXRQYXNz
PS:v1牌借、v2 是作者自己為了區(qū)分而命名的版本號(hào),主要依據(jù)是核心 JS 文件分為 mkd.js 和 mkd_v2.js 兩個(gè)版本割按,如下圖所示:
此外膨报,在界面上也有所區(qū)別,v2 版本的旋轉(zhuǎn)适荣、滑塊圖片有很明顯的陰影现柠、線條干擾,如下圖所示:
上面給的地址中弛矛,點(diǎn)選驗(yàn)證碼的地址有時(shí)候是點(diǎn)選够吩,有時(shí)候會(huì)變成旋轉(zhuǎn),估計(jì)是異常等級(jí)不同導(dǎo)致的丈氓,此外周循,傳聞還有一種無(wú)感驗(yàn)證,不過(guò)作者到處找也沒(méi)找到個(gè)地址扒寄,估計(jì)邏輯都是差不多的鱼鼓,無(wú)感驗(yàn)證如下圖所示:
抓包分析
以下以 v1 旋轉(zhuǎn)驗(yàn)證碼為例(v2 接口名稱不一樣,但邏輯是一樣的)该编,第一次 viewlog
接口迄本,請(qǐng)求的 ak
是固定值,當(dāng)然不同場(chǎng)景不同網(wǎng)站是不一樣的课竣,callback
回調(diào)值嘉赎,_
時(shí)間戳,返回值 as
于樟、tk
都是后面會(huì)用到的公条。
然后是一個(gè) getstyle
接口,其中的 tk
就是前面 viewlog
接口返回的迂曲,返回值里 backstr
后續(xù)參數(shù)加密會(huì)用到靶橱,img
就是旋轉(zhuǎn)圖片地址,info
是一些版權(quán)信息路捧。
旋轉(zhuǎn)驗(yàn)證碼開(kāi)始驗(yàn)證关霸,此時(shí)第二次出現(xiàn) viewlog
接口,as
和 tk
參數(shù)是第一次 viewlog
返回的杰扫,fs
參數(shù)需要我們逆向队寇,包含了旋轉(zhuǎn)角度等信息,如果旋轉(zhuǎn)角度正確且參數(shù)沒(méi)問(wèn)題章姓,則返回值里的 op
為 1佳遣,另外返回的 ds
和 tk
后續(xù)還會(huì)用到识埋。
上一步驗(yàn)證走完后,并不意味著通過(guò)驗(yàn)證了零渐,后續(xù)還會(huì)有一個(gè) viewlog/c
的接口需要進(jìn)一步驗(yàn)證窒舟,其中的 tk
、ds
參數(shù)就是上一步返回的相恃,如果驗(yàn)證失敗辜纲,返回值 code
為 1笨觅,驗(yàn)證成功拦耐,code
則為 0。
逆向分析 fs
接下來(lái)分析主要加密參數(shù) fs
见剩,跟棧到 mkd.js:
可以看到 o
就是 fs
杀糯,而 o
又是 r.rzData
經(jīng)過(guò)加密后得到的,輸出一下 r.rzData
苍苞,結(jié)構(gòu)如下圖所示:
重要參數(shù):
-
ac_c
:一看就知道和旋轉(zhuǎn)的角度有關(guān)固翰; -
backstr
:getstyle
接口返回的; -
cl
:x羹呵,y 坐標(biāo)以及時(shí)間戳骂际,量一下就知道這個(gè)坐標(biāo)是鼠標(biāo)點(diǎn)擊下面那個(gè)滑動(dòng)條按鈕的時(shí)候的坐標(biāo); -
mv
:鼠標(biāo)軌跡冈欢,鼠標(biāo)動(dòng)一下就記錄一下坐標(biāo)和時(shí)間戳歉铝; -
cr
:屏幕長(zhǎng)寬高等信息; - 其他值都是空或者0凑耻。
實(shí)際測(cè)試太示,cl
和 mv
都不校驗(yàn),寫死或者置空都行香浩,當(dāng)然想要自己偽造一下也是可以的类缤,量一下滑動(dòng)按鈕在屏幕中的位置,cl
根據(jù)這個(gè)位置隨機(jī)生成就行了邻吭。重點(diǎn)看看 ac_c
餐弱,直接搜索即可定位:
可以看到這個(gè)值的計(jì)算方法為 parseFloat(o / a).toFixed(2)
,a
是定值 212囱晴,實(shí)際上就是滑動(dòng)條能夠滑動(dòng)的最大長(zhǎng)度膏蚓,o
是滑動(dòng)的距離,如果我們識(shí)別出來(lái)的是旋轉(zhuǎn)角度 angle
速缆,則 ac_c
計(jì)算方法如下:
var o = angle * 212 / 360
var ac_c = parseFloat(o / 212).toFixed(2)
// 也可以直接寫成:
var ac_c = parseFloat(angle / 360).toFixed(2)
r.rzData
搞定后降允,就只有個(gè) r.encrypt()
方法了,直接跟進(jìn)去就是我們熟悉的 AES 算法艺糜,其中 iv 是 viewlog
接口返回的 as 值加上一個(gè)定值 appsapi0
剧董,其他就不用多說(shuō)了幢尚。至此加密參數(shù)就搞完了,還是非常簡(jiǎn)單的翅楼。
旋轉(zhuǎn)角度識(shí)別
這里推薦一個(gè)國(guó)外大佬的 RotNet 項(xiàng)目尉剩,可以用于預(yù)測(cè)圖像的旋轉(zhuǎn)角度以糾正其方向,還有基于此項(xiàng)目開(kāi)發(fā)的毅臊,Nanda 大佬的 RotateCaptchaBreak理茎、另一個(gè)大佬的 rotate-captcha-crack 等,鏈接如下:
- https://github.com/d4nst/RotNet
- https://github.com/chencchen/RotateCaptchaBreak
- https://github.com/Starry-OvO/rotate-captcha-crack
深度學(xué)習(xí)大佬可以基于這些項(xiàng)目進(jìn)一步訓(xùn)練管嬉,像我這種對(duì)這方面一竅不通的當(dāng)然是選擇打碼平臺(tái)了皂林,云碼打碼還不錯(cuò),只不過(guò)官網(wǎng)只放出了 v1 版本沒(méi)有陰影干擾的蚯撩,找他們客服可以拿到 v2 版本有陰影干擾的類型础倍,這里就不多說(shuō)了,免得被認(rèn)為是打廣告了哈哈哈胎挎。
v2 版本分析
v2 版本和 v1 版本基本上差不多沟启,區(qū)別在于 rzData
的結(jié)構(gòu)不太一樣,ac_c
的計(jì)算方法不一樣犹菇,以及 AES 的 IV 不一樣德迹,先看 AES 的 IV,v2 版本是 as 值加上固定值 appsapi2
:
然后再看看 rzData
揭芍,common
字段下基本上就是 v1 的 rzData
的格式胳搞,captchalist
下,至少有 spin-0
(旋轉(zhuǎn))沼沈、``puzzle-0(滑塊)流酬、
click-0(點(diǎn)選)三種,
ac_c` 依舊是旋轉(zhuǎn)角度占比列另、滑動(dòng)占比以及點(diǎn)選坐標(biāo)信息芽腾,其他的依舊是寫死或者置空就行。
然后就是 ac_c
的計(jì)算方法了页衙,首先是旋轉(zhuǎn)驗(yàn)證碼摊滔,直接搜索 ac_c
:
往上跟棧,有個(gè) percent 的地方店乐,一個(gè)三目表達(dá)式艰躺,e 是固定值 290,e - 52 = 238
眨八,238 也就是滑動(dòng)條能夠滑動(dòng)的最大長(zhǎng)度:
如果我們識(shí)別出來(lái)的是旋轉(zhuǎn)角度 angle
腺兴,則 ac_c
計(jì)算方法如下:
var distance = angle * 238 / 360
var ac_c = Number((distance / (290 - 52)).toFixed(2))
// 也可以直接寫成:
var ac_c = Number((angle / 360).toFixed(2))
而對(duì)于滑塊驗(yàn)證碼就有所不同,同樣是這個(gè)地方的三目表達(dá)式廉侧,但是要走后面的邏輯:
如果我們識(shí)別出來(lái)的是滑動(dòng)距離 distance
页响,則滑塊 ac_c
的計(jì)算方法如下:
var ac_c = Number((distance / 290).toFixed(2))
同樣對(duì)于點(diǎn)選驗(yàn)證碼來(lái)說(shuō)篓足,也不一樣,ac_c
的值是點(diǎn)擊的 xy 坐標(biāo)以及時(shí)間戳:
其他問(wèn)題
前面我們說(shuō)了百度的驗(yàn)證應(yīng)該有兩次闰蚕,對(duì)于第二次驗(yàn)證栈拖,也就是 v1 的 viewlog/c
接口,v2 的 cap/c
接口没陡,即便你第一次校驗(yàn)通過(guò)了涩哟,這個(gè) c 接口校驗(yàn)也有可能不通過(guò),出現(xiàn)這種情況的原因是通過(guò)的時(shí)間太短了盼玄,隨機(jī) time.sleep
1-3 秒即可贴彼,如果時(shí)間太短,c 接口可能會(huì)報(bào)以下驗(yàn)證錯(cuò)誤:
{'code': 1, 'isRectified': False, 'msg': 'Verification Failed'}
還有一種情況就是提示存在安全風(fēng)險(xiǎn)强岸,請(qǐng)?jiān)俅悟?yàn)證
锻弓,出現(xiàn)這種情況你會(huì)發(fā)現(xiàn)去瀏覽器手動(dòng)滑也是一樣的砾赔,所以在本地加個(gè)再次驗(yàn)證的邏輯就行了蝌箍,一般來(lái)說(shuō)第二次驗(yàn)證就能通過(guò)。
{'code': 0, 'msg': 'success', 'data': {'f': {'feedback': 'https://www.baidu.com/passport/ufosubmit.html', 'reason': '存在安全風(fēng)險(xiǎn)暴心,請(qǐng)?jiān)俅悟?yàn)證'}}}
然后就是請(qǐng)求 header 里沒(méi)有 Referer
或者 Referer
不正確的話妓盲,會(huì)報(bào)錯(cuò):
// v1 沒(méi)有 Referer
{'code': 1, 'msg': 'Unregistered Host'}
// v1 Referer 不正確
{'code': 1, 'msg': 'Invalid Request', 'data': []}
// v2 沒(méi)有 Referer 或者 Referer 不正確
{'code': 100600, 'msg': 'Unauthorized Host'}
還有一個(gè)小技巧,如果你想自己驗(yàn)證一下旋轉(zhuǎn)的角度對(duì)不對(duì)专普,怎么去測(cè)量這個(gè)角度呢悯衬?我們可以借助一些做圖軟件,簡(jiǎn)單點(diǎn)兒的比如美圖秀秀檀夹,新建一個(gè)畫布筋粗,然后直接將驗(yàn)證碼圖片拖進(jìn)去,就可以自由旋轉(zhuǎn)了炸渡,旋轉(zhuǎn)的時(shí)候軟件會(huì)自動(dòng)標(biāo)注出旋轉(zhuǎn)的角度娜亿,如下圖所示:
結(jié)果驗(yàn)證
爬蟲工具站
K哥新上線了一個(gè)爬蟲工具站,歡迎測(cè)試:https://www.kgtools.cn/