记一次网易云歌词进度内存逆向过程

看到B站有个给win桌面加灵动岛歌词的很cool,于是想做一个差不多相同的

首先考虑的是如何获取到网易云的进度,首先想到了SMTC协议

这是一个系统级媒体接口,能获取到当前播放音频数据的元数据信息(如果软件有适配的情况下)

但经过搜索后发现网易云原生似乎并不支持SMTC,需要安装BetterNCM以及InfLink插件

但我并不想使用外置各种繁杂的框架及直接修改网易云程序,况且BNCM也已接近停更,性能方面也不太能及时完善

索性抱着试试的态度,先尝试获取一下SMTC信息,看看能不能获取到有用的东西

代码大概如下(C#)

using Windows.Media.Control;

// 获取 Session 管理器
var manager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync();

// 获取当前会话 (通常是最后活动的媒体App)
var session = manager.GetCurrentSession();

if (session != null)
{
    // 获取元数据 (歌名/歌手)
    var mediaProperties = await session.TryGetMediaPropertiesAsync();
    Console.WriteLine($"{mediaProperties.Artist} - {mediaProperties.Title}");

    // 获取进度
    var timeline = session.GetTimelineProperties();
    Console.WriteLine($"当前进度: {timeline.Position} / {timeline.EndTime}");
    
    // 监听变化
    session.TimelinePropertiesChanged += (sender, args) => {
        var t = sender.GetTimelineProperties();
    };
}

但尝试后发现无法正常获取,看来网易云开发团队确实很懒(Q音好像新版支持了

![[Pasted image 20251208195656.png]]

随后Ai给出另一个尝试,可能网易云没被正常激活?那就试一下获取全部活跃媒体

using Windows.Media.Control;

Console.WriteLine("正在扫描所有媒体会话...");
var manager = await

GlobalSystemMediaTransportControlsSessionManager.RequestAsync();
var sessions = manager.GetSessions();

Console.WriteLine($"扫描到 {sessions.Count} 个活跃媒体应用:");
if (sessions.Count == 0) {
    Console.WriteLine("❌ 真的一个都没扫到。");
}

结果自然是

![[Pasted image 20251208200251.png]]

看来SMTC这条路是走不通了

我尝试找找有没有其他的办法,好像都没有确切的方法能获取

那看来只能拿出Cheat Engine,启动!

尝试直接通过读内存的方式来实现这一功能(简单暴力属于是)

首先是扫描获取当前歌曲的进度数值,也就是播放到了哪一秒

但我不确定网易云是使用的哪种数据类型来存放,可能是秒,也可能是毫秒,或者Double等等

首先从最能保险的方式开始扫,把歌曲调整到00:00,首次扫描

![[Pasted image 20251208200817.png]]

可以看到有1000w个扫描数值,接下来就是层层筛选

这里我首先使用的是绝对数值(假设他是使用的秒)

先把歌曲调整到00:10,然后搜索新的数值10

![[Pasted image 20251208200943.png]]

结果直接缩减到22,再次进行筛选,往后推

![[Pasted image 20251208201021.png]]

看来第一步猜测失败,他并没有直接使用秒存储,那就尝试Plan B,使用毫秒

但是对于这种只能显示到秒精度的播放器,我无法知道确切的毫秒数值,只能使用增大/减少的数值来找出哪些出现了变化

![[Pasted image 20251208201248.png]]

依次循环进行这个过程 往后拉进度条->再次扫描->往后拉进度条->再次扫描

当然只扫描增大的可能很浪费时间,因为有些无关数值他就是会不停增大

可以随机反向多推一些 往前拉->减少的数值->再次扫描

这样往返多筛选几次,最后得到了以下几个

![[Pasted image 20251208201730.png]]

此时很显而易见了,当前歌曲进度是00:54,而地址列表里有五个类似的数值,看来是毫秒没错了

然后是点击播放音乐,这些地址的数值也会跟着变动,音乐停他们就停,基本确定了

接下来就是确定UI层和实际逻辑层的地址,将五个地址进行分别更改,查看哪个可以变动到实际的音乐进度

![[Pasted image 20251208201914.png]]

找到了,25593767568这个地址就是实际音乐进度的

但我发现一个问题,这个地址可以更改音乐进度,但点击播放时,他没有随实时进度更新,他只在用户手动拖动进度条时更新,那就没法用了,但可以保留这个地址,作为调整进度使用

![[Pasted image 20251208202427.png]]

那也就是说这个地址实际上是UI 控件的定位值,而不是音频引擎的播放时钟

经过资料查找和Ai分析,选择了更换搜索类型,以Double方式查找

在网易云(基于 Chromium/CEF)这种架构里,以及大多数音频库(如 FFmpeg, BASS)中,实时时间戳通常是 Double (双精度浮点数) 类型,单位是 

然后我就试着变换思路,选择双浮点查找

![[Pasted image 20251208202915.png]]

再次经过各种筛选,最后得出了以下这个地址

![[Pasted image 20251208213359.png]]

碰巧也是静态地址,不用找偏移值确定实际地址,只要网易云不更新,这个地址就可以一直用

结果很顺利,一切正常,重启网易云后也能正常继续实时读取

![[Pasted image 20251208213920.png]]

接下来是扩展一个写(控制进度)也就是上面提到的可控制地址

因为那个是动态地址,如果程序退出后再启动,实际地址会发生变化,需要计算偏移值,得出实际通向这个的地址

此时需要重新进行刚才的扫描步骤,然后拿到控制地址1734FC13228

![[Pasted image 20251208214647.png]]

双击地址添加到下面的地址列表,右键 - 生成 指针映射集

保存后再次右键对该地址进行指针扫描,选择使用保存的指针映射集,选择刚刚保存的映射集

![[Pasted image 20251208215356.png]]

保存到同目录下,然后就得到了几个基址+偏移值

![[Pasted image 20251208215655.png]]

如果列表有很多不相关的(查看右侧指针是否数值对应实际数值,显示空或不对应则直接排除)

这个过程可以多次重复尝试,不要关闭指针扫描器窗口,重启网易云,重新按上面步骤找地址,找到后进行进一步重新扫描查找筛选,多次筛选后即可得到

![[Pasted image 20251208215930.png]]