这其实也是我之前做过的一个逆向,本来想先写今日头条的signature的,结果网站直接把反爬给下了,一点含金量都没有 😅😅😅

还是来写知乎吧,之前的过程忘得也差不多了,一边逆向一边记录咯 🧔🧔🧔

目标是知乎的搜索接口,其他问答文章专栏接口什么的也大同小异,老规矩,先fiddler抓包分析,找到搜索接口返回的数据:

请求头里面的参数太多了,哪些是必要的也不清楚,把请求拖到组合器,一个一个删除来测试:

最后确定了,x-zse-93 x-zse-96 Cookie里面的d_c0 这三个是必须的

第一个不用看,每次都是固定的值 101_3_2.0

d_c0的话则是**/udid**接口返回的,在每次请求前先访问一次拿到就行

重点来说说x-zse-96这个参数,直接搜索关键词,有两个结果,都打上断点,然后刷新页面

从图中可以看到 x-zse-96 其实就是 signature 的值,而signature的生成点在这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
T = function (e, t, n, r) {
var i = n.zse93,
o = n.dc0,
a = n.xZst81,
c = H(e),
u = q(t),
s = [i, c, o, W(u) && u, a].filter(Boolean).join("+");
return {
source: s,
signature: (0,
B(r).encrypt)(f()(s))
}
}(t, c.body, {
zse93: g,
dc0: E,
xZst81: A
}, l)

我们一行一行来分析,F8一步一步调试,直到接口地址是 /api/v4/search_v3的时候停下

前面两行的值就不再赘述了,重点是第三行 n.xZst81 的值,其实就是传入A的值,而

1
A = a.xZst81 || p.get("x-zst-81")

其中 a.xZst81 是 null,p是headers对象,这里如果开启的是无痕浏览器访问的话,这里面其实是null,所以可以不用考虑

filter(Boolean) 则是用来过滤false的对象,比如:

1
2
[0, 1, 2, false].filter(Boolean)
>>> [1, 2]

调试到这里的时候发现一行一行来太慢了,还不如直接下xhr断点,然后追栈

可以清楚看到 s的值就是 x_zse_93 + path + d_c0,可以来分析 (0,B(r).encrypt)(f()(s))

f()

从结果来看很像md5,测试一下,果然是

B(r).encrypt

进入内部看一下,看不出具体是用了哪种算法,直接扣代码吧

如下图所示,从 46805行抠到47210行

补环境

网上几乎所有的教程都是教你补jsdom环境,一开始我也是这么想的,但本地的node不知道抽了什么风

首先是安装 jsdom模块,否则会报错:Error: Cannot find module 'jsdom'

安装命令:npm install -g jsdom

其中 -g 是全局安装,否则 npm 会将模块安装到当前所在目录

查看全局安装了哪些包:npm list --depth=0 --global

安装指定版本的包:npm install jsdom@16.2.0

安装完之后以为万事大吉可以运行了,结果jsdom各种乱七八糟的报错,索性就卸了

骚操作

干脆我就不补环境了,搜了一下,代码里面也只有两处调用了windows,其他地方根本没用到环境

第二处只是一个逻辑判断,直接删除 "undefined" != typeof window && 就行了

第一处则是用了atob,也就是base64解码,这就有点棘手了,于是各种搜node的base64实现,很多文章都提到了可以用buffer来实现

1
2
3
4
5
6
7
8
9
10
const base64 = 'QmFzZTY0IEVuY29kaW5nIGluIE5vZGUuanM=';

// create a buffer
const buff = Buffer.from(base64, 'base64');

// decode buffer as UTF-8
const str = buff.toString('utf-8');

// print normal string
console.log(str.length);

也确实可以解码,但在解码知乎的时候,得到的结果有亿点点的不一样,长度首先就不相等了……

✨✨✨

本来已经打算放弃了,洗澡的时候突然有了灵感,源码里面只调用了一次atob,那我是不是可以现在浏览器解码得到结果,然后直接替换到本地的js代码里面,然后不调用atob就行了,说干就干

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
var A = "2.0",
__g = {};

function s() {}

function i(e) {
this.t = (2048 & e) >> 11,
this.s = (1536 & e) >> 9,
this.i = 511 & e,
this.h = 511 & e
}

function h(e) {
this.s = (3072 & e) >> 10,
this.h = 1023 & e
}

function a(e) {
this.a = (3072 & e) >> 10,
this.c = (768 & e) >> 8,
this.n = (192 & e) >> 6,
this.t = 63 & e
}

function c(e) {
this.s = e >> 10 & 3,
this.i = 1023 & e
}

function n() {}

function e(e) {
this.a = (3072 & e) >> 10,
this.c = (768 & e) >> 8,
this.n = (192 & e) >> 6,
this.t = 63 & e
}

function o(e) {
this.h = (4095 & e) >> 2,
this.t = 3 & e
}

function r(e) {
this.s = e >> 10 & 3,
this.i = e >> 2 & 255,
this.t = 3 & e
}
s.prototype.e = function (e) {
e.o = !1
},
i.prototype.e = function (e) {
switch (this.t) {
case 0:
e.r[this.s] = this.i;
break;
case 1:
e.r[this.s] = e.k[this.h]
}
},
h.prototype.e = function (e) {
e.k[this.h] = e.r[this.s]
},
a.prototype.e = function (e) {
switch (this.t) {
case 0:
e.r[this.a] = e.r[this.c] + e.r[this.n];
break;
case 1:
e.r[this.a] = e.r[this.c] - e.r[this.n];
break;
case 2:
e.r[this.a] = e.r[this.c] * e.r[this.n];
break;
case 3:
e.r[this.a] = e.r[this.c] / e.r[this.n];
break;
case 4:
e.r[this.a] = e.r[this.c] % e.r[this.n];
break;
case 5:
e.r[this.a] = e.r[this.c] == e.r[this.n];
break;
case 6:
e.r[this.a] = e.r[this.c] >= e.r[this.n];
break;
case 7:
e.r[this.a] = e.r[this.c] || e.r[this.n];
break;
case 8:
e.r[this.a] = e.r[this.c] && e.r[this.n];
break;
case 9:
e.r[this.a] = e.r[this.c] !== e.r[this.n];
break;
case 10:
e.r[this.a] = t(e.r[this.c]);
break;
case 11:
e.r[this.a] = e.r[this.c] in e.r[this.n];
break;
case 12:
e.r[this.a] = e.r[this.c] > e.r[this.n];
break;
case 13:
e.r[this.a] = -e.r[this.c];
break;
case 14:
e.r[this.a] = e.r[this.c] < e.r[this.n];
break;
case 15:
e.r[this.a] = e.r[this.c] & e.r[this.n];
break;
case 16:
e.r[this.a] = e.r[this.c] ^ e.r[this.n];
break;
case 17:
e.r[this.a] = e.r[this.c] << e.r[this.n];
break;
case 18:
e.r[this.a] = e.r[this.c] >>> e.r[this.n];
break;
case 19:
e.r[this.a] = e.r[this.c] | e.r[this.n];
break;
case 20:
e.r[this.a] = !e.r[this.c]
}
},
c.prototype.e = function (e) {
e.Q.push(e.C),
e.B.push(e.k),
e.C = e.r[this.s],
e.k = [];
for (var t = 0; t < this.i; t++)
e.k.unshift(e.f.pop());
e.g.push(e.f),
e.f = []
},
n.prototype.e = function (e) {
e.C = e.Q.pop(),
e.k = e.B.pop(),
e.f = e.g.pop()
},
e.prototype.e = function (e) {
switch (this.t) {
case 0:
e.u = e.r[this.a] >= e.r[this.c];
break;
case 1:
e.u = e.r[this.a] <= e.r[this.c];
break;
case 2:
e.u = e.r[this.a] > e.r[this.c];
break;
case 3:
e.u = e.r[this.a] < e.r[this.c];
break;
case 4:
e.u = e.r[this.a] == e.r[this.c];
break;
case 5:
e.u = e.r[this.a] != e.r[this.c];
break;
case 6:
e.u = e.r[this.a];
break;
case 7:
e.u = !e.r[this.a]
}
},
o.prototype.e = function (e) {
switch (this.t) {
case 0:
e.C = this.h;
break;
case 1:
e.u && (e.C = this.h);
break;
case 2:
e.u || (e.C = this.h);
break;
case 3:
e.C = this.h,
e.w = null
}
e.u = !1
},
r.prototype.e = function (e) {
switch (this.t) {
case 0:
for (var t = [], n = 0; n < this.i; n++)
t.unshift(e.f.pop());
e.r[3] = e.r[this.s](t[0], t[1]);
break;
case 1:
for (var r = e.f.pop(), o = [], i = 0; i < this.i; i++)
o.unshift(e.f.pop());
e.r[3] = e.r[this.s][r](o[0], o[1]);
break;
case 2:
for (var a = [], c = 0; c < this.i; c++)
a.unshift(e.f.pop());
e.r[3] = new e.r[this.s](a[0], a[1])
}
};
var k = function (e) {
for (var t = 66, n = [], r = 0; r < e.length; r++) {
var o = 24 ^ e.charCodeAt(r) ^ t;
n.push(String.fromCharCode(o)),
t = o
}
return n.join("")
};

function Q(e) {
this.t = (4095 & e) >> 10,
this.s = (1023 & e) >> 8,
this.i = 1023 & e,
this.h = 63 & e
}

function C(e) {
this.t = (4095 & e) >> 10,
this.a = (1023 & e) >> 8,
this.c = (255 & e) >> 6
}

function B(e) {
this.s = (3072 & e) >> 10,
this.h = 1023 & e
}

function f(e) {
this.h = 4095 & e
}

function g(e) {
this.s = (3072 & e) >> 10
}

function u(e) {
this.h = 4095 & e
}

function w(e) {
this.t = (3840 & e) >> 8,
this.s = (192 & e) >> 6,
this.i = 63 & e
}

function G() {
this.r = [0, 0, 0, 0],
this.C = 0,
this.Q = [],
this.k = [],
this.B = [],
this.f = [],
this.g = [],
this.u = !1,
this.G = [],
this.b = [],
this.o = !1,
this.w = null,
this.U = null,
this.F = [],
this.R = 0,
this.J = {
0: s,
1: i,
2: h,
3: a,
4: c,
5: n,
6: e,
7: o,
8: r,
9: Q,
10: C,
11: B,
12: f,
13: g,
14: u,
15: w
}
}
Q.prototype.e = function (e) {
switch (this.t) {
case 0:
e.f.push(e.r[this.s]);
break;
case 1:
e.f.push(this.i);
break;
case 2:
e.f.push(e.k[this.h]);
break;
case 3:
e.f.push(k(e.b[this.h]))
}
},
C.prototype.e = function (A) {
switch (this.t) {
case 0:
var t = A.f.pop();
A.r[this.a] = A.r[this.c][t];
break;
case 1:
var s = A.f.pop(),
i = A.f.pop();
A.r[this.c][s] = i;
break;
case 2:
var h = A.f.pop();
A.r[this.a] = eval(h)
}
},
B.prototype.e = function (e) {
e.r[this.s] = k(e.b[this.h])
},
f.prototype.e = function (e) {
e.w = this.h
},
g.prototype.e = function (e) {
throw e.r[this.s]
},
u.prototype.e = function (e) {
var t = this,
n = [0];
e.k.forEach((function (e) {
n.push(e)
}));
var r = function (r) {
var o = new G;
return o.k = n,
o.k[0] = r,
o.v(e.G, t.h, e.b, e.F),
o.r[3]
};
r.toString = function () {
return "() { [native code] }"
},
e.r[3] = r
},
w.prototype.e = function (e) {
switch (this.t) {
case 0:
for (var t = {}, n = 0; n < this.i; n++) {
var r = e.f.pop();
t[e.f.pop()] = r
}
e.r[this.s] = t;
break;
case 1:
for (var o = [], i = 0; i < this.i; i++)
o.unshift(e.f.pop());
e.r[this.s] = o
}
},
G.prototype.D = function (e) {
for (var t = e, n = t.charCodeAt(0) << 8 | t.charCodeAt(1), r = [], o = 2; o < n + 2; o += 2)
r.push(t.charCodeAt(o) << 8 | t.charCodeAt(o + 1));
this.G = r;
for (var i = [], a = n + 2; a < t.length;) {
var c = t.charCodeAt(a) << 8 | t.charCodeAt(a + 1),
s = t.slice(a + 2, a + 2 + c);
i.push(s),
a += c + 2
}
this.b = i
},
G.prototype.v = function (e, t, n) {
for (t = t || 0,
n = n || [],
this.C = t,
"string" == typeof e ? this.D(e) : (this.G = e,
this.b = n),
this.o = !0,
this.R = Date.now(); this.o;) {
var r = this.G[this.C++];
if ("number" != typeof r)
break;
var o = Date.now();
if (500 < o - this.R)
return;
this.R = o;
try {
this.e(r)
} catch (e) {
this.U = e,
this.w && (this.C = this.w)
}
}
},
G.prototype.e = function (e) {
var t = (61440 & e) >> 12;
new this.J[t](e).e(this)
},
(new G).v(
'\x03\x18à\x07\x93\x00\x9C\x00¨\x00\x9C\x01¤\x00\x00\x00\x10\x00 \x02\x9C\x02¨\x000\n´\x034Id\x06pR\x9C\x02¨\x00\x90\x00 \x02\x18\x02\x9C\x04 \x00 \x03\x9C\x05¨\x00 \x04\x18\x020\x14\x1A\x02\x9C\x06¡@¸\x079\x854\x87d\x06pª°\b\x1A\x004@\x91\x00$\x00\x18\x030\x14\x1A\x03\x9C\t¡@5\x144Gd\x06pâ°\n\x1A\x004@\x91\x00$\x00°\v\x90\x00\x18\x03\x9C\t \x00\x9C\f\x80\x01\x9C\r\x8C\x05\x10\x003\x06`\x06q*°\x0E\x1A\x004@\x91\x00$\x00\x18\x02\x9C\x0F \x00\x1A\x02\x9C\x10¡@4G\x18\x02\x9C\x11 \x001\x07`\x06qr°\x12\x1A\x004@\x91\x00$\x00\x18\x02\x9C\x13 \x00\x1A\x02\x9C\x14¡@4Gd\x06qª°\x15\x1A\x004@\x91\x00$\x00\x18\x02\x9C\x16 \x00`\x06qÒ°\x17\x1A\x004@\x91\x00$\x00\x18\x02\x9C\x18 \x00`\x06qú°\x19\x1A\x004@\x91\x00$\x00\x18\x03\x9C\x1A \x00`\x06r"°\x1B\x1A\x004@\x91\x00$\x00\x18\x02\x9C\x1C \x00\x1A\x02\x9C\x1D¡@4Gd\x06rZ°\x1E\x1A\x004@\x91\x00$\x00\x18\x04\x9C\x1F \x000\x14`\x06r\x86° \x1A\x004@\x91\x00$\x00\x18\x03\x90\x00°\t\x90\x00\x18\x04\x9C\x1F\x80\tl\x06r¾°!\x1A\x004@\x91\x00$\x00\x18\x03\x90\x00°\x1A\x90\x00\x18\x04\x9C\x1F\x80\tl\x06rö°"\x1A\x004@\x91\x00$\x00°#\x90\x00\x18\x04\x9C\x1F \x00\x90\x00\x9C$¨\x00\x9C% \x00\x9C& \x00\x9C\'\x80\x05\x9C\r\x8C\x05\x10\x003\x0E`\x06sZ°(\x1A\x004@\x91\x00$\x00\x18\x01\x12*4G\x91\x00$\x01°) \x05\x18\x00\x9C* \x00\x12\x034D$\x06\x18\x06\x12\x014Ed\x06s²\x18\x00´+4@$\x00\x18\x06\x12\x024Ed\x06sÖ\x18\x00´,4@$\x00\x10\x00 \x07°- \b\x18\x00\x9C* \x00\x12\x014A$\t\x18\t\x12\x004Fd\x06v*\x10\b\x1A\x07\x14\x019\x80(\x07\x14\x049\x844\x82$\n\x18\t\x90\x00\x18\x00\x9C.\x80\x05\x18\x01\x1A\n4R\x10ÿ1\x0F3\x10 \v\x10\b\x1A\x07\x14\x019\x80(\x07\x14\x049\x844\x82\x91\x00$\n\x18\x01\x1A\n4R\x10ÿ1\x0F\x90\x00 \n\x18\v\x1A\t\x14\x019\x81\x92\x00\x1A\x00\x9C.\x84\x05\x1A\n7P\x14\b9\x914\x93$\v\x10\b\x1A\x07\x14\x019\x80(\x07\x14\x049\x844\x82\x91\x00$\n\x18\x01\x1A\n4R\x10ÿ1\x0F\x90\x00 \n\x18\v\x1A\t\x14\x029\x81\x92\x00\x1A\x00\x9C.\x84\x05\x1A\n7P\x14\x109\x914\x93$\v\x18\x05\x1A\v\x14?9\x8F\x92\x00\x1A\b\x9C/\x84\x054À$\x05\x18\x05\x1A\v\x14\x069\x92\x12?6O\x91\x00\x1A\b\x9C/\x84\x054À$\x05\x18\x05\x1A\v\x14\f9\x92\x12?6O\x91\x00\x1A\b\x9C/\x84\x054À$\x05\x18\x05\x1A\v\x14\x129\x92\x12?6O\x91\x00\x1A\b\x9C/\x84\x054À$\x05\x18\t\x12\x034A$\tsü\x1E\x05P\x00\x00\x03\x05\x18 \x00\b\x05"\x13\x15\t\x13\x11\x1C\x00\x06-\x06\x1F\x12\x13\x00\x00\t/\x03\x12\x19\x1B\x17\x1F\x13\x19\x00\t4\x17\x0F\x07\x16\x1E\r\x03\x05\x00\x06\x155\x10\x17\x1E\x0F\x00\x044\x17\x14\x10\x00\x064\x19\x13\x19\x17\x01\x00\x01J\x00\t/\x1E\x0E\x0F+>\x1A\x13\x02\x00\x01K\x00\b2\x15\x1C\x1D\x10\x11\x0E\x18\x00\v.\x03;;\x00\n\x0F):\n\x0E\x00\x073\x1F\x12\x19\x05/1\x00\x01H\x00\v9\x1A\x15\x18$ \x11\x17\x02\x03\x1A\x00\b\x057\x00\x11\x17\x02\x03\x1A\x00\v\x05\x187\x00\x11\x17\x02\x03\x1A\x14\n\x00\x01I\x00\x068\x0F\v\x18\x1B\x0F\x00\x06\x18/\v\x18\x1B\x0F\x00\x01N\x00\x04?\x10\x1C\x05\x00\x01O\x00\x05)\x1B\t\x0E\x01\x00\x01L\x00\t-\n\x1F\x1E\x0E\x03\x07\v\x0F\x00\x01M\x00\r>\x13\x1A4,\x19\x03\x1A\x14\r\x05\x1E\x19\x00\x17>\x13\x1A4,\x19\x03\x1A\x14\r\x05\x1E\x1954\x19\x02\x1E\x05\x1B\x18\x11\x0F\x00\x01B\x00\x18=\x1A\t# \x01&:\x05\x07\r\x0F\x1E\x15%9\x0E\b\t\x03\x01\x1C\x03\x05\x00\x01C\x00\x01@\x00\x01A\x00\r\x01-\x17\r\x05\x07\v][\x14\x13\x19 \x00\b\x1C+\x03\x15\x0F\x05\x1E\x19\x00\t*\x1A\x05\x03\x03\x03\x15\x11\r\x00\b.\x03$?\x1E\x03\x1F\x11\x00\x049\x1A\x15\x18\x00\x01F\x00\x00\x00\x066\x11\x13\x11\v\x04\x00\x02Z\x18\x00\x01Z\x00@\b?=<47\x17\x10<$9\vrY\x10\x1B=~G\'\r\x17\x14\x01vbkD8\x12\x14 \\z#0\x1671eB5=.\x0E\x13\x17pd;\x01AO\x1E($AL\x10\x16HZ\x02A\x00\n9\x13\x11\v)4\x13\x19<-\x00\x069\x13\x11\v+-'
);

var gen_x_96 = function (e) {
return __g._encrypt(encodeURIComponent(e))
};


console.log(gen_x_96('fd782efabee59d2c9e0b1bb7fb708d30'))

运行node文件,没有报错,而且结果和浏览器的一致,终于大功告成了

python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import requests
import execjs

from hashlib import md5
from w3lib.url import add_or_replace_parameters
from urllib.parse import urlencode, urlparse


session = requests.session()
session.headers.clear() # 不能是python的UA


def get_x_zse_96(url, params, d_c0):
api_v4 = urlparse(add_or_replace_parameters(url, params))
zh_path = api_v4.path + "?" + api_v4.query
j = "+".join(["101_3_2.0", zh_path, d_c0])
md5_str = md5(j.encode()).hexdigest()

with open("zhihu.js", "r") as f:
js_code = f.read()

ctx = execjs.compile(js_code)
x_86 = ctx.call("gen_x_96", md5_str)
return x_86[:-4]


def get_dc0():
url = "https://www.zhihu.com/udid"
session.post(url)
d_c0 = session.cookies.get("d_c0")
return d_c0


def main():
d_c0 = get_dc0()

url = "https://www.zhihu.com/api/v4/search_v3"
params = {
"t": "general",
"q": "诈骗",
"correction": "1",
"offset": "0", # 页数
"limit": "20",
"filter_fields": "",
"lc_idx": "0", # 和 offset 保持一致
"show_all_topics": "0",
"search_source": "Normal",
## 下面是一些筛选的参数
# "vertical": "answer",
# "sort": "created_time",
# "time_interval": "a_week",
}

x96 = get_x_zse_96(url, params, d_c0)
zh_headers = {
"x-zse-93": "101_3_2.0",
"x-zse-96": f"2.0_{x96}",
}
data = session.get(url, params=params, headers=zh_headers).json()
print(data)


if __name__ == "__main__":
main()

运行结果

后记

本来以为知乎的是jsvmp,所以才来研究的,逆向完才发现是webpack + base64,算是一个伪jsvmp吧 🤐🤐🤐

2022.09.08 补充

在逆向知乎小程序的时候,意外收获了一个 atob 的原生函数

1
2
3
4
5
6
7
8
function b(e) {
for (var t, n, i, r, o, a, s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", u = "", l =
0; l < e.length;) t = s.indexOf(e.charAt(l++)) << 2 | (r = s.indexOf(e.charAt(l++))) >> 4,
n = (15 & r) << 4 | (o = s.indexOf(e.charAt(l++))) >> 2, i = (3 & o) << 6 | (a = s.indexOf(e.charAt(l++))),
u += String.fromCharCode(t), 64 != o && (u += String.fromCharCode(n)), 64 != a && (u += String.fromCharCode(
i));
return u;
}

工作的原因,需要采集知乎的数据,才发现8月初进行了一次更新,旧版本的加密已经失效,新版本的知乎加入检测环境的步骤,目前抠出了代码,但计算结果和网页的总是不一致,索性就研究了知乎小程序的接口,发现加密没网页新版本的那么复杂,不过有检测微信环境,更加麻烦,先做一下记录,以后有时间了再来研究

1
2
x-zse-83: 7_1.0
x-zse-86: 1.0_qyERzknQEdUcp6fms8EQ8IIRhxXckafmaxzRpl6RhJz6

主要是 x-zse-86 参数的生成,抠出来的算法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

function i() {}
function r(e) {
this.i = (2048 & e) >> 11, this.s = (1536 & e) >> 9, this.h = 511 & e, this.a = 511 & e;
}
function o(e) {
this.s = (3072 & e) >> 10, this.a = 1023 & e;
}
function a(e) {
this.A = (3072 & e) >> 10, this.n = (768 & e) >> 8, this.e = (192 & e) >> 6, this.i = 63 & e;
}
function s(e) {
this.s = e >> 10 & 3, this.h = 1023 & e;
}
function u() {}
function l(e) {
this.A = (3072 & e) >> 10, this.n = (768 & e) >> 8, this.e = (192 & e) >> 6, this.i = 63 & e;
}
function d(e) {
this.a = (4095 & e) >> 2, this.i = 3 & e;
}
function p(e) {
this.s = e >> 10 & 3, this.h = e >> 2 & 255, this.i = 3 & e;
}
function c(e) {
this.i = (4095 & e) >> 10, this.s = (1023 & e) >> 8, this.h = 1023 & e, this.a = 63 & e;
}
function f(e) {
this.i = (4095 & e) >> 10, this.A = (1023 & e) >> 8, this.n = (255 & e) >> 6;
}
function m(e) {
this.s = (3072 & e) >> 10, this.a = 1023 & e;
}
function h(e) {
this.a = 4095 & e;
}
function y(e) {
this.s = (3072 & e) >> 10;
}
function g(e) {
this.a = 4095 & e;
}
function v(e) {
this.i = (3840 & e) >> 8, this.s = (192 & e) >> 6, this.h = 63 & e;
}
function _() {
this.o = [ 0, 0, 0, 0 ], this.k = 0, this.u = [], this.f = [], this.b = [], this.Q = [],
this.B = [], this.g = !1, this.C = [], this.S = [], this.r = !1, this.w = null,
this.G = null, this.v = [], this.R = 0, this.U = {
0: i,
1: r,
2: o,
3: a,
4: s,
5: u,
6: l,
7: d,
8: p,
9: c,
10: f,
11: m,
12: h,
13: y,
14: g,
15: v
};
}
function b(e) {
// if ("undefined" != typeof atob) return atob(e);
// u = atob(e);
for (var t, n, i, r, o, a, s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", u = "", l = 0; l < e.length; ) t = s.indexOf(e.charAt(l++)) << 2 | (r = s.indexOf(e.charAt(l++))) >> 4,
n = (15 & r) << 4 | (o = s.indexOf(e.charAt(l++))) >> 2, i = (3 & o) << 6 | (a = s.indexOf(e.charAt(l++))),
u += String.fromCharCode(t), 64 != o && (u += String.fromCharCode(n)), 64 != a && (u += String.fromCharCode(i));
return u;
}
function gen_xse_86(e) {
return E._encrypt(encodeURIComponent(e));
}

var E = {};
i.prototype.c = function(e) {
e.r = !1;
}, r.prototype.c = function(e) {
switch (this.i) {
case 0:
e.o[this.s] = this.h;
break;

case 1:
e.o[this.s] = e.f[this.a];
}
}, o.prototype.c = function(e) {
e.f[this.a] = e.o[this.s];
}, a.prototype.c = function(e) {
switch (this.i) {
case 0:
e.o[this.A] = e.o[this.n] + e.o[this.e];
break;

case 1:
e.o[this.A] = e.o[this.n] - e.o[this.e];
break;

case 2:
e.o[this.A] = e.o[this.n] * e.o[this.e];
break;

case 3:
e.o[this.A] = e.o[this.n] / e.o[this.e];
break;

case 4:
e.o[this.A] = e.o[this.n] % e.o[this.e];
break;

case 5:
e.o[this.A] = e.o[this.n] == e.o[this.e];
break;

case 6:
e.o[this.A] = e.o[this.n] >= e.o[this.e];
break;

case 7:
e.o[this.A] = e.o[this.n] || e.o[this.e];
break;

case 8:
e.o[this.A] = e.o[this.n] && e.o[this.e];
break;

case 9:
e.o[this.A] = e.o[this.n] !== e.o[this.e];
break;

case 10:
e.o[this.A] = n(e.o[this.n]);
break;

case 11:
e.o[this.A] = e.o[this.n] in e.o[this.e];
break;

case 12:
e.o[this.A] = e.o[this.n] > e.o[this.e];
break;

case 13:
e.o[this.A] = -e.o[this.n];
break;

case 14:
e.o[this.A] = e.o[this.n] < e.o[this.e];
break;

case 15:
e.o[this.A] = e.o[this.n] & e.o[this.e];
break;

case 16:
e.o[this.A] = e.o[this.n] ^ e.o[this.e];
break;

case 17:
e.o[this.A] = e.o[this.n] << e.o[this.e];
break;

case 18:
e.o[this.A] = e.o[this.n] >>> e.o[this.e];
break;

case 19:
e.o[this.A] = e.o[this.n] | e.o[this.e];
break;

case 20:
e.o[this.A] = !e.o[this.n];
}
}, s.prototype.c = function(e) {
e.u.push(e.k), e.b.push(e.f), e.k = e.o[this.s], e.f = [];
for (var t = 0; t < this.h; t++) e.f.unshift(e.Q.pop());
e.B.push(e.Q), e.Q = [];
}, u.prototype.c = function(e) {
e.k = e.u.pop(), e.f = e.b.pop(), e.Q = e.B.pop();
}, l.prototype.c = function(e) {
switch (this.i) {
case 0:
e.g = e.o[this.A] >= e.o[this.n];
break;

case 1:
e.g = e.o[this.A] <= e.o[this.n];
break;

case 2:
e.g = e.o[this.A] > e.o[this.n];
break;

case 3:
e.g = e.o[this.A] < e.o[this.n];
break;

case 4:
e.g = e.o[this.A] == e.o[this.n];
break;

case 5:
e.g = e.o[this.A] != e.o[this.n];
break;

case 6:
e.g = e.o[this.A];
break;

case 7:
e.g = !e.o[this.A];
}
}, d.prototype.c = function(e) {
switch (this.i) {
case 0:
e.k = this.a;
break;

case 1:
e.g && (e.k = this.a);
break;

case 2:
e.g || (e.k = this.a);
break;

case 3:
e.k = this.a, e.w = null;
}
e.g = !1;
}, p.prototype.c = function(e) {
switch (this.i) {
case 0:
for (var t = [], n = 0; n < this.h; n++) t.unshift(e.Q.pop());
e.o[3] = e.o[this.s](t[0], t[1]);
break;

case 1:
for (var i = e.Q.pop(), r = [], o = 0; o < this.h; o++) r.unshift(e.Q.pop());
e.o[3] = e.o[this.s][i](r[0], r[1]);
break;

case 2:
for (var a = [], s = 0; s < this.h; s++) a.unshift(e.Q.pop());
e.o[3] = new e.o[this.s](a[0], a[1]);
}
};
var T = function(e) {
for (var t = 66, n = [], i = 0; i < e.length; i++) {
var r = 24 ^ e.charCodeAt(i) ^ t;
n.push(String.fromCharCode(r)), t = r;
}
return n.join("");
};
c.prototype.c = function(e) {
switch (this.i) {
case 0:
e.Q.push(e.o[this.s]);
break;

case 1:
e.Q.push(this.h);
break;

case 2:
e.Q.push(e.f[this.a]);
break;

case 3:
e.Q.push(T(e.S[this.a]));
}
}, f.prototype.c = function(e) {
switch (this.i) {
case 0:
var t = e.Q.pop();
e.o[this.A] = e.o[this.n][t];
break;

case 1:
var n = e.Q.pop(), i = e.Q.pop();
e.o[this.n][n] = i;
break;

case 2:
var r = e.Q.pop(), o = 0;
o = wx;
e.o[this.A] = "__g" == r ? E : o;
}
}, m.prototype.c = function(e) {
e.o[this.s] = T(e.S[this.a]);
}, h.prototype.c = function(e) {
e.w = this.a;
}, y.prototype.c = function(e) {
throw e.o[this.s];
}, g.prototype.c = function(e) {
function t(t) {
var r = new _();
return r.f = i, r.f[0] = t, r.y(e.C, n.a, e.S, e.v), r.o[3];
}
var n = this, i = [ 0 ];
e.f.forEach(function(e) {
i.push(e);
}), t.toString = function() {
return "() { [native code] }";
}, e.o[3] = t;
}, v.prototype.c = function(e) {
switch (this.i) {
case 0:
for (var t = {}, n = 0; n < this.h; n++) {
var i = e.Q.pop();
t[e.Q.pop()] = i;
}
e.o[this.s] = t;
break;

case 1:
for (var r = [], o = 0; o < this.h; o++) r.unshift(e.Q.pop());
e.o[this.s] = r;
}
}, _.prototype.I = function(e) {
for (var t = b(e), n = t.charCodeAt(0) << 8 | t.charCodeAt(1), i = [], r = 2; r < 2 + n; r += 2) i.push(t.charCodeAt(r) << 8 | t.charCodeAt(r + 1));
this.C = i;
for (var o = [], a = 2 + n; a < t.length; ) {
var s = t.charCodeAt(a) << 8 | t.charCodeAt(a + 1), u = t.slice(a + 2, a + 2 + s);
o.push(u), a += 2 + s;
}
this.S = o;
}, _.prototype.y = function(e, t, n) {
for (t = t || 0, n = n || [], this.k = t, "string" == typeof e ? this.I(e) : (this.C = e,
this.S = n), this.r = !0, this.R = Date.now(); this.r; ) {
var i = this.C[this.k++];
if ("number" != typeof i) break;
var r = Date.now();
// if (500 < r - this.R) return;
this.R = r;
try {
this.c(i);
} catch (e) {
this.G = e, this.w && (this.k = this.w);
}
}
}, _.prototype.c = function(e) {
var t = (61440 & e) >> 12;
new this.U[t](e).c(this);
}, new _().y("AcLgB5MAnACoAJwBpAAAAJwCqAAgAhAAIAMYAmAGcFIYApwDgAGTACwDGAIwFGAGcHawBBoANECRACQAGAMwFBoDnAWhQDUUNEdkBnCusAYaADRAkQAkABgBEis0R5EAJAGwByAEGACcCKAAEgM0RCQFGAUSATRFZAZxBhgAtAk0QCQAGAUSAjRFZAZxKhgAtAo0QCQAEAAgBrALIAcYAJwIoAASATRBJAgYCBIANEZkBnN+EAgaBhQBOYAoBhQEOYQ0giQJGAiQABgAnAyABRgBGgk0UhD/MQ8zECAKEAgaBhQBOYAoBhQEOYQ0gpEAJAkYARoJNFIQ/zEPkAAgCRgKGggUATmBkgAaAJwMhAUaCTdQFAg5kTSTJAoQCBoGFAE5gCgGFAQ5hDSCkQAkCRgBGgk0UhD/MQ+QACAJGAoaCBQCOYGSABoAnAyEBRoJN1AUEDmRNJMkChgEGgoUPzmPkgAaB5wNhAU0wCQEGAQaChQGOZISPzZPkQAaB5wNhAU0wCQEGAQaChQMOZISPzZPkQAaB5wNhAU0wCQEGAQaChQSOZISPzZPkQAaB5wNhAU0wCQEGAgSAzRBJAhxUB4EUAAAAwUYIAAIBSITFQkTERwAAi0XABE9Ggk/MhIfCRA8PxARJDIPFQABSwAKCQ8XBSsPGQIeGQABSAAAAAY2ERMRCwQAAloYAAFaAEAMYwBLSHEfIxICWGoLJzYUHRUSYVQPIhkdLTgLLg0LJS4aRm0kWXkSCS9aXltYU21lYCESKTsSMjsjLTsQIQUEAAo5ExELKTQTGTwtAAY5ExELKy0=");

console.log(gen_xse_86('cxs123'))

检测点主要是这里:

1
2
3
4
case 2:
var r = e.Q.pop(), o = 0;
o = wx;
e.o[this.A] = "__g" == r ? E : o;

需要补充微信环境,类似windows