项目
该项目的目标是构建一个Spotify客户端,让它能够学习我的听曲习惯并跳过一些我通常会跳过的歌曲。不得不承认,这种需求来自于我的懒惰。我不想在当我有心情想要听某些音乐时,创建或查找播放列表。我希望的是在我的库中选择一首歌,然后可以随机播放其他歌曲,并从队列中删除不“flow(节奏与旋律的流畅)”的歌曲。
为了实现这一点,我需要学习某种能够执行此任务的模型(在未来的帖子中可能更多)。但是为了能够训练一个模型,我首先需要数据来训练它。
数据
我需要完整的听歌历史记录,包括我跳过的那些歌曲。获取历史记录很简单。虽然Spotify API仅允许获取最近50首播放的歌曲,但我们可以设置一个cron job来重复轮询该端点。完整代码已经发布在此处:https://gist.github.com/SamL98/c1200a30cdb19103138308f72de8d198
最困难的部分是跟踪跳过。Spotify Web API并没有为此提供任何的端点。之前我使用Spotify AppleScript API创建了一些控制播放的服务(本文的其余部分将涉及到MacOS Spotify客户端)。我可以使用这些服务来跟踪跳过的内容,但这感觉像是在回避挑战。我怎么能完成它呢?
Hooking
我最近学习了解了有关hooking的技术,你可以在其中“拦截”从目标二进制文件生成的函数调用。我认为这将是跟踪跳过的最佳方法。
最常见的钩子类型是interpose hook。这种类型的钩子会覆盖PLT中的重定位,但这究竟意味着什么呢?
PLT或过程链接表允许你的代码引用外部函数(想想libc)而不知道该函数在内存中的位置,你只需引用PLT中的一个条目。链接器在运行时为PLT中的每个函数或符号执行“重定位”。这种方法的一个好处是,如果外部函数在不同的地址加载,则只需要更改PLT中的重定位,而不是每次对代码中该函数的引用。
因此,当我们为printf创建一个interpose hook时,每当我们hooking的进程调用printf时,我们将调用printf的实现而不是libc(我们的自定义库通常也会调用标准实现)。
在对钩子有了一些基本的知识背景后,下面我们准备尝试在Spotify中插入一个钩子。但首先我们需要弄清楚我们想要hook的是什么。
寻找 hook 的位置
如前所述,只能为外部函数创建一个interpose hook,因此我们将在libc或Objective-C runtime中查找函数。
在研究在哪hook时,我认为一个开始hooking的好地方是Spotify处理“media control keys”或我MacBook上的F7-F9。假设这些键的处理程序在spotify应用程序中单击Next按钮被调用时会调用函数。我最终在:https://github.com/nevyn/spmediakeytap上找到了SPMediaKeyTap库。我想我可以试一试,看看Spotify是否复制并粘贴了这个库中的代码。在SPMediaKeyTap库中,有一个方法startWatchingMediaKeys。我在Spotify二进制文件上运行了strings命令,看看他们是否有这个方法,果然:
Bingo!!如果我们将Spotify二进制文件加载到IDA(当然是免费版本)并搜索此字符串,我们就会找到相应的方法:
如果我们查看这个函数对应的源码,我们会发现CGEventTapCreate函数的有趣参数tapEventCallback:
如果我们回顾一下反汇编,我们可以看到sub_10010C230子例程作为tapEventCallback参数传递。如果我们查看这个函数的源码或反汇编,我们看到只调用了一个库函数CGEventTapEnable:
让我们尝试hook这个函数。
我们需要做的第一件事是创建一个库来定义我们的自定义CGEventTapEnable。代码如下:
#include <corefoundation> #include <dlfcn.h> #include <stdlib.h> #include <stdio.h> void CGEventTapEnable(CFMachPortRef tap, bool enable) { typeof(CGEventTapEnable) *old_tap_enable; printf(“I'm hooked!\n”); old_tap_enable = dlsym(RTLD_NEXT, “CGEventTapEnable”); (*old_tap_enable)(tap, enable); }</stdio.h></stdlib.h></dlfcn.h></corefoundation>
dlsym函数调用获取实际库CGEventTapEnable函数的地址。然后我们调用旧的实现,这样我们就不会意外地破坏任何东西。让我们像这样编译我们的库(https://ntvalk.blogspot.com/2013/11/hooking-explained-detouring-library.html):
gcc -fno-common -c <filename>.c gcc -dynamiclib -o <library> <filename>.o</filename></library></filename>
现在,让我们尝试在插入钩子时运行Spotify:DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=
Spotify打开正常,但Apple的系统完整性保护(SIP)没有让我们加载未签名库:(。
幸运的是,我是Apple的reasonably priced developer项目的成员,所以我可以对库进行代码签名。这个问题算是得到了解决。让我们用100美元证书签名我们的库,运行上一个命令,然后......
失败。这一点不奇怪,Apple不允许你插入使用任何旧标识签名的库,只允许使用签名原始二进制文件时使用的库。看起来我们必须要找到另一种方法来hook Spotify了。
作为补充说明,细心的读者可能会注意到我们hook的函数CGEventTapEnable,只有在media key event超时时才会被调用。因此,即使我们可以插入钩子,我们也可能不会看到任何的输出。本节的主要目的是详细说明我最初的失败(和疏忽),并作为一个学习经验。
HookCase
经过一番挖掘,我发现了一个非常棒的库HookCase:https://github.com/steven-michaud/HookCase。HookCase让我们实现一种比插入钩子( patch hook)更为强大的钩子类型。
通过修改你希望hook的函数触发中断插入Patch hooks。然后,内核可以处理此中断,然后将执行转移到我们的个人代码中。对于那些感兴趣的人,我强烈建议你阅读HookCase文档,因为它更为详细。
Patch hooks不仅允许我们对外部函数的hook调用,而且允许我们hook目标二进制文件内的任何函数(因为它不依赖于PLT)。HookCase为我们提供了一个框架来插入patch和/或interpose hooks,以及内核扩展来处理patch hooks生成的中断,并运行我们的自定义代码。
寻找 sub_100CC2E20
既然我们已经有办法hook Spotify二进制文件中的任何函数了,那么只剩下最后一个问题......就是位置在哪?
让我们重新访问SPMediaKeyTap源码,看看如何处理媒体控制键。在回调函数中,我们可以看到如果按下F7,F8或F9(NX_KEYTYPE_PREVIOUS,NX_KEYTYPE_PLAY等),我们将执行handleAndReleaseMediaKeyEvent选择器:
然后在所述选择器中通知delegate:
让我们看看repo中的这个delegate方法:
事实证明它只是为处理keys设置了一个模板。让我们在IDA中搜索receiveMediaKeyEvent函数,并查看相应函数的图形视图:
看起来非常相似,不是吗?我们可以看到,对每种类型的键都调用了一个公共函数sub_10006FE10,只设置了一个整数参数来区分它们。让我们hook它,看看我们是否可以记录按下的键。
我们可以从反汇编中看到,sub_10006FE10获得了两个参数:1)指向SPTClientAppDelegate单例的playerDelegate属性的指针,以及2)指定发生了什么类型事件的整数(0表示暂停/播放,3表示下一个,4表示上一个)。
看看sub_10006FE10(我不会在这里包含它,但我强烈建议你自己检查一下),我们可以看到它实际上是sub_10006DE40的包装器,其中包含了大部分内容:
哇!这看起来很复杂。让我们试着把它分解一下。
从这个图的结构来看,有一个指向顶部的节点有许多outgoing edges:
正如IDA所建议的那样,这是esi(前面描述的第二个整数参数)上的switch语句。看起来Spotify的处理的不仅仅是Previous,Pause/Play和Next。让我们把关注点集中到处理Next或3 block:
不可否认,为此我花了一些时间,但我想请你注意底部第四行的call r12。如果你查看其他的一些情况,你会发现一个非常相似的调用寄存器的模式。这似乎是一个很好的函数,但我们如何知道它在哪呢?
让我们打开一个新工具:debugger(调试器)。我最初尝试调试Spotify时遇到了很多麻烦。现在可能是因为我对调试器不太熟悉的原因,但我认为我想出了一个相当聪明的解决方案。
我们首先在sub_10006DE40上设置一个hook,然后我们在代码中触发一个断点。我们可以通过执行汇编指令int 3来做到这一点(例如像GDB和LLDB之类的调试)。
以下是在HookCase框架中hook的样子:
将此添加到HookCase模板库后,你还必须将其添加到user_hooks数组:
然后我们可以使用Makefile HookCase提供的模板来编译它。然后可以使用以下命令将库插入Spotify:HC_INSERT_LIBRARY=
然后我们可以运行LLDB并将其attach到正在运行的Spotify进程,如下所示:
尝试按F9(如果Spotify不是活动窗口,它可能会打开iTunes)。钩子中的int $3行应该触发了调试器。
现在我们可以进入到sub_10006DE40入口点这步。请注意,PC将位于与IDA中显示的地址相对应的位置(我认为这是由于进程加载到内存的位置所导致的)。在我当前的进程中,push r15指令位于0x10718ee44:
在IDA中,该指令的地址为0x10006DE44,它给了我们一个偏移量0x7121000。在IDA中,调用r12指令的地址为0x10006E234。然后我们可以将偏移量添加到该地址,并相应地设置一个断点,b -a 0x10718f234,然后继续。
当我们点击目标指令时,我们可以打印出寄存器r12的内容:
我们要做的就是从这个地址减去偏移量,看,我们获取到了我们名义上的地址:0x100CC2E20。
Hooking sub_100CC2E20
现在,让我们来hook这个函数:
将其添加到user_hooks数组,编译,运行,并观察:每次按F9或单击Spotify应用程序中的next按钮,都会记录我们的消息。
现在我们已经hook了skip功能,
我将发布剩余的代码,但我不会完成其余部分的逆向工作,因为这篇文章已经够长的了。
简而言之,我也hook了previous功能(如果你照着做的话,这会是一个很好的练习)。然后,在这两个钩子中,我首先检查当前的歌曲是否已经过了一半。如果是的话,我什么都不做,假设我只是对这首歌感到厌倦,而不是觉得它不合适。然后在backs (F7),我弹出last skip。
针对如何检查当前歌曲是否已经过了一半的方法我想说几句。我最初的方法是实际调用popen,然后运行相应的AppleScript命令,但感觉这不太对。
我在Spotify二进制文件上运行了class-dump,发现了两个类:SPAppleScriptObjectModel和SPAppleScriptTrack。这些方法公开了播放位置,持续时间和曲目ID所需的必要属性。然后,我为这些属性hook了getter,并使用next和back hooks调用它们(我认为Swizzle更合理,但我无法让它正常工作)。
我使用一个文件来跟踪skips,其中第一行包含跳过次数,在跳过时我们增加这个计数器,并将跟踪ID和时间戳写入计数器指定行上的文件。在back按钮,我们只是减少这个计数器。这样,当我们按下back按钮时,我们只是将文件设置为对已回溯文件写入new skips。
以上是如何逆向分析Spotify.app并hook其功能获取数据的详细内容。更多信息请关注PHP中文网其他相关文章!

类似小红书的app有:1、绿洲,是一款新浪微博出品的移动端时尚社交应用软件;2、杂志迷,是一款手机各类杂志供大家阅读的APP;3、美丽修行,是一款提供护肤解决方案及化妆品购买决策的产品;4、凹凹啦,是一款手机化妆品点评软件,为用户提供最实用、最新鲜、最全方位的护肤、化妆点评和分享信息;5、抹茶美妆,一款实用的化妆品交流社区;6、美丽说,一款以分享为主题的趣味社交平台。

微软于今年早些时候推出了Windows11安全功能SmartAppControl。当时,微软将其描述为“阻止不受信任或具有潜在危险的应用程序”的保护工具。当时该工具的独特之处在于它决定了它是否应该在Windows11设备上运行。SmartAppControl一开始以评估模式运行;正是在这种模式下,应用程序决定是否应该打开它。微软确实透露用户可以在Windows安全应用程序的应用和浏览器控制部分启用智能应用控制。仅根据Microsoft的说法,SmartAppC

橙色软件指的是“淘宝”。淘宝是随时随地轻松购物app,为用户提供新的购物渠道,享受更多优惠活动,让用户不用出门就可以享受优惠购物平台,方便买卖家之间的沟通,购物更加方便。淘宝能满足人们生活中的各种需求:搜索和浏览商品、加入购物车、下单支付、物流查询、客服交流、发表购物评论、分享优质商品等等,还能通过本地功能,找到附近的生活优惠信息。

苏州地铁用“苏e行”app扫码进站。苏e行app ,提供苏州地铁扫码乘车服务,先乘车,后付款,结合苏州城市文化及地铁出行场景,围绕“地铁大脑”构建公共交通智慧出行,利用 LBS 、物联网、大数据、人工智能等先进技术为乘客提供扫码过闸、乘车服务、附近地铁商业、同时为苏州本地商家提供用户引流、活动推广等服务,构建互联网化的苏州城市生活服务。

防诈骗的app叫“国家反诈中心”,是一款帮助用户预警诈骗信息、快速举报诈骗内容、提升防范意识的反电信诈骗应用。它的“反诈预警、身份验证、App自查、风险预警”等核心功能可以最大限度减少民众被骗的可能性;可以对那些诈骗电话或信息快速向平台举报,帮助他人减少遇到类似的情况;能够帮助用户随时监控各种恶意软件,让各种骗局无路可走,给每个用户带来一个非常安全的生活环境。

AppStore是iOS相关应用程序的市场。在这里,您还可以找到免费应用程序和付费应用程序。应用程序可以是游戏应用程序、提高工作效率的应用程序、实用应用程序、社交媒体应用程序以及更多类别的应用程序。您可能已经从AppStore下载或购买了许多适用于iPhone的应用程序。现在您可能想知道如何查看在App Store中购买的应用程序的购买历史记录。有时,出于隐私原因,您可能需要从购买历史记录中隐藏某些购买。在本文中,我们将指导您查找购买历史记录以及如何根据需要从购买历史记录中删除/隐藏购买。第1部

tiktok是抖音短视频国际版,是字节跳动旗下短视频社交app软件,于2017年5月上线,愿景是“激发创造,带来愉悦”。用户可以通过这款软件选择歌曲,拍摄音乐短视频,形成自己的作品,会根据用户的爱好,来更新用户喜爱的视频。

猴山指的是“AcFun”,是一个视频播放软件。AcFun以视频为载体,逐步发展出基于原生内容二次创作的完整生态,是中国弹幕文化的发源地。AcFun以“认真你就输了”为文化导向,倡导轻松欢快的亚文化,受广大二次元用户的深度喜爱,入驻超多原创视频的作者,覆盖面超广阔。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

Dreamweaver CS6
视觉化网页开发工具

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

WebStorm Mac版
好用的JavaScript开发工具

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。