震驚!他居然用控制台自動植入JS實現某度破解!


震驚!他居然用控制台自動植入JS實現某度破解!

前言

一切都要從某度網盤(下稱某盤)的倍速功能說起。

任意一個沒有開VIP的賬號隨變打開一個視頻。

切換VIP的時候會提醒VIP專享功能,需要。。。🤔

image

emmmmmm

等我先把我之前寫的插件關一下 ,不然倍速和畫質都解鎖了還教啥。。。🤣

嗯,再看一下,圖標變回來了。

👉image👈 ----> 👉image👈

黑金尊貴金屬科技感沒了,那這次應該關掉了。好了我們繼續。不過廣告也出現了,果然是魚與熊掌不可兼得。

哦對了,順便說一下,這個也就是我【之前在論壇里發過的帖子】中的【某盤腳本】,只不過更新了好幾代,現在相對更完善而已。。。😏

好,回到本次主題上。

引入

很久前寫腳本時,想解鎖某盤的倍速功能,就去分析了當時某盤倍速會跳回去的原因,分析了一下,大概就是某盤代碼里會每隔500ms把視頻播放的速率調整為當前的設置,非 VIP 就是寫死的 1 ,VIP 就是把這個速率調整為 X ,其實也是鎖定的,但是沒有改動所以不會感受到而已。

於是,在各個地方出現的各種所謂的解鎖腳本,都是以更快的頻率去重置達到所謂的解鎖目的。因為至少也算達到了目的,姑且就算稱之為“解鎖”吧。🙄

我使用的解決辦法不是設置比他更快的定時器的執行方式,畢竟兩個定時,一個比一個快(比快我是真的不擅長),瀏覽器吃得消么?所以導致頁面也會越來越卡,但願瀏覽器沒事。🙏

某盤使用的是 setTimeout 每隔500 ms調用自己,於是我。。。

for(let k=0;k<99999;clearTimeout(k++));

說白了,在循環里清除所有延時定時。。。確實還真的有奇效。😂

但是好景不長,后來某盤更新了算法,大量的腳本都失效了(這一部分現在也是類似的算法),我們本文引入部分需要討論的也是這部分內容。

簡單的搜索一下倍速播放按鈕上面的提示,定位到定義的位置,因為本文描述的只是一些稀奇古怪的東西,因此其他的基礎內容(比如控制台的打開啊,格式化啊,斷點啊,js 基礎的操作之類的)請自行查找,我之前的教程也有涉及到,也可以去翻看。

image

定位到位置向下翻,最終呈現的UI上有“立即開通SVIP”,那我開了肯定就不顯示了,果然翻到一個非常清楚的問號冒號條件判斷語句:

image

順便補一下基礎知識吧(雖然說要基礎,但是總要照顧一下讀者嘛。。。),很多語言中都有類似的語法,

a?b:c

上述的a,b,c分別代表三組表達式,為什么不是說三個呢?因為不僅可以像他這樣放上 json ,還可以是一連串的表達式,比如下面的偽代碼所示:

判斷1&&判斷2&&判斷3?
(成立做的事情1,成立做的事情2,成立做的事情3):
(不成立做的事情1,不成立做的事情2,不成立做的事情3)

等等這些都可以。

什么?這就看不懂了?沒關系,還有很多其他的你也不懂🤏,當然,也還有更多我所不懂的,一起探索世界嘛,都懂的世界有什么意義呢對吧,畢竟我們還沒達到看破紅塵的境界。

好,收回來,我們知道了之前代碼的意思是:

如果d.userInfo.isSVip不是空(或者0),就把下面的哪個 json 賦值給他,然后顯示出來。

翻譯一下,如果用戶信息里的isSvip不是“假”的話,就不顯示哪個按鈕

再翻譯一下,如過是Svip就不顯示那個按鈕了

那么我就把這個isSvip改成真試試。

好,下斷點,因為這是一個大json,因此直接下斷點是無法直接斷下來的,因此我們需要在json定義的位置下斷點,然后刷新頁面,頁面暫停,斷點處斷下。

image

鼠標放到上面懸浮幾秒,參數明了了,確實是我不SVIP,那改了不就有了?😘

修改的方式有很多,雙擊彈窗,在上面直接修改(左下圖),

image image

或是在右邊的寄存器里找到然后雙擊修改(右上圖),再或者是在控制台輸入:d.userInfo.isSVip=true然后敲回車。我最喜歡第三種因為有點很久前那種修改前端讓自己以為沖上QB啊之類的快感。。。

改完發現,誒,不僅倍速解鎖了,連畫質都解鎖了。好了下面就是擼腳本了,但是如果你只是自己用呢?就算你會寫,在億堆代碼里找調用的位置也是很難的,此外js中最頭疼的是什么?是this的內容和作用域。。。

這么說吧,我代碼中最終呈現出來的效果,肯定是我分析過了的,但是我沒呈現出來的就不一定我沒做,有可能是技術原因沒搞出來,有可能是純粹的因為我懶,但是我個人覺得最多的情況其實應該是難以下手別看你這里顯示的又是isSvip,又是userinfo的,這都是關鍵數據,沒混淆的,你隨手往上看一眼,就是用我們下斷點前面一點的截圖說明吧:

image

那我問你,這圖上所有的參數e我都用紅框標出來了,哪個e是哪個e分得清么?最上面的三個e是另一個函數里的,跟我們這個函數無關,function后面括號里的e是參數,是什么還需要找這個函數的調用位置(本函數名是d),而function后面緊跟着的是定義的一個新函數,這個函數的名字是e,而var后的那個e則是一個新的變量,完全沒有任何關系的一堆e集中在一張圖里。。。🤐😨

那你可能說要下斷點,然后控制台賦值,回車然后再運行。沒錯可以,但是不夠智能,那我寫這篇文字的意義在哪里?🙄教你如何修改某盤的倍速么?那不如直接用我的插件🤔

解決

我們可以利用chrome的條件斷點完成賦值。

跟OD之類的調試器一樣,控制台也支持條件斷點。

下斷點怎么下的?直接左鍵點一下行號前面,那右鍵呢?

image

東西還挺多的,上圖①就相當於OD中的F4,運行到這里,和②下斷點然后運行其實是差不多的;

⑤一般可以用於反調試臨時防止一直在某個地方斷點,⑥就是忽略這個腳本,跟我們更沒關系。。。

最想說的就是③和④,其中③:當表達式為true的時候斷下,而④:運行到這里的時候會打印輸入的表達式。

很多語言都一樣,比如逗號連接的幾個表達式是相同級別的,而最終的返回值則是最后一個逗號后面的值

比如

image

前面不管干什么,主要最后一個值是false,那就是false,反之亦然。

所以完全可以利用剛才的條件斷點完成注入(這就是本文最主要想說的內容)

我們在條件斷點里直接寫上賦值語句,然后刷新頁面(控制台不關)這里會斷下來,然后賦值是成功的,

image

當我們再在后面加上 ,false 就可以實現控制台不斷下自動注入(並且不用考慮注入的時間)

image

額外新知識

此外就是沒事找事了,使用代碼倍速,如果使用代碼修改的話還很麻煩的,首先因為他用了shadowroot技術把video標簽關閉封裝了,

image

這都不是關鍵問題,通過其他方式我們還是可以通過代碼獲取到這個標簽的,控制倍速什么的也都是正常的。

image

但是!如果是試用舊版SDK,且我們沒有之前那樣修改isSviptrue,同樣的操作,獲取當前的倍速信息就會變成

image

這樣,然后賦值的時候則是沒效果。。。😫

分析一下原因吧。這個原因我找遍了國內外,都沒有找到原因,然后我就全頁面搜索關鍵詞playbackRate挨個排查所有搜到的js,最后看到了這串代碼(因為代碼看的不直觀就截圖了)

image

image

我怎么不僅看到鎖定播放速率,還看到了奇怪的東西?如果不是SVIP,並且有視頻播放器,並且沒有剩余的數量(指試用次數,最上面判斷是否顯示購買SVIP圖標的地方有相關字樣),就定義屬性?(附:MDN說明文檔

image

🤔???(心里疑惑)再看一下get和set

image

所以那段代碼的意義就是非SVIP把video標簽的playbackrate系統屬性重寫了,讀取速率時返回自己的速率,然后自己又會去讀取自己,造成炸堆棧效果?而設置速率就改成空行為。。。

😲真的是學到了,這波騷操作是真的服氣。。。其實之前也在論壇里提過,不過是在一個帖子里的子樓層提出來的,並且沒有給出響應的解釋,這里解釋一下。並且艾特一下這位大佬()

現學現賣

你以為到這里就結束了?你以為我只是分享這個屬性重寫覺得他厲害么?😏😎

顯然不是,就算這么搞,我還是修改成功了,所以我最厲害🤣(開個玩笑。。。)

轉到某度文檔(下稱:某文)解鎖免VIP復制、全屏純凈閱讀的時候(相關腳本也在最上面那個帖子里,【腳本地址】),老規矩,搜關鍵詞,不對,先關腳本。。。廣告出現就出現吧,好歹免VIP復制和純凈閱讀的特權是不存在了。

👉image👈 ----> 👉image👈

隨變打開一篇文章,隨變選中一些文字,點復制,彈出購買VIP框。搜索關鍵詞“開通VIP可繼續復制”,只找到一處。

image

找到定義地方下斷點,此時是創建VIP彈窗,且沒有判斷,因此考慮找找堆棧回溯。F5刷新,重復操作,斷下后點運行,發現第一次斷下是彈出懸浮欄的功能,點擊復制按鈕后第二次斷下,才是復制的功能彈窗。

image

因此第二次斷下后查看堆棧,堆棧截圖如下

image

一般相關的代碼都是寫在一起的(包括require引入方式),而xreader一看就像是一個什么插件庫之類的東西🤔,因此我們重點看common這個庫相關的調用。

一眼嫖見clickCopy,點擊復制按鈕,點擊跳轉過去

clickCopy: function() {
    r.a.xsend(102222),
    this.setVisible(!1),
    this.setIsCopyActivated(!0)
},

一看第一個就是記錄日志然后發送去提升體驗感的,直接略過。第二個設置不可見(!1為false),應該是隱藏當前懸浮欄彈窗,最后一個設置復制狀態,因為vue調試時候的問題,直接定位不過去,這里可以兩種辦法找到定位:

  1. 直接搜索setIsCopyActivated一般沒有人會定義兩個同樣名稱的函數

    image

    這不就有了么

  2. 在這里下斷點,斷下后到堆棧里找位置

    唔,注意一層層找,稍微有點麻煩,不過也不比搜索慢

    image

    斷下后this->setIsCopyActivated->[[TargetFunction]]->[[FunctionLocation]],點一下就同樣可以跳過去。

    emmm不過這里貌似不可行,他被翻譯成native code 了,問題不大反正是一種思路😅

    (這又不能怪我,都怪編譯器把他編譯成native code了,你瞧我們現在所在的clickCopy不是好好的么😕)

    image

    注:其原因應該是與函數的影響的參數類型有關,下面會說到

找到setIsCopyActivated所對應的函數了:

setIsCopyActivated: function(t, e) {
    t.isCopyActivated = e
},

但是只有一行賦值,那他是怎么實現彈窗操作的呢?

這又要涉及到vue生命周期的機制了,他的參數你只需要賦值,然后你代碼里所有使用的地方都會同步更新,並且如果添加了監聽或是計算等屬性是會被自動調用的,(或許這就是為什么上面那個函數是native的原因了,因為有大量的函數是Vue實現的,所以並不是我們對其操作😶不管你信不信,反正我是這么理解的,畢竟也沒有看到有幾個vue逆向的教程啥的之類的,這里的某文是vue的,上面提到的某盤新主界面也是基於vue的,但是都被我完成修改了hhhhhh😏)因此我們需要知道哪里對於isCopyActivated這個參數的值做出了監聽或者是計算之類的。

或者你要是沒有vue的基礎知識,聽不懂我在說什么,換個角度也行:到這里我們就陷入死胡同了,因為沒有調用任何地方,我們只是賦值而已。那接下來干什么?是不是肯定跟isCopyActivated這個參數有關?搜索一下看一下這個是在哪里被使用是不是說不定也可以找到蛛絲馬跡?或者實在不行就每個調用的地方都下斷點,看看哪里在賦值之后斷下唄。

那么怎么找呢?理論上也可以通過寄存器查找,不過我吸取了上的教訓就沒找(其實是我沒找到🤣),直接搜索即可找到watch監聽的地方

watch: {
    isCopyActivated: function(t) {
        t && this.cannotCopy && (this.showVipGuideCard(),
        r.a.xsend(101643, {
            index: 1
        }))
    },
    formatedText: function(t) {
        this.canCopy(t.length) ? (Object(o.a)(".".concat(this.copyBtnId)).attr("data-clipboard-text", t),
        this.cannotCopy = !1) : this.cannotCopy = !0
    }
},

看到cannotCopy的時候有沒有豁然開朗?🤣下斷點直接運行,果然成功斷下。

image

果然是這么調用過來的,具體發生了什么都不知道,但是問題是確實解決了,接着就是重蹈覆轍(簡稱重復),比如找到cannotCopy賦值的地方(當然也可以使用剛剛的技巧直接復制false,屢試不爽),看看能不能連什么isvip什么的一起連根解決

image

找了一圈沒發現像剛剛那種定義函數,不過看到了下面的formatedText有對cannotCopy賦值的操作this.canCopy(t.length)返回真就給cannotCopy賦值false,否則就是true。這個canCopy函數名確實沒毛病😉

這次寄存器里又可以找到定義的位置了,直接跳轉過去。

image

canCopy: function(t) {
    var e = this.getCountFromCookie() < 10;
    return t > 100 && !this.isVip && this.docBizType !== B.a.SECRET && (e = !1),
    this.isVip || e
},

誒,這個熟啊,剛剛不是剛干過isSvip么,這就來了isVip😁不得不說規范化變量名還是有好處的對吧😘

下斷點,斷下后輸入我們心愛的this.isVip=true,然后回車。。。。

然后就報錯了,截圖放下面👇了

image

翻譯一下就是isVip定義了但是沒有完全定義🤐

翻譯一下:

image

沒有分配setter?是不是有點熟悉?

沒錯!剛剛的屬性定義,連系統中native的屬性都可以重定義了,那我構造一個。。。

Object.defineProperty(this,"isVip",{
    get: function() {
        return true
    }
})

獲取isVip值的時候,我不管其他的,直接返回這不就闊以了,用lambda語法糖稍微優化一下:

Object.defineProperty(this,"isVip",{
    get:()=>true
    }
})

壓縮一下,再加上最后熟悉的,false

Object.defineProperty(this,"isVip",{get:()=>true}),false

直接運行,完美🎉🎉🎉

image

至此,全局終。

什么?控制台不方便?想拿代碼實現?

那我Greasy Fork代碼不是開源的么。。自己分析去啊💢

總結

我只負責將道理,講的是人情事故,我講是人情,但是翻車了那是事故。

那同理,我講了,你聽懂了,那是世故,那如果你沒聽懂,那也是事故,問題不大。

(摘自B站UP主“阿三解說”,跟樓主沒有任何關系)

本文作者:吾愛破解@濤之雨

本來是打算web分類新成立發個簡單的水水的來着,結果越寫越多,順便把vue相關的也都謝了一大堆,就當是我知道的第一個vue相關的破解教程叭,

晚安。

時2021年7月30日00:45:38


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM