js aes加密_某高考咨询网js逆向分析笔记

一、某高考资讯网逆向分析

某网站的js加密分析,安全签名signsafe + HmacSHA1 + AES

一年前分析过网站数据还没有加密,最近需要获取新的数据发现原先的爬虫失效,请求和响应都经过加密。于是重新分析,记录下分析思路以及分析过程中遇到的问题。

二、signsafe分析

2.1 抓包请求
打开谷歌浏览器,f12开发者模式抓包,分析请求参数:
f1fe7a9b4ce970df684528dee9f1adbe.png
抓包请求
local_province_id:省份id
local_type_id:可类型,固定参数,可以忽略
page:当前页数
school_id:学校id
signsafe:安全签名,动态变化
size:响应返回数据数量
url:固定值,可以忽略
year:年份
2.2 寻找signsafe加密算法
一般遇到这种明确的加密参数,例如 signsafe=xxx这种,通常做法都是尝试搜索参数名。按住ctrl+shift+f,调出搜索框,搜索关键词signsafe。
f068f34673fb8bb971fdd802278e7df7.png
搜索signsafe
这里只搜索到一条包含signsafe关键字的文件,main.75.js文件,跟进去。格式化代码,按住ctrl+f调出文件内搜索框,继续搜索定位signsafe的位置。
36996312c6682b5c33c2812ab912abe2.png
signsafe加密函数
定位到疑似函数,打断点测试该函数是否就是我们需要的加密函数。
55a336e7c6db8608831ed37b6ac3079b.png
断点分析
断下来的数据可以看到,t就是请求中的signsafe参数。而且,函数中也出现了HmacSHA1、base64等方法。由此可知,定位的加密位置是正确的。接下来需要将加密函数抠下来改写,方便调用。下断点继续跟踪方法调用。跟踪v.a.enc.Utf8.parse方法,如下:
bdd5b6333bc56df3ee93273d60cfaf53.png
v.a.enc.Utf8.parse方法
单步步入,继续跟c.parse方法,如下:
243244714bbe16895a74211e63af6118.png
c.pars方法
这里又出现了一个i.init方法,继续跟进去,如下:
5c42ae43369abf1aa4abf15ce73db107.png
i.init方法
跟完v.a.enc.Utf8.parse之后,继续跟踪外层v.a.HmacSHA1方法,如下:
5951af65739b5d69e486f41b83e385fb.png
v.a.HmacSHA1方法
跟到这里能看出,很容易的定位加密函数位置,而且关键函数代码量不多,但是代码可读性较差,断点跟踪的方式反而将问题复杂化,反思有可能是分析的方式有误。由于网站应该是经过webpack或类似的工具打包,将多个js文件打包成一个,导致代码文件冗长。仔细想想,如果是自己开发网站,也不可能手写各种加密算法,极大可能是调用第三方现成的加密库。如果是未压缩前的代码文件,必然会引用第三方的加密库。所以转换思路,直接搜索关键字require,尝试找到引用的加密库。ctrl+f 搜索 require,如下:
a7db3df743b75c09f91b2c1f66a873d5.png
搜索关键字require
通过搜索发现,代码中确实引用了Crypto文件,而且查阅Crypto文档,发现api函数名与加密函数中的方法一致。初步证实猜想是正确的,那么接下来安装CryptoJs库,照着仿写加密流程。
e7878e1c7468c5661badee3670287d31.png
加密流程

梳理一下加密流程:

  • v.a为Crypto-js的引用对象;
  • 第一步:v.a.enc.Utf8.parse(e),参数e为请求的get链接,将utf8字符串转换为WordArray;
  • 第二步:v.a.HmacSHA1(result, M),result为上一步中的WordArray,M为加密密钥,打断点可知M="D23ABC@#56",为固定值。

HMACSHA1 是从 SHA1 哈希函数构造的一种键控哈希算法,被用作 HMAC(基于哈希的消息验证代码)。它将任意长度的字符串生成 28位长的字符串。

961fd823177e8ddf8414c0a4a2c5ef91.png
HMACSHA1加密返回结果
  • 第三步:v.a.enc.Base64.stringify(t).toString(),将第二步的结果进行一次base64编码。
4209eb4b2ef42f9c64a81c6fed911a9e.png
base64编码
  • 第四步:t = C()(t),直观看上去不知道函数作用,打断点跟进去函数内部发现是进行了一次md5运算。
fab9a1c5459bdbe38b3a35ecfb97265b.png
md5加密
至此,signsafe参数加密过程分析结束。先将get请求链接转utf8,然后将utf8字符串转WordArray,再进行一次HMACSHA1加密,又将结果进行base64编码,最后再进行一次md5得到最终的signsafe结果。
2.3 代码实现
弄清楚加密流程,直接调用CryptoJs库,照着流程实现即可:
// e get请求链接, M 为加密密钥
function initSignSafe(e, M) {
 let t = CryptoJS.enc.Utf8.parse(e);
 let a = CryptoJS.HmacSHA1(t, M);
 let b = CryptoJS.enc.Base64.stringify(a).toString();
 let c = CryptoJS.MD5(b).toString();
 return c;
}

三、响应解码

这个网站还是做了一些防护的,请求参数和响应数据都进行了加密。上面我们分析了请求中的安全签名加密,接下来分析响应数据解密方法。照例抓包进行分析,抠出解密代码。
3.1 抓包查看响应
87a6446df96e1b1fa21099deb1ecf09e.png
返回响应抓包
这一长串就是加密后的数据,乍一看无从下手,但有意思的是,响应中method的值说明响应是通过aes-256-cbc的方式进行加密。百度解释:

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥。AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同。

看多了太复杂,这里只需要知道使用的加密方法是aes-256,密钥长度256位,cbc指的是在加密和解密是需要一个初始化向量(Initialization Vector, IV),在每次加密之前或者解密之后,使用初始化向量与明文或密文异或。说白了,就是设定的密钥,添加一个初始化偏移量。加密时,明文先与iv偏移量异或,再将结果进行256位的块加密,得到的输出就是密文,同时本次的输出密文作为下一个块加密的IV。
3.2 响应解密分析
分析思路跟signsafe参数类似,按住ctrl+shift+f,搜索关键字aes。
5b7894ecb304d56a98bb4dc3883a766f.png
搜索aes关键字
按住ctrl+f,文件内搜索aes关键字:
32466cab57e1c634d1469bc6e41ba50c.png
文件内搜索aes关键字
有11个结果,对可疑的函数段下断点找到加密函数:
3b3d46405faf6698a5ad07346dd7553f.png
断点找到加密函数

梳理一下加密流程:

  • 第一步:将响应中的数据赋值到变量中保存,s为安全签名的密钥;
  • 第二步:将两个原始密钥s("D23ABC@#56")和l("apidata/api/gk/plan/special")进行PBKDF2加密;

PBKDF2(Password-Based Key Derivation Function)是一个用来导出密钥的函数,常用于生成加密的密码。它的基本原理是通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥。

  • 第三步:将密文初始化为一个cipher params 对象;
  • 第四步:进行aes-256-cbc加密,传入cipher params 对象,密钥是经过PBKDF2加密的s("D23ABC@#56"),偏移量lv为经过PBKDF2加密的l("apidata/api/gk/plan/special");
  • 第五步:将aes加密后的结果WordArray转换为字符串g.toString(v.a.enc.Utf8)。
简而言之,将两个密钥进行PBKDF2加密,需要加密的数据初始化为cipher params 对象。进行一次aes256cbc加密,加密结果转换为字符串,最终获得解密后的响应内容。
3.3 代码实现
复制加密流程代码,将v.a替换为CryptoJs引用对象进行改写:
function decodeRes(e, _s, _l) {
 let a = e, s = _s, l = _l;
 if (e.data && e.data.text) {
  let c = e.data.text;
  let u = CryptoJS.PBKDF2(s, "secret", {
   keySize: 8,
   iterations: 1e3,
   hasher: CryptoJS.algo.SHA256
  }).toString();
  let f = CryptoJS.PBKDF2(l, "secret", {
   keySize: 4,
   iterations: 1e3,
   hasher: CryptoJS.algo.SHA256
  }).toString();
  let m = CryptoJS.lib.CipherParams.create({
   ciphertext: CryptoJS.enc.Hex.parse(c)
  });
  let g = CryptoJS.AES.decrypt(m, CryptoJS.enc.Hex.parse(u), {
   iv: CryptoJS.enc.Hex.parse(f)
  });
  a = {
   code: "0000",
   data: JSON.parse(g.toString(CryptoJS.enc.Utf8)),
   message: ""
  }
  return JSON.stringify(a);
 }
 return undefined;
}
解密后的内容如下:
0deaa5c4c07a0846ec7198b931696d04.png
解密后的响应内容

四、总结

  • 加密参数优先通过搜索的方式进行定位;
  • 现在的js文件一般都经过压缩,可读性较差,可以通过搜索require等关键字转换思路;
  • 抠出加密函数的方法可以通过断点一步一步跟踪,查缺补漏,或者手动仿写;
  • 逆向的技巧性很强,要善于利用搜索引擎。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/527449.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opencv 的norm_22、OpenCV用卷积Filter2D进行滤波器

迄今为止,看到的函数中,卷积的操作发生在OpenCV函数的内部。理论上,图像卷积就是将内核与图像覆盖区域对应位置相乘之后求和。从调用函数上来看,它需要一个数组参数来描述内核。在实践层面,有一个重要的微妙因素会对结…

glide加载gif图不显示动画_用Python绘制会动的柱形竞赛图

我们经常看到的Bar Chart Race(柱形竞赛图),可以看到数据的呈现非常的直观。今天就一起来学习下如何生成和上面一样的柱形竞赛图。1、导入Python库2、加载数据集这里使用的是城市人口数据集,加载我们想要的数据:其中&a…

不冲突的端口范围_网络中IP地址发生冲突故障怎么办

——————欢迎新老朋友们加入微信群,方便技术讨论,信息互通,行业交流:智能弱电行业专家群;智能弱电行业技术群;智能弱电行业信息群;申请加入请加小编微信:15537112161———————有朋友提…

项目结构_组织结构对项目影响系列课程---项目式组织结构

在前面的几篇文章中我们分别介绍了,系统型(简单型),职能型,弱矩阵,平衡矩阵,强矩阵结构的优点和缺点及它们带给项目的影响。今天我们介绍项目式组织结构的优点和缺点及其可能产生的影响。从结构…

第三范式的作用_钟启泉:教学范式的转型,让一线教师面临三大挑战 | 头条

培育“核心素养”的方法论——能动学习真实性的学习境脉所谓“能动学习”是“基于学习者的主体性参与与学习者之间能动的交互作用的学习而产生的”。它不是单纯记忆知识的学习,而是指学习者能够活跃地应对种种课题,并富有实感支撑的学习。基于“核心素养…

云服务器 管理控制台_关于小白如何初步管理自己的云服务器

博主在刚刚接触云服务器的时候,买的云服务是Linux系统的,反正是一脸懵,后来找了很多资料。所以博主认为步骤主要为以下几步第一步:如果买的是Linux系统将其重装成windows系统。以腾讯云服务器为例1.点击右上角的控制台2.进入买的云…

leetcode 贪心_利用贪心算法解LeetCode第1253题:重构2行二进制矩阵

题目描述给你一个 2 行 n 列的二进制数组:矩阵是一个二进制矩阵,这意味着矩阵中的每个元素不是 0 就是 1。第 0 行的元素之和为 upper。第 1 行的元素之和为 lower。第 i 列(从 0 开始编号)的元素之和为 colsum[i],col…

pgadmin连接服务器失败_增值税发票税控软件:连接服务器失败是否使用离线文件进行更新?...

增值税发票税控软件:连接服务器失败是否使用离线文件进行更新?第一步:确认本地电脑是否可以正常打开网页;打开电脑,网页查看一下是否可以正常上网,打开百度发现,可以正常上网。第二步&#xff1…

移除镜像_这是否是你心目中的英雄联盟手游?镜像地图。水晶塔,传送移除

自从5月29日之后,RIOT官方放出了英雄联盟手游最新开发者日志后。关于视频内展示的多个游戏关键内容。在玩家群体中引起了大量的争议和讨论。以下是争议和讨论最多的内容1.游戏内英雄的攻击是否为AOE伤害?在大多数的玩家心中,英雄联盟手游是不应该有这种…

电脑重启bootmgr_电脑出现bootmgr is missing怎么办

展开全部电脑开机,或者重启以后显示:Bootmgr is missing, 是代表硬盘的主引导记录(MBR)出错,从而导致无法引e68a8462616964757a686964616f31333337613931导系统,哪只能重建主引导记录,还有一个可能是丢失系统文件&…

qt 在label上以光标位置进行缩放_缩放|位移|渐变简单动画

本文简单介绍Qt的一些动画效果(缩放,位移,渐变)。缩放动画将窗口的geometry(位置,大小)属性作为动画参考实现缩放动画。代码QWidget *w new QWidget;w->setWindowTitle(QStringLiteral("缩放动画Qt君"));w->resize(320, 240)…

虚拟机中ubuntu可以使用显卡吗_在KVM下使用ubuntu19.10安装Anbox

导言:Anbox是一个Android模拟器,可以从linux系统运行Android应用程序或游戏。对于Anbox的安装已经有了各种教程,主要针对ubuntu18.04之前的版本。最近在做一个关于虚拟机中跑安卓的项目,因此在虚拟机中使用ubuntu18.04系统&#x…

mysql tree_MySQL树形遍历(二)

转载自:http://blog.csdn.net/dreamer0924/article/details/7580278英文原文:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/预排序遍历树算法:modified preorder tree traversal algorithm这个算法有如下几个数据结构1 lft 代表左 left2 r…

mysql 常用数据库连接池_常见的数据库连接池

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入 2.C3P0 在Hibernate和Spring中默认支持该数据库连接池 需要引入:c3p0-0.9.1.2.jar包,如果报错再引入mchange-commons-0.2.jar 1. 在类路径下编写一个c3p0-config.xml文件 c3p0-co…

win32_bios 的对象编辑器无法保存对象_怎样创建Femap对象

创建Femap对象主要有两种方式,一是直接在Femap内置的API程序窗体中创建,二是在API程序窗口以外的开发环境中创建。一、使用FEMAP集成的API程序窗口开始使用FEMAP API的最快方法是打开API编程窗口。它提供了一个完整的编辑、调试和运行的环境,…

未定义变量: data_三、变量声明

三、变量声明var声明主要特点: - var是函数作用域,只针对函数声明 - 可以多次声明同一个变量不会报错 - 捕获变量怪异之处function fnVar(flag: boolean) {if(flag) {var x 10;}return x; } fnVar(true); // 10 fnVar(false); // undefinedvar isDone: …

表单的默认提交方式_对于PHP表单提交有哪集中方式讲解

PHP 做网页后端还是很优秀的&#xff0c;PHP 表单提交&#xff0c;不外乎两种方法&#xff0c;即 GET 和 POST 方法&#xff1b;PHP后台使用全局变量$_POST;$_GET;来获取提交数据。代码&#xff1a;<!DOCTYPE HTML> <html> <head><meta charset"utf-…

spring中怎么让事物提交_Spring怎么在一个事务中开启另一个事务

点击上方“Java知音”&#xff0c;选择“置顶公众号”技术文章第一时间送达&#xff01;作者&#xff1a;Mazinmy.oschina.net/u/3441184/blog/893628Spring项目&#xff0c;需要在一个事务中开启另一个事务。上面提到的情景可能不常见&#xff0c;但是还是会有的&#xff0c;一…

通过对象指针的方式强行指定到子类_C++中的虚指针与虚函数表

​ 最近在逛B站的时候发现有候捷老师的课程&#xff0c;如获至宝。因此&#xff0c;跟随他的讲解又复习了一遍关于C的内容&#xff0c;收获也非常的大&#xff0c;对于某些模糊的概念及遗忘的内容又有了更深的认识。以下内容是关于虚函数表、虚函数指针&#xff0c;而C中的动态…

如何手动输入给数组赋值_你是否真的了解VBA数组呢?让我带你认识一下真正的数组...

大家好&#xff0c;我们今日继续讲解VBA代码解决方案的第110讲内容&#xff1a;VBA数组讲解&#xff0c;什么是数组&#xff0c;如何定义数组&#xff0c;如何创建数组一、什么是数组 就是数组共享一个名字&#xff0c;有着多个元素按顺序排列的变量。在数组中&#xff0c;元素…