python爬蟲 - js逆向解密之某翻譯加密算法V2


 

前言

 

本次針對某個翻譯平台的js逆向,同時並不存在惡意,只是本着學習研究為主,同時,在分析期間並未高頻次測試導致該平台服務器不可用

 

 

 

 

附言:

 

 

 

 

 

看出是哪個平台的朋友請不要評論或者說明是哪個網站,謝謝,為了安全起見哈!

 

 

 

 

分析

 

分析,找到接口

 

 

 

 

接口就是它了

 

 

 

 

請求參數有這些:

 

 

 

 

 

 

 

 

返回結果:

 

 

 

 

 

 

我接着又翻譯了下【main】,請求參數是:

 

 

 

 

 

 

好,對比一下,參數的值:

 

from: en
to: zh
query: main
transtype: realtime
simple_means_flag: 3
sign: 386060.67389
token: dc4823cc11a335a56342628f85dc66fc
domain: common

----------------------------


from: en
to: zh
query: cat
transtype: realtime
simple_means_flag: 3
sign: 661701.982004
token: dc4823cc11a335a56342628f85dc66fc
domain: common

 

 

 

除了sign是變的以外,其他都是固定的。后面就是sign怎么來的了

 

 

找sign

 

同樣的,全局搜

 

 

 

 

 

 

 搜索結果有點多啊,沒事,一個一個找

 

無關的我就不展示了,實際的sign部分就是以下,同時打上斷點看

 

 

 

 

 

輸入put翻譯查看,果然斷上了

 

 

 

 

 鼠標放到sign后面的L方法上:

 

 

 

 

 

這個位置應該就是實際的sign加密算法了,不急,斷點一步一步進去看看,結果直接就進入L方法了,如下,我已經打上斷點:

 

 

 

 

 

 

其實實際的代碼就是這三個函數【a,n,e】

 

具體的流程就不展示了,可以肯定的說,就是這三個函數

 

 

調試

 

我把這三個函數復制出來,然后准備在控制台調試的時候,發現了一個問題:

 

 

 

 

反正就是提示我這個e方法(函數)沒有定義,奇了怪了,上面不是定義了嗎,我一度以為是我用的js語法有問題,我自定了一個函數:

 

 

 

 

 

結果還是如此,很騷了,讓我一度以為我搞了那么久的js,語法給整不會了,我另外開了一個瀏覽器標簽頁:

 

 

 

 

 

很秀了,應該是這個平台做了限制,不讓在控制台自定義代碼調試使用,可以的,這方面很多平台都沒有

 

 

我在另外開的標簽頁里,重新定義了上面三個函數,然后調用測試:

 

 

 

 

報錯提示split沒有定義,而,split就這里u.split在用

 

 

 

 

那說明上面的u變量可能沒有正常獲取結果,而經過我的調試發現,u其實是一個固定的值:

 

 

 

 

因為,看下這一句:

 

 

 

稍微懂點js語法的就知道,u其實就是變量 i 的值,i 就是window對象的 L 索引對應的值 gtk,而再看上面的代碼截圖

 

l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107)

 

 

 這個變量 L也基本是固定生成的,再看window對象,點這個三角符號展開

 

 

 

 

 

 

 

發現這個gtk對應的值也是寫死在window對象里的:

 

 

 

 

 

 

也就是,實際上,u就是window對象gtk索引對應的值

 

那我們這里重新定義下 e函數,直接把u寫死吧,然后調用:

 

 

 

 

發現最后的結果,跟之前的請求參數的sign值能對上:

 

 

 

 

over,sign搞定

 

 

 

用代碼實現

 

由於a,n,e三個函數用python代碼實現可能有點復雜,所以,這里就用pyexecjs調用js了,當然,你要是有耐心或者說手撕過瑞數、數美這些的,當我沒說,這么點代碼肯定沒問題的。

 

 

 

我這里主要不想浪費時間了,就直接用execjs調用執行了

 

 

import execjs js = """ function a(r) { if (Array.isArray(r)) { for (var o = 0, t = Array(r.length); o < r.length; o++) t[o] = r[o]; return t } return Array.from(r) }; function n(r, o) { for (var t = 0; t < o.length - 2; t += 3) { var a = o.charAt(t + 2); a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a), a = "+" === o.charAt(t + 1) ? r >>> a : r << a, r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a } return r }; function e(r) { var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g); if (null === o) { var t = r.length; t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10)) } else { for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++) "" !== e[C] && f.push.apply(f, a(e[C].split(""))), C !== h - 1 && f.push(o[C]); var g = f.length; g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join("")) } var u = "320305.131321201"; var l = "gtk"; for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) { var A = r.charCodeAt(v); 128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)), S[c++] = A >> 18 | 240, S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224, S[c++] = A >> 6 & 63 | 128), S[c++] = 63 & A | 128) } for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++) p += S[b], p = n(p, F); return p = n(p, D), p ^= s, 0 > p && (p = (2147483647 & p) + 2147483648), p %= 1e6, p.toString() + "." + (p ^ m) } """ js_obj = execjs.compile(js) res = js_obj.call('e','cat') print(res)

 

 

 

執行結果:

 

 

 

 

這個值跟上面請求接口生成的值對應上,再試試其他字符呢,傳入main:

 

 

 

 

 

 

 

 

這個值【386060.67389】跟文章開頭翻譯測試【main】對應的上,再次驗證下,現在在接口上翻譯一個get看看,然后代碼這邊能不能對應上:

 

 

 

 

 

程序執行:

 

 

 

果然對應得上,over。

 

 

完整代碼

完整代碼就不貼出來了(因為懶,並沒有寫出完整代碼,嘿嘿嘿),sign加密都破解了,后續的工作就是完善代碼,加測試了,后面就沒啥難度可言了。對了,我大概率猜測,這三個a,n,e函數的代碼有些地方估計會隨機變,所以,你可能需要每次都去請求源js地址,然后活動生成sign,我大概率猜,也不一定,因為上一篇的翻譯平台的某個值就是不定時更新的,另外上面改動的U變量,實際是不是寫死的,這個還得后續觀察,如果變了也需要對應處理

 

 

結語

其實也挺簡單的,也就是老辦法一把梭,如果你想用python實現這個加密算法,完全沒問題,研究好邏輯之后寫就行了,我是確實沒時間去研究了,所以直接調用能執行js代碼的庫拿結果了,另外如果你想比較深入的研究接口整個執行過程,可以找到該接口,然后點這里查看:

 

 

 

 

 

 

 

 

 

 

 

 

 
 
 
 
 


免責聲明!

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



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