某站平台的签名算法分享

  • 先charles抓包,api.xxxxxx.com域名的包

  • 分析包 看到路径参数如下

  • appkey=1d8b6e7d45233436&build=5531000&channel=dw056&mobi_app=android&mode=0&oid=326052200&plat=2&platform=android&ps=20&statistics=%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%225.53.1%22%2C%22abtest%22%3A%22%22%7D&ts=1705305495&type=1&sign=2c9086d4acc853a017ec087699902634
    可以看到一个sign,是个32字符,128位,直觉告诉我可能是个md5签名

  • 然后用jadx打开xxx.apk包,全局搜索sign字符串,在众多函数方法中,找到一个SignedQuery函数,跟进去看,发现又个loadLibrary(xxx),那么直接告诉我是在一个so里

  • 用apktool把xxx.apk decode出来,拿到libxxx.so

  • 用ida打开该libxxx.so,直接看JNI_OnLoad函数,找到这一行

    if ( (*v5)->RegisterNatives(v5, v4, (const JNINativeMethod *)&register_native_struct, 5) < 0

  • register_native_struct跟进去

 

  • 每个函数进去看下,有惊喜,确实是个md5算法,找到 md5_impl,跟进去看看算法参数

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    111

    112

    113

    114

    115

    116

    117

    118

    119

    120

    121

    122

    123

    124

    125

    126

    127

    128

    129

    130

    131

    132

    133

    134

    135

    136

    137

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    int __fastcall md5_impl(JNIEnv *a1, jobject (*a2)(JNIEnv *, jclass, jmethodID, ...))

    {

    JNIEnv *v2; // r11

    jobject (*v3)(JNIEnv *, jclass, jmethodID, ...); // r6

    const char *v4; // r2

    const char *v5; // r1

    int result; // r0

    int v7; // r0

    JNIEnv v8; // r1

    int v9; // r0

    int v10; // r4

    int v11; // r0

    int v12; // r10

    signed int v13; // r9

    int v14; // r5

    int v15; // r8

    time_t v16; // r0

    int v17; // r6

    int v18; // r5

    const char *input_str; // r8

    _DWORD *v20; // r10

    int v21; // r4

    _DWORD *v22; // r0

    int v23; // r1

    int v24; // r2

    int v25; // r0

    unsigned int input_len; // r5

    signed int v27; // r4

    char *v28; // r5

    int v29; // r4

    const char *v30; // [sp+8h] [bp-C0h]

    int v31; // [sp+8h] [bp-C0h]

    int v32; // [sp+Ch] [bp-BCh]

    char v33; // [sp+10h] [bp-B8h]

    int s; // [sp+38h] [bp-90h]

    int v35; // [sp+3Ch] [bp-8Ch]

    int v36; // [sp+40h] [bp-88h]

    int v37; // [sp+44h] [bp-84h]

    char v38[24]; // [sp+90h] [bp-38h]

    int v39; // [sp+A8h] [bp-20h]

    v2 = a1;

    v3 = a2;

    if ( !sub_2D20((int)a1) )

    goto LABEL_5;

    v4 = "com.xxxxxxxx.nativelibrary.SignedQuery";

    v5 = "java/lang/ClassNotFoundException";

    LABEL_3:

    sub_401C((int)v2, (int)v5, (int)v4);

    result = 0;

    while ( _stack_chk_guard != v39 )

    {

    LABEL_5:

    if ( !v3 )

    {

      v5 = "java/lang/NullPointerException";

      v4 = "Null params!";

      goto LABEL_3;

    }

    v7 = is_empty(v2, (int)v3);

    v8 = *v2;

    if ( v7 )

    {

      v3 = v8->NewObject;

      result = ((int (__fastcall *)(JNIEnv *, int, int, _DWORD, _DWORD))v3)(

                 v2,

                 cls_signed_query,

                 signed_query_init,

                 0,

                 0);

    }

    else

    {

      v9 = ((int (__fastcall *)(JNIEnv *, const char *))v8->NewStringUTF)(v2, "appkey");

      v10 = v9;

      v11 = sub_60CC(v2, (int)v3, v9);          // // 校验appkey

      v12 = v11;

      if ( v11 )

      {

        v30 = (const char *)((int (__fastcall *)(JNIEnv *, int, _DWORD))(*v2)->GetStringUTFChars)(v2, v11, 0);

        v13 = check_app_key_get_type(v30);

      }

      else

      {

        v13 = -1;

        v30 = 0;

      }

      v14 = ((int (__fastcall *)(JNIEnv *, const char *))(*v2)->NewStringUTF)(v2, "ts");

      v15 = sub_60CC(v2, (int)v3, v14);

      if ( !v15 )

      {

        v36 = 0;

        v37 = 0;

        s = 0;

        v35 = 0;

        v16 = time(0);

        sprintf((char *)&s, "%ld", v16);

        ((void (__fastcall *)(JNIEnv *, int *))(*v2)->NewStringUTF)(v2, &s);

        sub_6188((int)v2);

      }

      sub_41D0(v2, v14);

      sub_41D0(v2, v15);

      v17 = ((int (__fastcall *)(JNIEnv *, int, int, jobject (*)(JNIEnv *, jclass, jmethodID, ...)))(*v2)->CallStaticObjectMethod)(

              v2,

              cls_signed_query,

              method_signed_query_r,

              v3);

      v18 = 0;

      if ( sub_3F70((int)v2) )

        v17 = 0;

      v32 = v17;

      input_str = (const char *)((int (__fastcall *)(JNIEnv *, int, _DWORD))(*v2)->GetStringUTFChars)(v2, v17, 0);

      if ( v13 != -1 )

      {

        ((void (__fastcall *)(JNIEnv *, int, const char *))(*v2)->ReleaseStringUTFChars)(v2, v12, v30);

        v20 = malloc(0x10u);

        if ( v20 )

        {

          v31 = v10;

          v21 = global_key[v13];

          v22 = &global_key[v13];

          v23 = v22[5];

          v24 = v22[10];

          v25 = v22[15];

          *v20 = v21;

          v20[1] = v23;

          v20[2] = v24;

          v20[3] = v25;

          _aeabi_memclr8(&v33, 33);

          input_len = strlen(input_str);

          _aeabi_memclr8(v38, 24);

          _aeabi_memclr8(&s, 88);

          md5_init(&s);

          md5_update((int)&s, (int)input_str, input_len);

          sprintf(v38, "%08x", v21);

          md5_update((int)&s, (int)v38, 8u);

          v27 = 1;

          do

          {

            sprintf(v38, "%08x", v20[v27]);

            md5_update((int)&s, (int)v38, 8u);

            ++v27;

          }

          while ( v27 != 4 );

          md5_final((int)v38, (int)&s);

          v28 = &v33;

          v29 = 0;

          do

          {

            sprintf(v28, "%02x", (unsigned __int8)v38[v29++]);

            v28 += 2;

          }

          while ( v29 != 16 );

          free(v20);

          v10 = v31;

          v18 = ((int (__fastcall *)(JNIEnv *, char *))(*v2)->NewStringUTF)(v2, &v33);

        }

        else

        {

          v18 = 0;

        }

      }

      sub_41D0(v2, v10);

      v3 = (*v2)->NewObject;

      result = ((int (__fastcall *)(JNIEnv *, int, int, int, int))v3)(v2, cls_signed_query, signed_query_init, v32, v18);

    }

    }

    return result;} 

  • 分析代码,发现关键在 check_app_key_get_type和global_key,一个是app key获取type,还有一个存着类似于secret key的 global key

  • 整体看下来,结论就是 md5加密,按参数字典序排序,然后拼接SecretKey,再md5得到sign,取其中一个type来验证下:

  • 图片描述


    和app请求生成的sign一样,secret key打码,如果想要,可以按步骤自己去试试,实测成功,关键地方都写清楚了

 最后,写个python脚本试试,确实都能访问,这里脚本就不放了,求赞求加精,求账号升级,感谢

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis核心技术与实战【学习笔记】 - 16.Redis 缓存异常:缓存和数据库不一致

概述 只要使用 Redis 缓存&#xff0c;就必须面对缓存和数据库的一致性问题。 重要的是&#xff0c;如果数据不一致&#xff0c;那么业务应用从缓存中读取的数据就不是最新数据&#xff0c;这会导致严重的问题。比如说&#xff0c;我们把电商商品的库存信息缓存在 Redis 中&am…

机器学习_13_SVM支持向量机、感知器模型

文章目录 1 感知器模型1.1 感知器的思想1.2 感知器模型构建1.3 损失函数构建、求解 2 SVM3 线性可分SVM3.1 线性可分SVM—概念3.2 线性可分SVM —SVM 模型公式表示3.3 线性可分SVM —SVM 损失函数3.4 优化函数求解3.5 线性可分SVM—算法流程3.6 线性可分SVM—案例3.7 线性可分S…

如何读论文

如何读论文 0. 目的 单篇文章从头读到尾&#xff0c;可以&#xff1b; 世界上那么多篇文章&#xff0c; 都这样读&#xff0c; 时间上划不来。 适合你的文章就那么一小撮。 paper 的八股文结构&#xff1a; titleabstractintromethodexpconclusion 1. 第一遍 海选&#…

HiveSQL题——聚合函数(sum/count/max/min/avg)

目录 一、窗口函数的知识点 1.1 窗户函数的定义 1.2 窗户函数的语法 1.3 窗口函数分类 聚合函数 排序函数 前后函数 头尾函数 1.4 聚合函数 二、实际案例 2.1 每个用户累积访问次数 0 问题描述 1 数据准备 2 数据分析 3 小结 2.2 各直播间最大的同时在线人数 …

计算视图里的projection和aggregation节点区别

Projection 和 Aggregation到底有什么区别&#xff1f; 看名字就能看出来的。 那么在什么场景下用呢&#xff1f; 1. Projection就是投影&#xff0c;也就是说你本来的源里有什么&#xff0c;就直接给你拿出来。 除了这个&#xff0c;它使用的场景就是&#xff1a; 只映射需…

Framework - ActivityThread 应用启动UI渲染流程

一、概念 ActivityThread拥有 main(String[] agrs) 方法&#xff0c;作为程序的入口&#xff0c;是应用程序的初始化类。&#xff08;ActivityThread不是主线程&#xff0c;它在 main() 方法中实例化&#xff0c;是运行在主线程中。&#xff09;ApplicationThread是 ActivityT…

解析Excel文件内容,按每列首行元素名打印出某个字符串的统计占比(超详细)

目录 1.示例&#xff1a; 1.1 实现代码1&#xff1a;列数为常量 运行结果&#xff1a; 1.2 实现代码2&#xff1a;列数为变量 运行结果&#xff1a; 1.示例&#xff1a; 开发需求&#xff1a;读取Excel文件&#xff0c;统计第3列到第5列中每列的"False"字段占…

STM32SPI通信协议--(2)W25Q64简介

一、W25Q64简介 1、W25Qxx中的xx是不同的数字&#xff0c;表示了这个芯片不同的存储容量&#xff1b; 2、存储器分为易失性与非易失性&#xff0c;主要区别是存储的数据是否是掉电不丢失&#xff1a; 易失性存储器&#xff1a;SRAM、DRAM&#xff1b; 非易失性存储器&#xff…

django+flask+python高校教材管理系统47nia

本.4论文结构 绪论&#xff1a;剖析项目可行性&#xff0c;表明研究方向。 开发技术&#xff1a;系统关键运用了Python技术性、Django框架、B/S架构和myspl数据库查询&#xff0c;并进行了详细介绍[6]。 系统分析&#xff1a;包含系统的总体构造&#xff0c;用例图和结构图。 系…

使用机器学习算法预测在线订餐需求

咱们国内的美团和国外的 Swiggy 和 Zomato 引入市场后&#xff0c;在线订餐的需求量很大。食品配送公司利用客户的购买习惯来加快配送过程。食品订单预测系统是这些公司可以用来加快整个交付过程的有用技术之一。 这些公司对客户的主要目标是在正确的时间交付食物。为了更快地…

二叉树的层序遍历 II

给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历&#xff09; 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[15,7],[9,20],…

【数据开发】pyspark入门与RDD编程

【数据开发】pyspark入门与RDD编程 文章目录 1、pyspark介绍2、RDD与基础概念3、RDD编程3.1 Transformation/Action3.2 数据开发流程与环节 1、pyspark介绍 pyspark的用途 机器学习专有的数据分析。数据科学使用Python和支持性库的大数据。 spark与pyspark的关系 spark是一…

[BUUCTF]-PWN:roarctf_2019_easy_pwn解析

先看保护 64位&#xff0c;got表不可写 看ida 大致就是alloc创建堆块&#xff0c;fill填充堆块&#xff0c;free释放堆块&#xff0c;show输出堆块内容 这里要注意的点有以下 alloc创建堆块&#xff1a;这里采用的是calloc而不是malloc&#xff0c;calloc在创建堆块时会初始…

小白水平理解面试经典题目_二维数组类LeetCode 2966 Divide Array【排序算法实现】

2966 将数组划分为具有最大差值的数组 小白渣翻译&#xff1a; 给定一个大小为 n 的整数数组 nums 和一个正整数 k 。 将数组分成一个或多个大小为 3 的数组&#xff0c;满足以下条件&#xff1a; nums 的每个元素都应该位于一个数组中。一个数组中任意两个元素之间的差异小…

python打造光斑处理系统6:高斯拟合

文章目录 构建拟合函数数据获取打印信息 光斑处理&#xff1a;python处理高斯光束的图像 光斑处理系统&#xff1a; 程序框架&#x1f31f;打开图像&#x1f31f;参数对话框/伪彩映射&#x1f31f;裁切ROI光强分布 构建拟合函数 scipy中提供了非线性最小二乘回归算法&#x…

创建型模式-单例模式:定义、实现及应用

目录 一、模式定义二、针对问题1.解决的问题2.解决方案3.举个例子4.设计模式适合场景5.实现方式6.优缺点7.与其他模式的关系 三、代码实现 一、模式定义 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型模式&#xff0c;用于限制某个类只能创建一个对象。它提…

CMake Msys2 搭配vscode

(一)MSYS2介绍 MSYS2&#xff08;Minimal SYStem 2&#xff09;是一个集成了大量的GNU工具链、工具和库的开源软件包集合。它提供了一个类似于Linux的shell环境&#xff0c;可以在Windows系统中编译和运行许多Linux应用程序和工具。 MSYS2基于MinGW-w64平台&#xff0c;提供了…

04、全文检索 -- Solr -- 管理 Solr 的 core(使用命令和图形界面创建、删除 core,以及对core 目录下的各文件进行详细介绍)

目录 管理 Solr 的 core创建 Core方式1&#xff1a;solr 命令创建演示&#xff1a;使用 solr 命令创建 Core&#xff1a;演示&#xff1a;命令删除 Core&#xff08;彻底删除&#xff09; 方式2&#xff1a;图形界面创建Web控制台创建CoreWeb控制台删除 Core&#xff08;未彻底…

使用css绘制小三角形

要使用CSS绘制小三角形&#xff0c;您可以使用border属性来设置边框样式。下面是一种常见的绘制小三角形的方法&#xff1a; <style>.box {width: 0;height: 0;/* border-top: 10px solid red; */border-bottom: 10px solid blue;border-left: 10px solid transparent;b…

【Mysql】事务的隔离级别与 MVCC

事务隔离级别 我们知道 MySQL 是一个 C/S 架构的服务&#xff0c;对于同一个服务器来说&#xff0c;可以有多个客户端与之连接&#xff0c;每个客户端与服务器连接上之后&#xff0c;就是一个会话&#xff08; Session &#xff09;。每个客户端都可以在自己的会话中向服务器发…