吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7036|回复: 64
收起左侧

[Web逆向] 某香医生sign值参数逆向分析

  [复制链接]
buluo533 发表于 2025-6-15 14:07
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关.本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责
一个简单的sign加密参数逆向分析思路:
食用地址:aHR0cHM6Ly93d3cuZHh5LmNuL2Jicy9uZXd3ZWIvcGMvY2FzZQ==


一、抓包分析目标参数
    1、分析目标接口:Cmh0dHBzOi8vd3d3LmR4eS5jbi9iYnMvbmV3d2ViL2Nhc2UtYmFuay9wYWdlLXBvc3QtaW5mbw==
        2、需要处理参数:
         

sign参数

sign参数

         非常明确就一个sign参数需要处理,爬虫老鸟可能会直接拿过来看看长度,猜一下大概是什么算法,像非常常见的标准32位md5也遇到过很多次
         

参数长度

参数长度

         很好,40位,当场退役,接下来就是跟栈分析
二、跟栈定位加密函数


       1、直接跟进来打个断点,其实我们跟栈的目的很明确,其实就是找到加密函数的生成位置,从而复现加密逻辑
      

跟栈

跟栈

        

断点

断点

   接下来,我们选择下滑点击查看更多,因为这是一个翻页的加密参数,刷新会导致不必要的接口加载,所以下滑更适合食用(所有都需要根据具体情况去选择)
   

作用域

作用域

  接下来我们根据断住的内容去分析参数的位置,大佬们可以自行选择作用于查看或者控制台打印查看

异步

异步

我们可以看到整个执行有自执行函数,异步,比较复杂的生成过程,我们直接往上走,看看加密参数的生成位置
         

第一个参数位置

第一个参数位置

         

第二个参数位置

第二个参数位置

     很明显都不是参数产生的位置,都是传进来的参数,我们继续往上走
         

第三次参数

第三次参数

    很快就到了异步的位置,还是不是加密产生的地方,所以我们要继续往上走,重新在异步位置下断点,下来加载更多刷新,然后把其他断点可以删掉

   

异步位置

异步位置

   

异步参数

异步参数

   还是一样sign已经生成了,这里依旧不是我们加密逻辑的地方,继续往上走一下
   

异步参数2

异步参数2

        

异步参数3

异步参数3

      

异步参数4

异步参数4

     

空值

空值

   这里我们就发现有问题了,我们没有找到加密参数sign,说明接下来就是生成sign的位置,我们一直往上走该结束了,可以往下走

      回到我们这张图的所在位置,接下来就是找相关的代码,进行加密参数的分析


三、加密算法及代码分析
       这一部分的话需要一些基本的js代码阅读能力,对代码执行逻辑进行分析
            

加密

加密

      这是一段控制流的代码,我们可以清晰地看到熟悉的参数sign,可以猜测是在这里形成加密参数,我们在可疑位置之前和之后打上断点,看看情况,放开其他断点加载更多
      

可疑位置

可疑位置

   

w

w

   这里可以看出,加密参数是w中的值,生成的,核心代码逻辑如下:
   
[JavaScript] 纯文本查看 复制代码
r === "get" || "delete" === r || "head" === r || "options" === r  ? w.params = f.sign(s.Z(s.Z({}, g), { serverTimestamp: R }), d.bl)
  : w.params = f.sign({ serverTimestamp: R }, d.bl)

   这段代码是一个三元表达式,根据变量r的值选择两种不同的方式构造w.params对象,条件为真时,执行:
[JavaScript] 纯文本查看 复制代码
w.params = f.sign(  s.Z(          
    s.Z({}, g),  
    { serverTimestamp: R }serverTimestamp
  ),
  d.bl 
)

   条件为假时执行:
  
[JavaScript] 纯文本查看 复制代码
w.params = f.sign(
  { serverTimestamp: R },
  d.bl                
)

    我们可以借助ai或者自己稍微改写一下逻辑,更方便理解
   
[JavaScript] 纯文本查看 复制代码
if (r === "get" || r === "delete" || r === "head" || r === "options") {  // 合并 g 和 serverTimestamp
  const merged = Object.assign({}, g, { serverTimestamp: R }); 
  w.params = f.sign(merged, d.bl);
} else {
  // 仅使用 serverTimestamp
  w.params = f.sign({ serverTimestamp: R }, d.bl);
}

   这个大概是针对不同的请求接口做加密是设计的,根据我们当前请求方式为get请求,直接下断点看看情况
     

新断点

新断点

    这里我们一定要利用单步调试,这样就是可以进入到核心的加密逻辑中
   

加密逻辑分析

加密逻辑分析

  这里我们们可以看到,sign值的产生应该是通过s函数f进行加密
  
[JavaScript] 纯文本查看 复制代码
 var f = Object.keys(o).filter((function(e) {                        return void 0 != o[e] && "" !== o[e] || (delete o[e],
                        !1)
                    }
                    )).concat("appSignKey").sort().map((function(e) {
                        var t = i[e] || (void 0 == o[e] ? "" : o[e]);
                        return "".concat(e, "=").concat(t)
                    }
                    )).join("&");

   

f参数的拼接

f参数的拼接

  可以看出,f是对appSignKey,noncestr,pageNum,pageSize,sectionCode,serverTimestamp,timestamp拼接产生的,我们可以通过不断地下来加载来确定哪些是是变得哪些是不变的,pageNum 是翻页的参数是根据具体的页码传入的,appSignKey 通过测试是一个定值,接下里分析的就是
[JavaScript] 纯文本查看 复制代码
 a = Date.now();
 e.serverTimestamp && !l && (l = e.serverTimestamp - a),
 o.timestamp = a + l,
o.noncestr = u(8, "number");


这些参数内容serverTimestamp是服务器的时间,timestamp就是当前时间和服务器时间的一个差值,u的逻辑我们跟进去看看
  
[JavaScript] 纯文本查看 复制代码
function u() {
                    for (var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 8, t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "alphabet", n = "", r = {
                        alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
                        number: "0123456789"
                    }[t], o = 0; o < e; o++)
                        n += r.charAt(Math.floor(Math.random() * r.length));
                    return n
                }

简单转化一下:
[Python] 纯文本查看 复制代码
import random

def random_string(length=8, charset='alphabet'):
    charsets = {
        'alphabet': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
        'number': "0123456789"
    }

    char_set = charsets.get(charset)
    if char_set is None:
        raise ValueError(f"Invalid charset: {charset}. Use 'alphabet' or 'number'")
    return ''.join(random.choice(char_set) for _ in range(length))

这样我们的加密参数就搞定了,接下来就是研究真正实现加密的s函数
  

sha1

sha1

   简单的看一下,密码学大佬(强烈推荐q佬的密码公众号,可以自行学习一下,我已经请教过了,可以观察常量的特征来分析)可能就直接秒了,对于密码学菜狗的我选择丢给ai分析一下,非常标准的sha1加密,可以简单测试一下
  

加密对比

加密对比


     非常标准,完美,这样我们直接调用就ok了
   
[Python] 纯文本查看 复制代码
from hashlib import sha1
def get_sign(datas: dict):
    sign = '&'.join([f'{key}={value}' for key, value in datas.items()])
    sign_sha1 = sha1(sign.encode()).hexdigest()
    return sign_sha1


然后就ok了,非常适合新手朋友食用

结果

结果





免费评分

参与人数 16威望 +2 吾爱币 +117 热心值 +13 收起 理由
maskll + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
dwn6905 + 1 + 1 用心讨论,共获提升!
hj170520 + 2 + 1 我很赞同!
天空宫阙 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
qiaoyong + 1 + 1 热心回复!
Yao2903 + 1 + 1 谢谢@Thanks!
涛之雨 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
tianyu925 + 1 我很赞同!
xlln + 1 + 1 我很赞同!
Reksam + 1 + 1 谢谢@Thanks!
anning666 + 1 + 1 我很赞同!
AdAStra + 1 + 1 谢谢@Thanks!
surepj + 1 + 1 用心讨论,共获提升!
飘缈孤鸿影 + 1 + 1 谢谢@Thanks!
杨辣子 + 1 + 1 谢谢@Thanks!
yjlxn + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

rayzju 发表于 2025-6-16 07:18
记得20多年前 某香论坛 那时候讨论氛围真的好,现在再也找不回当时的感觉了。
gxr2010 发表于 2025-6-16 15:37
[Python] 纯文本查看 复制代码
import requests
import random
import time
from hashlib import sha1
def get_sign(datas: dict):
    sign = '&'.join([f'{key}={value}' for key, value in datas.items()])
    sign_sha1 = sha1(sign.encode()).hexdigest()
    return sign_sha1
def random_string(length=8, charset='alphabet'):
    charsets = {
        'alphabet': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
        'number': "0123456789"
    }

    char_set = charsets.get(charset)
    if char_set is None:
        raise ValueError(f"Invalid charset: {charset}. Use 'alphabet' or 'number'")
    return ''.join(random.choice(char_set) for _ in range(length))

headers = {
    'accept': 'application/json',
    'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'content-type': 'application/json;charset=utf-8',
    'priority': 'u=1, i',
    'referer': 'https://www.dxy.cn/bbs/newweb/pc/case/search?keyword=%E9%AB%98%E8%A1%80%E5%8E%8B',
    'sec-ch-ua': '"Microsoft Edge";v="137", "Chromium";v="137", "Not/A)Brand";v="24"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    'sec-fetch-dest': 'empty',
    'sec-fetch-mode': 'cors',
    'sec-fetch-site': 'same-origin',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0',
}
noncestr = random_string()
# print(noncestr)
for i in range(1,12):
    # 调用get_sign函数,传入params1字典,获取sign的值
    params1 = {
        'appSignKey': '4bTogwpz7RzNO2VTFtW7zcfRkAE97ox6ZSgcQi7FgYdqrHqKB7aGqEZ4o7yssa2aEXoV3bQwh12FFgVNlpyYk2Yjm9d2EZGeGu3',
        'keyword': '高血压',
        'noncestr': noncestr,
        'pageNum': i,
        'pageSize': '20',
        'sectionCode': '0',
        'serverTimestamp':  int(time.time()),
        'timestamp': int(time.time())
    }
    sign = get_sign(params1)

    # print(sign)
    # 构造params2字典,requests库中的get方法,返回json值
    params2 = {
        'keyword': '高血压',
        'sectionCode': '0',
        'pageSize': '20',
        'pageNum': i,
        'serverTimestamp': int(time.time()),
        'timestamp': int(time.time()),
        'noncestr': noncestr,
        'sign': sign,
    }

    response = requests.get('https://www.dxy.cn/bbs/newweb/case-bank/page-post-info', params=params2, headers=headers).json()
    print(response)

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
uuwatch + 1 + 1 谢谢@Thanks!

查看全部评分

xsephiroth 发表于 2025-6-16 11:05
 楼主| buluo533 发表于 2025-6-15 20:36
bansjs 发表于 2025-6-15 20:13
会者不难,难者不会,如果弄个视频估计我们这些菜鸟才会看懂一点,楼主大才,感谢分享

收到,这篇文章主要也是给我的新手朋友写的,我也问问他们的感受我也不知道站里能不能放视频,有机会可以试试,我还在准备另一篇文章
rayzju 发表于 2025-6-17 08:16
buluo533 发表于 2025-6-16 08:23
20年前?我可能都没出生

当时还是一枚医学生,论坛里实习生虚心求教,医学大咖不吝赐教,很多病历分享和讨论,获益匪浅,比现在看那些水文期刊好多了。
yjlxn 发表于 2025-6-15 15:02
谢谢楼主这种教学式的分享!能学到东西!
sqzh 发表于 2025-6-15 16:32
高大上,很专业哈
bansjs 发表于 2025-6-15 20:13
会者不难,难者不会,如果弄个视频估计我们这些菜鸟才会看懂一点,楼主大才,感谢分享
bansjs 发表于 2025-6-15 21:13
buluo533 发表于 2025-6-15 20:36
收到,这篇文章主要也是给我的新手朋友写的,我也问问他们的感受我也不知道站里能不能放视频,有 ...

论坛支持原创视频,视频+图文更容易加精华,受众也会更多
 楼主| buluo533 发表于 2025-6-15 21:31
bansjs 发表于 2025-6-15 21:13
论坛支持原创视频,视频+图文更容易加精华,受众也会更多

住在宿舍欸,我看看情况呢
shanhu5235 发表于 2025-6-16 00:07
支持原创,谢谢分享
CGMSS 发表于 2025-6-16 02:51
感谢分享,厉害&#128077;&#127995;
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-4-17 19:14

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表