profileData纯算逆向分析

文章目录

  • [1. 写在前面](#1. 写在前面)
  • [2. 参数分析](#2. 参数分析)
  • [3. 纯算还原](#3. 纯算还原)

【🏠作者主页】:吴秋霖
【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作!
【🌟作者推荐】:对爬虫领域以及JS逆向分析感兴趣的朋友可以关注《爬虫JS逆向实战》《深耕爬虫领域》
未来作者会持续更新所用到、学到、看到的技术知识!包括但不限于:各类验证码突防、爬虫APP与JS逆向分析、RPA自动化、分布式爬虫、Python领域等相关文章

作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除!

1. 写在前面

profileData参数的目的则是为了获取gid,早期通过三四十组少量的数据集经过DES加密计算得出,目前数据集增至到了七八十组。从风控的角度来看这个参数在部分场景中影响可大也可小,毕竟它在加密之前的明文数据包含了设备指纹跟环境信息

风控系统的检测并不会对里面的几十个字段去逐一校验,但是从反作弊的场景来分析,则会基于风险权重来划分字段等级,如下:

高权重字段】: 直接决定是否判定环境或设备异常(必会检测)

中权重字段】: 用于交叉验证(辅助检测,单一字段异常不触发风控,但多个异常叠加会命中)

低权重|冗余字段】: 仅作为补充信息(基本不检测,固定或轻微异常不会影响)

2. 参数分析

如上可以看到目前最新的到达了82组,密文的长度也是达到了7000+,这里全局搜索就可以定位跟以前还是一样在VMP内完成加密,如下所示:

可以看到它加密之前的JSON明文是一个Base64,直接解码可以看到,如下所示:


核心字段 字段描述
x2(webdriver)、x44(时间戳) 区分 "自动化工具" 和 "真实用户"
x22(随机 MD5)、x53(随机 MD5) 验证设备 / 请求的 "随机性"
x7(显卡信息)、x9(分辨率) 设备硬件核心特征,需符合真实用户分布
x57(Cookies)、x1(UA) 与请求头信息交叉验证,必须一致

如上表格中为加密对象权重较高的一些字段信息,当然还有一些涉及CPU核数|设备内存的字段,长期固定的话肯定也是有一定风险的,可以适当的收集来增加随机真实性

需要注意的是动态生成的字段,如时间戳、随机哈希一般权重高,固定的话相当于自曝异常

然而与真实环境强相关的字段,如显卡、分辨率、CPU需符合用户的分布规律,固定在合理区间可以短期规避

整个风控系统是不会去孤立看待某一个字段的,而是通过规则引擎 + 机器学习模型从多个核维度交叉验证(固定某些值之所以有风险,本质是违背了这些检测逻辑

最终profileData参数加密算法的核心目标则是:

设备|浏览器信息 → 指纹字典 → 序列化 → Base64编码 → DES加密 → 十六进制编码 → profileData

整个环节拿到明文的大JSON后只需要找到DES的密钥差不多就可以了,密钥的话可以通过日志自吐出来,前缀如下所示:

3. 纯算还原

javascript 复制代码
const crypto = require('crypto');

/**
 * @param {Object} fp - 待加密的字典/对象数据
 */
function encrypt_profileData(fp) {
    const fpJsonify = JSON.stringify(fp);
    
    const fpBuffer = Buffer.from(fpJsonify, 'utf8');
    const fpBase64Str = fpBuffer.toString('base64');
    const fpBase64 = Buffer.from(fpBase64Str, 'utf8');
    
    const blockSize = 8;
    const padLen = blockSize - (fpBase64.length % blockSize);
    const fpPadded = Buffer.concat([
        fpBase64,
        Buffer.alloc(padLen, 0x00)
    ]);
    
    const key = Buffer.from('zbp3....', 'utf8');
    const cipher = crypto.createCipheriv('des-ecb', key, null);
    cipher.setAutoPadding(false);
    
    let ciphertext = cipher.update(fpPadded);
    ciphertext = Buffer.concat([ciphertext, cipher.final()]);
    
    return ciphertext.toString('hex');
}
相关推荐
sprintzer7 小时前
11.26-12.05力扣栈刷题
算法·leetcode·职场和发展
sin_hielo7 小时前
leetcode 3578
数据结构·算法·leetcode
ShiMetaPi8 小时前
SAM(通用图像分割基础模型)丨基于BM1684X模型部署指南
人工智能·算法·ai·开源·bm1684x·算力盒子
前端小白在前进8 小时前
力扣刷题:无重复字符的最长子串
算法·leetcode·职场和发展
小小的橙菜吖!8 小时前
联合体的学习
学习·算法
Xing_ke3098 小时前
3D点云分割与检测(后续更新)
算法·3d点云
4311媒体网8 小时前
C语言实现简单的二分查找算法
c语言·开发语言·算法
持续学习的程序员+18 小时前
π RL(piRL)算法支持用强化学习方法训练π 0/π 0.5(pi0/pi0.5)
算法
csuzhucong8 小时前
112魔方、113魔方、114魔方
算法