逆向分析海盗听书

11/8/2021

# 一、起因

在 52pojie论坛 看到一篇对「海盗听书」的逆向分析
刚好自己从事前端工作
刚好对逆向有着浓厚的兴趣 (对“破坏”有着一种本能冲动,和解开谜题后的自我成就感)
刚好最近在听一本付费有声小说 《诡秘之主》 (opens new window)

# 二、难点

# 2.1、无尽debugger

最简单的分析当然是从「源代码」以及「请求资源」开始分析。
当打开 Developer Tools时 会进入无尽 debugger 模式

解决方式有两种,一种是跳过所有的 debugger,自己设定的 debugger 也会跳过,效果欠佳 跳过所有的 debugger

另一种是永久跳过此处,Never pause here 永远不要停在这里 跳过所有的 debugger

# 2.2、分析接口

打开 Developer Tools 的 Network 页,观察到 Fetch/XHR 类别下请求了两个接口
其中一个接口分析后得出,是音频资源接口,资源路径部分(src)被简单加密了

https://www.tingxiaoshuo.cc/pc/index/getchapterurl/bookId/12502/chapterId/3899427.html

bookId后面拼接的是数据ID
chapterId后面拼接的是章节ID

{
    "status": 1,
    "message": "成功",
    "src": "104*116*116*112*115*58*47*47*97*111*100*46*99*111*115*46*116*120*46*120*109*99*100*110*46*99*111*109*47*115*116*111*114*97*103*101*115*47*97*53*52*55*45*97*117*100*105*111*102*114*101*101*104*105*103*104*113*112*115*47*54*49*47*65*56*47*67*75*119*82*73*82*119*70*81*115*74*114*65*65*117*80*74*65*68*116*119*72*51*45*46*109*52*97",
    "jsjm": 1
}

# 2.2、解密 SRC

由于 src 是被加密后的,则需要找寻解密函数
打开上面接口详情的「Initiator」切换页
看到有几个关联函数,进去康康 Initiator

看到几个熟悉的单词
有audiosrc 猜测是解密后的音频资源地址
data.src 是接口的音频资源参数,jsjm接口返回资源的状态参数

data.src 被传入到 $jc.abc() 函数中,这应该就是解密函数了
在控制台中输入 $jc.abc 得到了该函数代码,点击后可进入对应的 common.js 文件中
把代码序列化以后,提取关键内容 String.fromCharCode (opens new window)

    w.abc = function(u) {
        // 用*号进行分割Unicode 编码,
        var tArr = u.split("*");
          , str = '';//将转码后的地址放这里
        // for循环 将Unicode 编码转为一个字符
        for (var i = 0, n = tArr.length; i < n; i++) {
            str += String.fromCharCode(tArr[i]);
        }
        return str; //返回地址
    }

# 2.3、获取该书籍所有章节,并解密所有音频

把代码复制到 Developer Tools 的 Console 窗口,会自动加载完成

点击查看代码

/**
 * 获取该书籍的所有的chatperId
 * 书籍地址:https://www.tingxiaoshuo.cc/book/12502.html
 * 其中 12502 为书本ID
 */
function getAllChatperID() {
    let list = [];
    let ele = $("#playlist").find('li');
    for (let i = 0; i <= ele.length; i++) {
        let e = $(ele[i]).find("a");
        if (e) {
            let name = e.text();
            let href = e.attr('href');
            if (href) {
                let chatper = e.attr('href').substring(12, 19);
                list.push({ name, chatper });
            }
        }
    }
    return list;
}

/**
 * 通过接口查询ID
 * @param {*} chapterid 
 */
function getId(chapterid) {
    return fetch(`https://www.tingxiaoshuo.cc/pc/index/getchapterurl/bookId/12502/chapterId/${chapterid}.html`, {
        "headers": {
            "accept": "application/json, text/javascript, */*; q=0.01",
            "accept-language": "zh-CN,zh;q=0.9",
            "sec-ch-ua": "\"Chromium\";v=\"94\", \"Google Chrome\";v=\"94\", \";Not A Brand\";v=\"99\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-origin",
            "x-requested-with": "XMLHttpRequest"
        },
        "referrer": "https://www.tingxiaoshuo.cc/play/12502/3899426.html",
        "referrerPolicy": "strict-origin-when-cross-origin",
        "body": null,
        "method": "GET",
        "mode": "cors",
        "credentials": "include"
    }).then(d => d.json());
}


/**
 * 解析出URL
 * @param {*} u 
 * @returns 
 */
function decode(u) {
    var tArr = u.split("*")
        , str = '';
    for (var i = 0, n = tArr.length; i < n; i++) {
        str += String.fromCharCode(tArr[i]);
    }
    return str;
}


let source = [];

/**
 * 主入口
 */
function main() {

    let AllList = getAllChatperID();
    loop();
    function loop() {
        let { name, chatper } = AllList[0];
        getId(chatper).then(d => {
            let src = decode(d['src']);
            source.push({ name, chatper, src });
            AllList.shift();
            if (AllList.length > 0) loop();
        });
    }
}

main()

变量 source 会保存该数据的名称,以及音频地址,通过这个地址即可下载

[
    {
        "name": "多人有声剧《诡秘之主》主题音乐《最好的时代》(官方听友群~961082420)",
        "chatper": "3899426",
        "src": "https://aod.cos.tx.xmcdn.com/storages/aa22-audiofreehighqps/A4/14/CMCoOSMFQsJeAA1wxgDtwHqC.m4a"
    },
    {
        "name": "多人有声剧《诡秘之主》转运仪式主题音乐——《灰雾之上》",
        "chatper": "3899427",
        "src": "https://aod.cos.tx.xmcdn.com/storages/a547-audiofreehighqps/61/A8/CKwRIRwFQsJrAAuPJADtwH3-.m4a"
    },
    {
        "name": "多人有声剧《诡秘之主》——克莱恩侄女小剧场",
        "chatper": "3899428",
        "src": "https://aod.cos.tx.xmcdn.com/storages/5f91-audiofreehighqps/99/48/CMCoOSYFQsJ2ABKkpgDtwIEU.m4a"
    },
    {
        "name": "多人有声剧《诡秘之主》世界观主题音乐——《神战遗迹》",
        "chatper": "3899429",
        "src": "https://aod.cos.tx.xmcdn.com/storages/a0a7-audiofreehighqps/23/4E/CMCoOR4FQsKDAA21zADtwISp.m4a"
    },
    {
        "name": "多人有声剧《诡秘之主》生活主题音乐——《甜冰茶》",
        "chatper": "3899430",
        "src": "\u0000"
    },
    ....
]

# 三、APP端接口

APP端的接口抓取

获取数据所有章节
https://app.tingxiaoshuo.cc/listen/api/chapter?bookId=12502&uid=0&sort=asc&size=20

获取章节音频资源接口
https://app.tingxiaoshuo.cc/web/index/getChapterUrl?bookId=12323&chapterId=${chapterid}`

# 四、其他

现在接口有防爬操作,限制五分钟内只能访问N条

被限流了,暂时没有找到更好的解决办法





抓包听中国海盗听书网分析曲折辛酸历程 (opens new window)