当前位置: 首页 > news >正文

华为商城秒杀时加密验证 device_data 的算法研究

前言

  • 之前华为商城放出 Mate60 手机时, 想给自己和家人抢购一两台,手动刷了好几天无果后,决定尝试编写程序,直接发送 POST 请求来抢。
  • 通过抓包和简单重放发送后,始终不成功。仔细研究,发现 Cookie 中有一个名为 device_data 的数据比较可疑,看起来是加密后的 base64, 很有可能服务器是使用这些值进行了验证。于是决定研究一下,看是否可以破解并用于秒杀。
  • 最后虽然研究出加密算法,并尝试用于秒杀,但由于仍然有其他的限制,暂时放弃,并将相关信息开源。
  • 华为的兄弟姐妹们需要辛苦更改算法了 😃
    在这里插入图片描述

查找 device_data 的生成位置

通过搜索,定位到名为 cp_20230815/…/ars_event.js 的文件,里面有对 ‘device_data’ 赋值的操作,那么加密算法就在这里了。
补充信息: 最新版本的地址已经是 cp_20231215/…/ars_event.js, 但内容没有改变。
在这里插入图片描述

算法分析

初看 ars_event.js , 是进行过混淆的, 简直和天书一样, 而且以前也没怎么用过 js, 不知道怎么下手。不过好在知道 js 的所有源码都在里面, 只要肯花一点时间, 必然是能解析出来的。

于是开始分析, 此处省略一万字。。。

功夫不负有心人,断断续续经过一两周的时间,总算把算法反推出来,并且编写了 java 代码进行验证和 POST 秒杀。虽然事后证明,服务器还有其他验证方式没有破解(比如 IP、UID 验证?),并发10个线程请求, 有4个给我返回非法请求。。。)

算法解释

  • device_data 的数据分两部分:
    • 最前面的 *2k 常量 + 从 479752 中选出的两个数(间隔 3)
    • 要加密的字符串先 base64, 按 4 个字符进行编码
      • 然后在前面加上 8 个随机字符
      • 最后再按 8 个字符为一组的方式编码.

源码

  • 因为源码是从 js 中反推出来的, 主要是为了满足和原有的算法一致, 命名和写法上就比较乱.
/*** device_data 的加密/解密 算法* https://res.vmallres.com/cp_20230815/js/common/risk/ars_event.js* https://res.vmallres.com/cp_20231215/js/common/risk/ars_event.js*/
@Slf4j
public class ArsEventCrack {//获取华为 function _0x272042 函数中,对字符串加密时采用的位置索引列表public LinkedList<Integer> GetEncodeStringIndexArray(int strLength, int blockSize){//最后4字节保持原样int charArrayLength = strLength - 4;//String[] charArray = strInput.substring(0, strInput.length() - 4).split("");LinkedList<LinkedList<Integer>> tmpArray = new LinkedList<>();for(int i = 0; i < blockSize; i++){tmpArray.add(new LinkedList<>());for(int j = 0; j < charArrayLength; j++){int _tmpVal_1 = j * 2 * (blockSize - 1) + i;int _tmpVal_2 = 0;if (_tmpVal_1 < charArrayLength){tmpArray.get(i).add(_tmpVal_1);}if (i != 0) {_tmpVal_2 = j * 2 * (blockSize - 1) - i;if (_tmpVal_2 < charArrayLength && _tmpVal_2 > 0) {tmpArray.get(i).add(_tmpVal_2);}}if(_tmpVal_1 > charArrayLength || _tmpVal_2 > charArrayLength){break;}}}//log.info("tmpArray={}", tmpArray);//排序和删除重复数据List<List<Integer>> sortedDistinctLists = tmpArray.stream().map(linked -> linked.stream().sorted().distinct().collect(Collectors.toList())).collect(Collectors.toList());LinkedList<Integer> allPositions = new LinkedList<>();sortedDistinctLists.forEach(integers -> allPositions.addAll(integers));return allPositions;}public String EncodeString(String strInput, int blockSize){LinkedList<Integer> allPositions = GetEncodeStringIndexArray(strInput.length(), blockSize);StringBuilder sb = new StringBuilder();for (Integer pos : allPositions) {sb.append(strInput.charAt(pos));}sb.append(strInput.substring(strInput.length() - 4));String result = sb.toString();//log.info("result={}", result);return result;}public String repeatString(String str, int times){if (times <= 1){return str;}StringBuilder sb = new StringBuilder();for (int i = 0 ; i < times; i++){sb.append(str);}return sb.toString();}public String DecodeString(String strInput, int blockSize){//除了最后4个字节的,生成指定长度, 然后获取随机字符串位置索引, 并对应替换.int encodeLength = strInput.length() - 4;char[] chars = repeatString("0", encodeLength).toCharArray();LinkedList<Integer> allPositions = GetEncodeStringIndexArray(strInput.length(), blockSize);int index = 0;for (Integer pos : allPositions) {chars[pos] = strInput.charAt(index);index++;}String strResult = String.copyValueOf(chars) + strInput.substring(encodeLength);return strResult;}//再次调用就会恢复public String BlockString(String strInput, int blockSize){String strResult = "";String strWithoutLast4 = strInput.substring(0, strInput.length()-4);int blockCount = strWithoutLast4.length() / blockSize;for (int i = blockSize; i > 0; i--){String tmp = strInput.substring((i - 1)*blockCount, i*blockCount);strResult += tmp;}strResult += strInput.substring(strInput.length()-4);return strResult;}public String DecodeDeviceDataString(String strEncodedDeviceData){//去除前面的 *2k47 一类的随机开头String remove2KHeader = strEncodedDeviceData.substring(5);//第一次解码String outerDecode = DecodeString(remove2KHeader, 8);//解码出来, 前面8个字节是随机值String firstUnBlock = BlockString(outerDecode, 4);String realFirstBlock = firstUnBlock.substring(8);//再次解码,此时解出来的就是 base64String innerDecode = DecodeString(realFirstBlock, 4);String strOriginal = new String(Base64.getDecoder().decode(innerDecode));return strOriginal;}public String Get2kHeader(){//*2k92String strInput = "479752";int randomIndex = new Random(System.currentTimeMillis()).nextInt(3);return "*2k" + strInput.charAt(randomIndex) + strInput.charAt(randomIndex + 3);}public String EncodeDeviceDataString(String strEncodedDeviceData){String strBase64 = Base64.getEncoder().encodeToString(strEncodedDeviceData.getBytes());String innerEncode = RandomStringUtils.randomAlphanumeric(8) + EncodeString(strBase64, 4);String strBlocked = BlockString(innerEncode, 4);String strEncodeDeviceData = Get2kHeader() + EncodeString(strBlocked, 8);return strEncodeDeviceData;}@Testpublic void testAstEventCrack(){log.info("Get2kHeader={}", Get2kHeader());String strOriginal = "ABCDEFGHIJKLMNOPQRSTWVXYZabcdefghijklmnopqrstuvwxyz123456789";int blockSize = 8;String strEncoded = EncodeString(strOriginal, blockSize);String strDecoded = DecodeString(strEncoded, blockSize);log.info("strEncoded={}, strDecoded={}", strEncoded, strDecoded);Assert.assertEquals(strOriginal, strDecoded);String strBlocked = BlockString(strOriginal, blockSize);log.info("strBlocked={}", strBlocked);String strUnblocked = BlockString(strBlocked, blockSize);log.info("strUnblocked={}", strUnblocked);Assert.assertEquals(strOriginal, strUnblocked);}@Testpublic void TestDeviceData(){if(true){//只解密String strEncodedDeviceData = "*2k75xxxxxx";  // 此处输入通过 F12 或抓包获取的 device_data 字符串,运行后即可解密String strDeviceData = DecodeDeviceDataString(strEncodedDeviceData);log.info("strDeviceData: {}", strDeviceData);}if(false){//加密后再解密String strOriginalData = "";  //输入想要加密的字符串//String strOriginalData = GetDeviceFingerPrint() + "_" + "[object Object]";String strEncode = EncodeDeviceDataString(strOriginalData);String strDecode = DecodeDeviceDataString(strEncode);log.info("strDecode:{}", strDecode);Assert.assertEquals(strOriginalData, strDecode);}}
}

相关文章:

华为商城秒杀时加密验证 device_data 的算法研究

前言 之前华为商城放出 Mate60 手机时, 想给自己和家人抢购一两台&#xff0c;手动刷了好几天无果后&#xff0c;决定尝试编写程序&#xff0c;直接发送 POST 请求来抢。通过抓包和简单重放发送后&#xff0c;始终不成功。仔细研究&#xff0c;发现 Cookie 中有一个名为 devic…...

Wrk压测发送Post请求的正确姿势

一、Wrk简介 wrk 是一个能够在单个多核 CPU 上产生显著负载的现代 HTTP 基准测试工具。它采用了多线程设计&#xff0c;并使用了像 epoll 和 kqueue 这样的可扩展事件通知机制。此外&#xff0c;用户可以指定 LuaJIT 脚本来完成 HTTP 请求生成、响应处理和自定义报告等功能。 …...

【管理篇 / 登录】❀ 06. macOS下使用USB配置线登录 ❀ FortiGate 防火墙

【简介】飞塔防火墙上都会配有CONSOLE接口&#xff0c;包装里都会配置一根USB配置线&#xff0c;通过这个接口和这根线&#xff0c;我们可以用命令的方式登录飞塔防火墙。随着苹果电脑的普及&#xff0c;我们来学习如何在macOS中使用USB配置线登录飞塔防火墙。 早期飞塔防火墙包…...

linux系统shell语言的自动化交互

自动化交互 自动化交互expect交互expect用法 sshpass概念shhpass的脚本批量拷贝文件批量传递秘钥批量修改密码 自动化交互 expect交互 yum -y install expect tcl tcl-devel //安装expect交互工具expect用法 用法: 1)#!/usr/bin/expect //定义脚本执行的shell 2)set …...

HarmonyOS ArkTS 三方库的基本使用(十六)

如何获取三方库 目前提供了两种途径获取开源三方库&#xff1a; 1、通过访问Gitee网站开源社区获取 在Gitee中&#xff0c;搜索OpenHarmony-TPC仓库&#xff0c;在tpc_resource中对三方库进行了资源汇总&#xff0c;可以供开发者参考。 2、通过OpenHarmony三方库中心仓获取 …...

Spring boot封装rocket mq 教程

1、rocket mq版本 5.1.3 2、pom引入rocket mq依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client-java</artifactId><version>5.0.4</version></dependency> 3、发送MQ消息工具类 impor…...

Java Swing手搓童年坦克大战游戏(I)

前言 业余偶尔对游戏有些兴趣&#xff0c;不过这样的时代&#xff0c;硬件软件飞速进步&#xff0c;2D游戏画面都无比精美&#xff0c;之前的8bit像素游戏时代早就过去了&#xff0c;不过那时候有许多让人印象深刻的游戏比如魂斗罗、超级玛丽、坦克大战(Battle City)等等。 学…...

【DevOps-04]】Operate阶段工具

一、简要说明 安装Docker安装Docker-compose二、安装Docker 官网地址:https://www.docker.com文档地址:Docker Docs仓库地址:https://hub.docker.com1、Docker相关网站 官方网站Get Docker | Docker Docs...

力扣2807.在链表中插入最大公约数

思路&#xff1a;遍历链表&#xff0c;对于每一个结点求出它与下一个结点的最大公约数并插入到俩个结点之间 代码&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}…...

开始刷Leetcode之前你需要知道的 - The basic is all you need

数据结构&#xff1a;列表&#xff0c;哈希表&#xff0c;集合&#xff0c;栈&#xff0c;堆&#xff0c;链表&#xff0c;二叉树&#xff0c;图 入门算法&#xff1a;递归&#xff0c;排序算法&#xff0c;二分法&#xff0c;bfs&#xff0c;dfs list/array 列表常见操作&am…...

【PostgreSQL】模式Schema

PostgreSQL 数据库集群包含一个或多个命名数据库。角色和一些其他对象类型在整个集群中共享。与服务器的客户端连接只能访问单个数据库中的数据&#xff0c;该数据库在连接请求中指定。 数据库包含一个或多个命名schema&#xff0c;而这些schema又包含表。schema还包含其他类型…...

JavaScript实现的复杂功能:自动生成带水印的图片

#程序员的崩溃瞬间 在本文中&#xff0c;我们将讨论一个JavaScript实现的复杂功能&#xff0c;该功能可以自动为图片添加水印。这个功能在许多场景中都非常有用&#xff0c;例如&#xff0c;如果你想保护你的图片版权&#xff0c;或者你想在你的网站上显示自定义的水印。 一、…...

图神经网络|8.2 图卷积的计算基本方法

不同于一般的神经网络&#xff0c;网络层数的并不用特别多。 原因是只需要少数次数迭代后&#xff08;当迭代次数为图上的直径&#xff1f;任意两点最短距离的最大值&#xff1f;&#xff09;&#xff0c;某节点便可获取得到图上所有的节点。 通俗的理解是&#xff0c;在社会中…...

equals()与hashCode()方法详解

java.lang.Object类中有两个非常重要的方法&#xff1a; 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继承结构的基础&#xff0c;所以是每一个类的父类。所有的对象&#xff0c;包括数组&#xff0c;都实现了在Object类中定义的方法。 回到…...

六、基于Flask、Flasgger、marshmallow的开发调试

基于Flask、Flasgger、marshmallow的开发调试 问题描述调试方法一调试方法二调试方法三 问题描述 现在有一个传入传出为json格式文件的&#xff0c;Flask-restful开发的程序&#xff0c;需要解决如何调试的问题。 #!/usr/bin/python3 # -*- coding: utf-8 -*- # Project :…...

TypeScript 从入门到进阶之基础篇(三) 元组类型篇

系列文章目录 TypeScript 从入门到进阶系列 TypeScript 从入门到进阶之基础篇(一) ts基础类型篇TypeScript 从入门到进阶之基础篇(二) ts进阶类型篇TypeScript 从入门到进阶之基础篇(三) 元组类型篇TypeScript 从入门到进阶之基础篇(四) symbol类型篇 持续更新中… 文章目录 …...

现代CPU的多种运行模式

目前的CPU大多是支持X86-64技术的兼容CPU&#xff0c;这包括AMD64以及Intel的IA32E&#xff08;后被正式命名为EM64T&#xff0c;Extended Memory 64 Technology&#xff09;&#xff0c;因为AMD64先出&#xff0c;而EM64T与AMD64完全兼容&#xff0c;所以也统一称为AMD64技术。…...

Python PDF处理模块pypdf库详解

概要 PDF&#xff08;Portable Document Format&#xff09;是一种常见的文档格式&#xff0c;广泛用于存储和共享文本和图像数据。在 Python 中&#xff0c;有许多库可以用于处理 PDF 文件&#xff0c;其中之一就是 PyPDF。PyPDF 是一个功能强大的库&#xff0c;它允许你读取…...

C++上位软件通过LibModbus开源库和西门子S7-1200/S7-1500/S7-200 PLC进行ModbusTcp 和ModbusRTU 通信

前言 一直以来上位软件比如C等和西门子等其他品牌PLC之间的数据交换都是大家比较头疼的问题&#xff0c;尤其是C上位软件程序员。传统的方法一般有OPC、Socket 等&#xff0c;直到LibModbus 开源库出现后这种途径对程序袁来说又有了新的选择。 Modbus简介 Modbus特点 1 &#…...

PLSQL Developer 15安装和oracle客户端安装

文章目录 前言一、PLSQL Developer1.下载2.安装 二、oracle客户端1.下载2.环境变量 三、使用1. oci2. 连接3. 配置文件 总结 前言 oracle是经常使用的数据库&#xff0c;PLSQL Developer是众多产品中比较不错的一款工具&#xff0c;接下来我们来介绍PLSQL Developer的安装和使…...

【深度deepin】深度安装,jdk,tomcat,Nginx安装

目录 一 深度 1.1 介绍 1.2 与别的操作系统的优点 二 下载镜像文件及VM安装deepin 三 jdk&#xff0c;tomcat&#xff0c;Nginx安装 3.1 JDK安装 3.2 安装tomcat 3.3 安装nginx 一 深度 1.1 介绍 由深度科技社区开发的开源操作系统&#xff0c;基于Linux内核&#xf…...

解决flask启动报错:ImportError: DLL load failed while importing _dukpy: 找不到指定的程序

现象&#xff1a; 原因&#xff1a;dukpy没有win32执行库 解决办法&#xff1a; 到lfd.uci.edu 第三方库下载dukpy的win32 whl文件 注意&#xff1a; 需要跟你python版本和windows平台&#xff08;32位/64位&#xff09;对应 https://www.lfd.uci.edu/~gohlke/pythonlibs/#…...

腾讯面试总结

腾讯 一面 mysql索引结构&#xff1f;redis持久化策略&#xff1f;zookeeper节点类型说一下&#xff1b;zookeeper选举机制&#xff1f;zookeeper主节点故障&#xff0c;如何重新选举&#xff1f;syn机制&#xff1f;线程池的核心参数&#xff1b;threadlocal的实现&#xff…...

面向对象进阶(static关键字,继承,方法重写,super,this)

文章目录 面向对象进阶部分学习方法&#xff1a;今日内容教学目标 第一章 复习回顾1.1 如何定义类1.2 如何通过类创建对象1.3 封装1.3.1 封装的步骤1.3.2 封装的步骤实现 1.4 构造方法1.4.1 构造方法的作用1.4.2 构造方法的格式1.4.3 构造方法的应用 1.5 this关键字的作用1.5.1…...

Blazor项目如何调用js文件

以下是来自千问的回答并加以整理&#xff1a;&#xff08;说一句&#xff0c;文心3.5所给的回答不完善&#xff0c;根本运行不起来&#xff0c;4.0等有钱了试试&#xff09; 在Blazor项目中引用JavaScript文件&#xff08;.js&#xff09;以实现与JavaScript的互操作&#xff…...

Windows11 - Ubuntu 双系统及 ROS、ROS2 安装

系列文章目录 前言 一、Windows11 - Ubuntu 双系统安装 硬件信息&#xff1a; 设备名称 DESKTOP-B62D6KE 处理器 13th Gen Intel(R) Core(TM) i5-13500H 2.60 GHz 机带 RAM 40.0 GB (39.8 GB 可用) 设备 ID 7673EF86-8370-41D0-8831-84926668C05A 产品 ID 00331-10000-0000…...

深度学习(学习记录)

题型&#xff1a;填空题判断题30分、简答题20分、计算题20分、综合题&#xff08;30分&#xff09; 综合题&#xff08;解决实际工程问题&#xff0c;不考实验、不考代码、考思想&#xff09; 一、深度学习绪论&#xff08;非重点不做考察&#xff09; 1、传统机器学习&…...

html5实现好看的个人博客模板源码

文章目录 1.设计来源1.1 主界面1.2 认识我界面1.3 我的文章界面1.4 我的模板界面1.5 文章内容界面 2.结构和源码2.1 目录结构2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/135368653 html5实现好看…...

SpringSecurity深度学习

SpringSecurity简介 spring Security是什么&#xff1f; Spring Security 是一个强大且高度可定制的身份验证和访问控制框架&#xff0c;用于保护基于Spring的应用程序。它是Spring项目的一部分&#xff0c;旨在为企业级系统提供全面的安全性解决方案。 一个简单的授权和校验…...

odoo17 | 用户界面的基本交互

前言 现在我们已经创建了我们的新模型及其 相应的访问权限&#xff0c;是时候了 与用户界面交互。 在本章结束时&#xff0c;我们将创建几个菜单以访问默认列表 和窗体视图。 数据文件 &#xff08;XML&#xff09; Odoo在很大程度上是数据驱动的&#xff0c;因此模块定义的…...

网站建设实训计划书/windows优化大师卸载不掉

摘要&#xff1a;以“数字金融新原力(The New Force of Digital Finance)”为主题&#xff0c;蚂蚁金服ATEC城市峰会于2019年1月4日在上海如期举办。在ATEC区块链行业研讨会分论坛上&#xff0c;蚂蚁金服资深总监、BaaS业务负责人李杰力做了主题为《蚂蚁区块链BaaS&#xff0c;…...

wordpress vip会员插件/淄博信息港聊天室网址

模板介绍 精美PPT模板设计&#xff0c;中国农业大学本科毕业论文答辩PPT模板。一套高校PPT幻灯片模板&#xff0c;内含青色多种配色&#xff0c;精美风格设计&#xff0c;动态播放效果&#xff0c;精美实用。 一份设计精美的PPT模板&#xff0c;可以让你在汇报演讲时脱颖而出…...

金融商城快捷申请网站模板下载/sem优化软件选哪家

在 Rust 中&#xff0c;变量默认是不可变的。下面的例子展示了如何在变量名前使用 mut 来使一个变量可变&#xff1a; let foo 5; // 不可变 let mut bar 5; // 可变Rust 标准库中有很多叫做 Result 的类型&#xff1a;一个通用的 Result 以及在子模块中的特化版本&#xff…...

夫唯seo怎么样/第三方关键词优化排名

BUAA-OO-JML JML 概念与 toolchain JML 是一种为 Java 程序设计的、遵循 design by contract 范式的、基于 Hoare Logic 构建的 behaviour interface specification language。它通过使用 Hoare style precondition、postcondition and invariants 为程序员提供了一套规范而清晰…...

网站怎么建设以及维护/百度排名软件

采用版本为ckpalyer6.8,可在网上自行下载&#xff0c;也可直接复制底下ckpalyer6.8的js代码 1、ckpalyer6.8 js代码 /* -------------------------------------------------------------------------说明:正式使用时可以把该文件的注释全部去掉&#xff0c;节省加载时间ckplaye…...

三大框架对网站开发的作用/鄂州网站seo

1.双下划线开头 2.只能在类内部访问 3.在外部可以间接访问 4.子类也不能直接访问父类中的私有成员&#xff0c;只能间接访问 class Base:def __init__(self):self.__name pythonself.name Pdef BaseShow(self):return self.__nameclass Son(Base):def __init__(self):self.__…...