JS逆向:由 words 、sigBytes 引发的一系列思考与实践
【作者主页】:小鱼神1024
【擅长领域】:JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等
在做JS逆向时,你是否经常看到 words
和 sigBytes
这两个属性呢,比如:
{words: [2003644449, 1081552243, 594308145, 1718382376], sigBytes: 16
}
如果发现了它们的踪迹,那恭喜你了。基本可以确定,网站是使用 crypto-js
库中某一个加密算法实现加密的。
words 、sigBytes 它们是什么
在 crypto-js
这个流行的 JavaScript
加密库中,words
和 sigBytes
是 CryptoJS.lib.WordArray
对象的两个重要属性。
words
数组是 WordArray
对象的主体,它用于存储加密数据。在 crypto-js 中,一个 word
是由32位(或者说是4个字节)组成的,因此每个元素在 words 数组中实际上可以表示4个字节的数据。
在计算机系统中,一个32位的整数可以存储从-2,147,483,648到2,147,483,647的整数值(如果是有符号整数),或者从0到4,294,967,295(如果是无符号整数)。这种表示范围是因为32位可以表示2^32(即4,294,967,296)个不同的值。
补充
在计算机和信息技术中,32位(4字节)是一个常用的数据大小单位,用来表示数据的存储或处理容量。具体来讲:
- 1位(bit):是计算机数据的最基本单位,代表一个二进制数字,即0或1。
- 1字节(Byte):通常由8位组成,是基本的数据存储单位。1字节可以表示0到255(或者在二进制中是00000000到11111111)之间的一个数值。
- 32位:则相当于4字节(4 Bytes),因为1字节是8位,所以4字节就是4 * 8 = 32位。
如何生成 WordArray 对象
两种解决办法:
通过 CryptoJS.enc.Utf8.parse 生成
如果已知utf8编码的明文,则可以使用 CryptoJS.enc.Utf8.parse
方法生成 WordArray
对象。
const CryptoJS = require("crypto-js");// 生成 WordArray 对象
const keyWordArray = CryptoJS.enc.Utf8.parse("wm0!@w-s#ll1flo(");
console.log(keyWordArray);
通过 CryptoJS.lib.WordArray.create 生成
const CryptoJS = require("crypto-js");
const words = [2003644449, 1081552243, 594308145, 1718382376]; // 32位整数数组(words数组)
const sigBytes = 16;// 使用 CryptoJS 转换字节数组到 WordArray
const keyWordArray = CryptoJS.lib.WordArray.create(words, sigBytes);console.log(keyWordArray);
如何将 WordArray 转化为 UTF-8 字符串
const CryptoJS = require("crypto-js");
const wordArrayBytes = {words: [ 2003644449, 1081552243, 594308145, 1718382376 ],sigBytes: 16
};// 将 WordArray 转换为 UTF-8 字符串
const key = CryptoJS.enc.Utf8.stringify(wordArrayBytes);
console.log(key);// wm0!@w-s#ll1flo(
如何将 WordArray 转化为十六进制Hex
const CryptoJS = require("crypto-js");
const wordArrayBytes = {words: [ 2003644449, 1081552243, 594308145, 1718382376 ],sigBytes: 16
};// 将 WordArray 转换为十六进制Hex
const key = CryptoJS.enc.Hex.stringify(wordArrayBytes);
console.log(key);// 776d302140772d73236c6c31666c6f28
那如何判断一个字符串是否为有效的十六进制字符串,可以检查以下几点:
-
字符串长度:十六进制字符串的长度应该是偶数。
-
字符范围:十六进制字符串只能包含 0-9 以及 a-f 和 A-F 这些字符。
可以编写一个函数来实现这个逻辑:
// 判断一个字符串是否为十六进制字符串的函数
function isHexString(str) {// 检查长度是否为偶数if (str.length % 2 !== 0) {return false;}// 使用正则表达式检查字符串是否只包含合法的十六进制字符(0-9, a-f, A-f)const hexRegex = /^[0-9a-fA-F]+$/;return hexRegex.test(str);
}// 示例测试
const testHexString1 = "776d302140772d73236c6c31666c6f28";
const testHexString2 = "1a2b3g4d5e"; // 包含非法字符 'g'
const testHexString3 = "123"; // 长度为奇数console.log(isHexString(testHexString1)); // 输出:true
console.log(isHexString(testHexString2)); // 输出:false
console.log(isHexString(testHexString3)); // 输出:false
WordArray整数数组、Hex十六进制、ByteArray字节数组、UTF-8字符串之间的相互转换
// 判断一个数组是否为字节数组(每个元素为0到255之间的整数)
function isByteArray(arr) {// 首先检查是否为数组if (!Array.isArray(arr)) {return false;}// 检查每个元素是否为0到255之间的整数for (let i = 0; i < arr.length; i++) {if (typeof arr[i] !== 'number' || arr[i] < 0 || arr[i] > 255 || !Number.isInteger(arr[i])) {return false;}}return true;
}// 将字节数组转换为十六进制字符串的函数
function bytesToHex(bytes) {if (!isByteArray(bytes)) {throw new Error('输入必须是字节数组');}return bytes.map(byte => byte.toString(16).padStart(2, '0')).join('');
}// 将十六进制字符串转换为字节数组的函数
function hexToBytes(hex) {let bytes = [];for (let c = 0; c < hex.length; c += 2) {bytes.push(parseInt(hex.substr(c, 2), 16));}return bytes;
}// 将32位整数数组(words数组)转换为字节数组的函数
function wordsToBytes(words) {let bytes = [];for (let i = 0; i < words.length; i++) {let word = words[i];bytes.push((word >> 24) & 0xFF);bytes.push((word >> 16) & 0xFF);bytes.push((word >> 8) & 0xFF);bytes.push(word & 0xFF);}return bytes;
}// 将字节数组转换为UTF-8字符串的函数
function bytesToStringUTF8(bytes) {if (!isByteArray(bytes)) {throw new Error('输入必须是字节数组');}return new TextDecoder('utf-8').decode(new Uint8Array(bytes));
}let key = { words: [2003644449, 1081552243, 594308145, 1718382376], sigBytes: 16 };// 将key的words数组转换为字节数组
let keyBytes = wordsToBytes(key.words);// 将字节数组转换为十六进制字符串,测试使用
let keyHex = bytesToHex(keyBytes);// 打印key和iv的十六进制字符串
console.log("十六进制Hex:", keyHex);// 将十六进制字符串还原为字节数组,以确保转换过程的无损失和准确性,测试使用
let keyBytesFromHex = hexToBytes(keyHex);// 将字节数组转换为UTF-8字符串,得到最终的字符串表示
let keyString = bytesToStringUTF8(keyBytes);// 打印key和iv的UTF-8字符串表示
console.log("字符串UTF-8:", keyString);
用 Uint8Array 生成字节数组
Uint8Array 的特点包括以下几点:
-
无符号整数:Uint8Array 存储的是无符号的 8 位整数(0 到 255),因此每个元素的取值范围是从 0 到 255。这意味着每个元素可以表示一个字节的数据,适用于处理字节数据和二进制数据。
-
定长数组:Uint8Array 是一种定长数组,它的长度在创建时就已经确定,并且不能动态改变。这有助于提高操作效率和性能,尤其在处理大量数据时非常有用。
// 用 Uint8Array 生成字节数组
const uint8Array = Uint8Array.from([119, 109, 48, 33, 64,119, 45, 115, 35, 108,108, 49, 102, 108, 111,40
]);// 使用 TextDecoder 将 bytes 转换为字符串
const textDecoder = new TextDecoder();
const decodedString = textDecoder.decode(uint8Array);console.log(decodedString);// wm0!@w-s#ll1flo(
为什么 AES、DES等加密时,要先转化 WrodArray
// AES 加密
function encrypt(word) {// 转化为 WordArrayconst iv = CryptoJS.enc.Utf8.parse("0102030405060708");// 转化为 WordArrayconst key = CryptoJS.enc.Utf8.parse('wm0!@w-s#ll1flo(');const encrypted = CryptoJS.AES.encrypt(word, key, {iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7})return encrypted.toString();
}
转化为32位二进制数据再进行加密是出于以下几个主要原因:
-
加密算法的要求:几乎所有的现代加密算法,包括对称加密(如AES)和非对称加密(如RSA),在底层操作时都是以二进制数据形式工作的。这是因为加密算法在设计时需要操作位(bit)和字节(byte),而不是高级语言中的文本或数字等类型。因此,将数据转换为二进制形式是执行这些算法的必要步骤。
-
安全性增强:通过转换为二进制数据,可以确保在加密过程中原始数据的内容不会因其格式或结构而泄露信息。此外,某些加密方式(如块加密)要求数据以特定大小的块来处理。将数据预先转化为二进制形式,可以更容易地按块对数据进行操作和填充。
-
性能优化:直接对二进制数据进行操作比对高级数据类型(如字符串或对象)进行操作要有效率得多。加密和解密操作通常需要大量的数据处理工作,特别是在数据量大或需求高性能的应用场景中。预先将数据转换为二进制格式,可以最大限度地减少处理时间和资源消耗。
创作不易,动动您发财的小手,点赞关注一波,支持我创作更多对您有帮助的文章!
相关文章:
JS逆向:由 words 、sigBytes 引发的一系列思考与实践
【作者主页】:小鱼神1024 【擅长领域】:JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 在做JS逆向时,你是否经常看到 words 和 sigBytes 这两个属性呢,比如ÿ…...
计算机的错误计算(十五)
摘要 介绍历史上由于计算精度问题引起的灾难或事件。 今天换个话题,说说历史上曾经发生过的一些事件。 1961 年 , 美国麻省理工学院气象学家洛伦兹在仿真天气预报时 , 将 0.506127 舍入到 0.506 , 所得计算结果大相径庭 ! 这种“差之毫厘 , 谬以千里”的现象…...
制作img文件
安装软件包 sudo apt-get install dosfstools dump parted kpartx 创建空白img文件 sudo dd if/dev/zero ofraspberrypi.img bs1M count4000 给img文件分区 sudo parted raspberrypi.img --script -- mklabel msdos sudo parted raspberrypi.img --script -- mkpart primar…...

GB28181视频汇聚平台EasyCVR接入Ehome设备视频播放出现异常是什么原因?
多协议接入视频汇聚平台EasyCVR视频监控系统采用了开放式的架构,系统可兼容多协议接入,包括市场标准协议:国标GB/T 28181协议、GA/T 1400协议、JT808、RTMP、RTSP/Onvif协议;以及主流厂家私有协议及SDK,如:…...
Java利用poi实现word,excel,ppt,pdf等各类型文档密码检测
介绍 最近工作上需要对word,excel,ppt,pdf等各类型文档密码检测,对文件进行分类,有密码的和没密码的做区分。查了一堆资料和GPT都不是很满意,最后东拼西凑搞了个相对全面的检测工具代码类,希望能给需要的人带来帮助。 说明 这段…...
顺序表与链表学习笔记
顺序表及其结构定义 (1)结构定义 顺序存储: 顺序表的元素按顺序存储在一块连续的内存区域中,每个元素占用相同大小的存储空间。通过数组实现,每个元素可以通过下标快速访问。 存储密度高: 因为顺序表使用…...

2.SQL注入-字符型
SQL注入-字符型(get) 输入kobe查询出现id和邮箱 猜测语句,字符在数据库中需要用到单引号或者双引号 select 字段1,字段2 from 表名 where usernamekobe;在数据库中查询对应的kobe,根据上图对应上。 select id,email from member where usernamekobe;编写payload语…...
在Ubuntu 14.04上安装和配置Elasticsearch的方法
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 Elasticsearch 是一个用于实时分布式搜索和数据分析的平台。它因易用性、强大功能和可扩展性而备受欢迎。 Elasticsearch 支持 R…...
C++:inline关键字nullptr
inline关键字 C中inline使用关键点强调 (1)inline是一种“用于实现的关键字”,而不是一种“用于声明的关键字”,所以关键字 inline 必须与函数定义体放在一起,而不是和声明放在一起 (2)如果希望在多个c文件中使用,则inline函数应…...

数字信号处理实验三(IIR数字滤波器设计)
IIR数字滤波器设计(2学时) 要求: 产生一复合信号序列,该序列包含幅度相同的28Hz、50Hz、100Hz、150Hz的单音(单频)信号;其中,50Hz及其谐波为工频干扰(注:采样…...

Why is Kafka fast?(Kafka性能基石)
Kafka概述 Why is kafka fast? 思考一下,当我们在讨论Kafka快的时候我们是在谈论什么呢?What does it even mean that Kafka is fast? 我们是在谈论kafka的低延迟(low latency)还是在讨论吞吐量(through…...
Linux下的SSH详解及Ubuntu教程
前言 SSH(Secure Shell)是一种用于计算机之间安全通信的协议,广泛应用于远程登录、系统管理和文件传输等场景。本文将详细介绍SSH在Linux系统(特别是Ubuntu)下的使用,包括安装、配置、密钥管理和常见应用&…...

MobPush HarmonyOS NEXT 版本集成指南
开发工具:DevEco Studio 集成方式:在线集成 HarmonyOS API支持:> 11 集成前准备 注册账号 使用MobSDK之前,需要先在MobTech官网注册开发者账号,并获取MobTech提供的AppKey和AppSecret,详情可以点击查…...
什么是封装?为什么要封装?
什么是封装? 封装是计算机科学中的一个重要概念,尤其在面向对象编程(OOP)中占据核心地位。封装主要指的是将数据(属性)和对这些数据的操作(方法)组合在一个单元中(我们称…...

远程桌面无法复制粘贴文件到本地怎么办?
远程桌面不能复制粘贴问题 Windows远程桌面为我们提供了随时随地访问文件和数据的便捷途径,大大提升了工作和生活的效率。然而,在使用过程中,我们也可能遇到一些问题。例如,在通过远程桌面传输文件时,常常会出现无法复…...

LeetCode 207. 课程表
思路:这是一道拓扑排序问题,拓扑排序听起来可能有点复杂,但实际上它是个相当直观的概念。想象一下,你有很多事情要做,但有些事情必须在另一些事情完成之后才能开始,就像你得先穿上袜子再穿鞋子 拓扑排序就…...
数据结构历年考研真题对应知识点(树的基本概念)
目录 5.1树的基本概念 5.1.2基本术语 【森林中树的数量、边数和结点数的关系(2016)】 5.1.3树的性质 【树中结点数和度数的关系的应用(2010、2016)】 【指定结点数的三叉树的最小高度分析(2022)】 5.1…...
Pytorch和Tensorflow安装【Win和Linux】
Ubuntu/win安装Pytorch和Tensorflow 说明: 这两种框架的搭建,均基于Anaconda进行搭建。先在系统中安装Anaconda软件。 一、Pytorch的搭建 windows安装 (1)搭建参考官网给的命令,pytorch官网 (2)下载地址:https://download.pytorch.org/whl/torch_stable.html 从上述…...

筑算网基石 创数智未来|锐捷网络闪耀2024 MWC上海
2024年6月26日至28日,全球科技界瞩目的GSMA世界移动大会(MWC 上海)在上海新国际博览中心(SNIEC)盛大召开。作为行业领先的网络解决方案提供商,锐捷网络以“筑算网基石 创数智未来”为主题,带来了…...

T4打卡 学习笔记
所用环境 ● 语言环境:Python3.11 ● 编译器:jupyter notebook ● 深度学习框架:TensorFlow2.16.1 ● 显卡(GPU):NVIDIA GeForce RTX 2070 设置GPU from tensorflow import keras from tensorflow.keras…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...