最近女高中生の廃度日常を見ていますが、b 站のアニメの画質が圧縮されすぎているので、解析サイトを探しました。
結果、サイトの js コードが難読化されていることがわかり、逆向きに解析しました。
逆向きの目標#
aHR0cHM6Ly9qeC5wbGF5ZXJqeS5jb20v
分析#
動画が読み込まれたことがわかりますが、動画に関するリクエストは見えません。
これらのリクエストの応答データは読み込めませんが、動画の断片であると推測できます。
ファイルを開くと次のように表示されます:
おおよそのリクエストプロセスは次の通りです:
M3U8 ファイルは、video clip のリクエスト URL を保存するテキストファイルです。
これがあれば、全体の動画ファイルの URL を取得できます。
上に遡って、m3u8 ファイルを受け取るリクエストを見つけました:
リクエスト URL の構成:
https:// ドメイン名 / タイムスタンプ / 不明 / 不明.m3u8 + 固定パラメータ
ここで注意を怠ると、簡単に xhr ブレークポイントを使って js コードを追跡してしまいます。私自身、最初に分析しているときにこの誤解に陥り、複雑なコードとさまざまな暗号の中で迷ってしまいました。
しかし、このリクエストは私たちが構築する必要はなく、前のリクエストによって受け取られ、暗号化もされておらず、平文で送信されてきました!
このリクエストのペイロードを見てみましょう:
二つのパラメータtime、key
time はタイムスタンプで、key は md5 暗号のようです。js コードを逆向きに解析した結果、実際には CBC 暗号化ですが、私を困惑させたのは、私が js コードを分析し終えて python でリクエストをシミュレートし始めたとき、key と time が前のリクエストで平文で送信されてきたことを発見したことです!
コードを書く#
#getPram.py
import time
import requests as rq
from lxml import etree
from lxml import html
headers = {
"referer": "https://jx.playerjy.com/",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
"Cache-Control": "no-cache",
"Host": "jy.we-vip.com:5433"
}
def getHtml(ep):
url = "https://jy.we-vip.com:5433/?url=" + ep
return rq.get(url=url, headers=headers, verify=False).content
# timeとkeyを取得
def getData(bili_url):
htmlString = html.fromstring(getHtml(bili_url))
result = htmlString.xpath('//body/script/text()')
#timeを取得
timebegin = result[0].index('time') + 8
timeend = int(str(result[0]).index('",', timebegin))
time = result[0][timebegin:timeend]
#keyを取得
keybegin = result[0].index('key') + 7
keyend = int(str(result[0]).index('",', keybegin))
key = result[0][keybegin:keyend]
return time, key
if __name__ == "__main__":
time, key = getData()
print(f"time is {time}, key is {key}")
import requests as rq
import getPram
time, key = getPram.getData(input("bilibili_url:"))
headers = {
"authority" : "jy.we-vip.com:5433",
"accept" : "application/json, text/javascript, */*; q=0.01",
"content-type" : "application/x-www-form-urlencoded; charset=UTF-8",
"user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
"Host" : "jy.we-vip.com:5433",
"Content-Length": "115",
"Cache-Control": "no-cache"
}
url = r"https://jy.we-vip.com:5433/API.php"
data = {
"url": "https://www.bilibili.com/bangumi/play/ep276690",
"time": time,
"key": key
}
rsp = rq.post(url, headers=headers, data=data, verify=False)
print(rsp.content)
反省#
- 分析の思考は答弁に依存しており、ぐるぐる回って最終的にリクエストプロセスをしっかり分析できず、多くの時間を無駄にしました。逆向きは高校の数学の問題のようで、最初はぼんやりした方向しかなく、忍耐強く源を追跡する必要があります。
- コードは答弁に依存しており、論理があまり明確ではなく、サブ文字列を抽出する方法を多く考えましたが、最終的には最も単純で可読性の低い方法を選びました...