突破喜马拉雅的 xm-sign 验证,爬取有声读物

本文详细介绍了如何通过Python爬虫分析并破解喜马拉雅的xm-sign验证机制。通过断点调试js代码,发现xm-sign由u.getSign()生成,涉及到服务器时间戳、当前时间戳及随机数。经过函数处理后的结果类似MD5编码,验证后成功匹配,揭示了获取xm-sign的关键步骤。

首先找到 xm-sign 参数的js代码,断点调试,如下:


可见, xm-sign 的值是由函数u.getSign()生成的,直接进入该函数的内部看看


再次断点调试,可以发现,这里的 t 是喜马拉雅的服务器时间戳,由 time 这个包生成的,地址是:https://www.ximalaya.com/revision/time;而 e 就是现在的时间戳;两个小括号是100以内随机整数;花括号{himalaya-1570715660049}整个被替换成 函数 l(e)的值,进入该函数的内部:


这里传入函数的参数是himalaya-1570715660049;返回值未知,直接复制这个返回值到Console运行看看

发现可以运行,而且返回值像md5编码? 此时最直接的想法就是把"himalaya-1570715660049"这个参数md5试一下

结果是两个值一模一样!到此 xm-sign 的值就出来了

himalaya-服务器时间戳的md5编码+(100以内随机数)+服务器时间戳+(100以内随机数)+现在时间戳


范例代码:

"""
@ 功能:喜马拉雅有声读物下载
@ 作者:虫之吻
@ 时间:2019-10-10
"""
from queue import Queue
import threading
import requests
import hashlib
import random
import time
import re
import os


class XimaLaya(object):
    def __init__(self, page_url):
        self.headers = {'User-Agent': 'Mozilla/5.0', 'Host': 'www.ximalaya.com'}
        self.server_time_url = 'https://www.ximalaya.com/revision/time'
        self.requests_url = 'https://www.ximalaya.com/revision/play/album'
        self.page_url = page_url
        self.queue = Queue()

    def get_md5(self, str_time):
        """
        获取md5字段
        """
        return hashlib.md5('himalaya-{}'.format(str_time).encode()).hexdigest()

    def xm_sign(self):
        """
        获取xm-sign
        """
        # 喜马拉雅服务器时间戳
        server_time = requests.get(self.server_time_url, headers=self.headers).text
        # 现在的时间戳
        now_time = str(int(time.time()*1000))
        # 100内随机数
        random_num = '({})'.format(str(random.randrange(100)))
        # 获取xm-sign
        return self.get_md5(server_time) + random_num + server_time + random_num + now_time

    def get_album_info(self):
        """
        获取专辑id、页码、专辑名称
        """
        html = requests.get(self.page_url, headers=self.headers, timeout=10).text
        return (
            re.findall(r'/(\d{4,})/', self.page_url)[0],
            re.findall(r'min="1" max="(\d+)"', html)[0],
            re.findall(r'<h1 class="title _II0L">(.*?)</h1>', html)[0],
        )

    def crawler(self, albumId, page_num):
        """
        爬取音乐数据
        """
        try:
            for n in range(1, int(page_num) + 1):
                self.headers['xm-sign'] = self.xm_sign()
                params = {'albumId': albumId, 'pageNum': str(n), 'sort': '0', 'pageSize': '30'}
                r = requests.get(self.requests_url, params=params, headers=self.headers, timeout=8)
                music_list = r.json()['data']['tracksAudioPlay']
                for music in music_list:
                    music_name = re.sub(r'[\/:*?"<>|]', "", music['trackName'])
                    music_url = music['src'].replace('"', "")
                    print('添加到队列:', (music_url, music_name))
                    self.queue.put_nowait((music_url, music_name))
        except:
            pass

    def download(self):
        """
        下载音乐
        """
        while not self.queue.empty():
            try:
                music_url, music_name = self.queue.get_nowait()
                content = requests.get(music_url, timeout=20).content
                with open(path + '/' + music_name + '.m4a', 'wb') as f:
                    f.write(content)
                    print('已下载:{}.m4a'.format(music_name))
            except:
                pass

    def main(self):
        album_id, page_num, album_name = self.get_album_info()
        # 创建文件夹
        album_name = re.sub(r'[\/:*?"<>|]', "", album_name)
        global path
        path = "ximalaya/{}/".format(album_name)
        if not os.path.exists(path):
            os.makedirs(path)
        # 单线程爬取数据
        self.crawler(album_id, page_num)
        # 多线程下载
        t_l = []
        for x in range(5):
            t = threading.Thread(target=self.download)
            t_l.append(t)
            t.start()

        for t in t_l:
            t.join()


if __name__ == '__main__':
    # url = input('输入链接:')
    url = 'https://www.ximalaya.com/youshengshu/12642314/'
    xm = XimaLaya(url)
    xm.main()
<think>好的,我现在要处理用户关于喜马拉雅xm-sign逆向工程的问题。首先,我需要理解用户的需求。他们想知道如何分析xm-sign的生成方法,可能用于下载或其他用途。但逆向工程可能涉及法律问题,所以得先提醒用户注意合规性。 接下来,我应该拆解逆向工程的一般步骤。通常这类签名参数涉及加密算法,需要抓包分析请求,找到xm-sign的位置。然后可能需要反编译APK或使用Xposed框架动态调试,找到生成xm-sign的代码段。但具体到喜马拉雅,可能需要查看是否有公开的资料或社区讨论。 记得用户给的引用链接里有一个工具,可能已经有现成的解决方案。但用户想自己研究,所以得提供方法。比如,抓包工具如Charles或Fiddler的使用,反编译工具如Jadx或JEB,动态分析工具如Frida。需要分步骤说明这些工具如何配合使用。 同时,要提到可能的加密算法类型,比如HMAC-SHA256或AES,以及如何识别关键代码。比如搜索字符串"xm-sign"或相关参数,定位到加密函数。还要注意代码混淆的问题,可能需要动态分析来绕过。 最后,生成相关问题,帮助用户深入思考,比如如何绕过反调试,或者如何模拟生成xm-sign,以及合规性问题。确保回答结构清晰,步骤明确,同时强调法律风险。</think>### 喜马拉雅 xm-sign 逆向工程分析方法 #### 1. **基础逆向工程流程** - **抓包分析**:使用抓包工具(如 Charles/Fiddler/Wireshark)捕获含有 `xm-sign` 的请求,观察其参数结构、生成规律及加密特征[^1]。 - **参数关联性**:分析 `xm-sign` 与请求时间戳、设备ID、用户Token等参数的关联性,推测可能的哈希算法(如 HMAC-SHA256、MD5)。 - **算法定位**:若参数中包含时间戳,可尝试本地生成时间戳拼接密钥,通过哈希算法模拟签名过程。 #### 2. **APK逆向分析** - **反编译工具**:使用 Jadx/Ghidra/JEB 对喜马拉雅APK反编译,搜索关键字符串(如 `xm-sign`、`getSign`)定位加密代码。 - **代码动态调试**:通过 Frida/Xposed 注入Hook逻辑,拦截签名生成函数,观察输入输出及算法细节。 ```java // 示例:Hook签名函数 Java.perform(function() { let SignClass = Java.use("com.ximalaya.security.SignUtils"); SignClass.generateSign.implementation = function(params) { console.log("Input params: " + params); let result = this.generateSign(params); console.log("Generated xm-sign: " + result); return result; }; }); ``` - **代码混淆处理**:若遇混淆(如类名`a.b.c.d`),需结合动态调试与静态分析交叉验证。 #### 3. **算法复现与验证** - **本地模拟**:根据逆向结果编写Python/Node.js代码复现算法,例如: ```python import hmac import time def generate_xm_sign(params, secret_key): timestamp = str(int(time.time() * 1000)) data = timestamp + "|" + "&".join(sorted(params.items())) return hmac.new(secret_key.encode(), data.encode(), "sha256").hexdigest() ``` - **请求对比**:将本地生成的 `xm-sign` 与实际请求对比,调试参数顺序、编码方式(如 Base64/Hex)及密钥轮换机制。 #### 4. **注意事项** - **法律风险**:逆向工程可能违反《计算机软件保护条例》,需确保用途合规(如个人学习)。 - **反调试机制**:部分应用会检测Root/Xposed环境,需使用定制ROM或虚拟化技术绕过。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值