首页 > 其他分享 >咪咕视频m3u8地址解析及ddCalcu参数加密逆向

咪咕视频m3u8地址解析及ddCalcu参数加密逆向

时间:2024-08-12 13:38:29浏览次数:8  
标签:加密 m3u8 URL 咪咕 url int wasm 内存 ddCalcu

咪咕视频m3u8地址解析及ddCalcu参数加密逆向

概述

本文主要讲述咪咕视频m3u8地址的解析以及使用Wasm对视频的m3u8地址进行加密得到ddCalcu参数的方法。

使用视频ID获取未加密的视频URL

对咪咕视频进行抓包发现,通过接口

https://webapi.miguvideo.com/gateway/playurl/v3/play/playurl?contId=926412678&rateType=3&xh265=true&chip=mgwww&channelId=0132_10010001005

可以获取到视频的m3u8地址,接口的参数contId指定视频ID,这里是926412678,rateType指定视频分辨率,2为标清540P,3为高清720P,4为超清1080P(但超清一般只有前6分钟的试看时间)。

访问此接口需要使用GET方法,并设定以下请求头:

Appcode: miguvideo_default_www
Appid: miguvideo
Channel: H5
x-up-client-channel-id: 0132_10010001005

接口返回JSON,JSON的body->urlInfo->url键值就是视频的m3u8地址

http://gslbmgspvod.miguvideo.com/depository_nas03/asset/zhengshi/5105/544/165/5105544165/media/5105544165_5270812321_56.mp4.m3u8?msisdn=20240811111225909a4fdfb1964b7b802c2c47241b024c&mdspid=&spid=800033&netType=0&sid=5700895378&pid=2028597139&timestamp=20240811111225&Channel_ID=0132_10010001005&ProgramID=926412678&ParentNodeID=-99&assertID=5700895378&client_ip=183.6.24.190&SecurityKey=20240811111225&promotionId=&mvid=5105544165&mcid=1003&mpid=120000510768&playurlVersion=WX-A1-7.7.2.5-RELEASE&userid=&jmhm=&videocodec=h264&bean=mgspwww&puData=41a05276e61f2220e3a57b9eddf625a8

若直接访问获取到的m3u8地址并不能正常得到m3u8文件,需要对其进行加密最终得到加密后的m3u8地址

http://gslbmgspvod.miguvideo.com/depository_nas03/asset/zhengshi/5105/544/165/5105544165/media/5105544165_5270812321_56.mp4.m3u8?msisdn=20240811195035d062a3247070440fa88a380accb49b6a&mdspid=&spid=800033&netType=0&sid=5700895378&pid=2028597139&timestamp=20240811195035&Channel_ID=0132_10010001005&ProgramID=926412678&ParentNodeID=-99&assertID=5700895378&client_ip=183.6.24.190&SecurityKey=20240811195035&promotionId=&mvid=5105544165&mcid=1003&mpid=120000510768&playurlVersion=WX-A1-7.7.2.5-RELEASE&userid=&jmhm=&videocodec=h264&bean=mgspwww&puData=021d5e2e680350a1d51a47bdb1cec090&ddCalcu=0092z01ycdwe5zce12bed6b87043a5105ad1&sv=10000&ct=www

加密后的URL主要是多了ddCalcu参数,接下来就要知道网站是如何进行加密的。

视频URL的加密方法

既然ddCalcu是加密得到的参数,首先想到的是直接搜索这个关键词,发现在pcPlayer.js文件中能找到

打个断点调试,刷新网页发现这行代码没有被执行,看来这个并不是用于加密的代码。

换个思路,找到加密后的m3u8地址的网络请求,查看这个请求的调用栈并进行断点调试,最后在pcPlayer.js中误打误撞找到了用于加密的代码

这段代码中的var n = r._getEncrypt(l)十分可疑,很可能就是加密函数,打断点逐行调试这段代码,逐个查看这里的变量,结果发现在执行_getEncrypt函数前,这里的变量t就是未加密的URL

当执行_getEncrypt函数以及i = r.UTF8ToString(n)这行代码后,i变量就得到了加密后的URL(带有ddCalcu参数)

到这里基本就可以确定这就是用于加密URL的代码了。

继续查看_getEncrypt函数实现,发现这是个wasm函数,wasm文件名是pickproof1000.wasm,这就对了,pickproof就是防盗的意思,这也说明URL是使用wasm进行加密的。

既然URL是用wasm进行加密的,那么在加密前就必须先加载wasm模块,只要找到加载wasm模块的代码,从加载开始一步步调试,抽丝剥茧,应该就不难找到URL加密的方法了。

直接在pcPlayer.js中搜索WebAssembly.instantiate找到WebAssembly.instantiateStreaming(e, t).then(n, ...,这是用于创建wasm实例的函数,直接断点调试

这里wasm在实例化时导入了10个js函数,这些函数虽然参数列表不同,但逐个查看发现均返回0或无返回值,应该是用于混淆代码的。

此外,在wasm实例化后又立即将wasm的Module和Instance对象穿给函数n

函数n又将wasm实例对象传给了函数r

函数r中,变量t是wasm实例,wasm实例导出的对象赋值给了e.asm,变量y是从wasm实例中导出的对象k,结合pickproof1000.wasm的代码(memory $k (;0;) (export "k") 256 256)可知导出的对象k实际上是wasm实例中一段初始大小和最大大小均为256页的线性内存,由于wasm每页内存大小固定为64KB,所以导出的内存大小为16777216字节,紧接着非本地变量be.HEAPU8被赋值为可以读写此内存的Uint8Array数组。

function r(t, r) {  // t是WebAssembly.Instance对象
    var n, i, o = t.exports;
    e.asm = o,  // wasm实例导出的对象
    y = e.asm.k,  // wasm导出的对象k,查看wasm源码可知其实是wasm内存
    n = y.buffer,
    e.HEAPU8 = b = new Uint8Array(n)  // 得到可读写wasm内存的Uint8Array数组
    // 省略一些代码
}

接着就开始执行加密代码了,首先是l = r._malloc(4 * t.length + 1),这里的变量t是未加密的URL,_malloc函数是wasm实例中导出的p函数,这行代码的作用是在wasm内存中申请特定大小的空间,然后返回申请得到空间的起始地址,即变量l,这里得到的地址是5266520。

// 加密代码
l && r._free(l),
l = r._malloc(4 * t.length + 1),  // 申请空闲的wasm内存,返回起始地址
r.stringToUTF8(t, l, 4 * length + 1);  // 将未加密的URL写入刚刚申请的空闲内存
var n = r._getEncrypt(l)  // 
  , i = r.UTF8ToString(n);

随后执行r.stringToUTF8(t, l, 4 * t.length + 1),这行代码的作用是将未加密的URL的ASCII码逐一写入刚刚申请得到的wasm实例的内存,其写入的起始地址是前面通过_malloc申请内存得到的起始地址,而这具体读写wasm内存的操作正是通过读写前面在r函数中赋值给变量b的Uint8Array数组实现的。

然后就是var n = r._getEncrypt(l)_getEncrypt实际上是wasm实例中导出的m函数,向加密函数传入wasm实例内存中未加密URL的起始地址,用于指定URL在内存中的位置,得到完成加密后的URL的起始地址n,这里得到的是5272888,至于其具体的算法是如何实现的不用关心。

最后是i = r.UTF8ToString(n),向UTF8ToString函数传入完成加密后的URL在wasm实例内存中的起始地址,该函数能通过给出的起始地址提取出加密后的URL,然后赋值给变量i

另外,这里加密代码的r对象就是前面在r函数中的非本地变量er对象的HEAPU8就是r函数中的e.HEAPU8,也就是可以用于读写wasm实例内存的Uint8Array数组。

在内存查看器中查看可以看到wasm实例的内存,定位到加密URL的起始地址可以直接看到加密后的URL。

总结,URL加密的过程是这样的,在加载完wasm模块后进行一些变量的初始化,接着调用_malloc申请用于存放未加密URL的wasm内存,得到空闲内存的起始地址,再通过stringToUTF8函数将未加密的URL逐字符写入申请得到的空闲内存,然后调用_getEncrypt对wasm内存中未加密的URL进行加密,得到完成加密后的URL再wasm内存中的地址,最后通过UTF8ToString获取加密后的URL地址。

其实不使用_malloc申请wasm内存,直接将空闲内存的起始地址设为0,将URL存放在内存的最开头也是可行的。

代码实现

javascript实现

const importObj = {
  a: {
    a: (a,b,c)=>{},
    b: (a)=>{return 0}, 
    c: ()=>{},
    d: (a,b,c,d)=>{return 0},
    e: (a)=>{return 0},
    f: (a,b,c,d,e)=>{return 0},
    g: (a,b)=>{return 0},
    h: (a,b)=>{return 0},
    i: (a)=>{return 0},
    j: (a,b,c,d,e)=>{return 0}
  }
}
// Load wasm module and get wasm instance.
const wasmURL = "https://www.miguvideo.com/mgs/player/prd/v_20240727173237_cfa34b34/dist/pickproof1000.wasm"
const wasm = await WebAssembly.instantiateStreaming(fetch(wasmURL), importObj).then(w => w.instance)

// Get wasm memory.
const memory = wasm.exports.k
const memoryView = new Uint8Array(memory.buffer)

// Get encryption function.
const getEncrypt = wasm.exports.m

function encrypt(url) {
  // Write the origin URL into the wasm memory.
  let i;
  for (i = 0; i < url.length; ++i) {
    memoryView[i] = url.charCodeAt(i)
  }
  memoryView[i] = 0

  // Get the beginning index of encrypted URL in wasm memory.
  let start = getEncrypt(0)

  // Read the encrypted URL from wasm memory.
  encryptedURL = ""
  for (let i = start; memoryView[i] != 0; ++i) {
    encryptedURL += String.fromCharCode(memoryView[i])
  }
  return encryptedURL
}

var vid = 926412678
var rateType = 3
var apiURL = `https://webapi.miguvideo.com/gateway/playurl/v3/play/playurl?contId=${vid}&rateType=${rateType}&xh265=true&chip=mgwww&channelId=0132_10010001005`
var resp = await fetch(apiURL, {
    headers: {
        "Appcode": "miguvideo_default_www",
        "Appid": "miguvideo",
        "Channel": "H5",
        "x-up-client-channel-id": "0132_10010001005",
    }
})

var videoURL = (await resp.json()).body.urlInfo.url
var encryptedURL = encrypt(videoURL)
console.log(encryptedURL)

python实现

需要先安装以下三个包

requests
wasmer
wasmer_compiler_cranelift

测试代码:

import requests
from wasmer import Store, Function, Module, Instance


def a(a: int, b: int, c: int): pass
def b(a: int) -> int: return 0
def c(): pass
def d(a: int, b: int, c: int, d: int) -> int: return 0
e = b
def f(a: int, b: int, c: int, d: int, e: int) -> int: return 0
def g(a: int, b: int) -> int: return 0
h = g
i = e
j = f

store = Store()
import_obj = {
    'a': {
        'a': Function(store, a),
        'b': Function(store, b),
        'c': Function(store, c),
        'd': Function(store, d),
        'e': Function(store, e),
        'f': Function(store, f),
        'g': Function(store, g),
        'h': Function(store, h),
        'i': Function(store, i),
        'j': Function(store, j),
    },
}

wasm_url = 'https://www.miguvideo.com/mgs/player/prd/v_20240727173237_cfa34b34/dist/pickproof1000.wasm'
wasm_binary = requests.get(wasm_url).content
module = Module(store, wasm_binary)
wasm = Instance(module, import_obj)
memory = wasm.exports.k
memory_view = memory.uint8_view()


def encrypt(url: str):
    for i,c in enumerate(url.encode()):
        memory_view[i] = c
    start = wasm.exports.m(0)
    encrypted_url = ''
    i = start
    while memory_view[i]:
        encrypted_url += chr(memory_view[i])
        i += 1
    return encrypted_url


def get_url(vid, rate_type=3):
    channel_id = '0132_10010001005'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4343.0 Safari/537.36 Edg/89.0.727.0',
        'Appcode': 'miguvideo_default_www',
        'Appid': 'miguvideo',
        'Channel': 'H5',
        'x-up-client-channel-id': channel_id,
    }
    url = f'https://webapi.miguvideo.com/gateway/playurl/v3/play/playurl?contId={vid}&rateType={rate_type}&xh265=true&chip=mgwww&channelId={channel_id}'

    resp = requests.get(url, headers=headers)
    video_url = resp.json()['body']['urlInfo']['url']
    return video_url


def main():
    video_id = 926412678
    video_url = get_url(video_id)
    encrypted_url = encrypt(video_url)
    print(encrypted_url)


if __name__ == '__main__':
    main()

标签:加密,m3u8,URL,咪咕,url,int,wasm,内存,ddCalcu
From: https://www.cnblogs.com/kiradiana/p/18354802

相关文章

  • m3u8下载工具N_m3u8DL-CLI的图形界面增强版
    摘自:https://zhuanlan.zhihu.com/p/672615148 简介(仅windows)N_m3u8DL-CLI是个非常方便的开源免费m3u8下载工具,自带一个叫SimpleGUI的简单图形界面。但是这个图形界面工具,太过简单,连任务列表都没有。所以,这里二次开发,增加了任务列表功能。新增的所有功能,请在项目页面查看详......
  • vue播放flv、hls(m3u8)视频及动态切换视频流
    【了解video.js】官方地址: https://github.com/videojs/video.js【用法】1、安装npminstallvideo.js--savenpminstallvideojs-flash--save//rtmp格式//flv格式npminstallflv.js--savenpminstallvideojs-flvjs-es6--save//hls格式video.js7.0以后版本......
  • 基于腾讯云播 SDK 开发的 M3U8 在线播放器
    随着网络视频的普及,M3U8格式的推流和播放逐渐成为主流。M3U8文件是一种可以存储一系列视频片段的索引文件,它常用于HLS(HTTPLiveStreaming)流媒体播放。为了方便开发者快速构建视频播放器,腾讯云提供了强大的云播SDK。本文将详细介绍如何使用腾讯云播SDK开发一个M3U8格式的......
  • 推荐一款m3u8视频下载工具:MediaGo
    MediaGo是一款功能强大的M3U8视频下载工具,专为流媒体视频下载而设计。它不仅支持m3u8视频的在线提取,还能通过软件自带的浏览器轻松嗅探网页中的视频资源,从资源列表中选择并下载所需视频,操作简便快捷。软件特点无需抓包:使用软件自带的浏览器,用户可以轻松嗅探网页中的视频资源......
  • java把m3u8视频转为mp4
    java把m3u8视频转为mp4代码importjava.io.*;importjava.nio.charset.Charset;importjava.nio.file.Path;importjava.nio.file.Files;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.TimeUnit;/***@Title:Process*@Authorcx......
  • 基于M3u8的视频加密及播放
    准备工作安装ffmpeg  mac安装brewinstallffmpeg 加密准备生成enc.keyopensslrand16>enc.key(生成一个enc.key文件)生成ivopensslrand-hex16(生成一段字符串,记下来)新建一个文件enc.keyinfo内容格式如下:KeyURI#enc.key的路径......
  • 基于 HTML5 和腾讯云播放 SDK 开发的 M3U8 在线播放器
    在当前的网络视频领域,M3U8文件格式是一种广泛应用的流媒体播放格式,具有广泛的兼容性和稳定性。为了在网页上实现M3U8格式的在线播放,我们可以结合HTML5技术和腾讯云播放SDK,快速开发一个功能强大的M3U8在线播放器。体验地址:https://m3u8player.org1.HTML5和M3U8HTML......
  • 基于 HTML5 和腾讯云播放 SDK 开发的 M3U8 在线播放器
    在当前的网络视频领域,M3U8文件格式是一种广泛应用的流媒体播放格式,具有广泛的兼容性和稳定性。为了在网页上实现M3U8格式的在线播放,我们可以结合HTML5技术和腾讯云播放SDK,快速开发一个功能强大的M3U8在线播放器。体验地址:https://m3u8player.org1.HTML5和M3U......
  • Dplayer播放m3u8
    <!--引入DPlayer--><linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css"><scriptsrc="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script><scriptsrc=&quo......
  • 下载M3U8/Blob视频教程
     准备工作:以下操作默认为google浏览器,如微信中的视频提示“请在微信客户端打开链接”,则按如下设置微信客户端(默认浏览器设置为google浏览器) 1、安装”篡改猴“           安装成功,其他插件安装方法类似。2、打开视频网站播放视频,并下载......