Python 爬蟲進階必備 | Js 逆向之補環(huán)境到底是在補什么?
↑ 關注 + 星標 ,每天學Python新技能
后臺回復【大禮包】送你Python自學大禮包

雖然當時的主題寫的是 App 爬蟲,不過并不妨礙的我們理解爬蟲。
今天寫的 Js 逆向之補環(huán)境,就可以理解是在 Js 環(huán)境下精進我們的 " 騙術 "
正文
大家在看文章之前應該都清楚,Node 環(huán)境和瀏覽器環(huán)境是完全不同的,平臺有很多的檢測點可以發(fā)現我們是在瀏覽器運行 Js 還是在 Node 環(huán)境下運行 Js
補環(huán)境做的就是盡可能根據網頁上的 Js 完善本地的 Node 環(huán)境,讓 Js 運行在 Node 中像瀏覽器一樣正常運行,最高境界當然是 Js 拿來套上環(huán)境就跑,不過可以說是道阻且長
。
window
最基本的補環(huán)境是公眾號早期的文章,例如下面的幾篇文章
這些個文章中大家經常遇到的是
'window' is not defined
那像這樣的報錯提示應該如何處理?
Node 環(huán)境下一般如下定義
window = global;
如果只是單單缺少了window這一個變量的定義,像上面這樣報錯自然就消失了。
document
除了window之外,我們經常還遇到類似下面這些文章中的情況
Python 爬蟲進階必備 | 某采購網站 cookie 加密分析(仿加速樂)
Python 爬蟲進階必備 | 某常見 cookie 加密算法邏輯分析 (加速樂 - jsl)
這些網站我們一般稱之為加速樂,因為標志性的 cookie 參數是以jsl開頭,而這種類型的加密一般操縱的是document.cookie這個參數
那像這樣的document應該怎么補?
在沒有檢測只是為了能讓 js 運行不報錯的情況下,我是這樣寫的
var document = {
cookie:"xxxxxx"
}
或者像下面這樣寫

那么這樣寫就一定保險嗎?
不一定。開頭就已經提及,要根據網頁上的 Js 完善本地的 Node 環(huán)境,所以只要網頁上的 Js 不檢測我們這么寫也沒毛病
那么檢測的 Js 長什么樣?
Object.getOwnPropertyDescriptor
這里可以參考之前寫的關于某乎的分析文章
Python 爬蟲進階必備 | 某著名人均百萬問答社區(qū) header 參數加密邏輯分析
這里Header中的x-zse-96的加密邏輯之前看過文章的,通過插樁調試應該可以看到下面這樣的代碼

這個東西是個啥?
官方定義是這樣的
“
Object.getOwnPropertyDescriptor()方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性)
通過描述有點晦澀,你可以這樣理解,如果是自己構造的對象,例如
var navigator = {
platform:"win32"
}
就沒辦法通過這樣的檢測
這里是檢測對象的屬性是不是自己賦值給他的
這里打印下剛剛的例子看看有啥不一樣的地方
先是我們自己寫的例子
var navigator1 = {
platform:"win32"
}

再看看瀏覽器里面是啥樣的

所以對于這樣的代碼檢測,我們應該如何構造呢?
這里站在前人的肩膀上,寫一下
var Navigator = function() {};
Navigator.prototype = {"platform": "win32"};
navigator = new Navigator();
# 只針對檢測 Navigator 原型鏈的寫法
這樣就可以通過上面的原型鏈檢測了
這里的platform是Navigator上的屬性,在使用 new 實例化后,navigator.platform 取到的是繼承自Navigator的屬性值,而不是直接賦予該對象的屬性,所以得到的結果和瀏覽器是一樣的。
這樣看是不是很簡單,但是像某乎的校驗用到了很多次getOwnPropertyDescriptor,就需要一個個插樁調試他檢測了什么對象的什么屬性,相當惡心。
那么又回到上面的代碼,這里用到的prototype又是個啥?
prototype 與 _ _ proto _ _
首先先上一張圖

是不是很懵逼,懵逼就對了,我們是搞爬蟲的,知道個大概意思就行了。
我們需要知道的是 prototype 與 _ _ proto _ _ 咋對應起來就行了
按照官方的說法
“在JS里,萬物皆對象。方法(Function)是對象,方法的原型(Function.prototype)是對象。因此,它們都會具有對象共有的特點。即:對象具有屬性_ _ proto _ _,可稱為隱式原型,一個對象的隱式原型指向構造該對象的構造函數的原型,這也保證了實例能夠訪問在構造函數原型中定義的屬性和方法。
方法(Function)這個特殊的對象,除了和其他對象一樣有上述_proto_屬性之外,還有自己特有的屬性——原型屬性(prototype),這個屬性是一個指針,指向一個對象,這個對象的用途就是包含所有實例共享的屬性和方法(我們把這個對象叫做原型對象)。原型對象也有一個屬性,叫做constructor,這個屬性包含了一個指針,指回原構造函數。
理解大概的意思(別被搞暈了)可以得出下面這行代碼
xxx.__proto__ == yyy.prototype
這里我們需要用到谷歌瀏覽器驗證一下我們的想法

有一定基礎的同學知道,瀏覽器里 window 是由 Window 實例而來的,那么 Window 是怎么來的?
我們在瀏覽器的控制臺里看看


可以看到原來我們之前以為簡簡單單就構造出來的 window 和 navigator 這么復雜
這樣一看像我們上面直接使用var定義的方法去補環(huán)境就很容易被識別
例如
var window1 = {
bbb:"xxxx"
};
# 在瀏覽器里沒法定義 window 這里用 window1 做個樣子

這里window1的結果和我們上面瀏覽器中window的輸出結果大相徑庭。
不僅僅是window,包括document以及navigator等等囊括DOM、BOM、worker、網絡請求這些的方方面面都需要我們一個一個分析他的__proto__以及屬性是定義在自己的prototype上還是繼承自上一層。
這里就又涉及了關于上述各類的繼承關系,這里分享我找到的一張DOM中各類的繼承關系圖,希望對大家補環(huán)境有所幫助

總結
這篇文章我的定義并不是關于補環(huán)境的總綱或者是總述,只能說是掀起了補環(huán)境神秘面紗的一角,希望大家多多交流,不斷完善自己的環(huán)境框架,做到一鍵通殺~
還有就是關于文章中如果描述不準確的地方,歡迎在留言區(qū)指正,大家共同進步。
以上就是本次的全部內容了,咱們下次再會~
Peace and Love
- END -
推薦閱讀
推薦一個公眾號,幫助程序員自學與成長
覺得還不錯就給我一個小小的鼓勵吧!


