猿人学 App 第二十一题「二十四桥明月夜」离机复现:答案藏在视频第一个 ts 里

本文最后更新于:2026年9月2日 下午

[猿人学 App 逆向系列]第二十一题「二十四桥明月夜【m3u8】」。这题不翻页取数,而是”看视频交答案”型:ExoPlayer 播放一段 HLS 视频,你把答案填进输入框,提交到 app_check 校验。
有意思的是——视频画面里根本没有答案。本文记录怎么排除画面/音频/元数据,最终定位到”答案 = 视频第一个 ts 分片的 MD5”。

⚠️ 猿人学闯关 App 是面向逆向练习的 CTF 式靶场;本文仅用于授权范围内的学习研究,请遵守相关服务条款与法律。

本文目录

  • 请求模型:一个视频 + 一个校验接口
  • 拿到视频:AES-128 加密的 HLS
  • 排除法:画面、音频、元数据里都没有答案
  • 答案 = 第一个 ts 的 MD5

一、请求模型:一个视频 + 一个校验接口

ChallengeTwentyOneFragment 里没有翻页逻辑,只有:

1
2
3
4
// 播放一段 HLS 视频(URL 是混淆字符串,解出来见下)
player.setMediaItem(MediaItem.fromUri(<video_url>));
// 输入框 + 提交按钮
onClick: api.OooOo0(48, editText.getEditValue(), token); // POST challenge/api/app_check

OooOo0(id, anw, token) 对应 challenge/api/app_check——就是通关答案提交接口,id=48 是本题。所以第二十一题没有数据 API,核心是”搞到那个要填进输入框的答案”。

混淆字符串用 JVM 预言机解一下(把 dex2jar 出的 app.jar 挂上,直接调解密函数):

1
video_url = https://www.python-spider.com/static/app/media/stream.m3u8

二、拿到视频:AES-128 加密的 HLS

stream.m3u8 是个加密的点播流:

1
2
3
4
5
6
7
8
#EXTM3U
#EXT-X-KEY:METHOD=AES-128,URI=".../enc.key",IV=0x76E4CF6C...
#EXTINF:6.006,
segment-0.ts
#EXTINF:6.006,
segment-1.ts
... 共 4 段 ...
#EXT-X-ENDLIST

ffmpeg 能自己去拉 key、解密、拼接:

1
ffmpeg -allowed_extensions ALL -i "https://www.python-spider.com/static/app/media/stream.m3u8" -c copy out.mp4

拿到一段约 23 秒的视频。

三、排除法:画面、音频、元数据里都没有答案

按”看视频取答案”的惯性,先去画面里找数字:

  • 逐帧扫描 + 拼接图:整段就是一段黑白海面空镜,没有任何数字/文字叠加。
  • 场景切换检测(select='gt(scene,0.15)'):0 个切换帧——没有一闪而过的叠加。
  • 多帧平均(tmix,静止的水印会保留、流动的水面会糊掉):平均出来还是海面,没有隐藏水印。
  • 音频:astats 显示 Max level: 0.0——音轨全静音,不可能是播报/DTMF/摩尔斯。
  • TS 元数据 / ID3:解密后的 ts 里只有 H264 + AAC,没有可读的答案串。

画面、音频、元数据全排除。视频本身(“二十四桥明月夜”的空镜)只是主题装饰,答案不在它”演的内容”里,而在它”作为文件”的属性上。

四、答案 = 第一个 ts 的 MD5

这类题的答案落点,常是”对某个资源做个哈希”。这题的答案就是——视频第一个分片 segment-0.ts 原始字节(下载来的加密 ts,不用解密)的 MD5:

1
2
3
4
5
6
7
8
import hashlib, requests
from urllib.parse import urljoin

M3U8 = "https://www.python-spider.com/static/app/media/stream.m3u8"
m3u8 = requests.get(M3U8, timeout=15).text
seg = next(l.strip() for l in m3u8.splitlines() if l.strip() and not l.startswith("#")) # 第一个分片
ts = requests.get(urljoin(M3U8, seg), timeout=30).content # 原始字节
print(hashlib.md5(ts).hexdigest()) # -> 提交到 app_check(id=48)的 anw

把这个 MD5 填进输入框提交,即通关。

小结

第二十一题的坑在于惯性:一看到”播放视频”,就下意识去画面里找答案,结果逐帧、平均、音频、元数据一通折腾全是空。当所有”内容通道”都排除时,就该换个角度——答案往往不在视频演了什么,而在这个文件本身(整段 md5、首个分片 md5、文件大小、时长等)。这里正是”第一个 ts 的 MD5”。

离机复现只要:读 m3u8 → 取第一个分片 → 算 MD5。连解密都不用。


猿人学 App 第二十一题「二十四桥明月夜」离机复现:答案藏在视频第一个 ts 里
https://kingjem.github.io/2026/09/02/猿人学App第二十一题离机复现-答案藏在视频第一个ts里/
作者
Ruhai
发布于
2026年9月2日
许可协议