js逆向-加解密定位
作者:YXN-python 阅读量:70 发布日期:2025-03-06
接口分析
1、加密:
1)找到我们所需要抓取数据的接口;
2)观察请求头、cookies、请求参数、请求体中是否有加密参数;
3)分析加密参数的值是变化的还是固定不变的,可不可以直接复制;
(通过多次请求可以观察到有些加密参数的值虽然是个密文,但是每次请求中,这个加密参数的值却是不变的,那么我们就可以直接使用这个密文,不用去逆向它如何生成而来的)
4)分析加密参数的值是本地生成的还是服务器返回的。
(有些网站的加密参数的值就是在之前的请求中返回到了给我们,我们则不需要去逆向,直接找到返回密文的请求,对它进行请求然后将它返回的响应结果添加到我们数据接口的请求中来。当我们在前端页面中只执行了一个操作,不一定就是只对应一个请求,可能会连带多个请求,那么我们的加密参数的值可能就在前面的请求中返回给我们的)
2、解密:
1)找到我们所需要抓取数据的接口;
2)观察该请求返回回来的数据是否是密文。
定位技巧
1、关键字搜索
关键字并非只可以搜索参数名。
比如参数是sign,可以是sign、sign:、sign =、sign :、sign = 等等
(加密)encrypt(、(解密)decrypt(、
headers[
JSON.parse(、JSON.stringify(
interceptors
(请求拦截器interceptors.request)、(响应拦截器interceptors.response)
等等
2、正常堆栈分析
堆栈是程序执行时记录函数调用关系的数据结构,遵循"后进先出"(LIFO)原则。每当函数被调用时,其上下文会被压入堆栈;函数执行完毕时弹出堆栈。
3、异步堆栈分析
1)堆栈、任务队列以及事件循环
- 堆栈:JavaScript 引擎使用调用堆栈来管理函数调用。当一个函数被调用时,它会被压入调用堆栈中,执行完成后,它会被弹出堆栈。
- 任务队列:用于存储待执行的异步任务,分为宏任务队列和微任务队列。当异步操作完成时,其回调函数会被推入任务队列中,等待事件循环处理。
- 事件循环:事件循环负责协调调用堆栈和任务队列。当调用堆栈为空时,事件循环会从任务队列中取出任务并执行。
事件循环的工作方式:
- 执行堆栈中的同步代码;
- 同步代码执行完毕后,检查微任务队列。
- 执行所有微任务,直到队列为空。
- 检查宏任务队列,执行一个宏任务。
- 重复上述过程。
2)宏任务、微任务
宏任务:
- 定义:较大的异步任务,执行时间较长。
- 常见来源:setTimeout、setInterval、I/O 操作、UI 渲染
- 执行时机:微任务队列清空后,执行一个宏任务。
微任务:
- 定义:较小的异步任务,执行时间较短。
- 常见来源:Promise的 .then、.catch、.finally
- 执行时机:在当前宏任务结束后,立即执行所有微任务。
3)同步代码
console.log("1");
console.log("2");
// 输出顺序:1 → 2
// 特点:简单直观,1执行完了才执行2
4)Promise(微任务):
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); // 输出:1
return result + 1;
})
.then(result => {
console.log(result); // 输出:2
throw 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)); // 输出:错误
还有很多Promise 的静态方法,这里就不一一做赘述。
Promise实现异步代码
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.
// 微任务优先于宏任务执行,适合处理高优先级异步操作。
5)async/await(基于 Promise 的语法糖)
async用于声明一个异步函数。异步函数会隐式返回一个Promise对象。如果手动设置函数的返回值,那么也会自动变成Promise.resolve(返回值)。
await用于等待一个Promise的结果。await只能在async 函数中使用。等待它会暂停当前 async 函数的执行,直到Promise完成(resolve 或 reject)。
await会暂停 async 函数的执行,直到 Promise 完成。
Promise完成后,await 后面的代码会被安排在微任务队列中执行。
console.log("1");
async function example() {
console.log("2");
await new Promise(function (resolve) {
resolve(); // 立即将 Promise 状态变为 fulfilled
console.log("3"); // 这是 Promise 内部的同步代码,会立即执行
});
console.log("4"); // 这段代码会作为微任务执行,相当于.then()回调
}
example();
console.log("5");
// 输出顺序
// 1
// 2
// 3
// 5
// 4
6)setTimeout(宏任务)
setTimeout和setInterval都是JavaScript 提供的定时器函数,前者用于在指定的时间后执行某段代码(回调函数),后者用于按照指定的时间间隔重复执行某段代码(回调函数)。
如果相同延迟的setTimeout:严格按注册顺序执行,当延迟不同时,较短的延迟会先执行。
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3"); // 输出顺序:1 → 3 → 2
// 1执行完了执行3,setTimeout里面的回调函数加入宏任务队列,等待同步任务执行完再执行。
// 即使延迟设为 0,实际执行可能因同步代码阻塞而延迟。
// 属于异步中的宏任务,优先级低于微任务(如 Promise)。
7)组合
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。
8)堆栈先执行同步任务接着微任务然后再是宏任务
任务类型 | 执行优先级 | 典型实例 |
同步任务 | 最高(阻塞主线程) | console.log()、变量赋值、普通函数调用等 |
微任务 | 次高(宏任务之前) | Promise.then()、await等 |
宏任务 | 最低 | setTimeout、setInterval和DOM事件回调等 |
说白了就一句话,咱们逆向加解密的位置可能在异步的回调函数中。
4、hook
hook函数:在js逆向中,我们通常把替换原函数的过程都称为Hook。(重写会被调用的函数,然后使其debugger方便回溯调试,并不要改变原执行流程调用原函数)
参考文章:Js Hook
断点技巧
- 普通断点:普通断点就是直接点击js代码左边打上断点,程序在代码的指定行暂停执行,用于观察变量状态和调用堆栈。
- 条件断点:当指定条件为真时暂停执行。过滤循环中的特定迭代或特定参数值的触发。
- 日志断点:不暂停执行,仅在控制台输出日志。跟踪高频触发事件或记录变量变化。
- dom断点:在某个特定的DOM元素上设置了一个断点。一旦该元素被修改、删除或者属性发生变化,断点就会触发,浏览器会暂停执行JavaScript 代码,使你能够检查变化的内容、调试代码或者分析程序行为。
- xhr断点(俗称小黄人断点):xhr全称 XMLHttpRequest 。前面说过我们可能在前端页面中只操作了一下,但是不一定只发送一个请求,所以需要使用到xhr断点精准断到我们需要的请求。(注:主要针对xhr类型的请求)
- 事件监听断点:在事件触发时暂停。(如点击、键盘、脚本等事件)
YXN-python
2025-03-06