Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

求教DMM视频流破解方法; #473

Open
tkbianyuan opened this issue Jul 22, 2021 · 99 comments
Open

求教DMM视频流破解方法; #473

tkbianyuan opened this issue Jul 22, 2021 · 99 comments

Comments

@tkbianyuan
Copy link

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="https://www.dmm.com/service/-/drm_iphone?ld=IBaD%2BQ72dPSQw780KGJEaF3mBxEpqAGiYGK7JrXe2Q0o61WY%2BCSjhLGrGhrJaZAsddpvbF173Lrl7xEmiWBWOip1OnExBBrmpp69oaHSCy0%2FD0rGUNb3zsVXMDVpP31PCdEB9xThKpHEjo8ufDHBSw%3D%3D&luid=com"
#EXTINF:4.004,
media_b300000_0.ts
#EXTINF:4.004,
media_b300000_1.ts
#EXTINF:4.004,
media_b300000_2.ts

@tkbianyuan
Copy link
Author

16字节密钥提取了,base64编码也转换了。media_b6000000_0.ts路径不清楚是哪一个?
用 N_m3u8DL-CLI-SimpleG.exe 试了很多次,不是 地址不正确 就是填充无效、无法被移除 。
还需要什么操作呢?
111
222

@nilaoda
Copy link
Owner

nilaoda commented Jul 22, 2021

@tkbianyuan
Copy link
Author

http://www.tomeko.net/online_tools/hex_to_base64.php?lang=en

谢谢大佬,成功了,转码工具用错了。

@royiie
Copy link

royiie commented Jul 23, 2021

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="https://www.dmm.com/service/-/drm_iphone?ld=IBaD%2BQ72dPSQw780KGJEaF3mBxEpqAGiYGK7JrXe2Q0o61WY%2BCSjhLGrGhrJaZAsddpvbF173Lrl7xEmiWBWOip1OnExBBrmpp69oaHSCy0%2FD0rGUNb3zsVXMDVpP31PCdEB9xThKpHEjo8ufDHBSw%3D%3D&luid=com"
#EXTINF:4.004,
media_b300000_0.ts
#EXTINF:4.004,
media_b300000_1.ts
#EXTINF:4.004,
media_b300000_2.ts

16字节如何提取,能告知下方法吗?

@royiie
Copy link

royiie commented Jul 23, 2021

http://www.tomeko.net/online_tools/hex_to_base64.php?lang=en

大佬,保利威的16字节如何提取,能告知下方法吗?

@81pla
Copy link

81pla commented Aug 26, 2021

@royiie 保利威看这个#498

@lvzhenbo
Copy link

我也发过一个issue来着,已经解决了。
第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓
第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。
第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

@ccl750521
Copy link

请问lvzhenbo 兄弟,
我照您的方法操作后,
一直卡在:
00:22:41.929 / (NORMAL) 开始解析 xxx.m3u8
00:22:41.951 / (NORMAL) 解析m3u8内容
00:22:41.953 / (NORMAL) 获取m3u8 key... file:///xxx/drm_iphone
00:22:41.973 / (NORMAL) 写出meta.json
00:22:42.068 / (NORMAL) 开始下载文件
00:22:42.083 / (NORMAL) 读取文件信息...
00:22:42.084 / (NORMAL) Error in reading file
00:22:42.132 / (NORMAL) 完成数量 ...
00:22:42.133 / (NORMAL) 重试次数 1 / 5
00:22:45.161 / (NORMAL) 开始下载文件
00:22:45.167 / (NORMAL) 读取文件信息...
00:22:45.168 / (NORMAL) Error in reading file

无法下载的,想请教是哪出了问题? 谢谢!

@lvzhenbo
Copy link

你这是文件读取失败,用m3u8链接啊,不要直接用m3u8文件,文件里面的地址是不全的

@ccl750521
Copy link

你这是文件读取失败,用m3u8链接啊,不要直接用m3u8文件,文件里面的地址是不全的

已搞定 多謝兄弟指點!

@bbb1099
Copy link

bbb1099 commented Dec 2, 2021

我也发过一个issue来着,已经解决了。 第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓。 第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。 第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

感谢兄弟分享方法

@ghost
Copy link

ghost commented Dec 27, 2021

我也发过一个issue来着,已经解决了。 第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓。 第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。 第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

请问我把m3u8链接复制了,解析时说地址无效是为什么

@Qf0602
Copy link

Qf0602 commented Mar 12, 2022

我也发过一个issue来着,已经解决了。 第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓。 第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。 第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

大神成功了,感谢,那这个办法有办法批量下载吗?尤其是KEY的这个DRM_IPHONE文件,求解?

@18236176689
Copy link

我也发过一个issue来着,已经解决了。 第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓。 第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。 第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

大神成功了,感谢,那这个办法有办法批量下载吗?尤其是KEY的这个DRM_IPHONE文件,求解?

请问什么是gui?我这个视频有3个m3u8的文件全都下载吗,下载之后怎么合并?

@missdgsn
Copy link

我也发过一个issue来着,已经解决了。 第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓。 第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。 第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

大神成功了,感谢,那这个办法有办法批量下载吗?尤其是KEY的这个DRM_IPHONE文件,求解?

请问什么是gui?我这个视频有3个m3u8的文件全都下载吗,下载之后怎么合并?

DMM的无需手工合并,软件自动合并。m3u8出现多个是因为DMM里面有不同的码率,一般来说,dmm的码率标识是固定的,1080P的是6000的那个,720P是4000那个,你就只需要复制6000那个M3U8就可以,后面会自动合并的

@18236176689
Copy link

18236176689 commented Apr 29, 2022 via email

@huangxin168
Copy link

huangxin168 commented May 6, 2022

第一步:猫抓得到m3u8的链接。
第二步应该是:复制m3u8链接,到浏览器地址栏,然后回车,将生成m3u8文件,文件里有key链接,将key链接复制到浏览器地址栏,然后回车,将生成drm_iphone文件
第三步:同上大佬

@kurtn2005
Copy link

VR视频没办法搞吧?这个方法只适用于2D视频。我看VR必须要用DMM的播放器才行。

第一步:猫抓得到m3u8的链接。 第二步应该是:复制m3u8链接,到浏览器地址栏,然后回车,将生成m3u8文件,文件里有key链接,将key链接复制到浏览器地址栏,然后回车,将生成drm_iphone文件 第三步:同上大佬

@missdgsn
Copy link

VR视频没办法搞吧?这个方法只适用于2D视频。我看VR必须要用DMM的播放器才行。

第一步:猫抓得到m3u8的链接。 第二步应该是:复制m3u8链接,到浏览器地址栏,然后回车,将生成m3u8文件,文件里有key链接,将key链接复制到浏览器地址栏,然后回车,将生成drm_iphone文件 第三步:同上大佬

vr肯定不是这个方法

@kurtn2005
Copy link

VR视频没办法搞吧?这个方法只适用于2D视频。我看VR必须要用DMM的播放器才行。

第一步:猫抓得到m3u8的链接。 第二步应该是:复制m3u8链接,到浏览器地址栏,然后回车,将生成m3u8文件,文件里有key链接,将key链接复制到浏览器地址栏,然后回车,将生成drm_iphone文件 第三步:同上大佬

vr肯定不是这个方法

我感觉VR理论上来说也是视频流,只是视频流地址必须要调播放器才能看到。

不知道有没有什么方法能下载VR的。

@huangxin168
Copy link

VR视频没办法搞吧?这个方法只适用于2D视频。我看VR必须要用DMM的播放器才行。

第一步:猫抓得到m3u8的链接。 第二步应该是:复制m3u8链接,到浏览器地址栏,然后回车,将生成m3u8文件,文件里有key链接,将key链接复制到浏览器地址栏,然后回车,将生成drm_iphone文件 第三步:同上大佬

vr肯定不是这个方法

我感觉VR理论上来说也是视频流,只是视频流地址必须要调播放器才能看到。

不知道有没有什么方法能下载VR的。

如果没有下载的办法,只能靠抓包分析了?

@lvzhenbo
Copy link

不要瞎猜了,目前dmm就使用了两种技术,一种是目前可以破解的m3u8,另一种是近几年各个视频站开始广泛使用的技术dash,这种技术可以直接在代码层面进行加密。dmm的大容量视频包括4k x265和vr都是用dash。目前并没有特别方便的破解方式只能从代码层面进行分析

@kurtn2005
Copy link

不要瞎猜了,目前dmm就使用了两种技术,一种是目前可以破解的m3u8,另一种是近几年各个视频站开始广泛使用的技术dash,这种技术可以直接在代码层面进行加密。dmm的大容量视频包括4k x265和vr都是用dash。目前并没有特别方便的破解方式只能从代码层面进行分析

网上有好多BT站可以下4K和VR不知道是怎么破解的,看上去画质也挺好的。

@tb0668
Copy link

tb0668 commented Jun 9, 2022

不要瞎猜了,目前dmm就使用了两种技术,一种是目前可以破解的m3u8,另一种是近几年各个视频站开始广泛使用的技术dash,这种技术可以直接在代码层面进行加密。dmm的大容量视频包括4k x265和vr都是用dash。目前并没有特别方便的破解方式只能从代码层面进行分析

我之前在r18都是直接打开视频,然后用猫抓m3u8然后把m3u8链接放到gui里,直接启动go就可以分析下载了。可是现在不知道为什么不行了。F12查看也没有drm这文件(反而dmm都会有),是什么问题呢?有没有别的方法可以下载?

@crossover0552
Copy link

我也发过一个issue来着,已经解决了。 第一步先获取到m3u8的链接,这个很重要,因为key在这里面,我用的是猫抓。 第二步,复制key链接,贴到浏览器地址栏里,注意这时候浏览器里必须有dmm账号登录,然后回车,你会下载到drm_iphone这个文件。 第三步,把m3u8链接放到gui里,把drm_iphone这个文件拖到gui的自定义key里,然后点go就行了

我想请教一下大佬,安装了猫抓插件之后打开dmm在线播放,猫抓显示没有抓取到任何东西,应该如何解决?

@chuccp
Copy link

chuccp commented Jul 4, 2022

http://www.tomeko.net/online_tools/hex_to_base64.php?lang=en

大佬,保利威的16字节如何提取,能告知下方法吗?

https://github.com/chuccp/chrome_extensions

@lwx1660677335
Copy link

surfshark

用无限wifi可以避开这个问题.我用网线也是这样

无限wifi是什么

wifi访问

@lvzhenbo
Copy link

lvzhenbo commented Jul 19, 2024

dcv文件破解流程

需求工具

安卓开发工具,python

获取cdm

https://forum.videohelp.com/threads/408031-Dumping-Your-own-L3-CDM-with-Android-Studio
根据上面链接所说的方式获得cdm的两个文件

获取keyid

n大给了工具https://github.com/nilaoda/Blog/files/5861846/MP4DecryptGUI_20210124.zip
把dcv文件改名成mp4拖进去获得keyid

获取licenseUID和pssh

这一步需要dmm player v2播放器和抓包软件
登录好以后,启动抓包软件,抓取 https://mlic.dmm.com/drm/widevine/license 请求
在请求头的cookie中能够获得licenseUID
在请求体(文本方式查看)中能够获得可读文本类似下面,这就是content-id

{"v":"2","fid":"这里是文件id","svid":"digital","pl":"xxx","cs":"xxx"}

将这个文本原封不动转成base16
https://github.com/shaka-project/shaka-packager/releases
下载pssh-box.py.tar.gz解压运行

python pssh-box.py --base64 --widevine-system-id --key-id '(KID值)' --content-id '(content-id的base16值)'

输出pssh

获取最终的key

下载工具并解压https://github.com/CrymanChen/WKS-KEYS/releases/tag/v2023.04.07
将cdm的两个文件分别重命名为device_client_id_blobdevice_private_key,放到WKS-KEYS\pywidevine\L3\cdm\devices\android_generic\下
修改header.py文件

headers = { 'Host': 'mlic.dmm.com', 'Cookie': 'licenseUID=xxx' }

运行l3.py,按照提示输入pssh和license_url,url为https://mlic.dmm.com/drm/widevine/license,可获得key,在MP4DecryptGUI中输入key,格式选择HEX进行解密

无需dmm player v2

这里唯一的问题就是如何从dmm的cookie中找到所需的数据转成content-id中的pl和cs,我暂时没有找到方法,不知道有没有人能够帮个忙

@ex-hentai
Copy link

@SameForYou
Copy link

SameForYou commented Jul 19, 2024 via email

@lvzhenbo
Copy link

@ex-hentai 404
@SameForYou 自己捣鼓,需要一些相关方面的知识,相关的库里都有

@ex-hentai
Copy link

404

@lvzhenbo 刚转 public

@lvzhenbo
Copy link

@ex-hentai 非常感谢,可以省去一些步骤了

@BlueSkyXN
Copy link

404

@lvzhenbo 刚转 public

看了下还是不行啊,404

@lvzhenbo
Copy link

@BlueSkyXN 他又重新改成私人库了,我正在用bun做一个,已经有结果了,正在收尾,今天或者明天就能发出来

@BlueSkyXN
Copy link

@BlueSkyXN 他又重新改成私人库了,我正在用bun做一个,已经有结果了,正在收尾,今天或者明天就能发出来

有意义,过两天看看效果(☻-☻)

@lvzhenbo
Copy link

@BlueSkyXN https://github.com/lvzhenbo/dcv-decryptor

@wfb2222wfb
Copy link

@lvzhenbo 你好,我通过上述方式拿到了cdm两个文件,但是使用dcv_decryptor拿密钥axios报400 bad request,是拿cdm播放的视频必须是dmm的视频么,我不清楚播放不同的drm视频拿到的文件是否一样

@lvzhenbo
Copy link

@wfb2222wfb 首先,我项目都叫dcv的解密器了,你拿不是dmm的视频去用我的工具有啥用,然后其实解密方式都是通用的都是拿到pssh和kid去请求视频网站的key分发服务器,所以你得找到pssh和kid还有你网站对应的key服务器地址才行

@wfb2222wfb
Copy link

@lvzhenbo 不知道是不是我描述的有歧义哈,我前面说的播放视频是指https://forum.videohelp.com/threads/408031-Dumping-Your-own-L3-CDM-with-Android-Studio 这里面播放的drm视频dump bin和key这一步骤,后面解密的dcv的确是dmm下载的,你的意思是说dump这一步骤播放的视频需要和解密的dcv一致吗?

@lvzhenbo
Copy link

lvzhenbo commented Aug 30, 2024

不需要,只要你能够拿到cdm那两个文件就行了 @wfb2222wfb
然后报400是哪个步骤报400

@wfb2222wfb
Copy link

wfb2222wfb commented Aug 30, 2024

@lvzhenbo 拿密钥的时候,前面 licenceUid 和 pssh都拿到了,有没有可能是模拟器模拟手机版本低导致dump的两个文件dmm那边处理不了,我是根据他选择的pixel6操作的,我后来尝试在模拟器里面播放dmm的付费视频,进入播放页面后会报连接错误,不知道有没有关系。

@000795435
Copy link

dcv文件破解流程

需求工具

安卓开发工具,python

获取cdm

https://forum.videohelp.com/threads/408031-Dumping-Your-own-L3-CDM-with-Android-Studio 根据上面链接所说的方式获得cdm的两个文件

获取keyid

n大给了工具https://github.com/nilaoda/Blog/files/5861846/MP4DecryptGUI_20210124.zip 把dcv文件改名成mp4拖进去获得keyid

获取licenseUID和pssh

这一步需要dmm player v2播放器和抓包软件 登录好以后,启动抓包软件,抓取 https://mlic.dmm.com/drm/widevine/license 请求 在请求头的cookie中能够获得licenseUID 在请求体(文本方式查看)中能够获得可读文本类似下面,这就是content-id

{"v":"2","fid":"这里是文件id","svid":"digital","pl":"xxx","cs":"xxx"}

将这个文本原封不动转成base16 https://github.com/shaka-project/shaka-packager/releases 下载pssh-box.py.tar.gz解压运行

python pssh-box.py --base64 --widevine-system-id --key-id '(KID值)' --content-id '(content-id的base16值)'

输出pssh

获取最终的key

下载工具并解压https://github.com/CrymanChen/WKS-KEYS/releases/tag/v2023.04.07 将cdm的两个文件分别重命名为device_client_id_blobdevice_private_key,放到WKS-KEYS\pywidevine\L3\cdm\devices\android_generic\下 修改header.py文件

headers = { 'Host': 'mlic.dmm.com', 'Cookie': 'licenseUID=xxx' }

运行l3.py,按照提示输入pssh和license_url,url为https://mlic.dmm.com/drm/widevine/license,可获得key,在MP4DecryptGUI中输入key,格式选择HEX进行解密

无需dmm player v2

这里唯一的问题就是如何从dmm的cookie中找到所需的数据转成content-id中的pl和cs,我暂时没有找到方法,不知道有没有人能够帮个忙

请问链接是不是改了, 我Dev Tool 里抓包发现是https://mlic.dmm.co.jp/drm/clearkey/license

@lvzhenbo
Copy link

lvzhenbo commented Aug 30, 2024

@wfb2222wfb 安卓版本低才是对的,高了才拿不到,然后dmm播放报错是不是你网络问题,不是非要播放dmm视频,只要能拿到cdm的两个文件就行
@000795435 我的方式只是解密dcv文件,mpd流是是其他方式

@wfb2222wfb
Copy link

@lvzhenbo 如果这样的话,前期流程应该都没问题,就是不知道为何拿不到密钥😂

@lvzhenbo
Copy link

哪个步骤报错 @wfb2222wfb

@wfb2222wfb
Copy link

@lvzhenbo 密钥获取失败
response: {
status: 400,
statusText: "Bad Request",
headers: {
date: "Fri, 30 Aug 2024 03:09:21 GMT",
"content-type": "application/problem+json; charset=utf-8",
"transfer-encoding": "chunked",
connection: "keep-alive",
"cache-control": "no-store",
server: "Microsoft-IIS/10.0",
"x-powered-by": "ASP.NET",

@lvzhenbo
Copy link

@wfb2222wfb 前面几步都是正常的吗,包括登录、获取pssh和uid

@wfb2222wfb
Copy link

@lvzhenbo 是的
WX20240830-140219@2x

接口报错

AxiosError {
  stack: "Error\n    at settle (B:/~BUN/root/dcv-decryptor:36182:12)\n    at handleStreamEnd (B:/~BUN/root/dcv-decryptor:37071:17)\n    at emit (native)\n    at endReadableNT (native)\n    at processTicksAndRejections (native)\n    at <anonymous> (B:/~BUN/root/dcv-decryptor:37817:58)\n    at processTicksAndRejections (native)",
  message: "Request failed with status code 400",
  name: "AxiosError",
  code: "ERR_BAD_REQUEST",
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false,
    },
    adapter: [ "xhr", "http", "fetch" ],
    transformRequest: [
      [Function: transformRequest]
    ],
    transformResponse: [
      [Function: transformResponse]
    ],
    timeout: 0,
    xsrfCookieName: "XSRF-TOKEN",
    xsrfHeaderName: "X-XSRF-TOKEN",
    maxContentLength: -1,
    maxBodyLength: -1,
    env: {
      FormData: [Function: FormData2],
      Blob: [class Blob],
    },
    validateStatus: [Function: validateStatus],
    headers: {
      Accept: "application/json, text/plain, */*",
      "Content-Type": "application/octet-stream",
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) DMMPlayerv2/2.4.0 Chrome/120.0.6099.227 Electron/28.2.0 Safari/537.36",
      Host: "mlic.dmm.com",
      Cookie: "licenseUID=XXX",
      "Content-Length": "2599",
      "Accept-Encoding": "gzip, compress, deflate, br",
      set: [Getter/Setter],
      get: [Getter/Setter],
      has: [Getter/Setter],
      delete: [Getter/Setter],
      clear: [Getter/Setter],
      normalize: [Getter/Setter],
      concat: [Getter/Setter],
      toJSON: [Getter/Setter],
      toString: [Getter/Setter],
      getContentType: [Getter/Setter],
      setContentType: [Getter/Setter],
      hasContentType: [Getter/Setter],
      getContentLength: [Getter/Setter],
      setContentLength: [Getter/Setter],
      hasContentLength: [Getter/Setter],
      getAccept: [Getter/Setter],
      setAccept: [Getter/Setter],
      hasAccept: [Getter/Setter],
      getAcceptEncoding: [Getter/Setter],
      setAcceptEncoding: [Getter/Setter],
      hasAcceptEncoding: [Getter/Setter],
      getUserAgent: [Getter/Setter],
      setUserAgent: [Getter/Setter],
      hasUserAgent: [Getter/Setter],
      getAuthorization: [Getter/Setter],
      setAuthorization: [Getter/Setter],
      hasAuthorization: [Getter/Setter],
      [Symbol(Symbol.iterator)]: [Function],
    },
    responseType: "arraybuffer",
    method: "post",
    url: "https://mlic.dmm.com/drm/widevine/license",
    data: Buffer(2599) [ 8, 1, 18, 159, 18, 18, 201, 1, 10, 198, 1, 10, 175, 1, 18, 16, 105, 151, 57, 244, 237, 4, 51, 190, 188, 44, 179, 23, 128, 53, 52, 70, 34, 154, 1, 123, 34, 118, 34, 58, 34, 50, 34, 44, 34, 102, 105, 100, 34, 58, 34, 55, 49, 103, 97, 115, 115, 48, 48, 48, 48, 49, 34, 44, 34, 115, 118, 105, 100, 34, 58, 34, 100, 105, 103, 105, 116, 97, 108, 34, 44, 34, 112, 108, 34, 58, 34, 101, 121, 74, 119, 97, 87, 81, 105, 79, 105, 73, 51, 77, 87, 100, 104, 99, 51, 77, 119, 77, 68, 65, 119, 77, 87, 82, 115, 78, 105, 73, 115, 73, 109, 82, 108, 98, 71, 108, 50, 90, 88, 74, 53, 88, 51, 82, 53, 99, 71, 85, 105, 79, 105, 74, 107, 98, 67, 74, 57, 34, 44, 34, 99, 115, 34, 58, 34, 48, 100, 56, 54, 57, 101, 50, 48, 53, 54, 102, 49, 53, 101, 97, 101, 102, 99, 97, 99, 97, 49, 50, 102, 57, 57, 97, 53, 48, 97, 57, 102, 34, 125, 16, 2, 26, 16, 32, 129, 68, 35, 180, 126, 152, 44, 142, 21, 76, 223, 78, 193, 135, 46, 24, 1, 32, 196, 184, 197, 182, 6, 48, 21, 56, 173, 156, 174, 245, 2, 66, 192, 16, 10, 20, 108, 105, 99, 101, 110, 115, 101, 46, 119, 105, 100, 101, 118, 105, 110, 101, 46, 99, 111, 109, 18, 16, 23, 5, 185, 23, 204, 18, 4, 134, 139, 6, 51, 58, 47, 119, 42, 140, 26, 128, 14, 230, 205, 166, 164, 43, 49, 135, 31, 250, 120, 106, 15, 86, 51, 188, 143, 177, 169, 41, 233, 235, 47, 253, 229, 183, 50, 112, 88, 56, 230, 68, 82, 81, 83, 41, 241, 1, 53, 22, 165, 82, 80, 3, 168, 115, 183, 119, 146, 5, 91, 80, 109, 34, 244, 177, 113, 112, 13, 121, 13, 87, 130, 52, 214, 108, 26, 175, 190, 253, 2, 205, 50, 130, 152, 146, 21, 233, 244, 7, 213, 246, 34, 70, 239, 9, 54, 33, 28, 255, 218, 3, 178, 41, 88, 101, 86, 35, 231, 23, 164, 196, 64, 191, 237, 124, 138, 99, 126, 115, 167, 142, 197, 10, 105, 161, 94, 7, 147, 206, 65, 243, 131, 51, 248, 19, 90, 44, 231, 106, 45, 121, 130, 236, 194, 190, 136, 226, 131, 212, 104, 64, 121, 232, 157, 202, 146, 200, 116, 153, 204, 168, 246, 149, 219, 106, 145, 155, 118, 60, 22, 194, 73, 7, 119, 77, 3, 157, 198, 113, 40, 234, 43, 27, 253, 123, 170, 197, 216, 18, 119, 211, 139, 140, 134, 151, 101, 191, 67, 62, 126, 88, 203, 207, 67, 220, 62, 47, 0, 215, 136, 11, 94, 69, 204, 19, 140, 95, 142, 240, 198, 248, 30, 110, 251, 60, 158, 195, 206, 192, 247, 91, 94, 238, 6, 147, 68, 13, 246, 77, 99, 206, 100, 124, 198, 190, 132, 50, 201, 174, 199, 73, 107, ... 2086 more ],
  },
  request: ClientRequest {
    _writableState: {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: true,
      needDrain: false,
      ending: true,
      ended: true,
      finished: true,
      destroyed: false,
      decodeStrings: true,
      defaultEncoding: "utf8",
      length: 0,
      writing: false,
      corked: 0,
      sync: false,
      bufferProcessing: false,
      onwrite: [Function: onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      constructed: true,
      prefinished: true,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      [Symbol(kOnFinished)]: [],
      getBuffer: [Function: getBuffer],
      bufferedRequestCount: [Getter],
    },
    _events: {
      abort: [
        [Function]
      ],
      aborted: [
        [Function]
      ],
      connect: [
        [Function]
      ],
      error: [
        [Function]
      ],
      socket: [
        [Function]
      ],
      timeout: [
        [Function]
      ],
    },
    _eventsCount: 6,
    _maxListeners: undefined,
    [Symbol(kCapture)]: false,
    headersSent: false,
    sendDate: true,
    [Symbol(finished)]: false,
    [Symbol(kEndCalled)]: false,
    [Symbol(kAbortController)]: AbortController {
      signal: [AbortSignal ...],
      abort: [Function: abort],
    },
    _httpMessage: [Circular],
    [Symbol(headers)]: Headers {
      "accept": "application/json, text/plain, */*",
      "content-type": "application/octet-stream",
      "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) DMMPlayerv2/2.4.0 Chrome/120.0.6099.227 Electron/28.2.0 Safari/537.36",
      "host": "mlic.dmm.com",
      "cookie": "licenseUID=XXX",
      "content-length": "2599",
      "accept-encoding": "gzip, compress, deflate, br",
    },
    _redirectable: Writable {
      _writableState: [Object ...],
      _events: [Object ...],
      _eventsCount: 3,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false,
      _options: [Object ...],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 2599,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function],
      _currentRequest: [Circular],
      _currentUrl: "https://mlic.dmm.com/drm/widevine/license",
      abort: [Function],
      destroy: [Function],
      write: [Function],
      end: [Function],
      setHeader: [Function],
      removeHeader: [Function],
      setTimeout: [Function],
      flushHeaders: [Function],
      getHeader: [Function],
      setNoDelay: [Function],
      setSocketKeepAlive: [Function],
      aborted: [Getter],
      connection: [Getter],
      socket: [Getter],
      _sanitizeOptions: [Function],
      _performRequest: [Function],
      _processResponse: [Function],
      pipe: [Function],
      cork: [Function],
      uncork: [Function],
      setDefaultEncoding: [Function: setDefaultEncoding],
      _write: [Function],
      _writev: null,
      closed: [Getter],
      destroyed: [Getter/Setter],
      writable: [Getter/Setter],
      writableFinished: [Getter],
      writableObjectMode: [Getter],
      writableBuffer: [Getter],
      writableEnded: [Getter],
      writableNeedDrain: [Getter],
      writableHighWaterMark: [Getter],
      writableCorked: [Getter],
      writableLength: [Getter],
      errored: [Getter],
      writableAborted: [Getter],
      _undestroy: [Function: undestroy],
      _destroy: [Function],
      [Symbol(nodejs.rejection)]: [Function],
      setMaxListeners: [Function: setMaxListeners2],
      getMaxListeners: [Function: getMaxListeners2],
      emit: [Function: emit],
      addListener: [Function: addListener],
      on: [Function: addListener],
      prependListener: [Function: prependListener],
      once: [Function: once2],
      prependOnceListener: [Function: prependOnceListener],
      removeListener: [Function: removeListener],
      off: [Function: removeListener],
      removeAllListeners: [Function: removeAllListeners],
      listeners: [Function: listeners],
      rawListeners: [Function: rawListeners],
      listenerCount: [Function: listenerCount2],
      eventNames: [Function: eventNames],
    },
    [Symbol(fakeSocket)]: Socket {
      _readableState: [Object ...],
      _events: [Object ...],
      _eventsCount: 0,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false,
      _writableState: [Object ...],
      allowHalfOpen: true,
      [Symbol(::bunternal::)]: undefined,
      bytesRead: 0,
      bytesWritten: 0,
      connecting: false,
      timeout: 0,
      isServer: false,
      address: [Function: address],
      bufferSize: [Getter],
      connect: [Function: connect],
      _destroy: [Function: _destroy],
      _final: [Function: _final],
      localAddress: [Getter],
      localFamily: [Getter],
      localPort: [Getter],
      pending: [Getter],
      _read: [Function: _read],
      readyState: [Getter],
      ref: [Function: ref],
      remoteAddress: [Getter/Setter],
      remotePort: [Getter/Setter],
      remoteFamily: [Getter/Setter],
      resetAndDestroy: [Function: resetAndDestroy],
      setKeepAlive: [Function: setKeepAlive],
      setNoDelay: [Function: setNoDelay],
      setTimeout: [Function: setTimeout],
      unref: [Function: unref],
      _write: [Function: _write],
      write: [Function],
      cork: [Function],
      uncork: [Function],
      setDefaultEncoding: [Function: setDefaultEncoding],
      _writev: null,
      end: [Function],
      writable: [Getter/Setter],
      writableHighWaterMark: [Getter],
      writableObjectMode: [Getter],
      writableBuffer: [Getter],
      writableLength: [Getter],
      writableFinished: [Getter],
      writableCorked: [Getter],
      writableEnded: [Getter],
      writableNeedDrain: [Getter],
      destroyed: [Getter/Setter],
      on: [Function],
      destroy: [Function: destroy2],
      _undestroy: [Function: undestroy],
      push: [Function],
      unshift: [Function],
      isPaused: [Function],
      setEncoding: [Function],
      read: [Function],
      pipe: [Function],
      unpipe: [Function],
      addListener: [Function],
      removeListener: [Function],
      off: [Function],
      removeAllListeners: [Function],
      resume: [Function],
      pause: [Function],
      wrap: [Function],
      iterator: [Function],
      readable: [Getter/Setter],
      readableDidRead: [Getter],
      readableAborted: [Getter],
      readableHighWaterMark: [Getter],
      readableBuffer: [Getter],
      readableFlowing: [Getter/Setter],
      readableLength: [Getter],
      readableObjectMode: [Getter],
      readableEncoding: [Getter],
      errored: [Getter],
      closed: [Getter],
      readableEnded: [Getter],
      asIndexedPairs: [Function],
      drop: [Function],
      filter: [Function],
      flatMap: [Function],
      map: [Function],
      take: [Function],
      every: [Function],
      forEach: [Function],
      reduce: [Function],
      toArray: [Function],
      some: [Function],
      find: [Function],
      [Symbol(nodejs.rejection)]: [Function],
      [Symbol(Symbol.asyncIterator)]: [Function],
    },
    _closed: true,
    path: [Getter],
    port: [Getter],
    method: [Getter],
    host: [Getter],
    protocol: [Getter],
    agent: [Getter],
    _write: [Function: _write],
    _writev: [Function: _writev],
    _destroy: [Function: _destroy],
    _ensureTls: [Function: _ensureTls],
    _final: [Function: _final],
    aborted: [Getter/Setter],
    abort: [Function: abort],
    setSocketKeepAlive: [Function: setSocketKeepAlive],
    setNoDelay: [Function: setNoDelay],
    setTimeout: [Function: setTimeout],
    [Symbol(kClearTimeout)]: [Function],
    _implicitHeader: [Function],
    appendHeader: [Function],
    flushHeaders: [Function],
    getHeader: [Function],
    getHeaders: [Function],
    getHeaderNames: [Function],
    removeHeader: [Function],
    setHeader: [Function],
    hasHeader: [Function],
    addTrailers: [Function],
    headers: [Getter],
    chunkedEncoding: [Getter/Setter],
    shouldKeepAlive: [Getter/Setter],
    useChunkedEncodingByDefault: [Getter/Setter],
    socket: [Getter/Setter],
    connection: [Getter],
    finished: [Getter],
    pipe: [Function],
    write: [Function],
    cork: [Function],
    uncork: [Function],
    setDefaultEncoding: [Function: setDefaultEncoding],
    end: [Function],
    closed: [Getter],
    destroyed: [Getter/Setter],
    writable: [Getter/Setter],
    writableFinished: [Getter],
    writableObjectMode: [Getter],
    writableBuffer: [Getter],
    writableEnded: [Getter],
    writableNeedDrain: [Getter],
    writableHighWaterMark: [Getter],
    writableCorked: [Getter],
    writableLength: [Getter],
    errored: [Getter],
    writableAborted: [Getter],
    destroy: [Function],
    _undestroy: [Function: undestroy],
    [Symbol(nodejs.rejection)]: [Function],
  },
  response: {
    status: 400,
    statusText: "Bad Request",
    headers: {
      date: "Fri, 30 Aug 2024 05:44:38 GMT",
      "content-type": "application/problem+json; charset=utf-8",
      "transfer-encoding": "chunked",
      connection: "keep-alive",
      "cache-control": "private,max-age=0",
      server: "Microsoft-IIS/10.0",
      "x-powered-by": "ASP.NET",
      set: [Getter/Setter],
      get: [Getter/Setter],
      has: [Getter/Setter],
      delete: [Getter/Setter],
      clear: [Getter/Setter],
      normalize: [Getter/Setter],
      concat: [Getter/Setter],
      toJSON: [Getter/Setter],
      toString: [Getter/Setter],
      getContentType: [Getter/Setter],
      setContentType: [Getter/Setter],
      hasContentType: [Getter/Setter],
      getContentLength: [Getter/Setter],
      setContentLength: [Getter/Setter],
      hasContentLength: [Getter/Setter],
      getAccept: [Getter/Setter],
      setAccept: [Getter/Setter],
      hasAccept: [Getter/Setter],
      getAcceptEncoding: [Getter/Setter],
      setAcceptEncoding: [Getter/Setter],
      hasAcceptEncoding: [Getter/Setter],
      getUserAgent: [Getter/Setter],
      setUserAgent: [Getter/Setter],
      hasUserAgent: [Getter/Setter],
      getAuthorization: [Getter/Setter],
      setAuthorization: [Getter/Setter],
      hasAuthorization: [Getter/Setter],
      [Symbol(Symbol.iterator)]: [Function],
    },
    config: {
      transitional: [Object ...],
      adapter: [ "xhr", "http", "fetch" ],
      transformRequest: [
        [Function: transformRequest]
      ],
      transformResponse: [
        [Function: transformResponse]
      ],
      timeout: 0,
      xsrfCookieName: "XSRF-TOKEN",
      xsrfHeaderName: "X-XSRF-TOKEN",
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object ...],
      validateStatus: [Function: validateStatus],
      headers: [AxiosHeaders ...],
      responseType: "arraybuffer",
      method: "post",
      url: "https://mlic.dmm.com/drm/widevine/license",
      data: Buffer(2599) [ 8, 1, 18, 159, 18, 18, 201, 1, 10, 198, 1, 10, 175, 1, 18, 16, 105, 151, 57, 244, 237, 4, 51, 190, 188, 44, 179, 23, 128, 53, 52, 70, 34, 154, 1, 123, 34, 118, 34, 58, 34, 50, 34, 44, 34, 102, 105, 100, 34, 58, 34, 55, 49, 103, 97, 115, 115, 48, 48, 48, 48, 49, 34, 44, 34, 115, 118, 105, 100, 34, 58, 34, 100, 105, 103, 105, 116, 97, 108, 34, 44, 34, 112, 108, 34, 58, 34, 101, 121, 74, 119, 97, 87, 81, 105, 79, 105, 73, 51, 77, 87, 100, 104, 99, 51, 77, 119, 77, 68, 65, 119, 77, 87, 82, 115, 78, 105, 73, 115, 73, 109, 82, 108, 98, 71, 108, 50, 90, 88, 74, 53, 88, 51, 82, 53, 99, 71, 85, 105, 79, 105, 74, 107, 98, 67, 74, 57, 34, 44, 34, 99, 115, 34, 58, 34, 48, 100, 56, 54, 57, 101, 50, 48, 53, 54, 102, 49, 53, 101, 97, 101, 102, 99, 97, 99, 97, 49, 50, 102, 57, 57, 97, 53, 48, 97, 57, 102, 34, 125, 16, 2, 26, 16, 32, 129, 68, 35, 180, 126, 152, 44, 142, 21, 76, 223, 78, 193, 135, 46, 24, 1, 32, 196, 184, 197, 182, 6, 48, 21, 56, 173, 156, 174, 245, 2, 66, 192, 16, 10, 20, 108, 105, 99, 101, 110, 115, 101, 46, 119, 105, 100, 101, 118, 105, 110, 101, 46, 99, 111, 109, 18, 16, 23, 5, 185, 23, 204, 18, 4, 134, 139, 6, 51, 58, 47, 119, 42, 140, 26, 128, 14, 230, 205, 166, 164, 43, 49, 135, 31, 250, 120, 106, 15, 86, 51, 188, 143, 177, 169, 41, 233, 235, 47, 253, 229, 183, 50, 112, 88, 56, 230, 68, 82, 81, 83, 41, 241, 1, 53, 22, 165, 82, 80, 3, 168, 115, 183, 119, 146, 5, 91, 80, 109, 34, 244, 177, 113, 112, 13, 121, 13, 87, 130, 52, 214, 108, 26, 175, 190, 253, 2, 205, 50, 130, 152, 146, 21, 233, 244, 7, 213, 246, 34, 70, 239, 9, 54, 33, 28, 255, 218, 3, 178, 41, 88, 101, 86, 35, 231, 23, 164, 196, 64, 191, 237, 124, 138, 99, 126, 115, 167, 142, 197, 10, 105, 161, 94, 7, 147, 206, 65, 243, 131, 51, 248, 19, 90, 44, 231, 106, 45, 121, 130, 236, 194, 190, 136, 226, 131, 212, 104, 64, 121, 232, 157, 202, 146, 200, 116, 153, 204, 168, 246, 149, 219, 106, 145, 155, 118, 60, 22, 194, 73, 7, 119, 77, 3, 157, 198, 113, 40, 234, 43, 27, 253, 123, 170, 197, 216, 18, 119, 211, 139, 140, 134, 151, 101, 191, 67, 62, 126, 88, 203, 207, 67, 220, 62, 47, 0, 215, 136, 11, 94, 69, 204, 19, 140, 95, 142, 240, 198, 248, 30, 110, 251, 60, 158, 195, 206, 192, 247, 91, 94, 238, 6, 147, 68, 13, 246, 77, 99, 206, 100, 124, 198, 190, 132, 50, 201, 174, 199, 73, 107, ... 2086 more ],
    },
    request: ClientRequest {
      _writableState: [Object ...],
      _events: [Object ...],
      _eventsCount: 6,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false,
      headersSent: false,
      sendDate: true,
      [Symbol(finished)]: false,
      [Symbol(kEndCalled)]: false,
      [Symbol(kAbortController)]: [AbortController ...],
      _httpMessage: [Circular],
      [Symbol(headers)]: Headers [Object ...],
      _redirectable: [Object ...],
      [Symbol(fakeSocket)]: [Object ...],
      _closed: true,
      path: [Getter],
      port: [Getter],
      method: [Getter],
      host: [Getter],
      protocol: [Getter],
      agent: [Getter],
      _write: [Function: _write],
      _writev: [Function: _writev],
      _destroy: [Function: _destroy],
      _ensureTls: [Function: _ensureTls],
      _final: [Function: _final],
      aborted: [Getter/Setter],
      abort: [Function: abort],
      setSocketKeepAlive: [Function: setSocketKeepAlive],
      setNoDelay: [Function: setNoDelay],
      setTimeout: [Function: setTimeout],
      [Symbol(kClearTimeout)]: [Function],
      _implicitHeader: [Function],
      appendHeader: [Function],
      flushHeaders: [Function],
      getHeader: [Function],
      getHeaders: [Function],
      getHeaderNames: [Function],
      removeHeader: [Function],
      setHeader: [Function],
      hasHeader: [Function],
      addTrailers: [Function],
      headers: [Getter],
      chunkedEncoding: [Getter/Setter],
      shouldKeepAlive: [Getter/Setter],
      useChunkedEncodingByDefault: [Getter/Setter],
      socket: [Getter/Setter],
      connection: [Getter],
      finished: [Getter],
      pipe: [Function],
      write: [Function],
      cork: [Function],
      uncork: [Function],
      setDefaultEncoding: [Function: setDefaultEncoding],
      end: [Function],
      closed: [Getter],
      destroyed: [Getter/Setter],
      writable: [Getter/Setter],
      writableFinished: [Getter],
      writableObjectMode: [Getter],
      writableBuffer: [Getter],
      writableEnded: [Getter],
      writableNeedDrain: [Getter],
      writableHighWaterMark: [Getter],
      writableCorked: [Getter],
      writableLength: [Getter],
      errored: [Getter],
      writableAborted: [Getter],
      destroy: [Function],
      _undestroy: [Function: undestroy],
      [Symbol(nodejs.rejection)]: [Function],
    },
    data: Buffer(163) [ 123, 34, 116, 121, 112, 101, 34, 58, 34, 104, 116, 116, 112, 115, 58, 47, 47, 116, 111, 111, 108, 115, 46, 105, 101, 116, 102, 46, 111, 114, 103, 47, 104, 116, 109, 108, 47, 114, 102, 99, 55, 50, 51, 49, 35, 115, 101, 99, 116, 105, 111, 110, 45, 54, 46, 53, 46, 49, 34, 44, 34, 116, 105, 116, 108, 101, 34, 58, 34, 66, 97, 100, 32, 82, 101, 113, 117, 101, 115, 116, 34, 44, 34, 115, 116, 97, 116, 117, 115, 34, 58, 52, 48, 48, 44, 34, 116, 114, 97, 99, 101, 73, 100, 34, 58, 34, 48, 48, 45, 56, 97, 52, 49, 98, 57, 97, 100, 55, 51, 102, 56, 54, 51, 54, 54, 50, 54, 99, 49, 100, 102, 57, 52, 99, 55, 49, 49, 100, 100, 100, 49, 45, 57, 52, 100, 51, 50, 101, 101, 97, 49, 102, 48, 54, 97, 53, 57, 51, 45, 48, 48, 34, 125 ],
  },
  toJSON: [Function: toJSON],
  isAxiosError: true,
  toString: [Function: toString],
}

@lvzhenbo
Copy link

@wfb2222wfb 我刚刚试了一部,是可以的,那我能想到的就是网络问题了,不用开梯子,可以直连,然后你其实可以自己试试我上面说的手动的方式

@wfb2222wfb
Copy link

@lvzhenbo 手动之前试过了,也不行,还有两个问题,再请教一下
1、你dcv用的是r18资源吗?
2、会不会跟dump那两个文件选的模拟器机型有关,你是按照教程选的吗?

@lvzhenbo
Copy link

@wfb2222wfb 是fanza的,机型其实无关,其实那个帖子后面评论也给了很多这两个文件,然后也说明了高版本系统怎么获取,你都看看,我现在用的cdm就是按照教程搞出来的

@wfb2222wfb
Copy link

@lvzhenbo 好的,我再研究一下,多谢

@000795435
Copy link

@wfb2222wfb 安卓版本低才是对的,高了才拿不到,然后dmm播放报错是不是你网络问题,不是非要播放dmm视频,只要能拿到cdm的两个文件就行 @000795435 我的方式只是解密dcv文件,mpd流是是其他方式

哦哦明白了, 你的意思是下载DMM Player V2 这个软件然后播放视频在后台抓包,我之前理解的是DMM网页端的播放器。
谢谢, 我再琢磨一下。

@atiAkizuki
Copy link

@lvzhenbo 拿密钥的时候,前面 licenceUid 和 pssh都拿到了,有没有可能是模拟器模拟手机版本低导致dump的两个文件dmm那边处理不了,我是根据他选择的pixel6操作的,我后来尝试在模拟器里面播放dmm的付费视频,进入播放页面后会报连接错误,不知道有没有关系。

可以使用https://github.com/sim0n00ps/L3-Dumping 这个一键脚本,具体用什么虚拟机系统看它的issue页面,有人回复
我拿他成功解密了fanza的视频

@atiAkizuki
Copy link

现在的验证地址没有变,具体可以用reqable抓PC端DMM Player V2的登陆和验证逻辑,另外只是widevine DRM加密的视频,那CDM文件就通用,所以上面的方式获取的CDM适用于fanza

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests