某苏人社异步JS逆向加解密分析(sm2+sm3+sm4)

前期准备

  • 网址:aHR0cHM6Ly9ycy5qc2hyc3MuamlhbmdzdS5nb3YuY24vaW5kZXgv
  • 目标:
    1. 接口请求内容加密和响应内容解密
    2. 请求头加密参数 Web-Encrypt-Response-Encrypt-KeyWeb-Encrypt-Sign
  • 涉及内容:
    1. js worker 多线程通信
    2. axios网络请求库
    3. 国密sm2sm3sm4

Axios

网址:Axios

这个网站用到了 axios,可以先了解一下 axios 这个网络请求库,主要是interceptor这块

拦截器

在请求或响应被 then 或 catch 处理前拦截它们。

jsx 复制代码
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
return config;
  },function (error) {
    // 对请求错误做些什么
return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
return response;
  },function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
return Promise.reject(error);
  });

分析流程

先来看一下要逆向的内容

如上图所示,获取考试列表(getExamTaskIM)这个接口的请求和返回数据都是加密的

请求加密分析

老规矩直接看堆栈,进去第一个下个断点,刷新页面

成功断下后发现 xhr send 发送已经完成了加密

往上找一下堆栈,发现一个axios的请求拦截器,直接下断点刷新

断住之后可以追进去看一下

有四个拦截器,分别进去下一个断点去查看,最终在最后一个拦截器发现关键数据

这是一个与worker进行通信的异步函数,我们往下看看其他逻辑

发现有一个onmessage的回调方法,我猜测加密流程是这样的:

  1. 主线程发送明文数据(postMessage)
  2. work 线程接收并开始加密(onMessage)
  3. work 线程加密完后发送加密数据给主线程(postMessage)
  4. 主线程接收加密数据(onMessage)

异步方法大都有一个回调的过程

下图主线程为postMessage一方,其它线程则需要使用onMessage接受数据

接着分析流程,我们先在这个onmessage回调方法内下段,再跟堆栈就容易找到调用位置了

找到postMessage后往上看看就能发现关键加密逻辑

  • 源流程代码,大量的 promise
jsx 复制代码
self.onmessage = function(t) {
        var r, e, o, h, a, f, c;
        (r = t.data.prefix,
        e = t.data.data,
        o = e._s1,
        h = e._s2,
        a = e.requestData,
        f = Math.floor(Date.now() / 1e3).toString(),
        c = function() {
            return 2 === s
        }
        ,
        u.timestamp = f,
        new Promise((function(t, e) {
            new Promise((function(t, e) {
                try {
                    t({
                        key: r + i.default._s2EN(o, h, 0)
                    })
...
            }
...
            new Promise((function(t, e) {
                try {
                    var o = r + i.default._s2EN(JSON.stringify(a), h, 0)
                      , s = f + o;
                    t({
                        content: o,
                        signature: (0,
                        n.default)(s)
                    })
...
            }
...
        }
...
    }

进到这里了直接单步调试就是了,直接跟到_s2EN 函数里,这里就是加密函数了,加密函数用到了两次,一次加密 sign,一次加密 payload

这个其实就是sm2标准算法,看方法名就能猜出个大概了,就懒得写过程了,直接给出个大概的代码吧

jsx 复制代码
var prefix = "04";
// 解密response的key
var _s1 = "862344dec7e0907a2b215c37a57caf95";
// 加密data的publicKey
var _s2 = "04fc439405f925df23510517e1e5a8078d19b23b24d62190c40e632f1d0bcd784fc6fcf1a8c3b5cf7f422815c6b322176e89f56f781ccd3c36aa02e5d31400090a";

// 计算key
key = prefix + sm2(_s1, _s2, 0);

// 加密payload,计算sign
payload = {
    "bge304": 202432990000309,
    "bge316": "320199"
}
var timestamp = Math.floor(Date.now() / 1000).toString();
var content = prefix + sm2(JSON.stringify(payload), _s2, 0)
var sign = sm3(timestamp + o);
headers= {
    "Web-Encrypt-Response-Encrypt-Key": key,
    "Web-Encrypt-Sign": sign ,
    "Web-Encrypt-Timestamp": timestamp
}

sign 加密过程忘记截图了,实际上就是个sm3加密

完成以上请求头和请求数据的加密后,就可以正常请求拿到返回数据了

响应解密分析

跟找加密过程差不多,直接找到响应拦截器就行

挨个下断点,发现第一个很像了

这个web-encrypt-sign是响应头里的一个值,往下翻翻会发现熟悉的postMessageonMessage

这里过程跟加密差不多就不详细写过程了,直接找关键点

看方法名能猜出个大概是sm4解密,解密的 key 就是之前传入的_s1

随便抓个包解密试一下,可以看到正常解密成功,解密出来的 response 还需要 html 实体解码一下才行

Python 还原实现

  • 代码:
  • 成果:

大功告成!

微信公众号

公众号更新比较快,欢迎关注!

相关推荐
API_Zevin11 小时前
如何优化亚马逊广告以提高ROI?
大数据·开发语言·前端·后端·爬虫·python·学习
数据小小爬虫12 小时前
淘宝商品详情API返回值说明:Python爬虫代码示例
java·爬虫·python
重剑无锋102412 小时前
【《python爬虫入门教程11--重剑无峰168》】
开发语言·爬虫·python
数据小爬虫@20 小时前
利用Java爬虫获取店铺所有商品:技术实践与应用指南
java·开发语言·爬虫
大数据魔法师2 天前
Python爬虫 - 豆瓣图书数据爬取、处理与存储
爬虫·python
有杨既安然2 天前
Python爬虫入门指南:从零开始抓取数据
开发语言·爬虫·python·信息可视化·数据分析·excel
lovelin+v175030409662 天前
区块链技术为电商API接口带来的数据安全革新
大数据·人工智能·爬虫·数据分析·api
小爬虫程序猿3 天前
爬虫代码中如何添加异常处理?
爬虫
single_ffish3 天前
数据挖掘入门介绍及代码实战
人工智能·爬虫·python·数据挖掘