某团 mtgsig1.2 | sdkVersion: 3.0.0 签名算法分析记录(2025/1/9)

【作者主页】:小鱼神1024

【擅长领域】:JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!若有侵权,请联系作者立即删除!

【该文章已同步至星球】:https://articles.zsxq.com/id_z0hwwtswwp1n.html

前言

最近听星球小伙伴说,mtgsig 签名算法升级到 1.2 了,出于学习目的,于是乎,我决定重新分析记录一下,希望能帮助到有需要的小伙伴。

前置分析

在请求时,发现请求头中存在 mtgsig 字段,如下所示:

美团 mtgsig

当请求不携带 mtgsig 字段时,会返回 403 错误,如下所示:

美团 mtgsig

逆向分析

通过堆栈进入 H5guard.js 文件中,发现有大量的混淆,如下所示:

美团 mtgsig

为了方便学习观察,我们先使用 AST 还原一下代码,如下所示:

美团 mtgsig

通过还原后的代码,很明显能看到许多浏览器环境参数,这样即使是补环境,也是清晰明了的。

当然了,咱们出于学习目的,这里就不补环境了,直接分析纯算 mtgsig

那么快速定位到 mtgsig 生产的位置呢?

通过观察发现,mtgsigjson 结构的字符串,很显然它是通过 JSON.stringify 生成的。于是,我们可以通过 hook 它。

JSON.stringify_ = JSON.stringify;
JSON.stringify = function () {if (arguments[0] && arguments[0]["a1"]) {debugger;}let result = JSON.stringify_.apply(this, arguments);return result;
};

如果想了解更多实用 hook,传送门:JS 逆向定位神器:史上最实用的 Hook 脚本

通过 hook,快速定位到 mtgsig 生成的位置,如下所示:

美团 mtgsig

很显然 mtgsig 是通过 new gO() 生成的,那找到这个 gO 类,如下所示:

美团 mtgsig

简单分析后,发现它是一个 JSVMP。那插桩呗!

说到插桩,可以先了解一下 日志插桩框架,让你插桩分析更高效。传送门:终极逆向插桩日志框架,让浏览器崩溃成为历史!

将常见的运算符,比如:+、-、*、/、&、>> 等等,都插入日志,如下所示:

美团 mtgsig

当日志执行完成后,发现 mtgsig 就生成了。如下所示:

美团 mtgsig

a1

这个就不用多说了。就是 1.2

a2

a2 就是一个时间戳,可以用 Date.now() 生成。

a3

搜索 a3 的值:wz71wxx81z4v5x001wyyy43161z01uz6805500982y397958uwyxux11, 如下所示:

美团 mtgsig

它其实就是 localStorage 中的 dfpId 的值。

如果喜欢刨根问底,可能会问,localStorage 中的 dfpId 的值又是哪里来的呢?

它可以本地生成,也可以通过请求 webdfpid 接口获取。

不管用那种方式,都需要生成临时的 dfpId 值,代码如下:

/*** 获取a3* @returns */
function get_dfpId() {const dfp_timestamp = Date.now()const constant_str = "AOMEOAG"const env = { "platform": "Win32", "vendor": "Google Inc." }const envUint8Array = new TextEncoder().encode(JSON.stringify(env))// md5.md5算法可以在星球获取const gA = md5.md5(envUint8Array)// 1736411131947AOMEOAGfd79fef3d01d5e9aadc18ccd4d0c9507return `${dfp_timestamp}${constant_str}${gA}`
}

Ok,到这里,a3 的值就搞定了。

a5

搜索日志,找到第一个 a5 值生成的地方,如下所示:

美团 mtgsig

通过日志发现,a5 是通过 kV 函数生成的。其中函数的参数数组又是通过函数 kX 生成的。

一步一步往上翻日志,它是通过截取 a6 值的前 10 位,再拼接上 a2 时间戳得到的。如图:

美团 mtgsig

根据箭头指向,就能找到 a6 生成所有需要的参数。

其中,所涉及到的函数,直接缺啥补啥就行。这个过程比较简单,就不赘述了。

a6

gU(kz, !1, kt) 找到这个位置,它就是 a6 的值。

美团 mtgsig

进入这个函数,看看它做了什么事情。

美团 mtgsig

看到这里就很清楚了。将环境参数进行 ase 加密后,再 base64 加密。

有一个坑点要注意,它的秘钥 key 是动态的。原因是生成的 66 位大数组是随机的。

剩下的就是扣代码了。这个不难了,直接扣就行。

a8

搜索日志,找到第一个 a8 值生成的地方,如下所示:

美团 mtgsig

通过分析可以发现,a8 是通过三个数组异或操作之后,再通过 toString(16) 转换为 16 进制字符串得到的。

const a5_index_arr16 = [202, 0, 115, 219, 118, 30, 116, 201, 100, 35, 92, 162, 207, 176, 73, 182] // 自行动态替换
const a6_index_arr16 = [51, 152, 137, 25, 242, 234, 154, 33, 133, 11, 152, 70, 200, 246, 61, 173] // 自行动态替换const a8_index_arr16 = [115, 77, 208, 7, 220, 219, 190, 23, 10, 174, 113, 15, 83, 31, 108, 51]function get_a8() {let a8 = ""for (let i = 0; i < 16; i++) {const v1 = a5_index_arr16[i] ^ a6_index_arr16[i]const v2 = v1 ^ a8_index_arr16[i]const v3 = v2.toString(16)if (v3.length === 1) {a8 = a8 + ("0" + v3)} else {a8 = a8 + v3}}return a8
}

其中,a8_index_arr16 是固定的数组。这个生成 a8 的算法不难还原,主要 a5_index_arr16a6_index_arr16 是动态生成的。需要花点时间分析一下。

OK,到这里,a8 的值就搞定了。

a9

搜索日志,找到第一个 a9 值生成的地方,如下所示:

美团 mtgsig

3.0.0sdkVersion 版本号,7 是固定的。45 是随机生成的,可以用 Math.floor(Math.random() * 256) 生成即可。

a9 也没啥难度了,直接生成即可。

a10

这个更简单了,直接去代码里扣就行。如图:

美团 mtgsig

function get_a10() {for (var m2 = [], m3 = "0123456789abcdef", m4 = 0; m4 < 2; m4++)m2[m4] = m3["substr"](Math["floor"](16 * Math["random"]()), 1);return m2["join"]("");
}

其实它就是在 0123456789abcdef 中随机区两个字符拼接起来。

x0

这个就不说了,就是固定 4

d1

这个才是重头戏。一起来看看吧。

找到第一个 d1 值生成的地方,如下所示:

美团 mtgsig

首先它是根据 16位数组 结合 toString(16) 生成的,生成代码如下:

function get_d1() {const result_arr = []; // 自行动态替换let d1 = "";for (let i = 0; i < result_arr.length; i++) {const v = result_arr[i].toString(16);if (v.length === 1) {d1 = d1 + ("0" + v);} else {d1 = d1 + v;}}return d1;
}

那么这个数组又是怎么来的呢?继续往下看。

美团 mtgsig

通过日志逐步分析得知,它是 a1a3a5a6a8a10 的值拼接起来的。

将拼接后的字符串:

41.21736410129324wz71wxx81z4v5x001wyyy43161z01uz6805500982y397958uwyxux11qIOev3SBPmKv0Imwif8vMvw1FM2mO8lW44ueWHC41uNU+CoUqc==h1.7Y4FJL8ZKH1YV87TLKT20o9eVBh+MFKyzDoQeZdPnueUWkLVh1aKXvwFwF/fohFW54blQoiRhD9Msea0fsBrQ+96IhtC7Duuf0jk6KG+j4Jpj89hygFdmSJC69KR/YkvtQsUi+iCbsNRLfjSJnvs2UA==34d26105456cd9b2494448073da64a1b3.0.0,7,45d76c3213382629f09445

通过 kK 函数,生成 16Uint8Array 数组。

function kK(lI) {for (var lJ = encodeURIComponent(lI), lK = [], lL = 0;lL < lJ["length"];lL++) {var lM = lJ["charAt"](lL);if ("%" === lM) {var lN = lJ["charAt"](lL + 1) + lJ["charAt"](lL + 2),lO = parseInt(lN, 16);lK["push"](lO), (lL += 2);} else lK["push"](lM["charCodeAt"](0));}return lK;
}
function get_table_string({a1,a3,a5,a6,a8,a10,randomNum,params,api,method,data,
}) {const string = `41.21736410129324wz71wxx81z4v5x001wyyy43161z01uz6805500982y397958uwyxux11qIOev3SBPmKv0Imwif8vMvw1FM2mO8lW44ueWHC41uNU+CoUqc==h1.7Y4FJL8ZKH1YV87TLKT20o9eVBh+MFKyzDoQeZdPnueUWkLVh1aKXvwFwF/fohFW54blQoiRhD9Msea0fsBrQ+96IhtC7Duuf0jk6KG+j4Jpj89hygFdmSJC69KR/YkvtQsUi+iCbsNRLfjSJnvs2UA==34d26105456cd9b2494448073da64a1b3.0.0,7,45d76c3213382629f09445`;const array = new Uint8Array(kK(string));return md5.md5(array);
}

那到索引表之后,再通过异或操作,生成 16 位数组。代码如下:

function get_arr16() {// const table = "8a1ba972861df8c6f1d9462890b29a32";const table = get_table_string();const temp_arr = [55, 63, 160, 244, 222, 253, 77, 56, 156, 75, 165, 121, 198, 117, 170, 115,];const result_arr = [];for (let i = 0; i < table.length; i += 2) {const v1 = "0x" + table.charAt(i);const v2 = v1 + table.charAt(i + 1);const v3 = temp_arr[i / 2] ^ parseInt(v2);result_arr.push(v3);}return result_arr;
}

这就是 16 位数组生成过程。

当然了,别看我写的简单,其实这里有很多细节需要注意的。自己可以尝试还原一下。

此时 mgtsig 就搞定了。

参数验证

写个小例子,验证下生成的参数是否正确,如下:

美团 mtgsig

搞定!!

如果还有什么疑问,请在星球里留言。

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

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

相关文章

(二)最长公共子序列、最长上升子序列、最大子段和、三角形最小路径和、矩阵连乘、0-1背包

最近刚考完算法设计分析课的考试&#xff0c;复习总结一下期末考试的几道算法题吧 目录 LCR 095. 最长公共子序列 300. 最长递增子序列 53. 最大子数组和 LCR 100. 三角形最小路径和 矩阵连乘问题 0-1背包 LCR 095. 最长公共子序列 给定两个字符串 text1 和 text2&#xff…

聚类系列 (二)——HDBSCAN算法详解

在进行组会汇报的时候&#xff0c;为了引出本研究动机&#xff08;论文尚未发表&#xff0c;暂不介绍&#xff09;&#xff0c;需要对DBSCAN、OPTICS、和HDBSCAN算法等进行详细介绍。在查询相关资料的时候&#xff0c;发现网络上对于DBSCAN算法的介绍非常多与细致&#xff0c;但…

通义灵码在跨领域应用拓展之物联网篇

目录 一.引言 二.通义灵码简介 三.通义灵码在物联网领域的设备端应用 1.传感器数据采集 (1).不同类型传感器的数据读取 (2).数据转换与预处理 2.设备控制指令接收和执行 (1).指令解析与处理 (2).设备动作执行 四.通义灵码在物联网领域的云端平台应用 1.数据存储和管…

DolphinScheduler自身容错导致的服务器持续崩溃重大问题的排查与解决

01 问题复现 在DolphinScheduler中有如下一个Shell任务&#xff1a; current_timestamp() { date "%Y-%m-%d %H:%M:%S" }TIMESTAMP$(current_timestamp) echo $TIMESTAMP sleep 60 在DolphinScheduler将工作流执行策略设置为并行&#xff1a; 定时周期调度设置…

CISAW-ES应急服务方向信息安全事件分级

网络安全事件事件分级 网络安全事件分为四级&#xff1a;特别重大网络安全事件、重大网络安全事大网络安全事件、一般网络安全事件。 1&#xff0e;特别重大网络安全事件 符合下列情形之一的&#xff0c;为特别重大网络安全事件。 &#xff08;1&#xff09;重要网络和信息系…

油猴支持阿里云自动登陆插件

遇到的以下问题,都已在脚本中解决: 获取到的元素赋值在页面显示,但是底层的value并没有改写,导致请求就是获取不到数据元素的加载时机不定,尤其是弱网情况下,只靠延迟还是有可能获取不到,且登陆不丝滑,通过元素发现机制,解决此问题并做到丝滑登陆根据密钥计算校验码之…

B树与B+树:数据库索引的秘密武器

想象一下&#xff0c;你正在构建一个超级大的图书馆&#xff0c;里面摆满了各种各样的书籍。B树和B树就像是两种不同的图书分类和摆放方式&#xff0c;它们都能帮助你快速找到想要的书籍&#xff0c;但各有特点。 B树就像是一个传统的图书馆摆放方式&#xff1a; 1. 书籍摆放&…

城市生命线安全综合监管平台

【落地产品&#xff0c;有需要可留言联系&#xff0c;支持项目合作或源码合作】 一、建设背景 以关于城市安全的重要论述为建设纲要&#xff0c;聚焦城市安全重点领域&#xff0c;围绕燃气爆炸、城市内涝、地下管线交互风险、第三方施工破坏、供水爆管、桥梁坍塌、道路塌陷七…

成为LabVIEW自由开发者

成为LabVIEW自由开发者的体验可以非常丰富且具有挑战性&#xff0c;同时也充满了自我成长和多样化项目的机会。 ​ 1. 高度的灵活性与自由度 工作时间与地点&#xff1a;作为自由开发者&#xff0c;你可以自由选择工作时间和地点。你可以在家工作&#xff0c;也可以选择在咖啡…

用于与多个数据库聊天的智能 SQL 代理问答和 RAG 系统(3) —— 基于 LangChain 框架的文档检索与问答功能以及RAG Tool的使用

介绍基于 LangChain 框架的文档检索与问答功能&#xff0c;目标是通过查询存储的向量数据库&#xff08;VectorDB&#xff09;&#xff0c;为用户的问题检索相关内容&#xff0c;并生成自然语言的答案。以下是代码逻辑的详细解析&#xff1a; 代码结构与功能 初始化环境与加载…

基于QT和C++的实时日期和时间显示

一、显示在右下角 1、timer.cpp #include "timer.h" #include "ui_timer.h" #include <QStatusBar> #include <QDateTime> #include <QMenuBar> Timer::Timer(QWidget *parent) :QMainWindow(parent),ui(new Ui::Timer) {ui->setup…

Elasticsearch学习(1) : 简介、索引库操作、文档操作、RestAPI、RestClient操作

目录 1.elasticsearch简介1.1.了解es1.2.倒排索引正向索引和倒排索引 1.3.es的一些概念:文档和字段&#xff1b;索引和映射&#xff1b;Mysql与ES1.4.安装es、kibana部署单点es部署kibanaIK分词器安装IK分词器与测试扩展与停用词词典总结 部署es集群 2.索引库操作2.1.mapping映…

【LeetCode Hot100 贪心算法】 买卖股票的最佳时机、跳跃游戏、划分字母区间

贪心算法 买卖股票的最佳时机买卖股票的最佳时机II跳跃游戏跳跃游戏II划分字母区间 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的…

如何在 Ubuntu 22.04 上使用 LEMP 安装 WordPress 教程

简介&#xff1a; 本教程旨在指导你如何在 Ubuntu 22.04 上使用 LEMP 栈安装 WordPress。 WordPress 是一个用 PHP 编写的开源内容管理系统。LEMP 栈是 Linux&#xff0c;NGINX&#xff0c;MySQL 和 PHP 的缩写。WordPress 非常用户友好&#xff0c;并提供了多种选项&#xff…

vue实现虚拟列表滚动

<template> <div class"cont"> //box 视图区域Y轴滚动 滚动的是box盒子 滚动条显示的也是因为box<div class"box">//itemBox。 一个空白的盒子 计算高度为所有数据的高度 固定每一条数据高度为50px<div class"itemBox" :st…

STM32小实验2

定时器实验 TIM介绍 TIM&#xff08;Timer&#xff09;定时器 定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断 16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断…

HTB:Timelapse[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 提取并保存靶机TCP开放端口号 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用nmap对靶机UD…

【贵州省】乡镇界arcgis格式shp数据乡镇名称和编码内容下载测评

shp数据字段乡镇名称和编码&#xff0c;坐标是wgs84&#xff0c;数据为SHP矢量格式&#xff0c;下载下来直接加载进ArcMap即可使用 下载地址&#xff1a;https://download.csdn.net/download/zhongguonanren99/14928126

[免费]微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序(高校就业)招聘系统(Springboot后端Vue管理端)&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序(高校就业)招聘系统(Springboot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项目介绍…

“AI智能实训系统:让学习更高效、更轻松!

大家好&#xff0c;作为一名资深产品经理&#xff0c;今天我来跟大家聊聊一款备受瞩目的产品——AI智能实训系统。在这个人工智能技术飞速发展的时代&#xff0c;AI智能实训系统应运而生&#xff0c;为广大学习者提供了全新的学习体验。那么&#xff0c;这款产品究竟有哪些亮点…