专用播放器 U 盘 / 光盘 视频提取
0. 边界与前提(先讲清楚)
- 仅用于你自己合法拥有、有权复制的介质。本 skill 是"把自己能看到的视频导出来",不是破解他人版权保护去分发。
- 多数"专用播放器"U 盘只是把文件藏起来了,并非真加密——这正是本 skill 的主战场。真正无解的是"只有播放器能挂载的虚拟加密分区"(见 §6)。
1. 核心判断:先建假设
用户说"专用播放器才能放、看不到文件",成因分三类:
| 类型 | 特征 | 本 skill 能否解决 |
|---|---|---|
| A. 文件藏在子目录,根目录列举 API 漏掉 | 卷接近占满,但 列举根目录 只见播放器 exe/dll |
✅ 主战场 |
| B. 视频以原始数据嵌在卷里、无目录项 | 原始扫描能找到 ftyp 等特征码,但任何路径都打不开 |
⚠️ 需 carving(§6) |
| C. 真加密 / 虚拟分区 | 只有播放器能挂载,原始扫描也找不到明文视频 | ❌ 只能播放器内录 |
第一步永远看"容量矛盾":若卷总容量接近占满、但可见文件总大小很小,说明数据确实在盘上 → 走 A/B。若卷几乎为空,那是真没拷进来或加密 → 走 C。
2. 诊断流程
步骤 1:看容量矛盾 + 卷类型(Windows / PowerShell)
Get-WmiObject -Class Win32_Volume | ForEach-Object {
"$($_.DriveLetter) 标签='$($_.Label)' 格式=$($_.FileSystem) 大小=$([math]::Round($_.Capacity/1GB,2))GB 可用=$([math]::Round($_.FreeSpace/1GB,2))GB 设备=$($_.DeviceID)"
}
要点:
- 记下 总容量 / 已用 / 可用 / 文件系统(CDFS=光盘文件系统,常见于伪装 CD-ROM 的 U 盘)/ DriveType。
- 一个盘符可能挂着两个卷(多会话、或"播放器小卷 + 数据大卷"共用盘符)。Win32_Volume 会列出全部卷及其设备路径 \\?\Volume{GUID},用 GUID 路径可绕过盘符冲突直接访问。
步骤 2:原始扇区扫描,定位视频特征码(通用,Python)
用 Python 以原始设备方式打开卷(\\.\X: 或 \\.\Volume{GUID}),分块扫描视频 magic bytes,同时搜文件名 / JSON 目录清单线索。脚本见 scripts/scan_volume.py:
python scripts/scan_volume.py --volume \\.\X: --cap 1073741824 --out scan.txt
# --cap 0 表示全量扫描;默认先扫前 1GB 快速验证
扫描会报告:
- 视频特征码命中:ftyp(MP4/MOV)、RIFF+AVI(AVI)、FLV\x01(FLV)、\x1a\x45\xdf\xa3(MKV)、ASF 头 GUID(WMV)
- 附近可读串:常能直接挖出 "video":"Videos/0.mp4" 这类 JSON 目录清单字段、或 Videos/、StreamingAssets/ 路径 → 这就是指路明灯
判读:
- 找到 ftyp...mp42...moov 之类真实 MP4 头 → 视频是普通封装,A/B 皆可解。
- 挖到 JSON 清单含 "video":"<相对路径>" → 拿路径进步骤 3。
> 原理:CDFS/NTFS 卷都能被 open(r"\\.\X:","rb") 原始读取;CDFS 同样可读。
步骤 3:按精确路径探测隐藏目录(关键技巧)
根目录 Get-ChildItem X:\ 可能漏掉子目录,但按完整路径直接访问常能成功。这是 A 类问题的破局点。
先读卷内 JSON 清单拿真实路径,再精确验证:
# 先验证清单里出现的路径是否可达
Test-Path X:\Videos\0.mp4 # 常返回 True,尽管根目录列不出 Videos
Get-ChildItem -LiteralPath X:\Videos -Force # 能列出全部视频文件
常见隐藏目录名(逐个 Test-Path 试):Videos / video / Media / data / StreamingAssets\Videos / 课程名拼音或英文缩写。若清单给的是相对路径(如 Videos/0.mp4),直接拼根路径访问即可。
3. 提取方案(A 类:路径可达时)
确认能按路径访问后,直接复制即可,无需 carving:
$src = "X:\Videos"; $dst = "Y:\提取目录"
if (-not (Test-Path $dst)) { New-Item -ItemType Directory -Path $dst -Force | Out-Null }
$items = Get-ChildItem -LiteralPath $src -Force
foreach ($f in $items) {
Copy-Item -LiteralPath $f.FullName -Destination (Join-Path $dst $f.Name) -Force
}
# 复制后去掉只读属性(源常是只读),方便后续改名/剪辑
Get-ChildItem -LiteralPath $dst -Force | ForEach-Object { if ($_.IsReadOnly) { $_.IsReadOnly = $false } }
- 目标目录先建好;复制方向严格 源 → 目标,永不写源盘。
- 若
<SRC_DIR>自身也列举不出(走到 B 类),才需要 §6 的 carving。
4. 校验
复制后抽样核对头部与总量:
$p = "Y:\提取目录\0.mp4"
$fs = [System.IO.File]::OpenRead($p)
$b = New-Object byte[] 12
$fs.Read($b,0,12) | Out-Null; $fs.Close()
# 期望前 12 字节形如: 00 00 00 xx 66 74 79 70 6D 70 34 32 (即 box长度 + "ftyp" + "mp42")
并确认 文件数 / 总大小 与源一致。MP4 头部正常的文件可用任意播放器(VLC / PotPlayer / 系统自带)直接播放。
5. 常见坑(来自实战)
- 别只信根目录列举:
Get-ChildItem X:\会漏掉隐藏子目录。用清单拿路径 +Test-Path精确验证才是正解。 - robocopy /L 在 CDFS 上可能列不出源文件:改用 PowerShell
Copy-Item逐文件复制,枚举更可靠。 - 卷设备原始读取:
\\.\X:在 Python 里open(r"\\.\X:","rb")可读;多卷共用盘符时用\\.\Volume{GUID}。 - 属性:源文件常是只读,复制后记得清只读,否则后续操作受阻。
- carving 兜底:任何路径都打不开、但原始扫描确认数据在,才走 §6。
6. 附录:何时走 carving(B 类)
若步骤 3 所有路径都 Test-Path 失败,但步骤 2 确认盘上有真实 MP4 特征码(无目录项,播放器靠偏移读取),则需按 MP4 box 结构 carving:
- 每个 MP4 以
ftypbox 开头;扫描所有ftyp出现位置作为候选起点。 - 解析后续 box(
moov、mdat)定长,确定单文件边界;跨ftyp之间即为一段视频。 - 把每段原始字节写出为
.mp4落盘。 - 此法对"视频首尾无间隙、且都是同封装"的盘最稳;若混合多种格式或带加密壳,需逐 box 精修。
> carving 是兜底手段,复杂度高、易错;优先确认 A 类(路径可达),成功率最高。
附:scan_volume.py 用法
python scripts/scan_volume.py --volume \\.\X: --cap 1073741824 --out scan.txt
输出:特征码命中统计 + 每个命中点附近的可读串(含可能的 JSON 目录清单片段)。--cap 0 全量;省略 --out 则打到 stdout。