声明
本文仅作学习参考,如有侵权请联系作者删除,切勿用于其他途径。若认为本文对您有所帮助,欢迎关注或收藏!
加解密定位
当我们从某个网站的接口抓取数据时,往往会需要携带加密参数或者需要解密返回回来的密文。但是网站会加载大量JavaScript文件,要在这么多JavaScript文件快速找到关键的加解密位置,显得尤为重要。
接口分析
1、加密:
1)找到我们所需要抓取数据的接口;
2)观察请求头、cookies、请求参数、请求体中是否有加密参数;
3)分析加密参数的值是变化的还是固定不变的,可不可以直接复制;
(通过多次请求可以观察到有些加密参数的值虽然是个密文,但是每次请求中,这个加密参数的值却是不变的,那么我们就可以直接使用这个密文,不用去逆向它如何生成而来的)
4)分析加密参数的值是本地生成的还是服务器返回的。
(有些网站的加密参数的值就是在之前的请求中返回到了给我们,我们则不需要去逆向,直接找到返回密文的请求,对它进行请求然后将它返回的响应结果添加到我们数据接口的请求中来。当我们在前端页面中只执行了一个操作,不一定就是只对应一个请求,可能会连带多个请求,那么我们的加密参数的值可能就在前面的请求中返回给我们的)
2、解密:
1)找到我们所需要抓取数据的接口;
2)观察该请求返回回来的数据是否是密文。
function funcA() {console.log("进入 funcA");funcB(); // 调用 funcBconsole.log("离开 funcA");}function funcB() {console.log("进入 funcB");funcC(); // 调用 funcCconsole.log("离开 funcB");}function funcC() {console.log("进入 funcC");console.trace("当前堆栈"); //打印堆栈console.log("离开 funcC");}// 执行入口funcA();// ===== 输出结果 =====// 进入 funcA// 进入 funcB// 进入 funcC// 当前堆栈// funcC (test.js:15:11)// funcB (test.js:9:3)// funcA (test.js:3:3)// (test.js:20:1) 所有不在任何具体名字的函数内(匿名函数)以及全局作用域内的代码执行,都会被标记为 (anonymous)。// 离开 funcC// 离开 funcB// 离开 funcA// 相当于全局作用域下执行程序,(anonymous)被压入堆栈// 调用funcA,funcA被压入堆栈// funcA内调用funcB,funcB被压入堆栈// funcB内调用funcC,funcC被压住堆栈// 然后funcC执行完弹出堆栈,// funcB执行完弹出堆栈,// funcA执行完弹出堆栈,// 最后全局作用域下的调用执行结束也弹出堆栈。
// 堆栈:JavaScript 引擎使用调用堆栈来管理函数调用。当一个函数被调用时,它会被压入调用堆栈中,执行完成后,它会被弹出堆栈。// 任务队列:用于存储待执行的异步任务,分为宏任务队列和微任务队列。当异步操作完成时,其回调函数会被推入任务队列中,等待事件循环处理。// 事件循环:事件循环负责协调调用堆栈和任务队列。当调用堆栈为空时,事件循环会从任务队列中取出任务并执行。// 事件循环的工作方式:// 1、执行堆栈中的同步代码;// 2、同步代码执行完毕后,检查微任务队列。// 3、执行所有微任务,直到队列为空。// 4、检查宏任务队列,执行一个宏任务。// 5、重复上述过程。
// 宏任务:// 定义:较大的异步任务,执行时间较长。// 常见来源:setTimeout、setInterval、I/O 操作、UI 渲染// 执行时机:微任务队列清空后,执行一个宏任务。// 微任务:// 定义:较小的异步任务,执行时间较短。// 常见来源:Promise的 .then、.catch、.finally// 执行时机:在当前宏任务结束后,立即执行所有微任务。
console.log("1");console.log("2");// 输出顺序:1 → 2// 特点:简单直观,1执行完了才执行2
Promise 是 JavaScript 中的一种异步编程解决方案,用于处理异步操作的结果(成功或失败)。
Promise有三种状态
pending(进行中):初始状态,既没有成功也没有失败。
fulfilled(已成功):操作成功完成。
rejected(已失败):操作失败。
状态一旦从pending变为fulfilled或rejected,就不可更改(不可逆)。
可以通过 .then()(成功执行) 和 .catch()(失败执行) 以及.finally ()(无论成功还是失败都执行)方法处理结果。
基本语法:
const promise = new Promise((resolve, reject) => {const success = true; // 模拟操作结果if (success) {resolve("操作成功"); // 状态变为 fulfilled} else {reject("操作失败");}});// 使用 .then() 和 .catch() 处理结果promise.then(result => {console.log(result); // 输出:操作成功}).catch(error => {console.error(error);}).finally(() => {console.log("我就要执行") // 输出我就要执行});
Promise的链式调用:
.then()返回一个新的Promise,可以连续调用,形成链式结构。
.catch()用于捕获链中任何地方抛出的错误。
new Promise((resolve, reject) => {resolve(1);}).then(result => {console.log(result); // 输出:1return result + 1;}).then(result => {console.log(result); // 输出:2throw new Error('发生错误'); // 抛出错误}).then(result => {console.log(result); // 不会被执行}).catch(error => {console.error(error.message); // 捕获错误并输出:发生错误});
Promise 的静态方法:
Promise.resolve(value):返回一个状态为fulfilled的Promise,结果为value。
Promise.resolve('成功').then(result => console.log(result)); // 输出:成功Promise.reject(reason):返回一个状态为rejected的Promise,结果为reason。
Promise.reject('失败').catch(error => console.error(error)); // 输出:失败Promise.all(iterable):接收一个Promise数组,返回一个新的Promise。如果所有Promise都为成功,则新Promise的结果为所有结果的数组。如果有一个Promise失败则新Promise立即失败。
const p1 = Promise.resolve(1); // p1成功const p2 = Promise.resolve(2); // p2成功const p3 = Promise.reject('错误'); // p3失败Promise.all([p1, p2, p3]).then(results => console.log(results)).catch(error => console.error(error)); // 输出:错误
console.log('1');const myPromise = new Promise((resolve, reject) => {console.log("2");resolve("成功");// 如果失败,可以使用 reject("失败");console.log("3")});myPromise.then((res) => console.log("4" + res));console.log("5");// 输出顺序:1 → 2 → 3 → 5 → 4成功// 1执行完了执行构造函数中的代码执行2,然后执行mypromise的状态从Pending转到Fulfilled(成功),执行3,.then()、.catch()以及.finally()里面的回调函数是异步执行的,它们会被放入微任务队列中,然后执行5.此时同步代码已经执行完,执行微任务的代码输出4.// 微任务优先于宏任务执行,适合处理高优先级异步操作。
console.log("1");async function example() {console.log("2");await new Promise(function (resolve) {resolve(); // 立即将 Promise 状态变为 fulfilledconsole.log("3"); // 这是 Promise 内部的同步代码,会立即执行});console.log("4"); // 这段代码会作为微任务执行,相当于.then()回调}example();console.log("5");// 输出顺序// 1// 2// 3// 5// 4
console.log("1");setTimeout(() => console.log("2"), 0);console.log("3"); // 输出顺序:1 → 3 → 2// 1执行完了执行3,setTimeout里面的回调函数加入宏任务队列,等待同步任务执行完再执行。// 即使延迟设为 0,实际执行可能因同步代码阻塞而延迟。// 属于异步中的宏任务,优先级低于微任务(如 Promise)。
console.log("1");setTimeout(() => {console.log("2"); // 宏任务}, 0);Promise.resolve().then(() => {console.log("3"); // 微任务});async function main() {await 0;console.log("4"); // 微任务}main();console.log("5");// 执行顺序:// 1// 5// 3// 4// 2// console.log("1") → 输出 1//setTimeout 的回调(输出2)被放入宏任务队列。// Promise.resolve().then 的回调(输出3)被放入微任务队列。// 调用 main() 函数,遇到 await 0(等价于 await Promise.resolve(0)),函数暂停,console.log("4") 被包装成微任务,放入微任务队列。// console.log("5") → 输出 5。// 处理微任务队列(先进先出):// 先执行 Promise.resolve().then 的回调 → 输出 3。// 再执行 main() 中 await 后的代码 → 输出 4。// 处理宏任务队列://setTimeout 的回调 → 输出 2。
| 次高(宏任务之前) | ||
1)Hook Eval
(function () {// 保存原始的 eval 方法window.__cr_eval = window.eval;// 自定义 eval 方法var myEval = function (src) {// 打印被传递到 eval 的代码console.log("执行的 eval 代码:");console.log(src);console.log("=============== eval end ===============");// 触发调试器,便于调试debugger;// 调用原始的 eval 方法return window.__cr_eval(src);};// 绑定上下文并保留原始 toString 方法var _myEval = myEval.bind(null);_myEval.toString = window.__cr_eval.toString;// 使用 Object.defineProperty 重写 window.evalObject.defineProperty(window, 'eval', {value: _myEval,writable: false, // 禁止重新赋值configurable: false // 禁止重新配置});console.log("window.eval 已被挂钩");})();
(function() {// 保存原始的 JSON.stringify 方法var originalStringify = JSON.stringify;// 重写 JSON.stringify 方法JSON.stringify = function(params) {// 打印日志,方便调试console.log("Hook JSON.stringify ->", params);// 触发调试器debugger;// 调用原始的 JSON.stringify 方法return originalStringify(params);};console.log("JSON.stringify 已被挂钩");})();
(function() {// 保存原始的 JSON.parse 方法var originalParse = JSON.parse;// 重写 JSON.parse 方法JSON.parse = function(params) {// 打印日志,便于调试console.log("Hook JSON.parse ->", params);// 触发调试器debugger;// 调用原始的 JSON.parse 方法return originalParse(params);};console.log("JSON.parse 已被挂钩");})();
(function () {// 保存原始的 XMLHttpRequest.prototype.setRequestHeader 方法var originalSetRequestHeader = window.XMLHttpRequest.prototype.setRequestHeader;// 重写 setRequestHeader 方法window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) {// 检查是否拦截到 Authorization 头if (key === 'Authorization') {console.log("拦截到 Authorization 请求头:", value);// 触发调试器debugger;}// 调用原始 setRequestHeader 方法return originalSetRequestHeader.apply(this, arguments);};console.log("XMLHttpRequest.setRequestHeader 已被挂钩");})();
(function () {'use strict';// 临时存储 cookie 的变量var cookieTemp = '';// 使用 Object.defineProperty 重写 document.cookie 的 setter 和 getterObject.defineProperty(document, 'cookie', {set: function (val) {// 如果设置的 cookie 包含特定关键字 '__dfp',触发调试器if (val.indexOf('__dfp') !== -1) {console.log('拦截到包含 "__dfp" 的 cookie 设置:', val);debugger;}// 打印捕获到的 cookie 设置console.log('Hook 捕获到 cookie 设置 ->', val);// 更新临时存储变量cookieTemp = val;return val;},get: function () {// 返回临时存储的 cookie``return cookieTemp;}});console.log('document.cookie 的 setter 和 getter 已被挂钩');})();






































































Promise.resolve(t).then(e[0], e[1]) // 使用索引0和1(成功回调为函数,失败回调为undefined).then(e[2], e[3]) // 使用索引2和3(成功回调为undefined,失败回调为函数).then(e[4], e[5]) // 使用索引4和5(成功回调为函数,失败回调为undefined).then(e[6], e[7]) // 使用索引6和7(成功回调为函数,失败回调为undefined).then(e[8], e[9]) // 使用索引8和9(成功回调为函数,失败回调为undefined).then(e[10], e[11]) // 使用索引10和11(成功回调为函数,失败回调为undefined).then(e[12], e[13]) // 使用索引12和13(成功回调为undefined,失败回调为函数).then(e[14], e[15]) // 使用索引14和15(成功回调为函数,失败回调为undefined)


















(function () {// 保存原始的 XMLHttpRequest.prototype.setRequestHeader 方法var originalSetRequestHeader = window.XMLHttpRequest.prototype.setRequestHeader;// 重写 setRequestHeader 方法window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) {// 检查是否拦截到 hexin-v 头if (key === 'hexin-v') {console.log("拦截到 hexin-v 请求头:", value);// 触发调试器debugger;}// 调用原始 setRequestHeader 方法return originalSetRequestHeader.apply(this, arguments);};console.log("XMLHttpRequest.setRequestHeader 已被挂钩");})();










