2.如何定位加密

明廷盛 嘻嘻😁

第一章 哪里可以加密

第一节 每次请求可以携带什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> 回顾网站数据交换的过程(假设高加密的网址):
①页面收集数据: pageindex, total, searchkey,...,时间戳,特定**鉴权信息**[加密A]
°页面发送数据给==>后端°
②后端处理数据: pageindex,...,对鉴权信息`解密A`并验证===>**返回数据**[加密B]
°后端返回数据给==>前端°
③页面拿到数据: 对后端给的数据`解密B`(抓包看到的),并渲染到页面上

> 每次请求可以携带什么[后面为在开发者工具的具体位置]**加密A**
1.正常请求参数(page, total,keyVale..)--->请求参数[载荷]
2.用户信息(username,userpassword...)--->Cookie[标头.Cookie/浏览器.内存.存储.Cookie]
3.用户浏览器信息(UA,Sign,TimeStamp..)--->请求头[标头.请求标头]
> 服务器返回什么[后面为在开发者工具的具体位置]**加密B**
4.响应数据(data,statecode..)--->[响应]

> 由此推出
也就是上述这4个地方可以加密,我们就只需要观察这4个地方是否有加密,有我们找JS解密,即可模拟发送请求

第二节 可以加密的地方

1.2.1 误区纠正GET和POST

  • 查询字符串参数: 就是拼接在URL?后面的内容, 只是浏览器为了展示在, “载荷”一栏中展示, 不要错认为是表单数据了!!!
  • GET请求: 点击”载荷”一栏后看到的是 “查询字符串参数” ; 这个参数是拼接在网址后面的, 在 link
  • POST请求: 点击”载荷”一栏后看到的是 “表单数据” ; 也可以有 “查询字符串参数” link

1.2.2 四大加密位置

网站名称请求头请求参数Cookie响应数据
中国观鸟技术中心
同花顺问财神
极志愿

Pasted image 20250206162104|650Pasted image 20250206162229|650
Pasted image 20250207093600|625Pasted image 20250207094416|675

第二章 定位加密—DOM/XHR

第一节 DOM断点

2.1.1 概念解析

1
**用户在页面触发事件** --> 构造请求对象 --> 请求拦截器 --> [加密数据] --> 发送请求 --> 返回数据 --> 响应拦截器 --> 请求成功的回调 --> 展示到开发者工具包中
  • $ 概念: 使用 DOM事件断点,你可以指定在哪些 DOM 事件上设置断点,比如点击(click)、改变(change)、加载(load)等。一旦设置了 DOM 事件断点,当相应的事件被触发时,浏览器会自动在触发事件的 JavaScript 代码行上暂停执行
  • $ 特点: 执行的比较靠前, 往后找, 距离加密函数比较远

2.1.2 实战DOM断点调试

需求: 找到 link 加密的位置

  1. 选中需要要定位的元素, 右侧 “事件监听器” 选中click 下的文件一个个进去下断点
  • click下可能不止一个文件
  • 文件不一定是JS, 如下就是HTML, 但调试下一步, 就会进到 Passprt.Login()方法
    |875
    |875

第二节 XHR断点

XHR可能不是最快的, 但是一定能定位到加密的方法

2.2.1 概念解析

1
用户在页面触发事件 --> 构造请求对象 --> 请求拦截器 --> **发送请求** --> 返回数据 --> 响应拦截器 --> 请求成功的回调 --> 展示到开发者工具包中
  • $ 概念: XMLHttpRequest, 浏览器自动帮你拦截 “指定URL” 发请求的 “send方法”
  • $ 特点: 往前找, 栈底找
  • & 说明:
    • ①XHR(XMLHttpRequest)是浏览器原生API, 底层通信协议实现
    • ②无论是ajax还是axios等其底层都是用的XHR发请求, 浏览器中发请求90%都是XHR
    • ③因为网址用的是ajax/axios, 所以他们的开发人员调用的是$.get()方法, 但是底层都会到XMLHttpRequest.send()方法去真正发请求
  • ! 注意: 浏览器自带的xhr拦截的是XMLHttpRequest.send()方法,

2.2.2 XHR完整请求流程

  • $ 语法: ①xhr.open()这个方法初始化请求 ②xhr.send()真正的发送请求 ③xhr.onreadystatechange() 成功/失败的回调
ins
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
// 1. 创建实例
const xhr = new XMLHttpRequest();

// 2. 初始化请求(未真正发送)
xhr.open('GET', 'https://api.example.com/data', true); // 第三个参数为是否异步

// 3. 设置请求头(可选)
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer token123');

// 4. 事件监听(核心回调)[必须写在 open之后, send之前]
xhr.onreadystatechange = function() {
// 请求状态变化时触发(会多次触发)
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('成功响应:', xhr.responseText);
} else {
console.error('请求失败:', xhr.status);
}
}
};

// 其他事件监听方式
xhr.addEventListener('load', function() {
console.log('请求完成');
});
xhr.addEventListener('error', function() {
console.error('网络错误');
});
xhr.addEventListener('timeout', function() {
console.error('请求超时');
});

// 5. 配置超时(单位毫秒)
xhr.timeout = 5000;

// 6. 发送请求(GET请求通常不传body)
xhr.send(/* POST数据放这里,例如 JSON.stringify(data) */);

2.2.3 axios拦截器

  • & 说明:
    • ①基于xhr的有ajax/$, axios, Fetch API, umi-request这些都可以发请求, 底层用的都是XHR
    • ②并且每个都可以实现 “请求拦截“, 和 “响应拦截
    • ③而在 拦截方法 里面就有可能存在加密/解密, 由此就可以定位 (但需要注意不是所有的网址都用拦截器)

      这里就展示axios的拦截器

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
// npm install axios
axios = require('axios')
//设置请求拦截器
axios.interceptors.request.use(function (config) {
console.log('请求拦截器 成功')
config.headers['sign'] = 'lili'
return config;
}, function (error) {
console.log('请求拦截器 失败')
return Promise.reject(error);
});

//设置响应拦截器
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功')
console.log('调解密函数进行解密数据')
// 鉴权通过后, 加密显示在 调试工具的包中给你看
return response.data; //修改响应数据
}, function (error) {
console.log('响应拦截器 失败')
return Promise.reject(error);
});

//发送请求
axios.get('http://httpbin.org/get').then(res=>console.log(res))

2.2.4 实战XHR断点调试

需求: 找到 link 加密的位置

  1. 抓包, 找到需要卡的网址, 然后 “掐头去尾“ 复制 “路径“ 部分
1
2
3
https://oauth.d.cn/auth/login?query_parameters...#section1
└──┬─┘ └───┬──────┘└───┬─────┘└─────┬─────┘ └───┬───┘
协议 域名 路径 查询参数 片段(不发给服务器, 只供客户端用)
  1. 粘贴到如下位置, 并打钩, 然后所有的包含这个 “路径” 的请求都会断住
  • ! 注意: 这个是断在xhr.send()位置
    |575

2.2.5 XHR进阶技巧❗

  • $ 技巧一: 对栈进行二分 去看
    • & 举例: 例如栈为A, B, C, D(D为栈底); 如果A加密, 看D; 如果D没加密, 看B; 如果B没加密, C加密===>加密在C; 二分时间O(nlogn)
  • $ 技巧二: 在异步的回调中加密
    • & 说明: n.then(成功的回调, 失败的回调)这里的n.then是在一个for循环里面的, 回调函数是放在一个 “长度为6的数组” 中的, 那其中0, 2, 4就是成功的回调(t.shift()方法是删除数组第0个元素, 并返回) 那加密就是在0, 2, 4里面去找
      |850
  • $ 技巧三: 栈突然往前跳!
    • & 说明: 还记得拦截器吗? 服务器返回数据 –> 拦截器 –> 成功的回调; 如果拦截器写在前面的栈里面, 当调用成功的回调时就会前跳
      |550

第三节 搜索关键字

搜索关键字的技巧比较多, 也是最快的, 常见的有以下几种

  1. 同一个”请求参数”中比较明显的参数进行搜索,
  2. 和启动器结合, 搜索关键中, 在启动器方法里面的
  3. 精确搜索, (比如要pass 排除password等), pass: pass=…
    |625

第三章 定位加密—Hook

link: https://www.cnblogs.com/xiaoweigege/p/14954648.html#%E8%BF%87debugger-%E9%98%BF%E5%B8%83%E7%89%9B%E9%80%BC

第一节 Hook JSON.parse

1
用户在页面触发事件 --> 构造请求对象 --> 请求拦截器 --> 发送请求 --> **返回数据** --> 响应拦截器 --> 请求成功的回调 --> 展示到开发者工具包中
请求头请求参数Cookie响应数据
JSON.parse

3.1.1 适用场景

1
2
js对象(字典/表单) ---JSON.stringify()--->JSON字符串
<--JSON.parse()--------
  • @ 问题: 所以该Hook能用在哪里?
  • & 说明: 有表单的位置, ①请求参数 ②响应数据; 只要这两个地方出现加密, 都可以考虑用这个Hook
1
2
3
4
5
6
7
8
(function() {
var _parse = JSON.parse;
JSON.parse = function(ps) {
console.log("Hook JSON.parse ——> ", ps);
debugger;
return _parse(ps); // 不改变原有的执行逻辑
}
})();

3.1.2 实战【响应数据加密】

需求: 找到 link 解密翻译结果的方法

  1. 确定需要 JSON.parse进行Hook
  2. 在调试前注入Hook代码
  • ! 注意: Hook代码一定要在调试开始前执行


|875

请求头请求参数Cookie响应数据
JSON.parse

3.2.1 适用场景

Object.definProperty 是ES5支持的代理, ES6变为了Proxy 视频讲解Proxy

  • $ 语法: 记得hook cookie前, 先清除下cookie [[1.JS基础与浏览器开发工具#7. 拦截对象的get和set方法]] link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function () {
cookieTemp = document.cookie;
Object.defineProperty(document, 'cookie', {
set: function (val) {
if (val.indexOf('需要捕获的Cookie名称') != -1) {
debugger;
}
console.log('Hook捕获到cookie设置->', val);
cookieTemp = val;
},
get: function () {
return cookieTemp;
},
});
})();

3.2.2 实战 【Cookie加密】

需求: 还没找到网站….

3.2.3 注意事项

cookie一般都需要刷新网页, 而刷新网页会导致hook的代码失效, 所以提供一下两种方法去解决

  1. 脚本断点: 等到第一个网页的js文件加载的时候 注入hook代码
  2. 油猴: 教程 油猴可以实现, 在网页加载(前/body加前等)时机进行hook; 如下给一个油猴hook的模板
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
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2025-02-05
// @description try to take over the world!
// @author You
// @match https://www.cnvd.org.cn/flaw/typelist?typeId=27
// @icon https://www.google.com/s2/favicons?sz=64&domain=csdn.net
// @grant none
// ==/UserScript==

(function () {
var cookieTemp = document.cookie;
Object.defineProperty(document, 'cookie', {
set: function (val) {
if (val.indexOf('__jsl_clearance_s') != -1) {
debugger;
}
console.log('Hook捕获到cookie设置->', val);
cookieTemp = val;
},
get: function () {
return cookieTemp;
},
});
})();

第三节 Hook XHR请求

1
用户在页面触发事件 --> 构造请求对象 --> 请求拦截器 --> **发送请求** --> 返回数据 --> 响应拦截器 --> 请求成功的回调 --> 展示到开发者工具包中

3.3.1 适用场景

  • & 什么讲的原生XHR中, 有XMLHttpRequest.open()(初始化请求) ; 和XMLHttpRequest.send()(真正发请求), 浏览器的xhr断点是断send, 我们可以手段断open(), 因为open()离发送请求的地方较近
1
2
3
4
5
6
7
8
9
10
11
12
// 如果是正数 表示存在里面
// 如果是-1 表示不在里面

(function () {
var open = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (method, url, async) {
if (url.indexOf("analysis") != -1) {
debugger;
}
return open.apply(this, arguments);
};
})();

3.3.2 实战【请求参数加密】

需求: 找到 七麦数据 请求参数加密位置


进过一番查找, 因为这里是异步的, 很难找; 但总的思路还是在的, 因为XHR open 就准备发送了, 加密一定往前找, 顶多就是多看几个栈


这里和原生的 浏览器 xhr断点 做一个对比: 有总比没有好

第四章 B/S的通讯

❗为什么要单独整理这个??? 因为只有知道别人请求是怎么发送的, 你XHR断点才有目标, 否则就算找到也是碰运气!

第一节 名词辨析

  • & 问题: XHR, Fetch, ajax, Jquery , Axios, Promise, async 这些都是啥😰 看完下面这4点, 就能明白, 耐心点!
    1. 概念: Ajax(Asynchronous JavaScript + XMLHttpRequest)①是一个概念, 支持异步发送请求, ②最原来浏览器渲染是不支持异步的, 只能通过 form/链接 给后端发送请求, 而如果想更新页面数据, 就必须刷新页面, ③直到有了Ajax这个技术, 才支持异步模式(不刷新网页, 也能更新数据)
    2. 浏览器API层: ①XHR(2005)和Fetch(2015)都是浏览器原生的API, ②都是基于Ajax这个概念, 支持和后端进行异步通讯
    3. 封装层: ①因为XHR和Fetch写起来很麻烦(原生的都很麻烦) ②才有了诸如, jquery, axios等工具库 ③✔️, 他们是js的工具库 ④其中jquery ajax和ajax是不同的概念, 前者是工具库,jquery中除了有ajax来发送请求, 还有可以获取页面元素的”语法糖”, 是一个js工具库; 后者单独的ajax是一个模式/技术, 是异步技术;
    4. JS语法: ①Promise和async可以理解为JS的语法 ②配合XHR/Fetch才能实现请求方发送
1
2
3
4
经历的阶段:
3. 传统模式:通过浏览器默认导航行为(表单form/链接href)的**同步页面跳转** [必须刷新才能更新数据]
4. AJAX模式:使用**XHR/Fetch**等技术实现的**异步HTTP请求** [不刷新也能更新数据]
5. WebSocket:独立实现的**双向实时通信**方案(不属于AJAX体系)[不关注]

1
2
3
4
5
6
7
8
9
浏览器可以给后端发请求的相关概念
├─ 浏览器API层
│ ├─ XHR (XMLHttpRequest) 【原生Ajax; Ajax模式(异步模式)】
│ ├─ Fetch API 【Ajax模式(异步模式)】
│ └─ WebSocket API 【不关注】

└─ 封装层
├─ jQuery AJAX(XHR封装)
└─ axios(基于XHR的Promise封装)

第二节 XHR发送请求

  • $ 语法: 原生的XHR没有 “请求拦截器” or “响应拦截器”
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>XHR GET实现</title>
</head>
<body>
<!-- 添加点击事件监听 -->
<button id="sendBtn">发送XHR GET请求</button>

<script>
// 封装请求函数
function sendRequest() {
// 每次点击创建新的XHR实例(避免重复请求问题)
const xhr = new XMLHttpRequest();

const params = new URLSearchParams({
ts: '2132312',
sign: '321321'
});

xhr.open('GET', `http://localhost:8080/get?${params}`);

xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer token123');

xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('响应数据:', JSON.parse(xhr.responseText));
} else {
console.error('请求失败:', xhr.status);
}
}
}

xhr.send();
}

// 绑定点击事件
document.getElementById('sendBtn').addEventListener('click', function(e) {
e.preventDefault(); // 防止按钮默认行为
console.log('开始发送请求...');
sendRequest();
});
</script>
</body>
</html>
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>XHR POST实现</title>
</head>
<body>
<button id="sendBtn">发送XHR POST请求</button>

<script>
function sendRequest() {
const xhr = new XMLHttpRequest();

// POST请求地址
xhr.open('POST', 'http://localhost:8080/post');

// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer token123');

// 请求参数(URL参数+请求体)
const urlParams = new URLSearchParams({
ts: '2132312',
sign: '321321'
});

// 请求体数据
const postData = {
page: '1',
content: 'test'
};

// 状态监听
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(`状态码: ${xhr.status}`, xhr.responseText);
}
}

// 合并URL参数并发送(GET风格参数 + POST请求体)
xhr.send(JSON.stringify(postData));
}

// 绑定点击事件
document.getElementById('sendBtn').addEventListener('click', function(e) {
e.preventDefault();
console.log('开始POST请求...');
sendRequest();
});
</script>
</body>
</html>

第三节 Fetch发送请求

视频: https://www.bilibili.com/video/BV1sT41197bV/?spm_id_from=333.337.search-card.all.click&vd_source=a2208fcbd48ebf44fafb42e682e09f82

第四节 JQuery发送请求

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery GET实现</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<button id="sendBtn">发送jQuery GET请求</button>

<script>
// 请求拦截器(全局设置)
$.ajaxSetup({
beforeSend: function(xhr) {
// 公共请求头设置
xhr.setRequestHeader('Authorization', 'Bearer token123');
// 添加公共参数
this.url += `?ts=${Date.now()}&sign=${btoa('secret')}`;
}
});

// 发送GET请求
function sendGet() {
$.ajax({
url: 'http://localhost:8080/get',
method: 'GET',
headers: {
'X-Custom-Header': 'jquery-demo'
},
data: {
page: 1,
size: 20
},
success: function(response) {
console.log('解密后的响应:', decrypt(response));
},
error: function(xhr) {
console.error('请求失败:', xhr.status);
}
});
}

// 绑定点击事件
$('#sendBtn').click(function(e) {
e.preventDefault();
console.log('jQuery GET请求启动');
sendGet();
});
</script>
</body>
</html>
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery POST实现</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<button id="sendBtn">发送jQuery POST请求</button>

<script>
// 请求前置拦截器
$.ajaxPrefilter(function(options) {
if (options.method === 'POST') {
// 加密请求体
options.data = JSON.stringify(encryptData(options.data));
options.contentType = 'application/json';
}
});

// 发送POST请求
function sendPost() {
$.ajax({
url: 'http://localhost:8080/post',
method: 'POST',
headers: {
'X-Request-Source': 'jquery'
},
data: {
username: 'admin',
password: 'encrypted123'
},
success: function(response) {
console.log('响应处理:', response);
}
});
}

// 绑定点击事件
$('#sendBtn').click(function(e) {
e.preventDefault();
console.log('jQuery POST请求启动');
sendPost();
});
</script>
</body>
</html>

第五节 axios发送请求

第五章 不同位置的加密怎么找

这里都是针对 XHR 的!!!

第一节 请求头加密

你XHR都是定位到send的位置, 设置请求头, 在发送请求前的任何位置都有可能

第二节 请求参数加密

第三节 载荷加密

第四节 响应体加密

第五节 Cookie加密

  • Title: 2.如何定位加密
  • Author: 明廷盛
  • Created at : 2025-02-15 14:34:49
  • Updated at : 2025-02-15 15:36:00
  • Link: https://blog.20040424.xyz/2025/02/15/🐍爬虫工程师/第二部分 JS逆向/2.如何定位加密/
  • License: All Rights Reserved © 明廷盛