錦州市廣廈電腦維修|上門維修電腦|上門做系統|0416-3905144熱誠服務,錦州廣廈維修電腦,公司IT外包服務
topFlag1 設為首頁
topFlag3 收藏本站
 
maojin003 首 頁 公司介紹 服務項目 服務報價 維修流程 IT外包服務 服務器維護 技術文章 常見故障
錦州市廣廈電腦維修|上門維修電腦|上門做系統|0416-3905144熱誠服務技術文章
Chrome CDM框架重大缺陷,DRM視頻輕易復制

作者: 佚名  日期:2017-05-19 07:46:52   來源: 本站整理

我的工作領域和視頻相關,保護視頻內容非常重要,主流的瀏覽器和移動設備都支持DRM。近日我偶然發現Google Chrome瀏覽器的CDM(Content Decryption Module-內容解密模塊)框架存在重大的設計缺陷,通過一些手段就可以輕松繞過DRM保護機制,非常容易的獲取解密后的數據,從而把視頻重新封裝為未壓縮的MP4等格式文件,還可以做到在觀看的過程中直接進行無加密的視頻直播。

發現問題后,我花了一點時間,寫了一個測試程序,驗證了我的想法。由于DRM的保護機制非常的重要,如果可以輕松被攻破,將對整個視頻領域是一個威脅,所以我當時就向Google Chromium提交了bug,說明了CDM的框架的重大缺陷,并描述了實現細節。
這是的issue url(一般人沒有權限查看,僅內部可見):
https://bugs.chromium.org/p/chromium/issues/detail?id=721639

Google有漏洞獎勵規則,這是規則描述地址:
https://www.google.com/about/app ... -rewards/index.html
其實我當時的想法是,如果能獲取來自Google的獎勵,不論獎金多少,都將是一個至高無上的榮譽。

我提交后,Chromium團隊很快的做出了回復,他們確認這是一個重大的安全問題,而且影響所有運行Chrome瀏覽器的操作系統,包括: Linux, Windows, Chrome, Mac等等. 但另一個員工說這是一個已知的問題,并提供了一個issue號: 658022,但我無限查看漏洞內容是否與我提交的一致。之后我向google 團隊的幾個成員發了郵件,說既然是已知的問題,那也就是不符合獎勵規則,因此我也就可以公布細節,讓視頻內容公司重視這個問題,以便盡早的商討更加安全的解決方案。

說了這么多,只想說明一下事件的背景,下面我就說明實現細節,很多東西可能有些專業,主要講述一個過程。

1.安裝Google Chrome 32bit版本(32版本容易使用工具進行調試)
2.Chrome內置的CDM是Widevine(幾年前收購來的),目錄在Google\Chrome\Application\58.0.3029.110\WidevineCdm,在子目錄_platform_specific\win_x86有下2個dll:
    widevinecdm.dll - widevine核心模塊,導出的函數有:InitializeCdmModule_4,DeinitializeCdmModule,CreateCdmInstance,GetCdmVersion,GetHandleVerifier
    widevinecdmadapter.dll - PPAPI插件標準適配庫,導出函數有:PPP_GetInterface,PPP_InitializeModule,PPP_ShutdownModule
3.正常情況下播放DRM視頻的流程:
    Chrome -> Widevine CDM Adapter(widevinecdmadapter.dll) -> Widevine CDM Module (widevinecdm.dll)
    widevinecdmadapter.dll調用widevinecdm.dll的導出函數CreateCdmInstance來創建CDM實例.
4.CDM框架是Google Chrome的標準,所以API參數和接口都有C++ include文件,比如API CreateCdmInstance:
    CDM_API void* CreateCdmInstance(int cdm_interface_version, const char* key_system, uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data);

    CDM實例要繼承于class ContentDecryptionModule_8,查看class ContentDecryptionModule_8,發現了一個非常重要的函數:Decrypt,主要是將加密的數據傳入,解密后的數據傳出,我的天吶,只要截獲了這個函數不就搞定了嗎!!!

[C++] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
class CDM_CLASS_API ContentDecryptionModule_8 {      // Decrypts the |encrypted_buffer|.
   //
   // Returns kSuccess if decryption succeeded, in which case the callee
   // should have filled the |decrypted_buffer| and passed the ownership of
   // |data| in |decrypted_buffer| to the caller.
   // Returns kNoKey if the CDM did not have the necessary decryption key
   // to decrypt.
   // Returns kDecryptError if any other error happened.
   // If the return value is not kSuccess, |decrypted_buffer| should be ignored
   // by the caller.
   virtual Status Decrypt(const InputBuffer& encrypted_buffer,
                          DecryptedBlock* decrypted_buffer) = 0;
 };


5.了解了API參數和class定義后,就設想如果在widevinecdmadapter.dll 和 widevinecdm.dll之間在互相調用時截獲到解密后的數據就可以繞過DRM保護機制.
6.開始寫一個DLL, 名為CdmProxy.dll, 我自己的CreateCdmInstance函數,這部分不解釋了:

[C++] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
extern "C" __declspec(dllexport) void * CDMAPI_DEFINE my_CreateCdmInstance(int cdm_interface_version, const char* key_system,
    uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data)
{
    gHostUserData = user_data;
    wsprintf(wchLog, L"CdmProxy - call CreateCdmInstance(%d, %S, %d, 0x%08X, 0x%08X)",
        cdm_interface_version, key_system, key_system_size, get_cdm_host_func, user_data);
    OutputDebugStringW(wchLog);
    void *p = pCreateCdmInstance(cdm_interface_version, key_system, key_system_size, get_cdm_host_func, user_data);
 
    cdm::ContentDecryptionModule_8 *pCdmModule = (cdm::ContentDecryptionModule_8 *)(p);
    MyContentDecryptionModuleProxy *pMyCdmModule = new MyContentDecryptionModuleProxy(pCdmModule);
 
    return pMyCdmModule;
}


    我的代{過}{濾}理class MyContentDecryptionModuleProxy,代碼不解釋:
    // class MyContentDecryptionModuleProxy

[C++] 純文本查看 復制代碼
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
39
40
41
42
43
44
45
46
47
class MyContentDecryptionModuleProxy : public cdm::ContentDecryptionModule_8
{
public:
    MyContentDecryptionModuleProxy(cdm::ContentDecryptionModule_8 *pCdm)
    {
        mCdm = pCdm;
    }
private:
    cdm::ContentDecryptionModule_8 *mCdm;
 
public:
    // 最重要的解密函數,保存原數據和解密后的數據
    virtual cdm::Status Decrypt(const cdm::InputBuffer& encrypted_buffer, cdm::DecryptedBlock* decrypted_buffer)
    {
        cdm::Status status = cdm::kSuccess;
        codelive();
        DebugDecryptBreak(encrypted_buffer.iv, encrypted_buffer.key_id, encrypted_buffer.data);
        status = mCdm->Decrypt(encrypted_buffer, decrypted_buffer);
         
        string strIV = data2HexString((const char *)encrypted_buffer.iv, encrypted_buffer.iv_size);
        string strEncData = data2HexString((const char *)encrypted_buffer.data, min(encrypted_buffer.data_size, 32));
        string strDecData = data2HexString((const char *)decrypted_buffer->DecryptedBuffer()->Data(),
            min(decrypted_buffer->DecryptedBuffer()->Size(), 32));
        wsprintf(wchLog, L"CdmProxy - call Decrypt(IV:%S, encData(%d):%S, decData(%d):%S)",
            strIV.c_str(), encrypted_buffer.data_size, strEncData.c_str(),
            decrypted_buffer->DecryptedBuffer()->Size(), strDecData.c_str());
        OutputDebugStringW(wchLog);
 
        if(mEncFile == NULL)
        {
            mEncFile = fopen("d:\\cdm_enc.bin", "wb");
        }
        if(mEncFile != NULL)
        {
            fwrite(encrypted_buffer.data, 1, encrypted_buffer.data_size, mEncFile);
        }
        if(mDecFile == NULL)
        {
            mDecFile = fopen("d:\\cdm_dec.bin", "wb");
        }
        if(mDecFile != NULL)
        {
            fwrite(decrypted_buffer->DecryptedBuffer()->Data(), 1, decrypted_buffer->DecryptedBuffer()->Size(), mDecFile);
        }
        return status;
    }
};


7.核心代碼寫完了,就要解決DLL加載的問題,嘗試了幾種簡單的方式,分別把widevinecdm.dll和widevinecdmadapter.dll改名為widevinecdm_org.dll和widevinecdmadapter_org.dll,然后自己寫一個DLL,導出和widevinecdm.dll或者widevinecdmadapter.dll相同的API,然后再調用原來DLL的方式,但這種方式發現不可行,原因在于Chrome的安全沙盒,所有的插件都是加載的沙盒進程空間,敏感的API都無法使用,比如:ReadProcessMemory,CeateFile,OutputDebugString等等. 逃脫沙盒(Sandbox Escape)是Google獎金數額非常高的,最高可達$15,000.
8.既然進程都是Chrome創建的,所以就直接對chrome.exe下手,直接patch chrome.exe,讓其加載我的CdmProxy.dll,結果成功了,畢竟chrome啟動時還未啟用沙盒機制,所以沒花費太多技術就解決了DLL加載問題.

9.改變API截獲方式,對widevinecdmadapter.dll進行動態的補丁,將調用API CreateCdmInstance的地址改為我自己的API my_CreateCdmInstance,然后在DLL加載時進行以下處理:

[C++] 純文本查看 復制代碼
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
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch(ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        {
            hWideVineCdm = LoadLibraryW(L"{PATH}\\widevinecdm.dll");
 
            pInitializeCdmModule_4 = (InitializeCdmModule_4Func)GetProcAddress(hWideVineCdm, "InitializeCdmModule_4");
            pDeinitializeCdmModule = (DeinitializeCdmModuleFunc)GetProcAddress(hWideVineCdm, "DeinitializeCdmModule");
            pCreateCdmInstance = (CreateCdmInstanceFunc)GetProcAddress(hWideVineCdm, "CreateCdmInstance");
            pGetCdmVersion = (GetCdmVersionFunc)GetProcAddress(hWideVineCdm, "GetCdmVersion");
 
            hWideVineCdmAdapter = LoadLibraryW(L"{PATH}\\widevinecdmadapter.dll");
            if(hWideVineCdmAdapter != NULL)
            {
                DWORD dwSrcAddr = (DWORD)hWideVineCdmAdapter + 0x0000446D;
                const BYTE chVerify[] = { 0xFF, 0x15 };
                BOOL isOK = patch_DsCallFunction(dwSrcAddr, (DWORD)my_CreateCdmInstance, chVerify, sizeof(chVerify));
                wsprintf(wchLog, L"CdmProxy - patch CreateCdmInstance, Address:0x%08X-0x%08X, %s.",
                    dwSrcAddr, (uint32_t)my_CreateCdmInstance,
                    isOK ? L"OK" : L"FAILED");
                OutputDebugStringW(wchLog);
            }
        }
        break ;
    }
}


10.然后進行測試,播放一個有DRM保護的DASH視頻:
    
https://shaka-player-demo.appspo ... gleKey/Manifest.mpd
    發現文件沒保存下來,LOG也沒輸出,想必是安全沙盒起作用了。
11.又要逃脫沙盒,經過研究,發現根本不需要,只要在chrome啟動參數增加 --no-sandbox 即可。我的天吶,為啥要提供這樣一個后門啊!!!

12.再次播放加密的視頻,文件順利保存下來,LOG也輸出成功,經驗證,解密后的數據與之前未加密的數據是一致的。

13.Google Chrome的CDM就這樣被破解了,非常的簡單的就繞過了Widevine DRM的算法,這應該是Chrome CDM的框架設計的嚴重問題,估計要改變也不是非常容易的。

這是LOG數據:

( "CdmProxy - call CreateCdmInstance(8, com.widevine.alpha, 18, 0x70F86310, 0x00D75A88)" )           0.0001399
( "CdmProxy - call CreateCdmInstance(8, com.widevine.alpha, 18, 0x70F86310, 0x00D757C8)" )           0.0000937
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F00000000000000000, encData(348):FFF158402B9FFC2FF05300F2BF83E9A0, decData(0):)" )           0.0001350
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F00000000000000000, encData(348):FFF158402B9FFC2FF05300F2BF83E9A0, decData(348):FFF158402B9FFC00D03403E95B8639BD)" )         0.0001335
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F00000000000000000, encData(348):FFF158402B9FFC2FF05300F2BF83E9A0, decData(348):FFF158402B9FFC00D03403E95B8639BD)" )         0.0001032
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F10000000000000000, encData(348):FFF158402B9FFC487380B8930FFFAB41, decData(348):FFF158402B9FFC00F43420C24620902C)" )         0.0001392
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F20000000000000000, encData(349):FFF158402BBFFC1175E15FE4B6154B30, decData(349):FFF158402BBFFC00FA342D90762A3188)" )         0.0001032
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F30000000000000000, encData(348):FFF158402B9FFCC45D5715E87235E5CF, decData(348):FFF158402B9FFC00F8342CEC825A2D85)" )         0.0000994
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F40000000000000000, encData(348):FFF158402B9FFC6749FBAF64926471DE, decData(348):FFF158402B9FFC00F83421884529290A)" )         0.0000880
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F50000000000000000, encData(349):FFF158402BBFFCF8132EFC31C186DDE1, decData(349):FFF158402BBFFC00F2342D9049124988)" )         0.0001088
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F60000000000000000, encData(348):FFF158402B9FFC82EDA0BD4AB7158938, decData(348):FFF158402B9FFC00EE342D7475223D85)" )         0.0001035
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F70000000000000000, encData(348):FFF158402B9FFC4B2C585CC10F74036E, decData(348):FFF158402B9FFC00F4342D74662A2088)" )         0.0001555
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F80000000000000000, encData(349):FFF158402BBFFCCF33665AC4E219EC92, decData(349):FFF158402BBFFC00FA342E30547B0604)" )         0.0001494
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818F90000000000000000, encData(348):FFF158402B9FFC2C9A7362594261CE23, decData(348):FFF158402B9FFC00F4342E305429150A)" )         0.0004035
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818FA0000000000000000, encData(348):FFF158402B9FFC1905A086AE3CEF0AEC, decData(348):FFF158402B9FFC00EE342E3456391906)" )         0.0005913
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818FB0000000000000000, encData(349):FFF158402BBFFC8D0EB865013262FB6E, decData(349):FFF158402BBFFC00F6342E34563A2186)" )         0.0001479
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818FC0000000000000000, encData(348):FFF158402B9FFC484211C612F22283FB, decData(348):FFF158402B9FFC0102342E74482A2E02)" )         0.0002507
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818FD0000000000000000, encData(348):FFF158402B9FFC283122B1DDE740DAC2, decData(348):FFF158402B9FFC0104342EB464190D08)" )         0.0003011
( "CdmProxy - call Decrypt(IV:6CD1F4FBCE5818FE0000000000000000, encData(349):FFF158402BBFFCAC8759D48FF1A258A3, decData(349):FFF158402BBFFC010E342ED04A1A2982)" )         0.0003095


DRM這么多年了,很多保護機制和算法都做的非常嚴密,但還是被Zhu一樣的隊友給出賣了。

公開這個研究,是為了讓廣大的視頻公司不要以為DRM非常的安全,有時候真的是不堪一擊,某個環節出現漏洞,同樣面臨極大的安全問題。

如果此篇文章不適合公布,請通知我,謝謝。



熱門文章
  • 機械革命S1 PRO-02 開機不顯示 黑...
  • 聯想ThinkPad NM-C641上電掉電點不...
  • 三星一體激光打印機SCX-4521F維修...
  • 通過串口命令查看EMMC擦寫次數和判...
  • IIS 8 開啟 GZIP壓縮來減少網絡請求...
  • 索尼kd-49x7500e背光一半暗且閃爍 ...
  • 樓宇對講門禁讀卡異常維修,讀卡芯...
  • 新款海信電視機始終停留在開機界面...
  • 常見打印機清零步驟
  • 安裝驅動時提示不包含數字簽名的解...
  • 共享打印機需要密碼的解決方法
  • 圖解Windows 7系統快速共享打印機的...
  • 錦州廣廈電腦上門維修

    報修電話:13840665804  QQ:174984393 (聯系人:毛先生)   
    E-Mail:174984393@qq.com
    維修中心地址:錦州廣廈電腦城
    ICP備案/許可證號:遼ICP備2023002984號-1
    上門服務區域: 遼寧錦州市區
    主要業務: 修電腦,電腦修理,電腦維護,上門維修電腦,黑屏藍屏死機故障排除,無線上網設置,IT服務外包,局域網組建,ADSL共享上網,路由器設置,數據恢復,密碼破解,光盤刻錄制作等服務

    技術支持:微軟等
    主站蜘蛛池模板: 亚洲精品无码日韩国产不卡?V| 亚洲av永久无码精品漫画| 暴力强奷在线播放无码| 亚洲AV无码AV男人的天堂| 成人年无码AV片在线观看| 成在线人免费无码高潮喷水| 无码射肉在线播放视频| 国模无码人体一区二区| 亚洲一区二区三区国产精品无码 | 无码人妻精品中文字幕免费东京热 | 日韩人妻无码免费视频一区二区三区| 中文字幕无码一区二区免费| 97久久精品无码一区二区| 人妻丰满熟妇A v无码区不卡 | 东京热无码av一区二区| 少妇爆乳无码专区| 亚洲中文字幕无码中文字| 人妻无码αv中文字幕久久| 无码视频一区二区三区在线观看| 无码A级毛片日韩精品| 亚洲国产成人精品无码区花野真一| 亚洲午夜国产精品无码老牛影视| 免费无码黄网站在线看| 白嫩无码人妻丰满熟妇啪啪区百度| 中文字幕av无码一二三区电影| 亚洲AV无码精品色午夜果冻不卡| 无码人妻丰满熟妇啪啪| 亚洲国产综合无码一区二区二三区 | 粉嫩高中生无码视频在线观看| 国产精品无码亚洲一区二区三区| 精品无码人妻夜人多侵犯18 | 加勒比无码一区二区三区| 亚洲人成网亚洲欧洲无码| 日韩精品人妻系列无码专区 | 国产成人亚洲综合无码| 野花在线无码视频在线播放| 日韩精品无码视频一区二区蜜桃| 亚洲中文字幕不卡无码| 久久青青草原亚洲AV无码麻豆| 少妇人妻无码精品视频| 男人av无码天堂|