一、站点分析
MTime 时光网是一个电影媒体与电商服务平台,而这次做的模拟登录则是依靠其手机端站点,站点地址为:https://m.mtime.cn/#。切换到登录页面,再分别输入账号和错误的密码,点击登录,登录失败,截图如下:
打开开发者工具, 选择“Network”,切换到“XHR”选项,找到一条名为 login.api 的请求,打开后可以发现就是登录所发送的请求,再查看该请求的参数部分,截图如下:
二、参数破解
1.参数分析
经过前面的分析可知有五个参数需要获取,分别是 t、name、password、code 和 codeId,其中 code 和 codeId 目前看来是空的,无须处理,而 name 就是输入的手机号,password 应该是输入的密码加密后的结果,剩下一个 t 还不知道是什么含义。
2.参数获取
在开发者工具中,Ctrl + F 全局搜索“password”,找到如下的 JavaScript 文件:
https://static3.mtime.cn/html5/20200116143308/js/views/member/signin.js
打开该文件后搜索“password”,首先是获取 name 属性为“password”的输入框,在下文中还发现了 vcode 和 vcodeId,这两个就是后面请求所需的 code 和 vcode 参数的值,截图如下:
继续搜索“password”,可以找到一个 getPassword() 方法,用于获取输入的密码内容,截图如下:
接着搜索“password”,找到如下内容:
这就是登录请求时的参数部分,其中密码 password 是将输入的密码进行加密后的结果,使用的是 f.desEcbPkcs7 方法,那这个方法具体是什么呢?
3.加密方法
在上面的 JS 文件中的 217 行打上断点,然后刷新页面并重新登录,页面会进入 debugger 模式,然后选中 desEcbPkcs7 部分,点击后跳转到 app.all.min.js 中的如下代码部分:
这个 af 函数就是加密方法了,其中用到了一个变量 CryptoJS,要获取这个变量的定义,就在上面代码中的1033行打上断点,再重新登录一遍,定位到 CryptoJS 的定义部分,截图如下:
对于变量 CryptoJS 的定义包含在 libs.all.min.js 中,但这个文件中的代码量比较大,若全部复制下来使用会不方便,而我们也只需要得到对变量 CryptoJS 进行定义的代码就够了,所以建议先把该 JS 文件保存到本地,再用编辑器打开,就能很快地得到我们所需要的代码了,即使如此还是有一千四百多行(汗~)。
1 var CryptoJS = CryptoJS || function (g, w) { 2 var m = {} 3 , q = m.lib = {} 4 , j = q.Base = function () { 5 function a() { 6 } 7 8 return { 9 extend: function (e) { 10 a.prototype = this; 11 var c = new a; 12 return e && c.mixIn(e), 13 c.$super = this, 14 c 15 }, 16 create: function () { 17 var c = this.extend(); 18 return c.init.apply(c, arguments), 19 c 20 }, 21 init: function () { 22 }, 23 mixIn: function (c) { 24 for (var f in c) { 25 c.hasOwnProperty(f) && (this[f] = c[f]) 26 } 27 c.hasOwnProperty("toString") && (this.toString = c.toString) 28 }, 29 clone: function () { 30 return this.$super.extend(this) 31 } 32 } 33 }() 34 , v = q.WordArray = j.extend({ 35 init: function (a, c) { 36 a = this.words = a || [], 37 this.sigBytes = c != w ? c : 4 * a.length 38 }, 39 toString: function (a) { 40 return (a || x).stringify(this) 41 }, 42 concat: function (a) { 43 var o = this.words 44 , f = a.words 45 , l = this.sigBytes 46 , a = a.sigBytes; 47 this.clamp(); 48 if (l % 4) { 49 for (var c = 0; c < a; c++) { 50 o[l + c >>> 2] |= (f[c >>> 2] >>> 24 - 8 * (c % 4) & 255) << 24 - 8 * ((l + c) % 4) 51 } 52 } else { 53 if (65535 < f.length) { 54 for (c = 0; c < a; c += 4) { 55 o[l + c >>> 2] = f[c >>> 2] 56 } 57 } else { 58 o.push.apply(o, f) 59 } 60 } 61 return this.sigBytes += a, 62 this 63 }, 64 clamp: function () { 65 var c = this.words 66 , a = this.sigBytes; 67 c[a >>> 2] &= 4294967295 << 32 - 8 * (a % 4), 68 c.length = g.ceil(a / 4) 69 }, 70 clone: function () { 71 var a = j.clone.call(this); 72 return a.words = this.words.slice(0), 73 a 74 }, 75 random: function (e) { 76 for (var a = [], c = 0; c < e; c += 4) { 77 a.push(4294967296 * g.random() | 0) 78 } 79 return v.create(a, e) 80 } 81 }) 82 , p = m.enc = {} 83 , x = p.Hex = { 84 stringify: function (a) { 85 for (var o = a.words, a = a.sigBytes, f = [], l = 0; l < a; l++) { 86 var c = o[l >>> 2] >>> 24 - 8 * (l % 4) & 255; 87 f.push((c >>> 4).toString(16)), 88 f.push((c & 15).toString(16)) 89 } 90 return f.join("") 91 }, 92 parse: function (a) { 93 for (var i = a.length, c = [], f = 0; f < i; f += 2) { 94 c[f >>> 3] |= parseInt(a.substr(f, 2), 16) << 24 - 4 * (f % 8) 95 } 96 return v.create(c, i / 2) 97 } 98 } 99 , b = p.Latin1 = { 100 stringify: function (a) { 101 for (var i = a.words, a = a.sigBytes, c = [], f = 0; f < a; f++) { 102 c.push(String.fromCharCode(i[f >>> 2] >>> 24 - 8 * (f % 4) & 255)) 103 } 104 return c.join("") 105 }, 106 parse: function (a) { 107 for (var i = a.length, c = [], f = 0; f < i; f++) { 108 c[f >>> 2] |= (a.charCodeAt(f) & 255) << 24 - 8 * (f % 4) 109 } 110 return v.create(c, i) 111 } 112 } 113 , h = p.Utf8 = { 114 stringify: function (a) { 115 try { 116 return decodeURIComponent(escape(b.stringify(a))) 117 } catch (c) { 118 throw Error("Malformed UTF-8 data") 119 } 120 }, 121 parse: function (a) { 122 return b.parse(unescape(encodeURIComponent(a))) 123 } 124 } 125 , k = q.BufferedBlockAlgorithm = j.extend({ 126 reset: function () { 127 this._data = v.create(), 128 this._nDataBytes = 0 129 }, 130 _append: function (a) { 131 "string" == typeof a && (a = h.parse(a)), 132 this._data.concat(a), 133 this._nDataBytes += a.sigBytes 134 }, 135 _process: function (y) { 136 var f = this._data 137 , s = f.words 138 , e = f.sigBytes 139 , l = this.blockSize 140 , z = e / (4 * l) 141 , z = y ? g.ceil(z) : g.max((z | 0) - this._minBufferSize, 0) 142 , y = z * l 143 , e = g.min(4 * y, e); 144 if (y) { 145 for (var c = 0; c < y; c += l) { 146 this._doProcessBlock(s, c) 147 } 148 c = s.splice(0, y), 149 f.sigBytes -= e 150 } 151 return v.create(c, e) 152 }, 153 clone: function () { 154 var a = j.clone.call(this); 155 return a._data = this._data.clone(), 156 a 157 }, 158 _minBufferSize: 0 159 }); 160 q.Hasher = k.extend({ 161 init: function () { 162 this.reset() 163 }, 164 reset: function () { 165 k.reset.call(this), 166 this._doReset() 167 }, 168 update: function (a) { 169 return this._append(a), 170 this._process(), 171 this 172 }, 173 finalize: function (a) { 174 return a && this._append(a), 175 this._doFinalize(), 176 this._hash 177 }, 178 clone: function () { 179 var a = k.clone.call(this); 180 return a._hash = this._hash.clone(), 181 a 182 }, 183 blockSize: 16, 184 _createHelper: function (a) { 185 return function (e, c) { 186 return a.create(c).finalize(e) 187 } 188 }, 189 _createHmacHelper: function (a) { 190 return function (e, c) { 191 return d.HMAC.create(a, c).finalize(e) 192 } 193 } 194 }); 195 var d = m.algo = {}; 196 return m 197 }(Math) 198 , CryptoJS = CryptoJS || function (g, w) { 199 var m = {} 200 , q = m.lib = {} 201 , j = q.Base = function () { 202 function a() { 203 } 204 205 return { 206 extend: function (e) { 207 a.prototype = this; 208 var c = new a; 209 return e && c.mixIn(e), 210 c.$super = this, 211 c 212 }, 213 create: function () { 214 var c = this.extend(); 215 return c.init.apply(c, arguments), 216 c 217 }, 218 init: function () { 219 }, 220 mixIn: function (c) { 221 for (var f in c) { 222 c.hasOwnProperty(f) && (this[f] = c[f]) 223 } 224 c.hasOwnProperty("toString") && (this.toString = c.toString) 225 }, 226 clone: function () { 227 return this.$super.extend(this) 228 } 229 } 230 }() 231 , v = q.WordArray = j.extend({ 232 init: function (a, c) { 233 a = this.words = a || [], 234 this.sigBytes = c != w ? c : 4 * a.length 235 }, 236 toString: function (a) { 237 return (a || x).stringify(this) 238 }, 239 concat: function (a) { 240 var o = this.words 241 , f = a.words 242 , l = this.sigBytes 243 , a = a.sigBytes; 244 this.clamp(); 245 if (l % 4) { 246 for (var c = 0; c < a; c++) { 247 o[l + c >>> 2] |= (f[c >>> 2] >>> 24 - 8 * (c % 4) & 255) << 24 - 8 * ((l + c) % 4) 248 } 249 } else { 250 if (65535 < f.length) { 251 for (c = 0; c < a; c += 4) { 252 o[l + c >>> 2] = f[c >>> 2] 253 } 254 } else { 255 o.push.apply(o, f) 256 } 257 } 258 return this.sigBytes += a, 259 this 260 }, 261 clamp: function () { 262 var c = this.words 263 , a = this.sigBytes; 264 c[a >>> 2] &= 4294967295 << 32 - 8 * (a % 4), 265 c.length = g.ceil(a / 4) 266 }, 267 clone: function () { 268 var a = j.clone.call(this); 269 return a.words = this.words.slice(0), 270 a 271 }, 272 random: function (e) { 273 for (var a = [], c = 0; c < e; c += 4) { 274 a.push(4294967296 * g.random() | 0) 275 } 276 return v.create(a, e) 277 } 278 }) 279 , p = m.enc = {} 280 , x = p.Hex = { 281 stringify: function (a) { 282 for (var o = a.words, a = a.sigBytes, f = [], l = 0; l < a; l++) { 283 var c = o[l >>> 2] >>> 24 - 8 * (l % 4) & 255; 284 f.push((c >>> 4).toString(16)), 285 f.push((c & 15).toString(16)) 286 } 287 return f.join("") 288 }, 289 parse: function (a) { 290 for (var i = a.length, c = [], f = 0; f < i; f += 2) { 291 c[f >>> 3] |= parseInt(a.substr(f, 2), 16) << 24 - 4 * (f % 8) 292 } 293 return v.create(c, i / 2) 294 } 295 } 296 , b = p.Latin1 = { 297 stringify: function (a) { 298 for (var i = a.words, a = a.sigBytes, c = [], f = 0; f < a; f++) { 299 c.push(String.fromCharCode(i[f >>> 2] >>> 24 - 8 * (f % 4) & 255)) 300 } 301 return c.join("") 302 }, 303 parse: function (a) { 304 for (var i = a.length, c = [], f = 0; f < i; f++) { 305 c[f >>> 2] |= (a.charCodeAt(f) & 255) << 24 - 8 * (f % 4) 306 } 307 return v.create(c, i) 308 } 309 } 310 , h = p.Utf8 = { 311 stringify: function (a) { 312 try { 313 return decodeURIComponent(escape(b.stringify(a))) 314 } catch (c) { 315 throw Error("Malformed UTF-8 data") 316 } 317 }, 318 parse: function (a) { 319 return b.parse(unescape(encodeURIComponent(a))) 320 } 321 } 322 , k = q.BufferedBlockAlgorithm = j.extend({ 323 reset: function () { 324 this._data = v.create(), 325 this._nDataBytes = 0 326 }, 327 _append: function (a) { 328 "string" == typeof a && (a = h.parse(a)), 329 this._data.concat(a), 330 this._nDataBytes += a.sigBytes 331 }, 332 _process: function (y) { 333 var f = this._data 334 , s = f.words 335 , e = f.sigBytes 336 , l = this.blockSize 337 , z = e / (4 * l) 338 , z = y ? g.ceil(z) : g.max((z | 0) - this._minBufferSize, 0) 339 , y = z * l 340 , e = g.min(4 * y, e); 341 if (y) { 342 for (var c = 0; c < y; c += l) { 343 this._doProcessBlock(s, c) 344 } 345 c = s.splice(0, y), 346 f.sigBytes -= e 347 } 348 return v.create(c, e) 349 }, 350 clone: function () { 351 var a = j.clone.call(this); 352 return a._data = this._data.clone(), 353 a 354 }, 355 _minBufferSize: 0 356 }); 357 q.Hasher = k.extend({ 358 init: function () { 359 this.reset() 360 }, 361 reset: function () { 362 k.reset.call(this), 363 this._doReset() 364 }, 365 update: function (a) { 366 return this._append(a), 367 this._process(), 368 this 369 }, 370 finalize: function (a) { 371 return a && this._append(a), 372 this._doFinalize(), 373 this._hash 374 }, 375 clone: function () { 376 var a = k.clone.call(this); 377 return a._hash = this._hash.clone(), 378 a 379 }, 380 blockSize: 16, 381 _createHelper: function (a) { 382 return function (e, c) { 383 return a.create(c).finalize(e) 384 } 385 }, 386 _createHmacHelper: function (a) { 387 return function (e, c) { 388 return d.HMAC.create(a, c).finalize(e) 389 } 390 } 391 }); 392 var d = m.algo = {}; 393 return m 394 }(Math); 395 (function () { 396 var a = CryptoJS 397 , b = a.lib.WordArray; 398 a.enc.Base64 = { 399 stringify: function (c) { 400 var k = c.words 401 , f = c.sigBytes 402 , h = this._map; 403 c.clamp(); 404 for (var c = [], d = 0; d < f; d += 3) { 405 for (var j = (k[d >>> 2] >>> 24 - 8 * (d % 4) & 255) << 16 | (k[d + 1 >>> 2] >>> 24 - 8 * ((d + 1) % 4) & 255) << 8 | k[d + 2 >>> 2] >>> 24 - 8 * ((d + 2) % 4) & 255, g = 0; 4 > g && d + 0.75 * g < f; g++) { 406 c.push(h.charAt(j >>> 6 * (3 - g) & 63)) 407 } 408 } 409 if (k = h.charAt(64)) { 410 for (; c.length % 4;) { 411 c.push(k) 412 } 413 } 414 return c.join("") 415 }, 416 parse: function (d) { 417 var d = d.replace(/\s/g, "") 418 , h = d.length 419 , j = this._map 420 , k = j.charAt(64); 421 k && (k = d.indexOf(k), 422 -1 != k && (h = k)); 423 for (var k = [], i = 0, l = 0; l < h; l++) { 424 if (l % 4) { 425 var c = j.indexOf(d.charAt(l - 1)) << 2 * (l % 4) 426 , g = j.indexOf(d.charAt(l)) >>> 6 - 2 * (l % 4); 427 k[i >>> 2] |= (c | g) << 24 - 8 * (i % 4), 428 i++ 429 } 430 } 431 return b.create(k, i) 432 }, 433 _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" 434 } 435 } 436 )(), 437 function (c) { 438 function m(a, x, q, v, f, w, u) { 439 return a = a + (x & q | ~x & v) + f + u, 440 (a << w | a >>> 32 - w) + x 441 } 442 443 function h(a, x, q, v, f, w, u) { 444 return a = a + (x & v | q & ~v) + f + u, 445 (a << w | a >>> 32 - w) + x 446 } 447 448 function k(a, x, q, v, f, w, u) { 449 return a = a + (x ^ q ^ v) + f + u, 450 (a << w | a >>> 32 - w) + x 451 } 452 453 function g(a, x, q, v, f, w, u) { 454 return a = a + (q ^ (x | ~v)) + f + u, 455 (a << w | a >>> 32 - w) + x 456 } 457 458 var l = CryptoJS 459 , j =