1. 程式人生 > >分析 PPTV 視訊真實播放地址全過程(Java版)

分析 PPTV 視訊真實播放地址全過程(Java版)

原文地址:https://www.52pojie.cn/thread-840710-1-1.html

 

分析視訊地址有什麼用?
有些朋友經常會問到這個問題,其實這也是思維肌肉訓練的問題。我舉一個宋老師講過的例子(天氣預報和投資機會之間的關係)。說加勒比海出現熱帶颶風,普通小白看到這個新聞就會想和自己有什麼關係呢?但是經過訓練的大腦就會上網查颶風的等級,在哪裡著落,移動方位是怎麼樣的。因為他知道俄克拉荷馬庫欣是美國原油期貨的交割地,颶風會造成原油淤積那裡運不出去,結果是庫存增加,原油價格下跌。你還在看新聞,別人的期貨單子已經飛出去了。回到問題上來,分析的這些地址怎麼用?經過訓練的人會想自己公司的 App 有哪些視訊是掛上騰訊或者其它地方的,廣告多不多,視訊質量如何。假如把視訊上傳到 PPTV 上,自己再把視訊地址分析出來,再做個播放器,那麼廣告問題、視訊質量問題、頻寬問題是不是都解決了啊。有一些影音 App,基本上都是用磁鏈搜尋 + 迅雷 Mini 庫來實現邊下邊播,技術痛點在哪裡啊?迅雷有版權限制,大多數視訊播放不了,Seed 少播放起來也很卡。還有一影音 App 找第三方解析網站,問題是同樣的啊,線路經常被封,域名經常變化。有的朋友說:我沒上班或者我們 App 沒有播放視訊的需求。那你也可以學學裡面用到的 url 簽名技術啊,將來和別的公司做資料共享的時候你們的 url 也是要加密的啊。 還有的朋友說:我根本不喜歡技術,也不打算從事程式設計師,這些地址對我一點用都沒有。將來你家有小孩,你可以把視訊下載到 U 盤上給孩子看啊,等等......



第三方視訊分析網站所存在問題

  • 被解析的視訊網站(PPTV、騰訊)url 簽名演算法改變,普遍來看,所有第三方平臺反映都很遲鈍;
  • 現在各大視訊網站也在封殺這種三方平臺,服務經常被中斷,域名經常改變,需要加群得知新域名;
  • 解析出來的地址依賴平臺提供的 H5 播放器,廣告一大堆,視訊清晰度還不夠。


專案執行效果
 
遊客模式下,PPTV 只提供標清、高清、超清三種格式,我感覺超清的效果就能滿足觀看需求了,給出播放地址(http://v.pptv.com/show/qk3vbLiahSojradE.html),輸出標清、高清、超清,三種格式的分段視訊地址,PPTV 視訊真實的播放地址主要的獲取渠道有:智慧電視、電視盒子、Web 以及 App,這次我準備分析一下如何從 Web 裡找出視訊的真實播放地址。



常見的視訊播放技術的套路
現在每行都有自己的套路,比如拍電影,只要出現武裝直升機就必然會墜毀,只要出現火車那一定會出現鐵路斷裂的情形。視訊播放也不例外,常見的有 H5 播放(一般有20分鐘的限制)、P2P 播放(這個也是輔助)、ts 播放、分段播放(Flash 或 H5)等等。PPTV 就採用了分段播放+P2P輔助的方法,我們找出分段資訊再反編譯出 swf 簽名演算法,這樣問題就迎刃而解了。

找出播放地址
使用帶開發者模式的瀏覽器(火狐、谷歌都行)開啟一個 PP 視訊,拖動進度條,然後按響應 Body 排序,你會發現播放地址:
 
 

http://42.56.93.26/16/5412864/0/59fcfcdf1e6bd26c3fa64c3c7a8a73f4.mp4?fpp.ver=1.3.0.24&key=14fb862504f61910d29de89e4981a93e&k=31a8c1459a1d7a7d5520e86da96f154b-bf57-1545129327%26bppcataid%3D38&type=web.fpp&vvid=52056dc1-d005-5d53-a186-c006bf1b3aa3


42.56.93.26:伺服器地址
16:分段視訊序號
5412864:偏移位,這個最後我們不傳
0:固定值
9fcfcdf1e6bd26c3fa64c3c7a8a73f4.mp4:視訊檔名
fpp.ver:播放器版本號
key:伺服器返回的時間生成 16 位固定字元 + 16 位隨機字元,可以不傳的,這是 PPTV 迷惑我們,增加我們的破解難度
k:非常關鍵,需要解密
type:web.fpp(說明是 Web 訪問的,App 這個值是不同的)
vvid:播放唯一標識,統計廣告展示次數,檢測卡頓時用的,我們同樣不傳

上面的地址是誰發出請求的呢?
 
原來是一個叫做“player4player2.swf”的檔案發出的,可以斷定這就是播放器檔案,我們現在要反編譯它,先把這個 swf 下載到本地磁碟,然後用 AS3 Sorcere 開啟這個檔案(反編譯),最好是把反編譯的原始碼匯出來,然後用 Sublime Text 開啟比較好(可以全域性搜尋)。

計算 k 值
我們搜尋 "k": 找到賦值的地方,當 flag 和 iv 不為空的時候就用 Decrypt 計算 k 值:
 

再搜尋 Global.getInstance()["crypto"],找到定義它的地方:
 

上面的 new this.Crypto() 引用的是 VodFacade_Crypto 類,找到 VodFacade_Crypto 類發現是空類,原來是 PPTV  把核心演算法以 swf 的方式嵌入到類裡面了,我們要把 VodFacade_Crypto 這個空類的內容提取出來。用 Flash Builder 新建一個 Flex 專案,程式碼如下:

[Actionscript3] 純文字檢視 複製程式碼

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

      xmlns:s="library://ns.adobe.com/flex/spark"

      xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"

      applicationComplete="init()">

 <fx:Declarations>

  <!-- 將非可視元素(例如服務、值物件)放在此處 -->

 </fx:Declarations>

 <fx:Script>

  <![CDATA[

   import flash.display.Loader;

   import flash.events.Event;

   import flash.net.URLRequest;

   import mx.core.ByteArrayAsset;

   private var byteArray:ByteArrayAsset;

    

   private function init():void{

    var _loader:Loader = new Loader();

    _loader.load(new URLRequest("player4player2.swf"));

    _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfComplete);

    function swfComplete(event:Event):void

    {

     var myClass:Class = _loader.contentLoaderInfo.applicationDomain.getDefinition("VodFacade_Crypto") as Class;

     byteArray = new myClass as ByteArrayAsset;

    }

   }

    

   private function onSaveClick():void

   {

    var fr:FileReference = new FileReference();

    fr.save(byteArray, "VodFacade_Crypto.swf");

   }

  ]]>

 </fx:Script>

  

 <mx:Button label="Save File" left="10" top="10" id="saveButton" click="onSaveClick()" />

 

</s:Application>



這裡要注意,把 player4player2.swf 放到 bin-debug 目錄中,執行後點擊 Save File 按鈕,彈出另存對話方塊儲存為 swf 檔案,我們在用 AS3 Sorcere 開啟這個儲存的 swf 檔案就看到計算 k 值的方法了。

計算 key 值(和上面的 k 不是同一個)
通過上圖不難發現 key 值的計算是用 constructKey 方法生成的,同樣搜尋 constructKey:
 
有了 as3 原始碼改成 Java 程式碼就不難了,這裡要注意原版 as3 的位運算是用無符號整型,Java 沒有這個型別,只能用 Long 模擬。

找出視訊分段資訊請求地址
到現在為止,我們已經分析出 k 值、key 值,現在要做的是怎麼找出視訊分段資訊。還是用之前的方法,找一找哪些檔案是由 player4player2.swf 發出的:
 

果真找來了,原來是個 xml 檔案,我們來分析一下:

http://web-play.pptv.com/webplay3-0-29412562.xml?zone=8&pid=5701&vvid=ebe7b84a-5255-9186-d549-c0461fbe153b&version=4&token=L24-CYpmKPLh9EfpvsprW1JRK40FS_8NA2zOtDTrtmtBspTp_bOph4ZnnBzfm9O3qIeAg1f0w4rV%0D%0Ayyrq3KamgIuaYBPZN6ViSHXjngETGhTIKw52H4Awhng9jaX62-F6UHxwJDbqiMQVc7hIkTY13duO%0D%0AlTOpicDi5svdemeWXZM%0D%0A&username=18642727712_180923o10&#182;m=type%3Dweb.fpp%26ahl_ver%3D1%26ahl_random%3D457772653e3f21707033616a26376824%26ahl_signa%3Dd73b26d0178a002db51a774299197937a7501c958c0fe78910495942899158c7%26userType%3D0%26o%3D0&ppi=302c393939&isSports=1&p_type=22&kk=ff70f71cb7d1660b20a68df11eb19474-69a2-5c18b372&referrer=&stime=2077&isIframe=0&o=0&duration=3086&sl=1&type=web.fpp&pageUrl=http%3A%2F%2Fv.pptv.com%2Fshow%2F0lzicfORKuvhb2UE.html&vts=1&r=1545119080458&scver=1&appplt=flp&appid=pptv.flashplayer.vod&appver=3.4.3.27&nddp=1


這個串引數比較多,實際上我們根本用不到,先看這個“webplay3-0-29412562.xml”,其中“webplay3-0-”是固定值,我們不關注,29412562.xml 裡面的數字我們可以在播放網頁的原始碼找出來。

appplt、appid、appver、type,我們需要這四個值,具體為啥別的值不要下面再說。

param 引數有4個值非常關鍵,少了任何一個就被判定為盜鏈。

ahl_ver:固定值(預設值為1)
type:固定值(預設值為web.fpp)
ahl_random:16 位隨機字元
ahl_signa:ahl_random + "web.fpp" + "-" + "1" + "V8oo0Or1f047NaiMTxK123LMFuINTNeI" 用這幾個值拼串然後用 SHA256 編下碼

把這幾個引數拼起來加上地址訪問後就可以得到視訊分段請求地址了。

現在驗證一下我上面說的演算法,搜尋 ahl_random 找到如下方法:
 
看到沒,這裡面還有 VIP 相關的引數等著你發掘新的功能。

回頭看
還記得我們計算 k 值的時候所有到的 flag、iv 的值在哪裡嗎?我們看看上面這個 xml 的內容:
 

channel 節點

  • nm -- 視訊標題
  • pic  -- 視訊縮圖


dt 節點

  • rid -- mp4檔名
  • sh -- 伺服器地址
  • st  -- 請求時間(以請求時間為準,計算過期時間)
  • id  -- 視訊主鍵
  • bh -- 備份伺服器地址
  • flag -- 這個沒猜出來
  • iv   -- 這個也沒猜出來
  • key -- 需要解密


dragdata 節點

  • sgm -- 視訊播放地址序列


dt 節點裡有我們計算 k 值所需要的引數,如果你打算自己開發播放器(帶播放進度條功能),那 sgm 裡的 dur(時長)、fs(大小)、os(偏移量),就很重要了。

至此,PPTV 視訊的真實播放地址在技術層面已經徹底脫光了給我們看,實際上演算法非常簡單,我稍後把 Java 原始碼發到 github 上給大家下載,謝謝觀看。

開源地址
https://github.com/qiuqiu3/pptv
把專案下載後匯入到 MyEclipse 中,右鍵 App.java 那個類-》Run as -》Java Application。