真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

【JS 逆向百例】某音 X-Bogus 逆向分析,JSVMP 純算法還原

為西平等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及西平網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、西平網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

聲明

本文章中所有內(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):某音網(wǎng)頁(yè)端用戶信息接口 X-Bogus 參數(shù)
  • 接口:aHR0cHM6Ly93d3cuZG91eWluLmNvbS9hd2VtZS92MS93ZWIvdXNlci9wcm9maWxlL290aGVyLw==

什么是 JSVMP?

JSVMP 全稱 Virtual Machine based code Protection for JavaScript,即 JS 代碼虛擬化保護(hù)方案。

JSVMP 的概念最早應(yīng)該是由西北大學(xué)2015級(jí)碩士研究生匡開圓,在其2018年的學(xué)位論文中提出的,論文標(biāo)題為:《基于 WebAssembly 的 JavaScript 代碼虛擬化保護(hù)方法研究與實(shí)現(xiàn)》,同年還申請(qǐng)了國(guó)家專利,專利名稱:《一種基于前端字節(jié)碼技術(shù)的 JavaScript 虛擬化保護(hù)方法》,網(wǎng)上可以直接搜到,也可在公眾號(hào)【K哥爬蟲】后臺(tái)回復(fù) JSVMP,免費(fèi)獲取原版高清無(wú)水印的論文和專利。本文就簡(jiǎn)單介紹一下 JSVMP,想要詳細(xì)了解,當(dāng)然還是建議去讀一下這篇論文。

JSVMP 的核心是在 JavaScript 代碼保護(hù)過程中引入代碼虛擬化思想,實(shí)現(xiàn)源代碼的虛擬化過程,將目標(biāo)代碼轉(zhuǎn)換成自定義的字節(jié)碼,這些字節(jié)碼只有特殊的解釋器才能識(shí)別,隱藏目標(biāo)代碼的關(guān)鍵邏輯。在匡開圓的論文中,利用 WebAssembly 技術(shù)實(shí)現(xiàn)了特殊的虛擬解釋器,通過編譯隱藏解釋器的執(zhí)行邏輯。JSVMP 的保護(hù)流程如下圖所示:

一個(gè)完整的 JSVMP 保護(hù)系統(tǒng),大致的架構(gòu)應(yīng)該是這樣子的:服務(wù)器端讀取 JavaScript 代碼 —> 詞法分析 —> 語(yǔ)法分析 —> 生成AST語(yǔ)法樹 —> 生成私有指令 —> 生成對(duì)應(yīng)私有解釋器,將私有指令加密與私有解釋器發(fā)送給瀏覽器,然后一邊解釋,一邊執(zhí)行。

JSVMP 有哪些學(xué)習(xí)資料?

除了匡開圓的論文以外,還有以下文章也值得學(xué)習(xí):

  • H5應(yīng)用加固防破解-js虛擬機(jī)保護(hù)方案淺談
  • JS加密?用虛擬機(jī)opcode保護(hù)JS源碼
  • 給"某音"的js虛擬機(jī)寫一個(gè)編譯器

JSVMP 逆向方法有哪些?

就目前來講,JSVMP 的逆向方法有三種(自動(dòng)化不算):RPC 遠(yuǎn)程調(diào)用,補(bǔ)環(huán)境,日志斷點(diǎn)還原算法,其中日志斷點(diǎn)也稱為插樁,找到關(guān)鍵位置,輸出關(guān)鍵參數(shù)的日志信息,從結(jié)果往上倒推生成邏輯,以達(dá)到算法還原的目的,RPC 技術(shù)K哥以前寫過文章,補(bǔ)環(huán)境的方式以后有時(shí)間再寫,本文主要介紹如何使用插樁來還原算法。

抓包情況

隨便來到某個(gè)博主主頁(yè),抓包后搜索可發(fā)現(xiàn)一個(gè)接口,返回的是 JSON 數(shù)據(jù),里面包含了博主某音號(hào),認(rèn)證信息、簽名,關(guān)注、粉絲、獲贊等,請(qǐng)求 Query String Parameters 里包含了一個(gè) X-Bogus 參數(shù),每次請(qǐng)求會(huì)改變,此外還有 sec_user_id 是博主主頁(yè) URL 后面那一串,webid 直接請(qǐng)求主頁(yè)返回內(nèi)容里就有,msToken 與 cookie 有關(guān),清除 cookie 訪問,就沒這個(gè)參數(shù)了,實(shí)測(cè)該接口不驗(yàn)證 webidmsToken,直接置空即可。

逆向分析

這條請(qǐng)求是 XHR 請(qǐng)求,所以直接下個(gè) XHR 斷點(diǎn),當(dāng) URL 中包含 X-Bogus 參數(shù)時(shí)就斷下:

往前跟棧,來到一個(gè)叫 webmssdk.js 的 JS 文件,這里就是生成參數(shù)的主要 JS 邏輯了,也就是 JSVMP,整體上做了一個(gè)混淆,這里可以使用 AST 來解混淆,K哥以前同樣也寫過 AST 的文章,這里還原混淆不是重點(diǎn),咱們直接使用 V 佬的插件 v_jstools 來還原:

還原后使用瀏覽器的 Overrides 替換功能將 webmssdk.js 替換掉,往上跟棧,如下圖所示,到 W 這里就已經(jīng)生成了 X-Bogus 了,this.openArgs[1] 就是攜帶了 X-Bogus 的完整 URL,仔細(xì)觀察這段代碼,有很多三元表達(dá)式,當(dāng) M 的值為 15 時(shí),就會(huì)走到這段邏輯,U 的值生成之后,有一個(gè) S[C] = U 的操作。

再往上看代碼,S 是一個(gè)數(shù)組,單步調(diào)試的話會(huì)發(fā)現(xiàn)代碼會(huì)一直走這個(gè) if-else 的邏輯,幾乎每一步都有 S 數(shù)組的參與,不斷往里面增刪改查值,for 循環(huán)里面的 I 值,決定著后續(xù) if 語(yǔ)句的走向,這里也就是插樁的關(guān)鍵所在,如下圖所示:

插樁分析

大的 for 循環(huán)和 if-else 邏輯有兩個(gè)地方,為了保證最后的日志更加詳細(xì)完整,在這兩個(gè)地方都下個(gè)日志斷點(diǎn)(右鍵 Add logpoint),斷點(diǎn)內(nèi)容為:

"位置 1", "索引I", I, "索引A", A, "值S: ", JSON.stringify(S, function(key, value) {if (value == window) {return undefined} return value})

"位置 2", "索引I", I, "索引A", A, "值S: ", JSON.stringify(S, function(key, value) {if (value == window) {return undefined} return value})

插樁輸出 S 的時(shí)候?yàn)槭裁匆獙戇@么長(zhǎng)一串呢?首先 JSON.stringify() 方法的作用是將 JavaScript 值轉(zhuǎn)換為 JSON 字符串,基礎(chǔ)語(yǔ)法是 JSON.stringify(value[, replacer [, space]]),如果不將其轉(zhuǎn)換成 JSON,那么 S 的值,輸出可能是這樣的:[empty, Array(26), 1, Array(0)],你看不到 Array 數(shù)組里面具體的值,該方法有個(gè)可選參數(shù) replacer,如果 replacer 為函數(shù),則 JSON.stringify 將調(diào)用該函數(shù),并傳入每個(gè)成員的鍵和值,在函數(shù)中可以對(duì)成員進(jìn)行處理,最后返回處理后的值,如果此函數(shù)返回 undefined,則排除該成員,舉個(gè)例子:

var obj1 = {key1: 'value1', key2: 'value2'}
function changeValue(key, value) {
    if (value == 'value2') {
        return '公眾號(hào):K哥爬蟲'
    } return value
}
var obj2 = JSON.stringify(obj1, changeValue)
console.log(obj2)

// 輸出:{"key1":"value1","key2":"公眾號(hào):K哥爬蟲"}

上面的代碼中 JSON.stringify 傳入了一個(gè)函數(shù),當(dāng) valuevalue2 的時(shí)候就將其替換成字符串 公眾號(hào):K哥爬蟲,接下來我們演示一下當(dāng) valuewindow 時(shí),會(huì)發(fā)生什么:

根據(jù)報(bào)錯(cuò)我們可以看到這里由于循環(huán)引用導(dǎo)致異常,要知道在插樁的時(shí)候,如果插樁內(nèi)容有報(bào)錯(cuò),就會(huì)導(dǎo)致不能正常輸出日志,這樣就會(huì)缺失一部分日志,這種情況我們就可以加個(gè)函數(shù)處理一下,讓 value 為 window 的時(shí)候,JSON 處理的時(shí)候函數(shù)返回 undefined,排除該成員,其他成員正常輸出,如下圖所示:

以上就是日志斷點(diǎn)為什么要這樣寫的原因,下好日志斷點(diǎn)后,注意前面我們下的 XHR 斷點(diǎn)不要取消,然后刷新網(wǎng)頁(yè),控制臺(tái)就開始打印日志了,因?yàn)橛泻芏?XHR 請(qǐng)求都包含了 X-Bogus,如果你 XHR 斷點(diǎn)取消了,日志就會(huì)一直打印直到卡死。日志輸出完畢后,大約有8千多條,搜索就能看到最后一條日志 X-Bogus 已經(jīng)生成了:

28個(gè)字符生成邏輯

直接在打印的日志頁(yè)面右鍵 save as..,將日志導(dǎo)出到本地進(jìn)行分析。X-Bogus 由28個(gè)字符組成,現(xiàn)在要做的就是看 DFSzswVOAATANH89SMHZqF9WX7n6 這28個(gè)字符是怎么來的,在日志里搜索這個(gè)字符串,找到第一次出現(xiàn)的地方,觀察一下可以發(fā)現(xiàn),他是逐個(gè)字符依次生成的,如下圖紅框所示:

在上圖中,第8511行,X-Bogus 字符串的下一個(gè)元素是 null,到了第8512行,就生成數(shù)字6了,那么在這兩步之間就是數(shù)字6的生成邏輯,這個(gè)時(shí)候我們看第8511行的日志斷點(diǎn)是 位置 2 索引I 16 索引A 738,那么我們回到原網(wǎng)頁(yè),在位置2,下一個(gè)條件斷點(diǎn)(右鍵 Add conditional breakpoint),當(dāng) I == 16 && A == 738 && S[7] && S[7] == 21 時(shí)就斷下。之所以要加 S[7] 是因?yàn)?索引I 16 索引A 738 的位置有很多,在日志里搜一下大概有40多個(gè),多加個(gè)限制條件就可以縮小范圍,當(dāng)然有可能加了多個(gè)條件仍然有多個(gè)位置都滿足,這就需要你細(xì)心觀察了,通過斷點(diǎn)斷下的時(shí)候看看控制臺(tái)前面輸出的日志來判斷是不是我們想要的位置。這也是一個(gè)小細(xì)節(jié),一定要找準(zhǔn)位置,千萬(wàn)別搞混了。(提示一下,像我這樣下斷點(diǎn)的話,一般情況下會(huì)斷下兩次,第二次是滿足要求的)

(注意:本文描述的日志的多少行、斷點(diǎn)的具體位置、變量的具體值,可能會(huì)有所變化,以你的實(shí)際情況為準(zhǔn),但思路是一樣的)

刷新網(wǎng)頁(yè),斷下之后開始單步跟,來到下圖所示的地方:

到這里之后,就不要下一步了,再下一步有可能整個(gè)語(yǔ)句就執(zhí)行完畢了,其中的細(xì)節(jié)你看不到,所以這里我們?cè)诳刂婆_(tái)挨個(gè)輸入看看:

可以看到實(shí)際上的邏輯就是返回指定位置的字符,y 的值就是 S[5],m 的值就是 S[4],經(jīng)過多次調(diào)試發(fā)現(xiàn) m 的值是固定的,M 就是 charAt() 方法,我們?cè)倏纯次覀儽镜氐娜罩荆?code>S[5] 的值為 [20]charAt() 取值出來就是6,邏輯完全正確。

現(xiàn)在我們還需要知道這個(gè)20是怎么來的,繼續(xù)往上看,找到20第一次出現(xiàn)的地方,在第8510行,那么我們就要使其在上一步斷下,也就是第8509行,如下圖所示:

第8509行的索引信息為 位置 2 索引I 47 索引A 730,同樣的下條件斷點(diǎn)觀察怎么生成的:

可以看到邏輯是 S[5] & S[6],再看我們本地 S[5] =、S[6] = 63 & 63 = 20,邏輯正確,20就是這么來的。接下來又開始找 63 是怎么生成的,同樣在生成的上一步,也就是8508行下個(gè)條件斷點(diǎn),這行的索引為 位置 2 索引I 72 索引A 726。

可以看到 63 是直接 q[A] 生成的,q 是一個(gè)大數(shù)組,A 就是索引為 726,q 這個(gè)大數(shù)組怎么來的先不用管,而 這個(gè)大數(shù)字,搜索一下,發(fā)現(xiàn)有很多,咱們也先放著,到這里咱們可以總結(jié)一下最后一個(gè)字符的生成步驟如下:

short_str = "Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe="

q[726] = 63
 & 63 = 20
short_str.charAt(20) = '6'

然后接日志著往上看,看倒數(shù)第二個(gè)字母是怎么來的,方法也和前面演示的一樣,不斷往前下條件斷點(diǎn),這里就不再逐步演示了,當(dāng)你找完四個(gè)數(shù)字后,就可以開始看 這個(gè)大數(shù)字怎么來的了,搜索這個(gè)數(shù)字,同樣的找到第一次出現(xiàn)的地方,在其前一步下條件斷點(diǎn),步驟捋出來會(huì)發(fā)現(xiàn)有一個(gè)亂碼字符串經(jīng)過 charCodeAt() 操作,再加上一些位運(yùn)算得到的,亂碼字符串類似下圖所示:

至于這個(gè)亂碼字符串怎么來的,我們后面再講,到這里先總結(jié)一下,首先我們的 X-Bogus = DFSz swVO AATA NH89 SMHZ qF9W X7n6,將其看成每四個(gè)為一組,之所以這么分組,是因?yàn)槟憬?jīng)過分析后會(huì)發(fā)現(xiàn),每一組的每一個(gè)字符生成流程都是一樣的,這里以最后兩組為例,流程大致如下:

short_str = "Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe="
X-Bogus = DFSz swVO AATA NH89 SMHZ qF9W X7n6

============== 第6組【qF9W】==============

"\u0002?-%.*yê^?s6ey??y?V,?".charCodeAt(15) = 158
q[342] = 16
158 << 16 = 
"\u0002?-%.*yê^?s6ey??y?V,?".charCodeAt(16) = 253
q[408] = 8
253 << 8 = 
 |  = 
"\u0002?-%.*yê^?s6ey??y?V,?".charCodeAt(17) = 156
156 |  = 

q[520] = 
 &  = 
q[532] = 18
 >> 18 = 39
short_str.charAt(39) = 'q'

q[590]= 
 &  = 
q[602] = 12
 >> 12 = 47
short_str.charAt(47) = 'F'

q[660] = 4032
 & 4032 = 3456
q[668] = 6
3456 >> 6 = 54
short_str.charAt(54) = '9'

q[726] = 63
 & 63 = 28
short_str.charAt(28) = 'W'

============== 第7組【X7n6】==============

"\u0002?-%.*yê^?s6ey??y?V,?".charCodeAt(18) = 86
q[342] = 16
86 << 16 = 
"\u0002?-%.*yê^?s6ey??y?V,?".charCodeAt(19) = 44
q[408] = 8
44 << 8 = 
 |  = 
"\u0002?-%.*yê^?s6ey??y?V,?".charCodeAt(20) = 148
148 |  = 

q[520] = 
 &  = 
q[532] = 18
 >> 18 = 21
short_str.charAt(21) = 'X'

q[590] = 
 &  = 
q[602] = 12
 >> 12 = 34
short_str.charAt(34) = '7'

q[660] = 4032
 & 4032 = 3200
q[668] = 6
3200 >> 6 = 50
short_str.charAt(50) = 'n'

q[726] = 63
 & 63 = 20
short_str.charAt(20) = '6'

將流程對(duì)比一下就可以發(fā)現(xiàn),每個(gè)步驟 q 里面的取值都是一樣的,這個(gè)可以直接寫死,不同之處就在于最開始的 charCodeAt() 操作,也就是返回亂碼字符串指定位置字符的 Unicode 編碼,第7組依次是 18、19、20,第6組依次是15、16、17,以此類推,第1組剛好是0、1、2,如下圖所示:

每一組的邏輯都是一樣的,我們就可以寫個(gè)通用方法,依次生成七組字符串,最后拼接成完整的 X-Bogus,代碼如下:(亂碼字符串的生成后文會(huì)講)

function getXBogus(originalString){
    // 生成亂碼字符串
    var garbledString = getGarbledString(originalString);
    var XBogus = "";
    // 依次生成七組字符串
    for (var i = 0; i <= 20; i += 3) {
        var charCodeAtNum0 = garbledString.charCodeAt(i);
        var charCodeAtNum1 = garbledString.charCodeAt(i + 1);
        var charCodeAtNum2 = garbledString.charCodeAt(i + 2);
        var baseNum = charCodeAtNum2 | charCodeAtNum1 << 8 | charCodeAtNum0 << 16;
        // 依次生成四個(gè)字符
        var str1 = short_str[(baseNum & ) >> 18];
        var str2 = short_str[(baseNum & ) >> 12];
        var str3 = short_str[(baseNum & 4032) >> 6];
        var str4 = short_str[baseNum & 63];
        XBogus += str1 + str2 + str3 + str4;
    }
    return XBogus;
}

亂碼字符串生成邏輯

在進(jìn)行下一步之前,我們要注意兩點(diǎn):

  • 文章演示有些變量前后不對(duì)應(yīng),因?yàn)槊看尾鍢兜闹刀际菚?huì)變的,看流程就行了,流程是正確的;

  • 我們?nèi)罩据敵鍪墙?jīng)過 JSON.stringify 處理了的,有些步驟是向某個(gè)函數(shù)傳入亂碼字符串進(jìn)行處理,你會(huì)發(fā)現(xiàn)處理后的結(jié)果和日志不一致,這是正常的。

亂碼字符串的生成相對(duì)來說稍微復(fù)雜一點(diǎn),但思路仍然一樣,這里就不一一截圖展示了,直接用日志描述一下關(guān)鍵步驟,注意以下日志是正向的步驟,就不逆著推了,建議自己先逆著把流程走一走,再來看這個(gè)步驟就看得懂了。

Step1:首先對(duì) URL 后面的參數(shù),也就是 Query String Parameters 進(jìn)行兩次 MD5、兩次轉(zhuǎn) Uint8Array 處理,最后得到的 Uint8Array 對(duì)象在后面的步驟中用得到,步驟如下:

位置 1 索引I 4  索引A 134:將 URL 后面的參數(shù)進(jìn)行 MD5 加密得到字符串
位置 1 索引I 16 索引A 460:將上一步的字符串轉(zhuǎn)換為 Uint8Array 對(duì)象
位置 1 索引I 4  索引A 134:將上一步的 Uint8Array 對(duì)象進(jìn)行 MD5 加密,得到字符串
位置 1 索引I 29 索引A 472:將上一步的字符串轉(zhuǎn)換為 Uint8Array 對(duì)象

上述步驟中,我們將最終得到的結(jié)果命名為 uint8Array,關(guān)鍵代碼實(shí)現(xiàn)如下:

var md5 = require("md5");

// 字符串轉(zhuǎn)換為 Uint8Array 對(duì)象,缺失的變量自行補(bǔ)齊
_0x5960a2 = function(a) {
    for (var c = a.length >> 1, e = c << 1, b = new Uint8Array(c), d = 0, f = 0; f < e; ) {
        b[d++] = _0x511f86[a.charCodeAt(f++)] << 4 | _0x511f86[a.charCodeAt(f++)];
    }
    return b;
}

// originalString: URL 后面的原始參數(shù)
var uint8Array = _0x5960a2(md5(_0x5960a2(md5(originalString))));

Step2:生成兩個(gè)大數(shù),一個(gè)是時(shí)間戳,我們稱之為 fixedString1,另一個(gè)調(diào)用某個(gè)方法生成,我們稱之為 fixedString2。

fixedString1
位置 1 索引I 43 索引A 806: / 1000 = .24

fixedString2
位置 1 索引I 16 索引A 834:M.apply(null, []) = 

上述步驟中,M 對(duì)應(yīng)以下方法,缺失的方法自行補(bǔ)齊(其中 _0x 是創(chuàng)建 canvas):

function _0x2996f8() {
    try {
        return _0x4b3b53 || (_0xb55f3e.perf ? -1 : (_0x4b3b53 = _0x(), _0x4b3b53));
    } catch (a) {
        return -1;
    }
}

Step3:先后生成兩個(gè)數(shù)組,我們稱之為 array1、array2array2 就是由 array1 的元素位置變換后得來的,嚴(yán)格來講,array1 不是一個(gè)完整的數(shù)組,而是一個(gè)個(gè)數(shù)字,這一點(diǎn)可以在日志中體現(xiàn)出來,為了方便我們就直接將其視為一個(gè)數(shù)組,兩個(gè)數(shù)組都有19個(gè)元素,步驟如下:

array1[0] 至 array1[3] 為定值

array1[4]
位置 1 索引I 25 索引A 946:uint8Array[14]

array1[5]
位置 1 索引I 25 索引A 970:uint8Array[15]

array1[6] 至 array1[7] 為定值,8、9 與 ua 有關(guān)

array1[10]
位置 1 索引I 52 索引A 1090:fixedString1 >> 24 = 99
位置 1 索引I 47 索引A 1098:99 & 255 = 99

array1[11]
位置 1 索引I 52 索引A 1122:fixedString1 >> 16 = 
位置 1 索引I 47 索引A 1130: & 255 = 73

array1[12]
位置 1 索引I 52 索引A 1154:fixedString1 >> 8 = 
位置 1 索引I 47 索引A 1162: & 255 = 3

array1[13]
位置 1 索引I 52 索引A 1186:fixedString1 >> 0 = 241
位置 1 索引I 47 索引A 1194:241 & 255 = 241

array1[14]
位置 1 索引I 52 索引A 1218:fixedString2 >> 24 = 32
位置 1 索引I 47 索引A 1226:32 & 255 = 32

array1[15]
位置 1 索引I 52 索引A 1250:fixedString2 >> 16 = 8192
位置 1 索引I 47 索引A 1258:8192 & 255 = 0

array1[16]
位置 1 索引I 52 索引A 1282:fixedString2 >> 8 = 
位置 1 索引I 47 索引A 1290: & 255 = 190

array1[17]
位置 1 索引I 52 索引A 1314:fixedString2 >> 0 = 
位置 1 索引I 47 索引A 1322: & 255 = 144

array1[18]
位置 1 索引I 27 索引A 1352:array1.reduce(function(a, b) { return a ^ b; }); = 100

array1 完整值如下
位置 1 索引I 27 索引A 1538:64,1.00,1,8,9,185,69,63,74,125,99,73,3,241,32,0,190,144,100

array2 由 array1 元素交換位置而來:
array2 = [array1[0], array1[2], array1[4], array1[6], array1[8], array1[10], array1[12], array1[14], array1[16], array1[18], array1[1], array1[3], array1[5], array1[7], array1[9], array1[11], array1[13], array1[15], array1[17]]

array2 完整值如下
array2 = [64,1,9,69,74,99,3,32,190,100,1.00,8,185,63,125,73,241,0,144]

Step4:將 Step3 得到的 array2 經(jīng)過轉(zhuǎn)換得到亂碼字符串,步驟如下:

位置 1 索引I 16 索引A 1706:
_0x2f2740.apply(null, array2) = "@\u0000\u0001\u000eíxE??\u0016c%>? \u0000??ó"

位置 1 索引I 16 索引A 1760:
_0x46fa4c.apply(null, ["?", "@\u0000\u0001\u000e\t1E?J}cI\u0003? \u0000??d"]) = "\u0002?-%.*yê^?s6ey??y?V,?"

位置 1 索引I 16 索引A 1812:
_0x2b6720.apply(null, [2, 255, "\u0002?-%.*yê^?s6ey??y?V,?"]) = "\u0002?-%.*yê^?s6ey??y?V,?"

其中用到的函數(shù):

function _0x2f2740(a, c, e, b, d, f, t, n, o, i, r, _, x, u, s, l, v, h, g) {
    let w = new Uint8Array(19);
    return w[0] = a,
    w[1] = r,
    w[2] = c,
    w[3] = _,
    w[4] = e,
    w[5] = x,
    w[6] = b,
    w[7] = u,
    w[8] = d,
    w[9] = s,
    w[10] = f,
    w[11] = l,
    w[12] = t,
    w[13] = v,
    w[14] = n,
    w[15] = h,
    w[16] = o,
    w[17] = g,
    w[18] = i,
    String.fromCharCode.apply(null, w);
}

function _0x46fa4c(a, c) {
    let e, b = [], d = 0, f = "";
    for (let a = 0; a < 256; a++) {
        b[a] = a;
    }
    for (let c = 0; c < 256; c++) {
        d = (d + b[c] + a.charCodeAt(c % a.length)) % 256,
        e = b[c],
        b[c] = b[d],
        b[d] = e;
    }
    let t = 0;
    d = 0;
    for (let a = 0; a < c.length; a++) {
        t = (t + 1) % 256,
        d = (d + b[t]) % 256,
        e = b[t],
        b[t] = b[d],
        b[d] = e,
        f += String.fromCharCode(c.charCodeAt(a) ^ b[(b[t] + b[d]) % 256]);
    }
    return f;
}

function _0x(a) {
    return String.fromCharCode(a);
}

function _0x2b6720(a, c, e) {
    return _0x(a) + _0x(c) + e;
}

自此,整個(gè)流程就走完了。可以用 JavaScript 來實(shí)現(xiàn)整個(gè)算法,用 Python 也可以,完善代碼后隨便請(qǐng)求一個(gè)博主主頁(yè),簡(jiǎn)單解析幾個(gè)數(shù)據(jù),輸出正常:


本文題目:【JS 逆向百例】某音 X-Bogus 逆向分析,JSVMP 純算法還原
文章來源:http://weahome.cn/article/dsogcdj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部