(最新)唯品会WEB端加密参数逆向分析

声明:本文内容仅供学习交流,严禁用于商业用途,否则由此产生的一切后果均与作者无关。如有冒犯,请联系我删除。

一、明确加密参数

首先,谷歌浏览器打开网站:aHR0cHM6Ly93d3cudmlwLmNvbS8=,从搜索结果的列表页中,随意点击其中一个商品,进入商品详情页(默认在新窗口打开)

在商品详情页,打开开发者工具,清空网站的所有缓存后,页面会自动刷新(唯品会网站的特点,一般网站都不会自动刷新),此时可从Network选显卡中,捕捉到详情页的数据接口,如下图所示:

请添加图片描述

经过比对,v4, v5, v6都含有商品详情数据,但v6是最完整的,故只需要分析v6接口即可。

如何为上述数据接口快速生成对应的Python请求代码呢?

在浏览器Network选项卡中,鼠标选中目标url --> 右键 --> Copy --> Copy as cURL(bash),然后在浏览器窗口中,打开这个网站【 https://curl.trillworks.com/ 】,在左边窗口粘贴刚才从浏览器中复制的内容,右侧就会自动生成对应的Python代码,如下图所示:

请添加图片描述

将右侧Python代码复制到Pycharm中,稍作修改,即可快读调试和运行起来。

Python代码示例:

# -*- encoding: utf-8 -*-
# @Author : qiang
# @File : demo.py
# @Time : 2022/3/15 11:03

import requests

headers = {
    'authority': 'mapi.vip.com',
    'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"',
    'sec-ch-ua-mobile': '?0',
    'authorization': 'OAuth api_sign=9e73ca11bc74f820ebff11d58b2b757eab93df2f',
    'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'accept': 'application/json, text/javascript, */*; q=0.01',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
    'sec-ch-ua-platform': '"Windows"',
    'origin': 'https://detail.vip.com',
    'sec-fetch-site': 'same-site',
    'sec-fetch-mode': 'cors',
    'sec-fetch-dest': 'empty',
    'referer': 'https://detail.vip.com/',
    'accept-language': 'zh-CN,zh;q=0.9',
    'cookie': 'user_class=a; VipUINFO=luc%3Aa%7Csuc%3Aa%7Cbct%3Ac_new%7Chct%3Ac_new%7Cbdts%3A0%7Cbcts%3A0%7Ckfts%3A0%7Cc10%3A0%7Crcabt%3A0%7Cp2%3A0%7Cp3%3A0%7Cp4%3A0%7Cp5%3A0%7Cul%3A3105; mars_cid=1647312296139_3b48068f5896fbf1403e5edc639145bf; vip_first_visitor=1; vip_address=%257B%2522pid%2522%253A%2522104104%2522%252C%2522cid%2522%253A%2522104104101%2522%252C%2522pname%2522%253A%2522%255Cu5e7f%255Cu4e1c%255Cu7701%2522%252C%2522cname%2522%253A%2522%255Cu5e7f%255Cu5dde%255Cu5e02%2522%257D; vip_province=104104; vip_province_name=%E5%B9%BF%E4%B8%9C%E7%9C%81; vip_city_name=%E5%B9%BF%E5%B7%9E%E5%B8%82; vip_city_code=104104101; vip_wh=VIP_NH; vip_ipver=31; mars_sid=5ad2ca78970c7100b5f2f27a663bc80d; vip_access_times=%7B%22detail%22%3A1%7D',
}

data = {
  'app_name': 'shop_pc',
  'app_version': '4.0',
  'warehouse': 'VIP_NH',
  'fdc_area_id': '104104101',
  'client': 'pc',
  'mobile_platform': '1',
  'province_id': '104104',
  'api_key': '70f71280d5d547b2a7bb370a529aeea1',
  'user_id': '',
  'mars_cid': '1647312296139_3b48068f5896fbf1403e5edc639145bf',
  'wap_consumer': 'a',
  'scene': 'detail',
  'productId': '6919508568358582982',
  'opts': 'priceView:13;quotaInfo:1;restrictTips:1;panelView:3;foreShowActive:1;invisible:1;floatingView:1;announcement:1;svipView:2;showSingleColor:1;svipPriceMode:1;promotionTips:6;foldTips:3;formula:1'
}

response = requests.post('https://mapi.vip.com/vips-mobile/rest/shopping/pc/detail/main/v6', headers=headers, data=data)
print(response.text)

仔细观察上述代码,结合经验,不难发现几个疑似加密的参数,如cookie中的mars_sidmars_cid, headers中的Authorization, 以及params中的api-keymars_cid

先让代码运行起来看看,发现可以正常拿到数据。这说明,这些疑似加密的参数此时并未失效。

那到底是哪些参数起关键作用呢?这里采用单因素分析法,逐个校验。比如逐个注释掉cookie中的字段,运行起来看是否能正常拿到数据。

最终发现,cookie中只校验mars_sid, headers中的Authorization是必须的,data中的mars_cid(值会变化)也是必不可少的,api_key是个固定值(多抓几次包,发现是个定值,且浏览器中全局搜索一下, 也能发现是个固定的值**)**。

二、加密参数的逆向分析和算法还原

经过上面的分析,待分析的加密参数只有3个,分别是:

  • cookie中的mars_sid

  • headers中的Authorization

  • data中的mars_cid

先从哪一个开始呢?

控制台Ctrl + Shift + F,对三个参数分别进行全局搜索,发现都有好几个结果,不太方便分析。

注意到v6接口是XHR请求,可以考虑加个XHR断点快速下断,也可以通过请求的调用链找到请求初始化的地方来下断点。这里采用的是后一种方式,如下图:

请添加图片描述

点击跳转后,可定位到如下代码,前后代码稍微一看,特征非常明显,这里就是v6接口请求初始化的地方了

请添加图片描述

authorization参数的值就是c, 通过var c = window.sign.getSign(d, g); 来生成。

2.1 authorization的逆向分析和还原

如上,在4788行处下断点,清空页面缓存信息后,刷新进入断点。可以看到,d参数值为接口链接,

g参数值为post表单数据

请添加图片描述

请添加图片描述

F11 跟进getSign函数,发现相关JS代码做了Obfuscator混淆保护,让人眼花缭乱,不方便分析。

请添加图片描述

硬刚吧,容易秃头。为了保护头发,采取AST解混淆 + JS替换调试的方案进行处理。

AST (Abstract Syntax Tree(抽象语法树)) 是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构。它由一堆节点(Node)组成,每个节点都表示源代码中的一种结构。

AST解混淆,是指通过ast开源工具库,如babel等,根据需要对JS代码节点进行裁剪,合共等一系列操作,重新生成JS代码的过程,可实现字符串解密替换,常量折叠合并,花指令移除,反控制流平坦化等功能,从而简化JS代码,方便阅读分析。

这里采用蔡老板的解混淆脚本,把网站的混淆代码全部复制保存到文件中,如vip_encode.js,运行如下命令,直接可得到解混淆后的js代码文件

node decode_obfuscator0219.js vip_encode.js vip_decode.js

JS替换这里使用的是谷歌插件ReRes, 其他工具如Fiddler, Charles, Mitmproxy等,也都可以实现类似的替换功能,哪个熟悉就用哪个吧。

如下图配置好ReRes的匹配规则

请添加图片描述

清空页面缓存并刷新,重新跟进getSign函数时,发现代码已经变得非常友好,又可以愉快地分析了。

请添加图片描述

继续单步调试,来到var _0x2f289b = _0x338046["replaceHost"](_0x3b5df6); 发现就是把入参url的域名擦除掉,replaceHost方法直接扣取下来

请添加图片描述

跟进hashParam,发现就是对param对象进行键值排序和拼接,最后sha1加密并返回结果,也没啥东西,照着把代码抠下来就行,缺啥补啥, 很简单

紧接着,来到下面这两行代码处

var _0x4d92bd = _0x338046["getCookie"]("mars_cid") ? _0x338046["getCookie"]("mars_cid") : "";

var _0x4fa5f8 = _0x338046["getCookie"]("mars_sid") ? _0x338046["getCookie"]("mars_sid") : "";

很明显,就是getCookie 方法,分别从cookie里分别获取mars_cidmars_sid

  • 其实mars_cid也可以从param对象取, 因为我们发现param对象的mars_cid的值,跟cookie里mars_cid的值是一模一样的, 具体它是怎么生成的,后面再分析。

  • mars_sid就只能从cookie中取值啦,也是先放着,一会再定位分析它是如何生成的。

继续单步调试,来到

var _0x4dd2d3 = _0x338046["getST"](_0x173ad1);

_0x680f99 = _0x338046["sha1"](_0x2f289b + _0x42d935 + _0x4fa5f8 + _0x4d92bd + _0x4dd2d3);
_0x680f99 = "OAuth api_sign=" + _0x680f99;
return _0x680f99;

其中getST方法涉及到AES加密,也没啥,照着扣下来

最后将api + hashParam + sid + cid + secret拼接,sha1加密后,返回加密结果。

照着扣下来,headers中的Authorization加密参数就分析完了。

2.2 mars_sid 的逆向分析和还原

由于该cookie值不是通过服务器set-cookie的方式返回的,我们直接上油猴插件,辅助定位分析,对应的hook脚本如下:

// ==UserScript==
// @name         hook cookie mars_sid
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to hook cookie mars_sid
// @author       zhuangqiang.huang
// @include      https://detail.vip.com*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    //document = {cookie: ''};
    var document = window.document;
    var cookie_cache = document.cookie;
    Object.defineProperty(document, 'cookie',{
        get: function () {
            console.log('Getting cookie');
            return cookie_cache;
        },
        set: function (val) {
            console.log("Setting cookie", val);
            if (val.indexOf("mars_sid") != -1){
                debugger;
            }
            var cookie = val.split(";")[0];
            var ncookie = cookie.split("=");
            var flag = false;
            var cache = cookie_cache.split(";");
            cache = cache.map(function (a) {
                if (a.split("=")[0] === ncookie[0]){
                    flag = true;
                    return cookie;
                }
                return a;
            })
            cookie_cache = cache.join(";");
            if (!flag){
                cookie_cache += cookie + ";";
            }
            this._value = val;
            return cookie_cache;
        },
    });
    // Your code here...
})();

上述脚本的注入时机,选择document-start,保存脚本,清空网站缓存,刷新页面后,注入的脚本就会生效,此时,断点停在脚本设置的debugger处

请添加图片描述

紧接着,堆栈回溯分析,逐个点击调用栈,在a处发现关键点

请添加图片描述

不难分析出,mars_sid就是通过参数b设置进去的,参数b的具体生成也在上面,跟进u.generateRand函数看一下吧

请添加图片描述

很简单,也是直接扣代码,mars_sid就分析完了。

2.3 mars_cid 的逆向分析和还原

细心的你可能早就发现,其实mars_cid的算法就在上面截图里,也很简单

请添加图片描述

三、代码整合与验证

最后,把扣下来的JS代码组合下,就可以调用啦,直接上效果图

请添加图片描述

请添加图片描述

没啥毛病,直接出货。

其它接口,v4, v5都是类似的,改改params就能拿数据啦。


感谢阅读!如有疑问,可联系QQ:630589959(不常在线)

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值