知乎sign加密算法反混淆


源碼來自 新版知乎x-zse-86加密破解分析 ,在添加了jsdom之后就可以通過nodejs運行了,但這在使用非js語言編寫爬蟲時肯定不是一個很好的調用方法,也有很大的局限性,在簡單分析后,jsdom應該是提供一些屬性變量如window,加密算法可能與之無關,不能運行可能是因為某些代碼做了檢測然后被反爬了,如今日頭條的signature算法,僅能通過nodejs運行而無法通過execjs等js引擎運行,因此嘗試對源碼進行解析和反混淆,試試精簡后能不能去掉jsdom,首先貼一下源碼以便讀者查看

  1 const jsdom = require("jsdom");
  2 const {JSDOM} = jsdom;
  3 const { window } = new JSDOM('<!doctype html><html><body></body></html>');
  4 global.window = window;
  5 
  6 
  7     function t(e) {
  8         return (t = "function" == typeof Symbol && "symbol" == typeof Symbol.A ? function(e) {
  9             return typeof e
 10         }
 11         : function(e) {
 12             return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e
 13         }
 14         )(e)
 15     }
 16     Object.defineProperty(exports, "__esModule", {
 17         value: !0
 18    });
 19     var A = "2.0"
 20       , __g = {};
 21     function s() {}
 22     function i(e) {
 23         this.t = (2048 & e) >> 11,
 24         this.s = (1536 & e) >> 9,
 25         this.i = 511 & e,
 26         this.h = 511 & e
 27     }
 28     function h(e) {
 29         this.s = (3072 & e) >> 10,
 30         this.h = 1023 & e
 31     }
 32     function a(e) {
 33         this.a = (3072 & e) >> 10,
 34         this.c = (768 & e) >> 8,
 35         this.n = (192 & e) >> 6,
 36         this.t = 63 & e
 37     }
 38     function c(e) {
 39         this.s = e >> 10 & 3,
 40         this.i = 1023 & e
 41     }
 42     function n() {}
 43     function e(e) {
 44         this.a = (3072 & e) >> 10,
 45         this.c = (768 & e) >> 8,
 46         this.n = (192 & e) >> 6,
 47         this.t = 63 & e
 48     }
 49     function o(e) {
 50         this.h = (4095 & e) >> 2,
 51         this.t = 3 & e
 52     }
 53     function r(e) {
 54         this.s = e >> 10 & 3,
 55         this.i = e >> 2 & 255,
 56         this.t = 3 & e
 57     }
 58     s.prototype.e = function(e) {
 59         e.o = !1
 60     }
 61     ,
 62     i.prototype.e = function(e) {
 63         switch (this.t) {
 64         case 0:
 65             e.r[this.s] = this.i;
 66             break;
 67         case 1:
 68             e.r[this.s] = e.k[this.h]
 69         }
 70     }
 71     ,
 72     h.prototype.e = function(e) {
 73         e.k[this.h] = e.r[this.s]
 74     }
 75     ,
 76     a.prototype.e = function(e) {
 77         switch (this.t) {
 78         case 0:
 79             e.r[this.a] = e.r[this.c] + e.r[this.n];
 80             break;
 81         case 1:
 82             e.r[this.a] = e.r[this.c] - e.r[this.n];
 83             break;
 84         case 2:
 85             e.r[this.a] = e.r[this.c] * e.r[this.n];
 86             break;
 87         case 3:
 88             e.r[this.a] = e.r[this.c] / e.r[this.n];
 89             break;
 90         case 4:
 91             e.r[this.a] = e.r[this.c] % e.r[this.n];
 92             break;
 93         case 5:
 94             e.r[this.a] = e.r[this.c] == e.r[this.n];
 95             break;
 96         case 6:
 97             e.r[this.a] = e.r[this.c] >= e.r[this.n];
 98             break;
 99         case 7:
100             e.r[this.a] = e.r[this.c] || e.r[this.n];
101             break;
102         case 8:
103             e.r[this.a] = e.r[this.c] && e.r[this.n];
104             break;
105         case 9:
106             e.r[this.a] = e.r[this.c] !== e.r[this.n];
107             break;
108         case 10:
109             e.r[this.a] = t(e.r[this.c]);
110             break;
111         case 11:
112             e.r[this.a] = e.r[this.c]in e.r[this.n];
113             break;
114         case 12:
115             e.r[this.a] = e.r[this.c] > e.r[this.n];
116             break;
117         case 13:
118             e.r[this.a] = -e.r[this.c];
119             break;
120         case 14:
121             e.r[this.a] = e.r[this.c] < e.r[this.n];
122             break;
123         case 15:
124             e.r[this.a] = e.r[this.c] & e.r[this.n];
125             break;
126         case 16:
127             e.r[this.a] = e.r[this.c] ^ e.r[this.n];
128             break;
129         case 17:
130             e.r[this.a] = e.r[this.c] << e.r[this.n];
131             break;
132         case 18:
133             e.r[this.a] = e.r[this.c] >>> e.r[this.n];
134             break;
135         case 19:
136             e.r[this.a] = e.r[this.c] | e.r[this.n];
137             break;
138         case 20:
139             e.r[this.a] = !e.r[this.c]
140         }
141     }
142     ,
143     c.prototype.e = function(e) {
144         e.Q.push(e.C),
145         e.B.push(e.k),
146         e.C = e.r[this.s],
147         e.k = [];
148         for (var t = 0; t < this.i; t++)
149             e.k.unshift(e.f.pop());
150         e.g.push(e.f),
151         e.f = []
152     }
153     ,
154     n.prototype.e = function(e) {
155         e.C = e.Q.pop(),
156         e.k = e.B.pop(),
157         e.f = e.g.pop()
158     }
159     ,
160     e.prototype.e = function(e) {
161         switch (this.t) {
162         case 0:
163             e.u = e.r[this.a] >= e.r[this.c];
164             break;
165         case 1:
166             e.u = e.r[this.a] <= e.r[this.c];
167             break;
168         case 2:
169             e.u = e.r[this.a] > e.r[this.c];
170             break;
171         case 3:
172             e.u = e.r[this.a] < e.r[this.c];
173             break;
174         case 4:
175             e.u = e.r[this.a] == e.r[this.c];
176             break;
177         case 5:
178             e.u = e.r[this.a] != e.r[this.c];
179             break;
180         case 6:
181             e.u = e.r[this.a];
182             break;
183         case 7:
184             e.u = !e.r[this.a]
185         }
186     }
187     ,
188     o.prototype.e = function(e) {
189         switch (this.t) {
190         case 0:
191             e.C = this.h;
192             break;
193         case 1:
194             e.u && (e.C = this.h);
195             break;
196         case 2:
197             e.u || (e.C = this.h);
198             break;
199         case 3:
200             e.C = this.h,
201             e.w = null
202         }
203         e.u = !1
204     }
205     ,
206     r.prototype.e = function(e) {
207         switch (this.t) {
208         case 0:
209             for (var t = [], n = 0; n < this.i; n++)
210                 t.unshift(e.f.pop());
211             e.r[3] = e.r[this.s](t[0], t[1]);
212             break;
213         case 1:
214             for (var r = e.f.pop(), o = [], i = 0; i < this.i; i++)
215                 o.unshift(e.f.pop());
216             e.r[3] = e.r[this.s][r](o[0], o[1]);
217             break;
218         case 2:
219             for (var a = [], s = 0; s < this.i; s++)
220                 a.unshift(e.f.pop());
221             e.r[3] = new e.r[this.s](a[0],a[1])
222         }
223     }
224     ;
225     var k = function(e) {
226         for (var t = 66, n = [], r = 0; r < e.length; r++) {
227             var o = 24 ^ e.charCodeAt(r) ^ t;
228             n.push(String.fromCharCode(o)),
229             t = o
230         }
231         return n.join("")
232     };
233     function Q(e) {
234         this.t = (4095 & e) >> 10,
235         this.s = (1023 & e) >> 8,
236         this.i = 1023 & e,
237         this.h = 63 & e
238     }
239     function C(e) {
240         this.t = (4095 & e) >> 10,
241         this.a = (1023 & e) >> 8,
242         this.c = (255 & e) >> 6
243     }
244     function B(e) {
245         this.s = (3072 & e) >> 10,
246         this.h = 1023 & e
247     }
248     function f(e) {
249         this.h = 4095 & e
250     }
251     function g(e) {
252         this.s = (3072 & e) >> 10
253     }
254     function u(e) {
255         this.h = 4095 & e
256     }
257     function w(e) {
258         this.t = (3840 & e) >> 8,
259         this.s = (192 & e) >> 6,
260         this.i = 63 & e
261     }
262     function G() {
263         this.r = [0, 0, 0, 0],
264         this.C = 0,
265         this.Q = [],
266         this.k = [],
267         this.B = [],
268         this.f = [],
269         this.g = [],
270         this.u = !1,
271         this.G = [],
272         this.b = [],
273         this.o = !1,
274         this.w = null,
275         this.U = null,
276         this.F = [],
277         this.R = 0,
278         this.J = {
279             0: s,
280             1: i,
281             2: h,
282             3: a,
283             4: c,
284             5: n,
285             6: e,
286             7: o,
287             8: r,
288             9: Q,
289             10: C,
290             11: B,
291             12: f,
292             13: g,
293             14: u,
294             15: w
295         }
296     }
297     Q.prototype.e = function(e) {
298         switch (this.t) {
299         case 0:
300             e.f.push(e.r[this.s]);
301             break;
302         case 1:
303             e.f.push(this.i);
304             break;
305         case 2:
306             e.f.push(e.k[this.h]);
307             break;
308         case 3:
309             e.f.push(k(e.b[this.h]))
310         }
311     }
312     ,
313     C.prototype.e = function(A) {
314         switch (this.t) {
315         case 0:
316             var t = A.f.pop();
317             A.r[this.a] = A.r[this.c][t];
318             break;
319         case 1:
320             var s = A.f.pop()
321               , i = A.f.pop();
322             A.r[this.c][s] = i;
323             break;
324         case 2:
325             var h = A.f.pop();
326             A.r[this.a] = eval(h)
327         }
328     }
329     ,
330     B.prototype.e = function(e) {
331         e.r[this.s] = k(e.b[this.h])
332     }
333     ,
334     f.prototype.e = function(e) {
335         e.w = this.h
336     }
337     ,
338     g.prototype.e = function(e) {
339         throw e.r[this.s]
340     }
341     ,
342     u.prototype.e = function(e) {
343         var t = this
344           , n = [0];
345         e.k.forEach(function(e) {
346             n.push(e)
347         });
348         var r = function(r) {
349             var o = new G;
350             return o.k = n,
351             o.k[0] = r,
352             o.v(e.G, t.h, e.b, e.F),
353             o.r[3]
354         };
355         r.toString = function() {
356             return "() { [native code] }"
357         }
358         ,
359         e.r[3] = r
360     }
361     ,
362     w.prototype.e = function(e) {
363         switch (this.t) {
364         case 0:
365             for (var t = {}, n = 0; n < this.i; n++) {
366                 var r = e.f.pop();
367                 t[e.f.pop()] = r
368             }
369             e.r[this.s] = t;
370             break;
371         case 1:
372             for (var o = [], i = 0; i < this.i; i++)
373                 o.unshift(e.f.pop());
374             e.r[this.s] = o
375         }
376     }
377     ,
378     G.prototype.D = function(e) {
379         for (var t = new Buffer(e,"base64").toString("binary"), n = t.charCodeAt(0) << 8 | t.charCodeAt(1), r = [], o = 2; o < n + 2; o += 2)
380             r.push(t.charCodeAt(o) << 8 | t.charCodeAt(o + 1));
381         this.G = r;
382         for (var i = [], a = n + 2; a < t.length; ) {
383             var s = t.charCodeAt(a) << 8 | t.charCodeAt(a + 1)
384               , c = t.slice(a + 2, a + 2 + s);
385             i.push(c),
386             a += s + 2
387         }
388         this.b = i
389     }
390     ,
391     G.prototype.v = function(e, t, n) {
392         for (t = t || 0,
393         n = n || [],
394         this.C = t,
395         "string" == typeof e ? this.D(e) : (this.G = e,
396         this.b = n),
397         this.o = !0,
398         this.R = Date.now(); this.o; ) {
399             var r = this.G[this.C++];
400             if ("number" != typeof r)
401                 break;
402             var o = Date.now();
403             if (500 < o - this.R)
404                 return;
405             this.R = o;
406             try {
407                 this.e(r)
408             } catch (e) {
409                 this.U = e,
410                 this.w && (this.C = this.w)
411             }
412         }
413     }
414     ,
415     G.prototype.e = function(e) {
416         var t = (61440 & e) >> 12;
417         new this.J[t](e).e(this)
418     }
419     ,
420     "undefined" != typeof window && (new G).v("AxjgB5MAnACoAJwBpAAAABAAIAKcAqgAMAq0AzRJZAZwUpwCqACQACACGAKcBKAAIAOcBagAIAQYAjAUGgKcBqFAuAc5hTSHZAZwqrAIGgA0QJEAJAAYAzAUGgOcCaFANRQ0R2QGcOKwChoANECRACQAsAuQABgDnAmgAJwMgAGcDYwFEAAzBmAGcSqwDhoANECRACQAGAKcD6AAGgKcEKFANEcYApwRoAAxB2AGcXKwEhoANECRACQAGAKcE6AAGgKcFKFANEdkBnGqsBUaADRAkQAkABgCnBagAGAGcdKwFxoANECRACQAGAKcGKAAYAZx+rAZGgA0QJEAJAAYA5waoABgBnIisBsaADRAkQAkABgCnBygABoCnB2hQDRHZAZyWrAeGgA0QJEAJAAYBJwfoAAwFGAGcoawIBoANECRACQAGAOQALAJkAAYBJwfgAlsBnK+sCEaADRAkQAkABgDkACwGpAAGAScH4AJbAZy9rAiGgA0QJEAJACwI5AAGAScH6AAkACcJKgAnCWgAJwmoACcJ4AFnA2MBRAAMw5gBnNasCgaADRAkQAkABgBEio0R5EAJAGwKSAFGACcKqAAEgM0RCQGGAYSATRFZAZzshgAtCs0QCQAGAYSAjRFZAZz1hgAtCw0QCQAEAAgB7AtIAgYAJwqoAASATRBJAkYCRIANEZkBnYqEAgaBxQBOYAoBxQEOYQ0giQKGAmQABgAnC6ABRgBGgo0UhD/MQ8zECALEAgaBxQBOYAoBxQEOYQ0gpEAJAoYARoKNFIQ/zEPkAAgChgLGgkUATmBkgAaAJwuhAUaCjdQFAg5kTSTJAsQCBoHFAE5gCgHFAQ5hDSCkQAkChgBGgo0UhD/MQ+QACAKGAsaCRQCOYGSABoAnC6EBRoKN1AUEDmRNJMkCxgFGgsUPzmPkgAaCJwvhAU0wCQFGAUaCxQGOZISPzZPkQAaCJwvhAU0wCQFGAUaCxQMOZISPzZPkQAaCJwvhAU0wCQFGAUaCxQSOZISPzZPkQAaCJwvhAU0wCQFGAkSAzRBJAlz/B4FUAAAAwUYIAAIBSITFQkTERwABi0GHxITAAAJLwMSGRsXHxMZAAk0Fw8HFh4NAwUABhU1EBceDwAENBcUEAAGNBkTGRcBAAFKAAkvHg4PKz4aEwIAAUsACDIVHB0QEQ4YAAsuAzs7AAoPKToKDgAHMx8SGQUvMQABSAALORoVGCQgERcCAxoACAU3ABEXAgMaAAsFGDcAERcCAxoUCgABSQAGOA8LGBsPAAYYLwsYGw8AAU4ABD8QHAUAAU8ABSkbCQ4BAAFMAAktCh8eDgMHCw8AAU0ADT4TGjQsGQMaFA0FHhkAFz4TGjQsGQMaFA0FHhk1NBkCHgUbGBEPAAFCABg9GgkjIAEmOgUHDQ8eFSU5DggJAwEcAwUAAUMAAUAAAUEADQEtFw0FBwtdWxQTGSAACBwrAxUPBR4ZAAkqGgUDAwMVEQ0ACC4DJD8eAx8RAAQ5GhUYAAFGAAAABjYRExELBAACWhgAAVoAQAg/PTw0NxcQPCQ5C3JZEBs9fkcnDRcUAXZia0Q4EhQgXHojMBY3MWVCNT0uDhMXcGQ7AUFPHigkQUwQFkhaAkEACjkTEQspNBMZPC0ABjkTEQsrLQ==");
421     var b = function(e) {
422         console.log(encodeURIComponent(e));
423         return __g._encrypt(encodeURIComponent(e));
424     };
425 
426    exports.ENCRYPT_VERSION = A,
427    exports.default = b;
428 
429   
View Code

 

不得不說,隨着技術的發展,各種各樣的稀奇古怪的混淆層出不窮,堪稱卷積雲,筆者的想要了解一下混淆的細節,並盡可能地將源碼變成人話,並讓更多人了解常見的混淆法,於是撰寫了本文,如有錯誤,歡迎指出和討論,謝謝

如讀者也嘗試執行以下的每一步更改,強烈建議每修改一部分就執行一次代碼以確認是否能正常運行

 

逗號表達式是能夠被正確編譯的,因為可以把相鄰表達式全部寫到一行里面,因此即便寫成多行,也無法分開斷點調試,這是為了加大調試難度而做的一個混淆操作,因此建議先全部改為語法建議的分號表達式

 改為 

 

通覽全文,發現存在三大類主要符號

第一類為函數,例如【function i()】中的【i】,為了便於區分,筆者將所有函數重命名為【Func_i】的格式,可以在【function G()】中的【this.J】找到大部分的函數,這時候,需要手動替換所有函數!!!不能借助IDE的替換功能替換,因為IDE替換會導致變量也被替換了,也就是說IDE會識別錯誤,因此這步替換對后面的分析有很大的幫助,能更清晰地看懂關系,第一次肯定是替換不全的,運行程序然后通過報錯再逐個修改

替換完會得到如下圖所示效果

 

第二類為局部變量,如第一類圖中的【e】、【t】、【s】、【i】和【h】,這些變量暫時不需要去變動,因為已經能和函數區分開了,不過因為原型prototype的字母也是e,因此將形參e改為data,如下圖所示

第三類為原型prototype,這段代碼中所有的prototype的命名都是【e】,如果使用IDE,原型e的顏色和局部變量【e】的顏色是不同的,因為只有一個特定的字母,注意即可,不需變動,那么肯定有人會問,原型是什么啊,文末給出的鏈接中很清晰地說明了原型的意義和用法,不過簡單來說,可以將function理解為class,那么原型就是方法,如果用python來實現,就如下圖所示,效果完全相同

既然沒有區別,那么就將原型都放入函數中方便理解,同時在調試中不會反復跳躍(因為代碼中是分散開的),調整后如下圖所示

 

這時,看下代碼建議,會發現代碼中使用了大量的【var】,建議改為【let】即局部變量,這個修改對理解變量的作用范圍也很有幫助,在替換的同時,很多地方可以做改進,讀者可以自行判斷后修改,比如

上圖中的【var t】、【var o】和【var a】的作用是完全相同的,因此可以提出來並重命名,變成如下所示

 

替換完,還有少部分的代碼建議提示,比如將【==】更改為【===】,將【!=】更改為【!==】,同時,有一些簡單的混淆也可以替換一下,比如【!0】改為【true】、【!1】改為【false】,這時,再回顧一下代碼,會發現有個函數叫【k】

這個函數的寫法和其他的不一樣,但是,效果是一樣的,那么,也調整過來

 

然后還有個函數叫【t】,初看很復雜,分析后發現,只要【"function" == typeof Symbol】不成立,整個函數就返回【false】,當然等式應該是成立的,不過作為嘗試,直接將函數改為下圖所示

居然一切正常,這就非常有意思了,減少了一大段代碼,不過沒有進一步分析,讀者有興趣可以嘗試進一步分析一下

 

此時還會有一些未被引用的變量,去除掉即可,比如【Func_e】中的【this.n】和【Func_G】中的【this.R】

 

首先,調試程序遇到的第一個問題,入口在哪里,在簡單地分析和打斷點之后發現,計算加密的入口在【Func_u】中的【r】處,但是,如何直接調用這個函數卻不觸發外層函數,筆者水平有限,暫無法解釋,不過,在到達入口的時候,程序已經完成了一次初始化,即【(new G).v()】處,里面有非常長的一個字符串,這個就是初始化用的數據,在反復請求網頁后發現,這是一個定值,那么,就打斷點逐步分析

在【v】函數里面,又用了和前面相同的方式即用【for】初始化變量,同時,讀者可能會注意到一個很有意思的地方,js的傳參數量對不上了,【v】僅有一個參數,怎么對應【(e, t, n)】呢,實參和形參中,以數量少的一方為准,多的就被舍棄,空缺的就是undefined,因此,初始化的時候會進到【D】函數,之后計算則將 【e、t、n】 賦值給 【this.G、this.c、this.b】,其中有一個【this.R】記錄了當前時間,如果在500ms內沒有到計算完,則會直接結束計算,只是一個反爬的手段,因此直接去掉即可,而【this.o】為true,放在for的第二個參數位,即等價於while(true),替換即可,這時因為還需要初始化,所以設置了一個字符串【start!】,后面可以去掉

 

之后就進到了【D】函數,第一行就開幕雷擊,連續的base64轉換、二進制轉換、移位操作、Unicode碼轉換,不過目的是獲得【Func_G.G】,之后又獲得了【Func_G.b】,也就是【D】函數執行了一個初始化的操作,那直接打斷點提取出兩個的值然后寫定即可,省去了不少計算量,如下圖所示

 

 那么肯定會有疑惑,這些數有意義還是只是純粹的隨機數,本想說自己打完斷點就知道了,不過就不賣關子了,【G】應該叫做無意義數,先設定好執行的順序,然后用移位反推出一個合適的數據寫入,執行的時候移位還原出結果然后在【J】中調用,而【b】生成了很多函數或者說變量名,在【Func_k】處打斷點就可以看到,長的數組都對應着一些變量名,其中包括【window】和【_encrypt】等,【_encrypt】也是加密計算的入口,這個在源碼中如何都找不到的函數是如何加入並執行的,筆者才疏學淺,就不深究了,不過應該和【Func_u】中的【native code】有一定關系,不過好的是,后面都能去掉

分析完初始化,就進入到正在的計算流程了,即上文提到的【while(true)】,提到【while】,那必定有結束信號,即判斷【r】是否越界,筆者嘗試直接用for遍歷,但發現是不行的,因為在計算過程中,【C】的值會變動,因此還是只能用【while】,然后就是將【r】代入原型【e】通過【J】選取一個函數並計算,這時會有一個try,觀察可發現catch后的內容不影響結果,直接刪除,同時【Func_g】中有throw,也可以去掉,最終得到下圖的結果

上文提到了【native code】和入口【Func_u.r】,於是嘗試對這一部分打斷點分析一下,上文提到過是直接跳轉到【r】函數的,那么這意味着前面這一段是否意味着不需要呢

嘗試刪掉后一切正常,有意思,然后注意到這一段

return有好幾個值,用quokka測試后發現,這種寫法等價於執行最后一個逗號之前的代碼,然后返回最后一項,同時,【o.v】的形參只有三項,那么可以直接去掉【data.F】,然后就是【toString】,抱着去掉試試的想法刪掉了,一切正常,那就更有意思了,不過全部去掉之后的【data】就是【e】的形參了,其中有這兩行代碼【o.k = n, o.k[0] = r】,通過斷點可以知道就是【o.k = [r]】,而這時的【r】是無法傳進來的,因此在【e】的后面增加一個形參【val】,然后代碼就變成了下圖所示

 

這時還缺少的就是val的初始值,在修改前打斷點可得知,是7,於是直接寫死,得到

 

全部修改完了,這時還需要jsdom嗎,去掉試試,居然能直接運行了,善哉,雖然不確定是哪一步使得這個可以被省去了,但是能運行就是好事了

那么還需要初始化那一遍嗎,也不需要了啊,直接走起了,也就是可以把【start】刪掉了 

 

把程序跑起來,會發現,生成的signature多了個后綴【_XUX】,應該是一個反爬機制或者是簡化程序的時候某一步出現了差錯,不過不是很重要了,直接去掉即可,有興趣的讀者可以自行研究一下如何不產生這個后綴

至此,程序已經變得非常通俗易懂了,也不存在晦澀的混淆代碼了,筆者盡量不跳步驟地解釋了格式化的步驟,不過文章是代碼完成后寫的,所以可能有部分地方順序存在問題,讀者需要自行思考下

筆者嘗試將代碼遷移到python,以嘗試完全理解加密算法的細節,但是遷移完成后發現源碼使用了大量的js特性,python實現難度非常大,需要自己實現很多底層操作,於是咕咕咕,比如,向數組中新增元素的時候,js可以直接向任意越界的位置新增,空缺的位置自動用undefined填充

 

如有讀者有興趣,可以嘗試遷移和修改,代碼在github上開源,此代碼僅供學習和研究反混淆使用,請勿用於其他用途或對他人造成困擾,非常感謝!

https://github.com/Pyrokine/zhihu_encrypt

 

 

感謝:
新版知乎x-zse-86加密破解分析
https://blog.csdn.net/weixin_40352715/article/details/107546166
JS 中 __proto__ 和 prototype 存在的意義是什么? https:
//www.zhihu.com/question/56770432
你可以不會 class,但是一定要學會 prototype
https://zhuanlan.zhihu.com/p/35279244


免責聲明!

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



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