某航后缀混淆逆向与顶像风控分析

news2025/6/4 11:48:08

文章目录

  • 1. 写在前面
  • 2. 接口分析
  • 3. 加密分析
  • 4. 风控分析

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

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

先赞后看、已成习惯~

1. 写在前面

   先之前分析了一下Web端的加密参数跟它的设备指纹风控策略。接下来在再分析一下分析的其他端(APPM)本期我们先继续来看看它在M端的接口加密防护以及风控强度

一般很多厂商它们外采第三方的风控防护产品的话一般不管是什么端大部分都会选择用同一家的!但是它这个明显是没有用一家的,Web用的是某东的然后M端的话用的是顶像

另外它的一个整体防护强度M端是做的比Web要好的很多(至少它的那个行为验证码好像是无法进行绕过的


分析网站

bS5haXJjaGluYS5jb20uY24=

2. 接口分析

它这个端一样不需要登录,直接去查询的接口搜索看看发包情况。请求头里面没有其他明显疑似加密的参数,Cookie的话看起来是有一些风控相关的参数(毕竟走的是非登录的游客浏览模式),然后请求参数有一个后缀参数加密,与Web端不相同的是这个参数不是请求参数的加密(是各种风控的信息加一些固定参数生成的)如下所示:

在这里插入图片描述

在第一次请求这个数据接口的时候,是需要过行为验证码的,接口返回信息如下所示:

{"msg":"成功","level":"REVIEW","risky":true}

意思就是告诉我们触发了人工介入的风控等级需要处理,这并不影响我们先对后缀参数加密先展开分析

在这里插入图片描述

上面我们把它的整个发包请求的参数转为Python代码可以看到,除了FECU这个参数是加密的外,还有它提交的data参数内有一个udidtk这个参数看起来也不像是固定的(会不会是沿用了Web的流程什么接口请求下发的)先不管它!另外就是checkToken这个参数,它是过了顶像的滑块给的,携带后方可正常获取到数据

3. 加密分析

这边跟Web端一样直接关键词参数全局搜索是无法找到有效信息的,还是通过XHR断点及跟栈分析,直接找到一个OB混淆的JS文件。遇到这种采取的关键步骤可以先尝试反混淆一下,AST算是目前处理混淆、函数变量重命名、多层级的level、控制流扁平化...主流有效的也是比较有优势的方法

这里我们也可以先使用工具来大致的反混淆一下,作用不大但不至于没用。可以看到JS代码中明显存在的一些检测项(浏览器环境、自动化还有调试检测)当然也是可以获取到一些跟加密相关的关键信息。比如MD5AES的加密。如下所示:

在这里插入图片描述
在这里插入图片描述

它上图的这个MD5调用了很多次,加密的对象有环境信息、也有一些动态固定的盐或字符。然后做完多次的MD5就会得到很多段字符串然后加了时间戳做了一个拼接得到了一个120多位的长串,然后对这个120+的字符串进行最后的一个AES加密。如下所示:

在这里插入图片描述
在这里插入图片描述

参数最终的长度是194位,根据上面的分析来总结一下它这个参数的计算加密流程,如下所示:

  • 对一个162位长度的字符串()做了MD5(这个长串几乎每天都会随这个JS动态更新)
  • 16位的数字盐进行了MD5(如上动态)
  • 32位的动态字符串进行MD5(动态)
  • 上面串起来以后末尾追加一个一个数字(动态)
  • 13位的一个时间戳
  • 动态混淆JS生成的5位字符串

上面所有通过动态加密生成出来的值拼接成上面调试看到的120多位参与最终AES加密的长字符串,AES加密生成出来的字符串是只有192位的,最终的194位是因为在做完AES以后在字符串的头尾部再次各插入了一个字符得到最终的加密值

这里来说一下最后那个动态JS混淆代码生成的5位字符是怎么来的,生成位置如下所示:

在这里插入图片描述

function a0_0x3ac913() {
    var a0_0x4ee28f = {
        _0x55f800: 0x3dd,
        _0xd300b0: 0x3ce,
        _0xbb5872: 0x35c,
        _0x25e711: 0x21e,
        _0x5835c1: 0x1af,
        _0x27bcc8: 0x2df,
        _0x35310c: 0x3dd,
        _0x389de6: 0x3ab,
        _0x2c9188: 0x58f,
        _0x3665e1: 0x328,
        _0x25f5b9: 0x329,
        _0x318c38: 0x21e,
        _0x59f07d: 0x329,
        _0x56c922: 0x3f7
    }
      , _0x76df49 = a0_0x5e6a13
      , _0x415cf6 = {};
    _0x415cf6[_0x76df49(a0_0x4ee28f._0x55f800)] = _0x76df49(a0_0x4ee28f._0xd300b0),
    _0x415cf6[_0x76df49(a0_0x4ee28f._0xbb5872)] = function(_0x2ea17a, _0xde9bd7) {
        return _0x2ea17a * _0xde9bd7;
    }
    ,
    _0x415cf6[_0x76df49(a0_0x4ee28f._0x25e711)] = function(_0x2abe69, _0x1f0d5e) {
        return _0x2abe69 + _0x1f0d5e;
    }
    ,
    _0x415cf6[_0x76df49(a0_0x4ee28f._0x5835c1)] = _0x76df49(a0_0x4ee28f._0x27bcc8);
    var _0x484dd3 = _0x415cf6;
    try {
        var _0x54fa41 = 0x5
          , _0x213abd = _0x484dd3[_0x76df49(a0_0x4ee28f._0x35310c)]
          , _0xcf844 = _0x213abd[_0x76df49(a0_0x4ee28f._0x389de6)]
          , _0x8eaac = '';
        for (var _0x3bac47 = 0x0; _0x8eaac[_0x76df49(a0_0x4ee28f._0x389de6)] < _0x54fa41; _0x3bac47++) {
            var _0xfcf239 = Math[_0x76df49(a0_0x4ee28f._0x2c9188)](_0x484dd3[_0x76df49(a0_0x4ee28f._0xbb5872)](Math[_0x76df49(a0_0x4ee28f._0x3665e1)](), _0xcf844));
            if (!_0x213abd[_0x76df49(a0_0x4ee28f._0x25f5b9)]('')[_0xfcf239])
                continue;
            _0x8eaac = _0x484dd3[_0x76df49(a0_0x4ee28f._0x318c38)](_0x8eaac, _0x213abd[_0x76df49(a0_0x4ee28f._0x59f07d)]('')[_0xfcf239]);
        }
        return _0x8eaac;
    } catch (_0x4e07db) {
        return console[_0x76df49(a0_0x4ee28f._0x56c922)](_0x484dd3[_0x76df49(a0_0x4ee28f._0x5835c1)], _0x4e07db),
        '';
    }
}

来稍微看一下上面的混淆代码做了什么操作,内部根据上面分析,直接对分析出来的加密流程进行代码还原,a0_0x5e6a13是一个解码的函数,解混淆后可以看到里面包含了62个字符!循环了5次来索引生成5位字符,通过Math.floor(Math.random() * 62) 生成0-61之间的随机数,从62位字符中选取字符,具体代码如下所示:

function a0_0x4ca3(_0x333150, _0x2c8f46) {
    var _0x343f67 = a0_0x13be();
    return a0_0x4ca3 = function(_0x4126d9, _0xba068e) {
        _0x4126d9 = _0x4126d9 - 0x181;
        var _0x13be7 = _0x343f67[_0x4126d9];
        if (a0_0x4ca3['JsCqYZ'] === undefined) {
            var _0x4ca322 = function(_0x3806ad) {
                var _0x258353 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
                var _0x35ed5b = ''
                  , _0x3b8797 = ''
                  , _0x49fd92 = _0x35ed5b + _0x4ca322;
                for (var _0xd393bf = 0x0, _0x1cec02, _0x4bf15c, _0x5a98b3 = 0x0; _0x4bf15c = _0x3806ad['charAt'](_0x5a98b3++); ~_0x4bf15c && (_0x1cec02 = _0xd393bf % 0x4 ? _0x1cec02 * 0x40 + _0x4bf15c : _0x4bf15c,
                _0xd393bf++ % 0x4) ? _0x35ed5b += _0x49fd92['charCodeAt'](_0x5a98b3 + 0xa) - 0xa !== 0x0 ? String['fromCharCode'](0xff & _0x1cec02 >> (-0x2 * _0xd393bf & 0x6)) : _0xd393bf : 0x0) {
                    _0x4bf15c = _0x258353['indexOf'](_0x4bf15c);
                }
                for (var _0x5f2dc5 = 0x0, _0xd9179c = _0x35ed5b['length']; _0x5f2dc5 < _0xd9179c; _0x5f2dc5++) {
                    _0x3b8797 += '%' + ('00' + _0x35ed5b['charCodeAt'](_0x5f2dc5)['toString'](0x10))['slice'](-0x2);
                }
                return decodeURIComponent(_0x3b8797);
            };
            a0_0x4ca3['dMwUfl'] = _0x4ca322,
            _0x333150 = arguments,
            a0_0x4ca3['JsCqYZ'] = !![];
        }
        var _0x5877e2 = _0x343f67[0x0]
          , _0x3fe196 = _0x4126d9 + _0x5877e2
          , _0x5dca38 = _0x333150[_0x3fe196];
        if (!_0x5dca38) {
            var _0xb0f2b1 = function(_0x565615) {
                this['yRUkPV'] = _0x565615,
                this['aAtqKx'] = [0x1, 0x0, 0x0],
                this['mmhcrU'] = function() {
                    return 'newState';
                }
                ,
                this['HZoHkF'] = '\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',
                this['BEzgTG'] = '[\x27|\x22].+[\x27|\x22];?\x20*}';
            };
            _0xb0f2b1['prototype']['KzabiP'] = function() {
                var _0xc855bd = new RegExp(this['HZoHkF'] + this['BEzgTG'])
                  , _0x3186d8 = _0xc855bd['test'](this['mmhcrU']['toString']()) ? --this['aAtqKx'][0x1] : --this['aAtqKx'][0x0];
                return this['Zwynsy'](_0x3186d8);
            }
            ,
            _0xb0f2b1['prototype']['Zwynsy'] = function(_0x448299) {
                if (!Boolean(~_0x448299))
                    return _0x448299;
                return this['iTzDTy'](this['yRUkPV']);
            }
            ,
            _0xb0f2b1['prototype']['iTzDTy'] = function(_0x43ac0b) {
                for (var _0x445e27 = 0x0, _0x3f4543 = this['aAtqKx']['length']; _0x445e27 < _0x3f4543; _0x445e27++) {
                    this['aAtqKx']['push'](Math['round'](Math['random']())),
                    _0x3f4543 = this['aAtqKx']['length'];
                }
                return _0x43ac0b(this['aAtqKx'][0x0]);
            }
            ,
            new _0xb0f2b1(a0_0x4ca3)['KzabiP'](),
            _0x13be7 = a0_0x4ca3['dMwUfl'](_0x13be7),
            _0x333150[_0x3fe196] = _0x13be7;
        } else
            _0x13be7 = _0x5dca38;
        return _0x13be7;
    }
    ,
    a0_0x4ca3(_0x333150, _0x2c8f46);
}

可以看到上面的解码JS内有一个方法a0_0x13be,里面包含了大量的字符串。这种一般都算是整个混淆体系里面的核心数据,可能会包括(加解密的密钥函数变量名

并通过定义了一个functionreturn _0x649c32重新定义为直接返回字符串数组的函数来隐藏原始函数防止静态分析或者工具直接获取到字符串的内容,如下所示:

function a0_0x13be() {
    var _0x649c32 = ['zMLSBa', 'ANDLCM0', ..., 'yw4T']; // 包含数百个字符串的数组
    a0_0x13be = function() {
        return _0x649c32;
    };
    return a0_0x13be();
}

至此,上述分析可以还原出后缀参数的加密。然后接着看一下data参数内的udidtk参数是怎么来的,因为它是动态的不管它校不校验(这种参数最好分析一下JS跟接口层面还原动态获取或生成流程)有的平台一般的就会通过某些动态风控参来埋点

在这里插入图片描述

通过上图查询的发包流程大致是这样:先获取udidtk参数–>第一次请求–>验证码拦截–>过验证码–>第二次请求–>拿到数据

所以udidtk在请求数据接口之前之前携带FUCE加密参数请求udid/c.do这个接口拿到就行。最后我们根据上面分析梳理的流程封装加密算法跟请求示例,来请求验证一下,如下所示:

在这里插入图片描述
在这里插入图片描述

可以看到查询请求失败了,出现了行为验证码的风控,跟我们页面访问发包接口出现了一样的情况。它这个M端不管页面还是接口请求访问都是要过这个顶像验证码的,下面我们来分析一下验证码,对接上去看看是否可以正常请求成功

4. 风控分析

它的这个验证码采用的还是顶像的多套组合,要是想完全解决多套验证的方案,需要花费比较多的时候来逆向验证码协议,目前看是3套(滑块还原图标点选单旋转)现在好多平台都搞了多套这种机制,从防护角度来说确实有一定的效果(对于爬虫方来说会很累,比较好的防护厂商的方案都是更新很频繁的

在这里插入图片描述

这里作者为了验证让文章更加完整,花了点时间就搞一个滑块还原来验证上面的流程!因为这个貌似频率比较高,如果要搞几种的话我都不想写了(喜欢没有强度的工作),过掉滑块验证以后拿到CheckToken参数就可以成功。最终测试一下整个查询航班信息的流程包括过顶像行为验证的结果,如下所示:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2395856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Protobuf]常见数据类型以及使用注意事项

[Protobuf]常见数据类型以及使用注意事项 水墨不写bug 文章目录 一、基本数据类型1、字段2、字段的修饰规则 二、自定义数据类型1、message类型2、enum类型3、Any类型4、oneof类型5、map类型 三、小工具1.hexdump2.decode 四、注意事项 一、基本数据类型 protobuf 支持多种基础…

模拟实现线程池(线程数目为定值)和定时器

前言 昨天学习关于定时器的相关知识。今天花时间去模拟实现了一个定时器&#xff0c;同时也去模拟实现了一个线程池(线程数目为定值)。我感觉我收获了很多&#xff0c;对于线程的理解加深了。跟大家分享一下~ 线程池和定时器(这个是主要)的实现 代码 线程池 import java.ut…

数据结构之队列实验

引言 在计算机科学中&#xff0c;进制转换是基础但重要的操作。例如将一个十进制数转换为二进制或八进制表示时&#xff0c;我们通常使用“短除法”——即不断用目标进制去除当前数&#xff0c;记录余数&#xff0c;直到商为0为止。 这种方法得到的是低位先产生的结果&#x…

【Ubuntu】摸鱼技巧之虚拟机环境复制

前言 提示&#xff1a;所有的操作都需要关闭虚拟机 如何快速在其它电脑布置&#xff0c;linux环境&#xff0c;如果我们有一个环境直接拷贝就有时间摸鱼呀。 1.直接复制简单粗暴 不做赘述&#xff0c;如果不会复制&#xff0c;那么请右击鼠标压缩复制 2.克隆虚拟机 2.1 …

室内VR全景助力房产营销及装修

在当今的地产行业&#xff0c;VR全景已成为不可或缺的应用工具。从地产直播到楼市VR地图&#xff0c;从效果图到水电家装施工记录&#xff0c;整个地产行业的上下游生态中&#xff0c;云VR全景的身影无处不在。本文将探讨VR全景在房产营销及装修领域的应用&#xff0c;并介绍众…

jenkins集成gitlab实现自动构建

jenkins集成gitlab实现自动构建 前面我们已经部署了Jenkins和gitlab&#xff0c;本文介绍将二者结合使用 项目源码上传至gitee提供公网访问&#xff1a;https://gitee.com/ye-xiao-tian/my-webapp 1、创建一个群组和项目 2、添加ssh密钥 #生成密钥 [rootgitlab ~]# ssh-keyge…

Spring Boot微服务架构(八):开发之初就引入APM工具监控

使用 APM&#xff08;Application Performance Management&#xff09;工具监控 Spring Boot 应用&#xff0c;可以帮助开发者实时追踪性能瓶颈、分析调用链路、监控资源使用情况&#xff0c;并快速定位故障。以下是详细的步骤和常用工具的选择指南&#xff1a; ​​一、常用 A…

大规模真实场景 WiFi 感知基准数据集

一段话总结 本文提出CSI-Bench,首个大规模真实场景WiFi感知基准数据集,覆盖26个室内环境、35名用户、16种商用设备,包含461小时有效数据,支持跌倒检测、呼吸监测、定位、运动源识别等单任务及用户身份、活动、 proximity联合标注的多任务学习。通过标准化评估协议和基线模…

Python实现HPSO-TVAC优化算法优化支持向量机SVC分类模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在当今数据驱动的时代&#xff0c;支持向量机&#xff08;SVM&#xff09;作为一种经典的机器学习算法&#xff0c;…

ck-editor5的研究 (3):初步使用 CKEditor5 的事件系统和API

前言 在上一篇文章中—— ck-editor5的研究&#xff08;2&#xff09;&#xff1a;对 CKEditor5 进行设计&#xff0c;并封装成一个可用的 vue 组件 &#xff0c;我已经把 CKEditor5 封装成了一个通用vue组件&#xff0c;并且成功在nuxt中运行&#xff0c;并具备一定的通用性&…

WPS快速排版

论文包括&#xff08;按顺序&#xff09;&#xff1a;封面&#xff08;含题目&#xff09;、摘 要、关键词、Abstract&#xff08;英文摘要&#xff09;、Keywords、目录、正文、参考文献、在读期间发表的学术论文及研究成果&#xff0c;致 谢 题目&#xff08;黑小一加粗&…

Java实现命令行图书管理系统(附完整源码)

一、项目概述 本文将介绍如何使用Java实现一个基于命令行的图书管理系统。系统支持管理员和普通用户两种角色&#xff0c;提供图书的增删改查、借阅归还等功能。项目采用面向对象设计原则&#xff0c;代码结构清晰&#xff0c;适合Java初学者学习。 二、系统功能架构 graph T…

【数据结构】顺序表和链表详解(上)

前言&#xff1a;上期我们介绍了算法的复杂度&#xff0c;知道的算法的重要性同时也了解到了评判一个算法的好与坏就去看他的复杂度(主要看时间复杂度)&#xff0c;这一期我们就从顺序表和链表开始讲起。 文章目录 一&#xff0c;顺序表1&#xff0c;线性表2&#xff0c;顺序表…

唯创WT2606B TFT显示灵动方案,重构电子锁人机互动界面,赋能智能门锁全场景交互!

在智能家居的浪潮中&#xff0c;门锁搭载显示屏已成为行业创新的焦点。据行业数据显示&#xff0c;2023年全球智能门锁出货量中&#xff0c;搭载显示屏的型号占比已突破40%&#xff0c;且年复合增长率达25%。而2024年国内智能门锁销量突破2200万套&#xff0c;预计2025年市场规…

智能穿戴新标杆:SD NAND (贴片式SD卡)与 SOC 如何定义 AI 眼镜未来技术路径

目录 一、SD NAND&#xff1a;智能眼镜的“记忆中枢”突破空间限制的存储革命性能与可靠性的双重保障 二、SOC芯片&#xff1a;AI眼镜的“智慧大脑”从性能到能效的全面跃升多模态交互的底层支撑 三、SD NANDSOC&#xff1a;11&#xff1e;2的协同效应数据流水线的高效协同端侧…

node_modules包下载不下来

如果项目里面的package-lock.json有resolved &#xff0c;就指向了包的下载来源&#xff0c;如果这个网址挂了&#xff0c;那npm i 就会一直卡着。而且&#xff0c;在终端去修改 npm的镜像是没有用的 解决办法是:把项目里面的 lock文件 .npmrc都删了 然后重新下载就可以了

yolo个人深入理解

卷积层的理解,通过云端服务器训练模型,模型构建的重要性,针对极低像素的处理,模型训练召回率提高技巧,卷积层2,4,8,16,32的小模型与大模型的理解 一.关于backbone,neck,head深入理解 1,backbone的主要组成部分是sppf和conv,这是backbone的核心,其中yolov5和yolov8…

从0开始学vue:Element Plus详解

一、核心架构解析二、技术实现指南三、高级特性实现四、性能优化方案五、生态扩展方案六、调试与测试七、版本演进路线 Element Plus 是专为 Vue 3 设计的桌面端 UI 组件库&#xff0c;基于 Vue 3 的 Composition API 重构&#xff0c;在保持与 Element UI 兼容性的同时&#x…

互联网向左,区块链向右

2008年&#xff0c;中本聪首次提出了比特币的设想&#xff0c;这打开了去中心化的大门。 比特币白皮书清晰的描述了去中心化支付的解决方案&#xff0c;并分别从以下几个方面阐述了他的理念&#xff1a; 一、由转账双方点对点的通讯&#xff0c;而不通过中心化的第三方&#xf…

Python6.1打卡(day33)

DAY 33 MLP神经网络的训练 知识点回顾&#xff1a; 1.PyTorch和cuda的安装 2.查看显卡信息的命令行命令&#xff08;cmd中使用&#xff09; 3.cuda的检查 4.简单神经网络的流程 1.数据预处理&#xff08;归一化、转换成张量&#xff09; 2.模型的定义 …