本帖最后由 blindcat 于 2023-10-29 10:06 编辑
破解Emby Server For macOS 4.7.14.0示例App获取地址: https://github.com/MediaBrowser/Emby.Releases/releases/download/4.7.14.0/embyserver-osx-x64-4.7.14.0.zip 1. 初步分析在设置中有一个专业版订阅,我们看下: 
点击保存我们发现 
https://mb3admin.com/admin/service/registration/validateDevice?xxxx 后面是随机生成的不可逆的hash数据,所以我没打码。 这个app我们打开,可以看到非常怀疑是前端页面资源直接返回到浏览器的 
dashboard-ui很明显。 我们用vscode搜索一下看看: 
还真搜索到了,这么容易就破解了吗?我不信。 2. 修改文件不起作用我们上一步找到的接口文件,如果我们伪造数据返回岂不是就能解锁专业版?我们试试。 
本地我们起了个3000端口服务,看看能不能收到数据包。 保存,重启app,订阅: 
此时神奇的一幕发生了,无论我怎么修改这个js文件的内容,永远不起作用,这是为什么呢? 答案只有一个,这个js文件无论内容是什么都不重要,重要是的这个文件存在就可以了,只要app拦截页面访问请求,在代码中构造一个内嵌的js文件,就可以做到这种效果。那么是哪个文件呢? 当然是我们最爱的暴力搜索辣! 由于dll文件无法被Sublime Text搜索到,我不知道是不是我的设置问题,所以我手动一个个文件放到HexFriends里面搜索字符串: 
终于搜索到了。 这个文件是Emby.Web.dll,是C#动态库,那么我们有请windows和dnSpy上场! 
在解析完成后,我们看到资源文件中果然出现了一个同名文件,我们导出这个文件: 
我们放到vscode中格式化后,可以看到这个请求的逻辑是: 
如果这个接口走通了,那么直接 return ( appStorage.setItem( cacheKey, JSON.stringify({ lastValidDate: Date.now(), deviceId: params.deviceId, cacheExpirationDays: response.cacheExpirationDays, lastUpdated: Date.now(), }) ), Promise.resolve() );
那么我们直接返回这个数据不就得了? 于是我插入了这一段修改后的代码: 
其作用是伪造了服务器返回的数据,让他走逻辑成功。 最后复制保存为js文件,切记文件名要和导出的文件名一致,重新把这个文件导入进dll中: 
在弹出的窗口中选择自己保存的同名文件即可。 最后保存文件修改: 
我这里保存过了,所以“全部保存”是灰色的,修改后一定要选择全部保存后才会对dll进行实际修改哦! 保存文件后替换app里的同名文件试试: 
打开app我们在再试一遍: 
这里打开f12后一定要长按左键清空浏览器缓存刷新,否则js文件可能不是最新的。 但是我们发现重新输入后这里好像没有发生变化,依然是让你订阅并告诉你没有有效订阅。 我们定位到/Applications/EmbyServer.app/Contents/Resources/dashboard-ui/embypremiere/embypremiere.js文件看一下,同样是暴力搜索这里不再赘述: 
我们注意到这里有一个IsMBSupporter, 这好像是一个非常关键的词。

也就是说,如果IsMBSupporter不为true,那么所有逻辑是不会往下走的。于是就显示出了“无效的订阅”字样,我们试着改一下: 
30行我们强制设置为true,并且下面伪造了一个http数据返回,让他正确读取到订阅信息。 我们保存,重新打开app看一下: 
还是一样 清空页面缓存强制刷新,点击保存按钮后可以看到直接就出现了付费版订阅。 至此,破解完毕,只需要修改一个js文件和一个dll文件中的js资源文件即可。 总结return ( appStorage.setItem( cacheKey, JSON.stringify({ lastValidDate: Date.now(), deviceId: params.deviceId, cacheExpirationDays: response.cacheExpirationDays, lastUpdated: Date.now(), }) ), Promise.resolve() );
return new Promise((resolve) => resolve({ deviceStatus: 0, planType: "超级会员", subscriptions: [ { autoRenew: true, store: "秋城落叶", feature: "all", planType: "超级会员", expDate: "且会员资格永远不会失效", }, ], }) );
完!
注:若转载请注明大神论坛来源(本贴地址)与作者信息。
下方隐藏内容为本帖所有文件或源码下载链接:
游客你好,如果您要查看本帖隐藏链接需要登录才能查看,
请先登录
|