
逆向备忘录
更新: 2025/2/24 字数: 0 字 时长: 0 分钟
常用函数
base64编解码
浏览器环境中进行 base64 编解码使用全局的 window
对象自带方法:
atob('字符串')
将字符串进行 base64 解码;btoa('字符串')
将字符串进行 base64 编码;
Node 环境中进行 base64 编解码使用特定模块 Buffer
对象方法:
Buffer.from('字符串').toString('base64')
将字符串进行 base64 编码;Buffer.from('字符串', 'base64').toString('utf-8')
将字符串进行 base64 解码,在进行 utf-8 编码;
// Base64 编码
const originalString = 'Hello, World!';
const base64Encoded = Buffer.from(originalString).toString('base64');
console.log('Base64 编码:', base64Encoded);
// Base64 解码
const decodedBuffer = Buffer.from(base64Encoded, 'base64');
const decodedString = decodedBuffer.toString('utf-8');
console.log('Base64 解码:', decodedString);
字节数组转换
CryptoJS
库提供了在 CryptoJS
中的字节数组(WordArray)的转换方法:
CryptoJS.enc.Utf8.parse('字符串')
用于将 UTF-8 编码的字符串转换为 CryptoJS 中表示的字节数组(WordArray);CryptoJS.enc.Utf8.parse(字节数组)
用于将 CryptoJS 中的字节数组(WordArray)转换为 UTF-8 编码的字符串;
// 导入CryptoJS库
const CryptoJS = require('crypto-js');
const Str = 'Hello, World!';
// 将UTF-8编码的字符串转换为CryptoJS中表示的字节数组(WordArray)
const wordArray = CryptoJS.enc.Utf8.parse(Str);
console.log(wordArray);
// 将CryptoJS中的字节数组(WordArray)转换为UTF-8编码的字符串
const utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
console.log(utf8String);
提醒
CryptoJS
库本身不是原生的 JavaScript 标准库的一部分,你需要通过 npm 或其他方式安装它,然后在你的代码中导入它。代码中的 require('crypto-js')
是一种导入 CryptoJS
的方式。
在 JavaScript 中,你可以将 Uint8Array
转换为字符串的方法有多种,以下是常用的两种方法:
方法 1: 使用 TextDecoder
TextDecoder
是一种用于将 Uint8Array
等编码字节数组解码为字符串的 API。它支持多种字符编码。
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // 示例 Uint8Array
const decoder = new TextDecoder('utf-8');
const string = decoder.decode(uint8Array);
console.log(string); // 输出 "Hello"
方法 2: 使用 String.fromCharCode
和 apply
String.fromCharCode
方法将 UTF-16 代码单元转换为字符串。你可以通过结合 apply
方法,将 Uint8Array
转换为字符串。
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // 示例 Uint8Array
const string = String.fromCharCode.apply(null, uint8Array);
console.log(string); // 输出 "Hello"
方法 3: 使用 String.fromCharCode
和 map
如果你担心数组长度过大导致 apply
方法超出函数参数数量限制,可以使用 map
方法:
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // 示例 Uint8Array
const string = Array.from(uint8Array).map(byte => String.fromCharCode(byte)).join('');
console.log(string); // 输出 "Hello"
方法 4: 使用 TextDecoderStream
如果你在处理流式数据时,可以使用 TextDecoderStream
,它是一个高级用法,可以直接将 Uint8Array
数据流解码为字符串。
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // 示例 Uint8Array
const readableStream = new ReadableStream({
start(controller) {
controller.enqueue(uint8Array);
controller.close();
}
});
const decoder = new TextDecoderStream();
readableStream.pipeThrough(decoder).getReader().read().then(({ value }) => {
console.log(value); // 输出 "Hello"
});
选择合适的方法
- 如果你处理的是 UTF-8 编码的文本,推荐使用
TextDecoder
。 - 如果你只需要简单转换,并且数组较短,
String.fromCharCode.apply
是快捷的方法。 - 对于更长的数组或特殊情况,
map
方法可能更适合。
要将你提供的 JS 中的 Uint8Array 对象转换为 Python 中的字节数据,可以使用类似的方法。以下是完整的代码和步骤。
JSON 对象
{
"0": 102,
"1": 178,
"2": 173,
"3": 4,
"4": 67,
"5": 210,
"6": 166,
"7": 172,
"8": 254,
"9": 59,
"10": 142,
"11": 84,
"12": 130,
"13": 132,
"14": 174,
"15": 22
}
Python 转换代码
# 定义 JSON 对象
json_object = {
"0": 102,
"1": 178,
"2": 173,
"3": 4,
"4": 67,
"5": 210,
"6": 166,
"7": 172,
"8": 254,
"9": 59,
"10": 142,
"11": 84,
"12": 130,
"13": 132,
"14": 174,
"15": 22
}
# 提取值并转换为 bytes 对象
byte_array = bytes(json_object.values())
print(byte_array)
输出
byte_array
将会包含以下字节数据:
b'f\xb2\xad\x04C\xd2\xa6\xac\xfe;\x8eT\x82\x84\xae\x16'
解释
json_object.values()
: 提取 JSON 对象中的所有值,这些值构成一个序列。bytes(json_object.values())
: 将序列转换为bytes
对象,生成的字节串可以在 Python 中直接使用。
这种方法非常适合将类似的 JSON 对象转换为字节数据,以用于各种需要二进制格式的应用场景。
逆向技巧
关键字搜索
一般来说,网站会加载含有加密算法的 JS 文件来加密数据,因此就会包含一些常见的加密关键词 crypto加密
、Encrypt加密方法
、Decrypt解密方法
、MD5哈希
、DES加密
、AES加密
、Base64编码
等,那么我们就可以通过关键词进行搜索、查询找到加密的位置,从而逆向还原加密过程。
拦截器定位
**拦截器通常是指在网络请求或异步操作中插入自定义逻辑的一种模式。**有的反爬网站在请求的时候,会返回加密的数据,再看 Initiator 启动器,会发现是异步的加载,那么数据解密操作就很有可能是在拦截器里面进行的:
**这里我们就可以全局搜索一下 interceptors
拦截器关键字,选择第一处进入,可以看到 a.interceptors.request.use
和 a.interceptors.response.use
就是请求和响应拦截器,它不会直接拦截异步加载的过程,但可以在发送请求之前或在接收到响应之后执行自定义逻辑。**因为我们是逆向数据解密的过程,因此在 a.interceptors.response.use
处打上断点进行调试:
抠代码
函数拷贝
在抠代码过程中,我们可能会遇到内容特别长的函数,例如下图的 window.md5
函数就特别长,如果用鼠标选中 JS 代码进行复制的话,会选中很长一段,而且在鼠标滑动的途中还可能中断,很不方便。这里我们就可以通过在 console 中输入 window.md5.toString()
将函数变成字符串拷贝出来。
**如果不想复制,还可以在 console 中输入 copy(window.md5.toString())
将函数字符串拷贝到剪切板。**不过首次使用 copy()
命令可能会给出如下警告:不要将你不理解或没有复习过的代码粘贴到 DevTools 控制台中。这可能允许攻击者窃取您的身份或控制您的计算机。请在下面键入“允许粘贴”以允许粘贴。
补环境
开始补环境前,我们再回顾以下 Node 环境和浏览器环境的差异:
全局对象
**因为在 Node 环境中没有 BOM,所以浏览器环境的全局对象 window
是用不了的,因此这里我们就必须使用 Node 环境的全局对象 global
,它类似于浏览器环境中的 window
对象。**在 Node 环境中,可以直接访问 global
对象,例如:
console.log(global);
**通常情况下,你无需显式使用 global
,因为在 Node 环境中,全局变量和函数会自动成为全局对象的属性。**例如:
// 在 Node.js 中,以下两种方式是等价的
global.myVariable = 42;
// 或者直接
myVariable = 42;
但这里有一个问题就是,从浏览器中抠出来的 JS 代码的凡是使用全局对象的都是 window
,没有 global
。其实这个问题很简单,只要在 JS 代码最前面加上下面这一句就可以了:
// global全局对象
window = global;