banner
ming5ming

ming5ming

⭐一起去追那遥不可及的星⭐ 正在赛马!

逆向日记0x1

最近女高中生の廃度日常を見ていますが、b 站のアニメの画質が圧縮されすぎているので、解析サイトを探しました。
結果、サイトの js コードが難読化されていることがわかり、逆向きに解析しました。


逆向きの目標#

aHR0cHM6Ly9qeC5wbGF5ZXJqeS5jb20v

分析#

Pasted image 20230214195931

動画が読み込まれたことがわかりますが、動画に関するリクエストは見えません。Pasted image 20230214200144

これらのリクエストの応答データは読み込めませんが、動画の断片であると推測できます。
ファイルを開くと次のように表示されます:

Pasted image 20230214200551

おおよそのリクエストプロセスは次の通りです:

request

M3U8 ファイルは、video clip のリクエスト URL を保存するテキストファイルです。
これがあれば、全体の動画ファイルの URL を取得できます。

上に遡って、m3u8 ファイルを受け取るリクエストを見つけました:

Pasted image 20230214201749
Pasted image 20230214201851

https:// 省略 / 1676376933/4d140af4cb5d1c5466a7491918b43e5b/b3489f29121e97e6dd1dcb1957e5788c-20230214.m3u8?from=https://banyung.pw

リクエスト URL の構成:
https:// ドメイン名 / タイムスタンプ / 不明 / 不明.m3u8 + 固定パラメータ

ここで注意を怠ると、簡単に xhr ブレークポイントを使って js コードを追跡してしまいます。私自身、最初に分析しているときにこの誤解に陥り、複雑なコードとさまざまな暗号の中で迷ってしまいました。

Pasted image 20230214202531

しかし、このリクエストは私たちが構築する必要はなく、前のリクエストによって受け取られ、暗号化もされておらず、平文で送信されてきました!

Pasted image 20230214202715

このリクエストのペイロードを見てみましょう:

Pasted image 20230214202821

二つのパラメータtimekey
time はタイムスタンプで、key は md5 暗号のようです。js コードを逆向きに解析した結果、実際には CBC 暗号化ですが、私を困惑させたのは、私が js コードを分析し終えて python でリクエストをシミュレートし始めたとき、key と time が前のリクエストで平文で送信されてきたことを発見したことです!

Pasted image 20230214203247

コードを書く#

#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)

反省#

  • 分析の思考は答弁に依存しており、ぐるぐる回って最終的にリクエストプロセスをしっかり分析できず、多くの時間を無駄にしました。逆向きは高校の数学の問題のようで、最初はぼんやりした方向しかなく、忍耐強く源を追跡する必要があります。
  • コードは答弁に依存しており、論理があまり明確ではなく、サブ文字列を抽出する方法を多く考えましたが、最終的には最も単純で可読性の低い方法を選びました...
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。