【爬虫JS逆向实战】某在线网JS逆向实例

8 阅读6分钟

==声明==:本文章仅用作技术交流,爬取网络数据应当合理合法,切勿爬取隐私数据或者高频率并发请求,造成的后果自负!


基本信息

  • 网站涉及加密参数businessDatae-signe-content-path

  • 逆向涉及技术webpack框架sm4加密

  • 目标数据网站招聘信息

接口寻找

首先打开调试窗口,看看数据接口在哪,首先还是点击翻页抓包 在这里插入图片描述

全是如下的数据包,并没有我们想要的数据 在这里插入图片描述

在这里插入图片描述

那就回到请求数据的初始页面

在这里插入图片描述

在这里插入图片描述

随便点击一个“IT/互联网”下的“测试工程师”,看一下请求接口数据

在这里插入图片描述

在这里插入图片描述

这个接口就是接收数据的了

初步判断

看一下这个接口有没有携带什么参数

  • 标头

在这里插入图片描述

  • 载荷

在这里插入图片描述

通过对比多次请求的接口,发现这三个参数都是会变化的,有些网站可能对其中的参数不会校验,但经过测试,这些参数都会被后端校验,所以都需要逆向出来。

载荷逆向

先从载荷入手吧(纯个人喜好),最简单的关键字搜索去碰碰运气

在这里插入图片描述

找到n先,一般都在这段代码的上面

在这里插入图片描述

打个断点调试一下

在这里插入图片描述

点进 “_” 这个方法看一看

在这里插入图片描述

主要是return后面的代码

在这里插入图片描述

这是一个判断式,简单来说 “ ? ” 前面的式子 "sm" === t.type 为真时执行 “ ? ” 和 “ : ” 之间的代码,反之则执行 “ : ” 后面的代码

从开始的代码可以判断出t.type一定是 “sm” 则这个判断式必为真,如下图

在这里插入图片描述

那么就是说,我们只需要关注“ ? ” 和 “ : ” 之间的代码,如下

在这里插入图片描述

可是事情没有那么简单,首先你并不能明确这段代码 现在 生成的值就是请求接口携带的值,在多次对比生成结果和最终携带的值之后,发现当第 6~7 次停到这段代码时,才是真正的生成位置

在这里插入图片描述

判断依据可以是上图标明的 word 具体值,也就是需要加密的 明文值 ,当其中出现 "target":"SEARCH_RESULT_PAGE" 字段时,但每次调试时都需要点个6~7次很烦,所以我们可以用浏览器调试用的 条件断点 功能,操作如下图

  • 右键需要断点的位置 在这里插入图片描述

  • 点击 “添加条件断点”,输入以下条件判断式(当word字段中存在"target":"SEARCH_RESULT_PAGE"时断住)

在这里插入图片描述

这样的话每当我们重新请求接口时,浏览器总是会在我们需要的时候断住

实际上这段代码明面上已经告诉我们了,这是那该死的 sm4 加密,不过也有可能魔改了,但不妨碍我们做个实验,因为 sm4 是固定的加密方式,直接网上搜或者问AI都可以获得加密模板,这里我提供了我的加密模板,不用谢

/* 通用sm4加密,已知key和iv的加密代码 */

// 引入sm-crypto库的sm4模块
const { sm4 } = require('sm-crypto'); // npm install sm-crypto

/**
 * SM4 CBC模式加密函数(PKCS7填充,128bit密钥,输出hex)
 * @param {string} plaintext - 待加密的明文
 * @param {string} key - 128bit密钥(hex格式)
 * @param {string} iv - 128bit初始向量(hex格式)
 * @returns {string} 加密后的hex格式密文
 */
function sm4CbcEncrypt(plaintext, key, iv) {
  try {
    // SM4 CBC加密(默认使用PKCS7填充)
    const ciphertext = sm4.encrypt(
      plaintext,       // 明文
      key,             // 128bit密钥(hex)
      {
        mode: 'cbc',   // 运算模式:CBC
        iv: iv,        // 初始向量(hex)
        output: 'hex'  // 输出格式:hex
      }
    );
    return ciphertext;
  } catch (error) {
    console.error('SM4加密失败:', error.message);
    throw error;
  }
}

用这个模板首先需要固定参数:需要加密的明文信息,key, iv,而这些在JS源码中都能找到

  • 明文信息(固定)

在这里插入图片描述

  • key(暂时固定,后面需要逆向)

在这里插入图片描述

  • iv(暂时固定,后面需要逆向)

在这里插入图片描述

  • 正确加密之后的值

在这里插入图片描述

  • 本地代码生成的值

在这里插入图片描述

在这里插入图片描述

文本对比完全一致

在这里插入图片描述

接下来去看一下 keyiv 吧,首先是 key ,它的生成位置在代码上方可以找到

在这里插入图片描述

点进 E 方法中看一下

在这里插入图片描述

这里直接扣代码了,t可以固定

在这里插入图片描述

在这里插入图片描述

w 未知

在这里插入图片描述

补呗,还能咋整

在这里插入图片描述

在这里插入图片描述

m函数 未知,下图补充

在这里插入图片描述

在这里插入图片描述

看着需要补window环境,不过这个 t 的作用除了用作 if 判断,也就个 getRandomValues 方法,我在这里借用了 AI 写了一个和原生浏览器对象 window 下的 getRandomValues 方法一模一样的方法

const nodeCrypto = require('crypto'); // npm install crypto

function getRandomValues(typedArray) {
    if (!typedArray || !(typedArray instanceof Uint8Array)) {
      throw new TypeError('参数必须是 Uint8Array 类型');
    }
    // 用 Node.js 原生 randomBytes 生成随机数并写入数组
    const randomBuffer = nodeCrypto.randomBytes(typedArray.length);
    typedArray.set(randomBuffer);
    return typedArray;
}

然后改写成如下代码就行了

在这里插入图片描述

还有个 o 方法需要找出来

在这里插入图片描述

0_o,看样子是 webpack 框架啊,打个断点看看(打完断点后记得刷新触发)

在这里插入图片描述

在这里插入图片描述

实锤了,就是 webpack 打包框架,将整个JS文件复制到本地,webpack 源码的逆向操作本文不涉及,可以参考以下文章:

guishou.blog.csdn.net/article/det…

其他的代码就很简单了

在这里插入图片描述

最后也是得到了key值

在这里插入图片描述

接下来是 iv

在这里插入图片描述

在这里插入图片描述

跟前面的 key 生成的方法一模一样,在此不做赘述。

此时此刻将上面的整合一下,就可以得到载荷 businessData 的值了。

e-sign逆向

这个依旧是关键字搜索

在这里插入图片描述

这个 n 有点眼熟,看了一下发现就是 businessData 的值,传递的参数已经解决

在这里插入图片描述

看一下 b 方法在哪里定义

在这里插入图片描述

也是跟 webpack 有关,好办,直接这样写就行了

var b = global.loader("gGBh").sm3;
var o = b("business" + n + "data"); // o 就是e-sign的值

e-content-path逆向

其实在上面逆向 e-sign 时,眼尖的你应该能看到,e-content-path 参数的生成位置和它在一起

在这里插入图片描述

经过反复测试,发现这个 e-content-path 其实和前面 businessData 生成的逻辑有点相似,都不是一步到位的,需要添加 条件判断式,主要判断依据为 t 中的 publicKey 的值,它是固定的

043f4a9673db98fd52a87e087da75ca8d4978748188e29373acc131887d7b78ee89b07364f644352e4cb4029d8330509368b27b10638345c8afd41149626d917aa

在以下位置打上条件断点

在这里插入图片描述

在这里插入图片描述

这个条件断点要搭配上面调试 businessData 的条件断点,执行顺序是

在这里插入图片描述

上面不是很难,看一下 k 函数

在这里插入图片描述

在这里插入图片描述

根据代码中的条件判断,想必一辈子都只会执行下图标记的代码

在这里插入图片描述

所以这个 k 方法可以删删减减,变成下面的样子

在这里插入图片描述

v 方法在这

在这里插入图片描述

那还说啥,直接这样写就行了

var v = global.loader("gGBh").sm2;

x 在这

在这里插入图片描述

这样写

var x = m(32);

C 在这

在这里插入图片描述

这样写

var C = m(32);

至此也是生成出来了

在这里插入图片描述

结果展示

相信到了这一步,你已经过了所有的难关,就美美地把所有参数整合起来

在这里插入图片描述

再通过 python 脚本请求接口获取数据

在这里插入图片描述

收工!!!


如有爬虫相关问题,可关注wx公众号“小恰学逆向”,我们一起讨论学习。