【Python 逆向某1688】 今天做一下1688的逆向分析,仅供学习

逆向日期:2024.12.16

使用工具:Python,Node.js

本章知识:逆向分析1688的sign参数,并用python实现调用并采集公开数据

文章难度:低等(没难度)

文章全程已做去敏处理!!!  【需要做的可联系我】 

AES解密处理(直接解密即可)(crypto-js.js 标准算法):​​​​​​在线AES加解密工具

仅供学习!仅供学习!仅供学习!

今天来逆向分析sign参数,并采集公开数据,给大家进行演示,仅供学习,文章全部已去敏,无需担心

1、打开某某网站(使用文章开头的AES在线工具解密):

99Lp55WUF/d7WIKTTODahbNWMWI/iO0K9bnAJp5+P0Y=

2、首先随便搜索一个产品,将页面下拉到最底部,然后F12打开控制台,点击第二页,抓到的接口可以进行查看,有商品数据的是正确的即可,然后我们打开接口可以看到有很多的载荷信息,其中【sign】就是我们要分析逆向的参数,其他参数都不需要逆向,只需要分析即可

3、好,接下来就是怎么去找这个加密位置,我们可以全局搜索一下【sign】,发现关键字太多,直接放弃

4、 我们要分析一下,他每次调用接口都会使用到【appkey】,而且这个值是固定的,那我们就用他的值去全局搜索试试,一下就搜索到了,而且只有两个关键字,是不是很方便

5、点击进去看了一下,我就知道这个就是加密的位置,我们直接打上断点,然后去翻一下页面,翻到第三页看看会不会断住

6、点击第三页,发现断住了,然后我们看图分析一下,其他都没什么好解释的,直接看【d】参数,这个就是sign,这个是sign就是将【r.token + "&" + c + "&" + s + "&" + n.data】这几个字符串合并,然后用ms5进行加密的来的,可以看下面的两个图

7、知道了他是怎么加密的了,那我们就直接本地模拟了,我就不扣代码了,他是标准的MD5算法,可以看下面的图片,全部转到本地js里,然后导入md5包,运行发现结果一样,这就成功了。

8、接下来我们要看一下他的【token】是哪里来的,经过我的分析,发现他的token是通过【_m_h5_tk】里提取的,他的这个参数是在cookie里保存的,所以大家要注意,可能图片里的这两个参数也要作为cookie使用,记得留一手

9、我们现在已经分析了全部,接下来就要全部打包并用python实现调用并生成sign。看下面两个图,一个是js打包后的,将js的代码全部整理成接口,可以用python直接嗲用接口进行获取sign,不仅方便,可以省去很多麻烦。另一个图片是python整理后的,整合为了类,直接看图看注释吧,比较直观

10、好了,接下来就要获取公开数据了,首先我们要先模拟一下,看他都需要什么参数,经过我的测试发现,他不需要headers,但需要cookie,cookie里只要有下面两个参数即可。然后我还发现请求后的数据不是字典格式的,很烦,还要正则提取,我都已经够懒了,怎么可能会提取呢,这很好处理,只需要将【type】【dataType】修改为json即可,下次请求的数据就是字典格式的数据了(为了测试,我修改了参数,所以请求的数据是无效的)

11、好了,我们将python代码进行再次融合,然后再运行一下看看怎么样,成功获取数据,截图截不全,先凑合看吧

12、接下来看动图,代码就这么多,没啥难度(此接口的调用不要太快,使用Ip池的情况下才可以并发,防止出现问题)

好了今天就到这里了 ,代码如下

【sign接口.js】
// 安装 crypto-js 包
// npm install crypto-js --save
const CryptoJS = require('crypto-js')
// npm install express --save
const express = require('express');
// MD5加密
function MD5(text){return CryptoJS.MD5(text).toString()}
const app = express();
app.use(express.json());
function sign_encryption(token,data,time_c){
    // appkey 固定值,写死即可
    s = '12574478'
    // 13位时间戳
    c = time_c
    // 将字典类目数据转为字符串类型数据 如果对面传递的字典已经经过了处理,则这里就不需要在处理
    // data = JSON.stringify(data)
    sign = MD5(token + "&" + c + "&" + s + "&" + data)
    return sign
}
// 使用post接口
app.post('/', (req, res) => {
    const {token, data, time_c} = req.body;
    // 加密数据
    sign_data = sign_encryption(token, data, time_c)
    console.log('生成的sign:',sign_data)
    // 返回数据
    res.status(200).json({code: 1, data: sign_data});
});
app.listen(4000, () => {
    console.log('Node.js 服务监听端口 127.0.0.1:4000');
});
【sign请求.py】 注意,代码经过base64去敏,不需要的可以自行整改
import json
import random
import time
import requests
import base64

# base64 解密
def base64_decode(str):
    # print(base64.b64decode('MTIz'.encode()))
    return base64.b64decode(str).decode('utf-8')
# 这个是链接被base64加密了,此步骤只用于去敏,无其他作用
URL = base64_decode('aHR0cHM6Ly9oNWFwaS5tLjE2ODguY29tLw==')

class response_1688:
    def __init__(self, data_dict):
        # 载荷数据 将数据转为字符串 字典转字符串的时候,一定要加 separators=(',', ':'),用于去除间隔,如果不去除间隔,他的值也是错误的
        self.data_dict = json.dumps({
            "appId": 32517,
            "params": json.dumps(data_dict, separators=(',', ':'))
        }
            , separators=(',', ':'))

        print(f'载荷数据处理:{self.data_dict}')
        # 用空的令牌请求获取新令牌  结果 {'_m_h5_tk': '3815a4dc1cfca5bbdbcae6eac7e15659_1734327147972', '_m_h5_tk_enc': '63a2009c320191df2d747d64baf11b5c'}
        self.cookie = self._m_h5_tk()
        print(f'获取Cookie:{self.cookie}')
        # 从令牌里提取token
        self.token = self.cookie['_m_h5_tk'].split('_')[0]
        print(f'获取token:{self.token}')
        # 生成13位时间戳(公用)
        self.time_c = int(time.time() * 1000)
        print(f'生成时间戳:{self.time_c}')
        # 生成获取sign值 返回 {'code': 1, 'data': '6d2310b6ddc3c501ccc3785f82c6505d'}
        self.sign = self.sign_encryption()
        print(f'生成并获取sign:{self.sign}')
        # 请求数据
        self.data1688 = self.mtop_relationrecommend_wirelessrecommend_recommend_v20()

    # 获取 _m_h5_tk 和 _m_h5_tk_enc (公用)
    def _m_h5_tk(self):
        '''
        :return: {'_m_h5_tk':'值','_m_h5_tk_enc':'值'}
        可以作为cookie使用,也可以提取token
        '''
        headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
        }
        url = URL + "h5/mtop.relationrecommend.wirelessrecommend.recommend/2.0/"
        params = {
            "jsv": "2.7.4",
            "appKey": "12574478"
        }
        response = requests.get(url, headers=headers, params=params)
        _m_h5_tk_Dict = {key: value for key, value in response.cookies.items() if key in ['_m_h5_tk', '_m_h5_tk_enc']}
        # 获取 _m_h5_tk 和 _m_h5_tk_enc
        # 可以直接用作cookies
        return _m_h5_tk_Dict

    # 生成sign
    def sign_encryption(self):
        """
        生成sign值
        :return:
        """
        headers = {'Content-Type': 'application/json'}
        url = "http://127.0.0.1:4000/"
        data = {
            'token': self.token,  # token
            'time_c': self.time_c,  # 13位时间戳
            'data': self.data_dict  # 字典数据
        }
        try:
            response = requests.post(url, headers=headers, data=json.dumps(data))
            if response.status_code == 200:
                return response.json()
        except:
            pass
        # 返回错误代码
        return {'code': -1}

    # 请求数据
    def mtop_relationrecommend_wirelessrecommend_recommend_v20(self) -> dict:
        '''
        接口:mtop.relationrecommend.WirelessRecommend.recommend/2.0
        当前接口版本:2.7.4
        :return:
        '''
        if self.sign['code'] != 1:
            return {'msg': 'sign生成错误', 'code': -1}

        headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
        }
        url = URL + "h5/mtop.relationrecommend.wirelessrecommend.recommend/2.0/"
        params = {
            "jsv": "2.7.4",
            "appKey": "12574478",
            "t": str(self.time_c),
            "sign": self.sign['data'],
            "api": "mtop.relationrecommend.WirelessRecommend.recommend",
            "v": "2.0",
            "jsonpIncPrefix": "reqTppId_32517_getOfferList",
            "type": "json",
            "dataType": "json",
            "callback": "mtopjsonpreqTppId_32517_getOfferList8",
            "data": self.data_dict
        }
        response = requests.get(url, headers=headers, cookies=self.cookie, params=params).json()
        return response



for i in range(10):
    data_dict = {
        "beginPage": i,  # 第几页
        "pageSize": 100,  # 每页获取多少数据 我设置为100,官方默认是60,我们可以不遵守
        "method": "getOfferList",
        "pageId": ''.join(random.choices('012QWERTYUIOPASDFGHJKLZXCVBNM3445qwertyuiopasdfghjklzxcvbnm6789', k=48)),
        # 不知道这个是什么,直接用随机代替,防止封锁
        "verticalProductFlag": "pcmarket",
        "searchScene": "pcOfferSearch",
        "charset": "GBK",
        "spm": "a260k.home2024.searchbox.0",
        "keywords": "鞋子"  # 关键字搜索商品
    }
    # 实例化并获取生成sign值,并请求数据
    data = response_1688(data_dict=data_dict)
    print('当前页面有多少条数据:',len(data.data1688['data']['data']['OFFER']['items']))
    # 提取数据
    for data_dict in data.data1688['data']['data']['OFFER']['items']:
        offerId = data_dict['data']['offerId']
        title = data_dict['data']['title']
        # 这个是链接被base64加密了,此步骤只用于去敏,无其他作用
        pageurl = base64_decode('aHR0cHM6Ly9kZXRhaWwuMTY4OC5jb20vb2ZmZXIv')
        print(f'{pageurl}{offerId}.html',title)

作者:小木_.

物联沃分享整理
物联沃-IOTWORD物联网 » 【Python 逆向某1688】 今天做一下1688的逆向分析,仅供学习

发表回复