娛樂網(wǎng)站模板手機網(wǎng)頁設(shè)計制作網(wǎng)站
聲明
本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用,不用于其他任何目的,不提供完整代碼,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口等均已做脫敏處理,嚴禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無關(guān)!
本文章未經(jīng)許可禁止轉(zhuǎn)載,禁止任何修改后二次傳播,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外,作者均不負責,若有侵權(quán),請在公眾號【K哥爬蟲】聯(lián)系作者立即刪除!
前言
K 哥之前在【JS 逆向百例】專欄中寫過一篇文章:【JS 逆向百例】房某下登錄接口參數(shù)逆向,該站如果通過輸入賬號和密碼的方式進行登錄,POST 請求參數(shù)中,密碼 pwd 被加密處理了,對其進行了逆向分析。最近在某博客平臺上,有粉絲在該篇文章的評論區(qū)詢問能不能出一期該站的滑塊逆向文章,經(jīng)過研究發(fā)現(xiàn)通過手機動態(tài)碼的方式登錄,點擊獲取短信驗證碼時,會彈出滑塊驗證,本文將對另一種登錄方式的反爬策略進行研究分析,既是滿足粉絲需求,也是對該站登錄逆向的補充完善。
逆向目標
- 目標:房某下手機動態(tài)碼登錄,滑塊驗證碼逆向分析
- 網(wǎng)站:aHR0cHM6Ly9wYXNzcG9ydC5mYW5nLmNvbS8=
抓包分析
隨便輸入一串手機號碼,點擊獲取短信驗證碼,即會彈出滑塊驗證,getslidecodeinit.api
接口響應(yīng)返回 challenge
和 gt
參數(shù)的值,這兩個參數(shù)在后面校驗滑塊驗證和獲取短信驗證碼的時候會用到:
c=index&a=jigsaw
接口響應(yīng)返回的參數(shù)中,surl
為滑塊驗證碼的背景圖片,url
為滑塊圖片,完整的下載地址需要在前面加上 https://static.soufunimg.com/common_m/m_recaptcha/jigsawimg/
:
需要注意的是,下載下來的背景圖片(320x160)以及滑塊圖片(60x158)的長寬與網(wǎng)頁上渲染出來的是不一致的:
渲染出來的背景圖片為 300x150,滑塊為 57x150,需要先對獲取到的圖片進行縮放處理后,再識別缺口距離:
拖動滑塊進行驗證,c=index&a=codeDrag
接口響應(yīng)返回校驗的結(jié)果,請求參數(shù)中 i
和 t
經(jīng)過了加密處理,需要逆向還原出加密算法,后文會進行研究分析,callback
生成方式如下:
"fangcheck_" + (parseInt(1e4 * Math.random()) + (new Date).valueOf())
- 1e4 * Math.random():生成一個介于 0 到 10000 之間的隨機數(shù);
- (new Date).valueOf():獲取當前的時間戳(以毫秒為單位)。
challenge
和 gt
參數(shù)是前面所說的 getslidecodeinit.api
接口響應(yīng)返回,start
和 end
為滑動軌跡開始及結(jié)束的時間戳:
滑塊驗證失敗,code 有兩種狀態(tài)碼:
101 —> 參數(shù)校驗失敗
102 —> 缺口識別錯誤
滑塊驗證成功,code 為 100:
驗證成功之后,會響應(yīng)返回 validate
參數(shù),攜帶該參數(shù)請求 loginsendmsm.api
接口,即可成功發(fā)送短信驗證碼:
發(fā)送成功,響應(yīng)返回的 message 為 Success,失敗則為 Error:
逆向分析
i 參數(shù)
先來分析下 i
參數(shù)是如何加密生成的,從驗證接口跟棧到 jigsawpc.1.0.1.js
文件中:
ctrl + f
搜索 i:
,只有一個結(jié)果:
在第 204 行打下斷點,滑動滑塊即會斷住,可以看到,l
即滑動軌跡,由 x 軸、y 軸距離以及時間戳組成,后面再對軌跡進行分析,前文所講到的 start
、end
在此驗證了,為滑動的開始及結(jié)束時間:
從第 203 行,跟進到 x.compress
方法中去:
可以看到,i
參數(shù)的值就是由 x.baseCompress
方法生成的,傳入的 e
參數(shù)很像是由一些值拼接而成的:
回到第 203 行,e
參數(shù)是由 function(e) {...}
方法生成的,點擊前大括號,找到該函數(shù)結(jié)束的位置,在第 301 行打下斷點,斷住后會發(fā)現(xiàn),e
參數(shù)的值是先通過 join( )
方法將 r
數(shù)組的所有元素用 !!
符分隔后連接成一個字符串,再使用 encodeURIComponent( )
方法進行編碼后得到的:
那 r
數(shù)組是由哪些元素組成的呢?往上跟到第 296 行就會發(fā)現(xiàn),r
數(shù)組中的元素如下,包括一些瀏覽器環(huán)境,最后確實校驗了,但不多:
["textLength", "HTMLLength", "documentMode", "screenLeft", "screenTop", "screenAvailLeft", "screenAvailTop", "innerWidth", "innerHeight", "outerWidth", "outerHeight", "browserLanguage", "browserLanguages", "systemLanguage", "devicePixelRatio", "colorDepth", "userAgent", "cookieEnabled", "netEnabled", "screenWidth", "screenHeight", "screenAvailWidth", "screenAvailHeight", "localStorageEnabled", "sessionStorageEnabled", "indexedDBEnabled", "CPUClass", "platform", "doNotTrack", "timezone", "canvas2DFP", "canvas3DFP", "plugins", "maxTouchPoints", "flashEnabled", "javaEnabled", "hardwareConcurrency", "jsFonts", "timestamp", "performanceTiming", "cwidth"]
下面是對數(shù)組中各環(huán)境屬性的簡單描述,可供參考:
- textLength:用于測量 HTML 元素文本內(nèi)容的長度;
- HTMLLength:獲取當前文檔中 HTML 根元素的內(nèi)部 HTML 內(nèi)容的長度;
- documentMode:用于在 Internet Explorer 瀏覽器中確定文檔的呈現(xiàn)模式;
- screenLeft,screenTop:窗口左上角相對于屏幕左上角的坐標;
- screenAvailLeft,screenAvailTop:可用屏幕空間左上角相對于屏幕左上角的坐標;
- innerWidth,innerHeight:瀏覽器窗口的內(nèi)部寬度和高度,不包括瀏覽器工具欄和滾動條;
- outerWidth,outerHeight:瀏覽器窗口的外部寬度和高度,包括瀏覽器邊框和工具欄;
- browserLanguage,browserLanguages:瀏覽器當前使用的語言或語言列表;
- systemLanguage:操作系統(tǒng)的默認語言;
- devicePixelRatio:設(shè)備像素比,用于在不同分辨率屏幕上進行適配;
- colorDepth:屏幕顏色深度;
- userAgent:瀏覽器的用戶代理字符串,通常包含瀏覽器和操作系統(tǒng)信息;
- cookieEnabled:表示瀏覽器是否啟用了 Cookie;
- screenWidth,screenHeight:屏幕的寬度和高度;
- screenAvailWidth,screenAvailHeight:可用屏幕的寬度和高度;
- localStorageEnabled,sessionStorageEnabled:表示瀏覽器是否啟用了本地存儲和會話存儲;
- indexedDBEnabled:表示瀏覽器是否啟用了 IndexedDB;
- CPUClass:表示 CPU 的等級或類別;
- platform:操作系統(tǒng)平臺信息;
- doNotTrack:表示用戶是否啟用了 “不跟蹤” 功能;
- timezone:用戶所在時區(qū);
- canvas2DFP,canvas3DFP:Canvas 防指紋技術(shù),用于保護用戶隱私;
- plugins:瀏覽器安裝的插件列表;
- maxTouchPoints:設(shè)備支持的最大觸摸點數(shù);
- flashEnabled:表示瀏覽器中是否啟用了 Flash;
- javaEnabled:表示瀏覽器中是否啟用了 Java 插件;
- hardwareConcurrency:表示設(shè)備的邏輯處理器核心數(shù);
- jsFonts:瀏覽器已安裝的字體列表;
- timestamp:時間戳,通常用于測量性能和時間間隔;
- performanceTiming:訪問有關(guān)頁面加載和性能計時的信息。
至此 e
參數(shù)的構(gòu)成方法分析完了,再回到 x.compress
方法中,也就是第 505 行,前文分析了,i
參數(shù)由 x.baseCompress
方法生成,該方法傳入了三個參數(shù),前兩個已經(jīng)分析完了,來看看第三個函數(shù)部分:
function(e) {return x.toChart16(t(e))
}
t
方法定義在第 502 行,就是 String.fromCharCode( )
,它用于將一組 Unicode 值(UTF-16 編碼)轉(zhuǎn)換成對應(yīng)的字符串,每個參數(shù)都是一個表示 Unicode 值的整數(shù)。再跟進到 x.toChart16
方法中去,定義在第 628 行,直接扣下來就行了:
最后直接將 baseCompress
方法扣下來即可,i
參數(shù)就分析完了:
t 參數(shù)
生成 t
參數(shù)的方法定義在第 302 行,同樣搜 t:
就可以找到,和 i
一樣,也是幾個自執(zhí)行函數(shù),直接跟到第 392 行,打下斷點,斷住后驗證了,t
參數(shù)就是在這里生成的:
t
參數(shù)是于一長串二進制字符串 e
中從前往后依次截取六位字符,再通過 parseInt
方法將截取到的二進制字符串轉(zhuǎn)換為整數(shù),即索引,最后使用 charAt
方法根據(jù)索引從固定字符串 E
中取值,循環(huán) e.length / 6
次后拼接而成的:
那一長串二進制字符串怎么來的呢?生成 t
參數(shù)的函數(shù)是個自執(zhí)行函數(shù),傳入的參數(shù)是 l
,l
定義在第 368 行,生成方法逐個跟,扣下來即可:
接著往上跟到 return
處,即第 360 行,此時傳入的 e
為鼠標軌跡,很明顯,這里對軌跡做了處理,不再是前文所講的 x、y、t
形式,被轉(zhuǎn)換成了一個大數(shù)組:
相關(guān)轉(zhuǎn)換算法在第 180 行,即 e
參數(shù),軌跡校驗的不是很嚴格,模擬構(gòu)造即可: