zoukankan      html  css  js  c++  java
  • 知乎sign加密算法彻底反混淆

    源码来自 新版知乎x-zse-86加密破解分析 ,在添加了jsdom之后就可以直接运行了,但这肯定不是一个很好的方法,也有很大的局限性,因为简单分析后,jsdom应该是主要是提供一个window属性,而加密算法很可能与其无关,或者可以通过另一种方式构造出来,因此尝试对源码进行进一步的解析,首先贴一下源码以便读者查看

      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】,这些变量暂时不需要去变动,因为已经能和函数区分开了,不过因为原型的字母也是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】可以删掉了 

    把程序跑起来,会发现,emmmmm多了个后缀【_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
  • 相关阅读:
    SqlSession接口和Executor
    MySQL 存储表情字符
    Lisp学习--Windows下面的开发环境搭建
    使用反射+缓存+委托,实现一个不同对象之间同名同类型属性值的快速拷贝
    GIT团队合作探讨之一-保持工作同步的概念和实践
    关于IE8下media query兼容的解决方案探讨
    git下的团队合作模型及git基础知识汇集
    互联网环境下服务提供的模式
    web统计数据搜集及分析原理
    网站统计及移动应用数据统计相关术语知识详解
  • 原文地址:https://www.cnblogs.com/Pyrokine/p/13828266.html
Copyright © 2011-2022 走看看