最终实现的结果:
可以跳过闪屏+直播间广告,如果是免费的比赛,或者你是会员的话,可以提取直播间的超清直播URL(没试过蓝光画质),该URL可以复制到手机Safari或者电脑端播放。
实践总结:
1) 所有拉流直播链接都是服务器鉴权的;
2) 一个普通非会员账号,是可以蹭几场会员才能看的比赛的,但是因为腾讯体育的服务器对同个账号的拉流有IP数量限制和流量限制,所以一般说来,除非是免费的比赛,否则不要把链接扩散给别人,另外就是蹭了几场比赛后,你的账号拿到的拉流URL,将只能试看1分钟,之后被断流。腾讯体育支持微信和QQ登录,你也可以准备多个账号用来救急某些重要比赛,当然还是买会员支持正版比较直接啦;
3) 会员才能看的比赛,非会员也有一个方式可以看直播,清晰度一般但是勉强能看。还是买会员看蓝光画质美滋滋;
4) 直播间获取直播链接的接口前缀为:,后面会拼接很多的参数,其中一个key跟用户账号绑定,服务器用这个来做ip打击和流量控制,抓包请认准该接口,返回数据为json格式,未做二次加密。在腾讯体育APP里,这个请求是用NSURLConnection这个类发出去的,要hook的话也要hook这个类的网络请求,而不是NSURLSession。
以下是具体操作流程,大致分为越狱,砸壳,静态分析,动态分析,写hook函数这么几个过程。
需要准备的硬件工具:
越狱手机,Windows电脑和Mac电脑。
iOS9.3.3系统的越狱
PP助手的Mac版已经没有在维护了,用Windows最新版本的pp助手可以实现一键越狱。如果手机越狱完了,重启之后Cydia会闪退,解决方案:
手机Safari打开z.25pp.com然后选择越狱版页面,点击iOS9.3.x越狱激活,按照指示的去做就OK(此步骤网络必须要OK)。之后如果出现重启手机后Cydia闪退,按照上述步骤做一次即可打开Cydia。
注意:执行上述步骤时,请退出Mac上的pp助手。
dumpdecrypted砸壳
需要注意的点是,如果砸壳失败,很有可能是dumpdecrypted出了问题,比如更新Xcode后,默认的SDK可能会有更改,重新拉代码make生成dumpdecrypted.dylib一般可以解决。
砸壳后拷贝到电脑端的是类似QQSportsV3.decrypted这种文件,把文件后缀直接去掉,然后chmod 777修改文件的权限为可读可写可执行,然后就可以进行class-dump和拷贝到APP包里替换掉原来的二进制文件了。
静态分析
1) 使用class-dump把砸壳后的二进制导出头文件;
2) 利用monkeyDev把目标APP用Xcode跑起来,在你想要的页面用Xcode查看这个页面的view所属的类,然后通过nextResponder去找响应链可以找到对应页面的控制器或跟这个view相关联的类;
3) 用sublime打开所有头文件,找到你想要分析的类,观察其属性的函数接口,如果函数很多的话,找到目标函数需要花的时间跟运气直接相关,一般也可以通过一些搜索匹配关键字来过滤;
4)hooper或者IDA静态分析二进制文件,搜索定位到对应的类和函数,看其内部实现。
恢复符号表(OC+Block)
因为你已经知道一些基本的类和函数名了,Xcode跑起来后可以设置一些符号断点,进行调试和观察。此时需要先恢复符号表,才能看到断点后具体的堆栈调用回溯。
恢复符号表可以参考这篇文章
如果用monkeyDev创建的工程,OC的符号表恢复可以通过targets→beuild settings的最下面的User-define里设置MONKEYDEV_RESTORE_SYMBOL为YES,但是block符号需要手动去恢复。
需要注意的就是,在用Xcode查看调用堆栈是,Xcode左侧边栏可能仅显示1个或2个调用,NSThread的callStackSymbols函数可能会打印出一些字符串很奇怪的函数调用堆栈,这并不代表block符号恢复失败,这个情况,通常要用LLDB的bt指令去检查看下是否OK。
动态挂载分析
可以参考这里提供的函数调用打印辅助分析。其实就是使用了一个叫做HookZz的库。
动态分析主要是指不通过Xcode,而是通过终端来调试别人的APP,如果是自己的APP,或者自己证书签名的APP,则可以用monkeyDev直接在Xcode里跑起来;
动态分析主要用到了debugserver和LLDB,通常在这一步前先做静态分析,才能知道要打的断点的位置,动态分析通过打断点和读取、修改寄存器值的方式来调试APP,观察APP的行为。
具体过程可以直接参考《iOS应用逆向工程》书里的步骤,需要注意的一点就是,使用WiFi来连接是在是有点慢,所以用iproxy通过USB来调试是比较合适的。
brew install usbmuxd安装好后即可以使用iproxy,
要启动debugserver,需要先ssh到越狱手机上,然后执行:
<p><pre style="box-sizing: border-box;margin-top: 0px;margin-bottom: 0px;padding: 0px;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;background-color: rgb(255, 255, 255);"> <span class="hljs-selector-tag" style="box-sizing: border-box;font-size: inherit;color: rgb(248, 35, 117);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">debugserver</span> *<span class="hljs-selector-pseudo" style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">:1234</span> <span class="hljs-selector-tag" style="box-sizing: border-box;font-size: inherit;color: rgb(248, 35, 117);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">-a</span> <span class="hljs-selector-tag" style="box-sizing: border-box;font-size: inherit;color: rgb(248, 35, 117);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">WeChat</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre></p>
这个指令的意思是让手机的1234端口待命,准备接受LLDB的指令,-a表示启动后面微信的process ,同时这个APP会被卡住暂停执行,所以也不会响应用户的手势;
在电脑上执行iproxy 1234 1234实现端口转发;
在电脑端直接执行lldb会打开lldb调试器,然后执行
<p><pre style="box-sizing: border-box;margin-top: 0px;margin-bottom: 0px;padding: 0px;font-size: 16px;color: rgb(62, 62, 62);line-height: inherit;background-color: rgb(255, 255, 255);"> <span class="hljs-attribute" style="box-sizing: border-box;font-size: inherit;color: rgb(238, 220, 112);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">process</span> connect connect://localhost:1234<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;" />
</pre></p>
可以连接到手机上。如果不使用iproxy来做转发,则需要把localhost替换为手机的ip,同时手机要跟电脑处于同一个网段;
之后等待,当终端出现Process 867 stopped类似这种就说明连接成功了,执行c即可让APP继续运行。
连接过程中可能会出现类似ImportError: cannot import name _remove_dead_weakref的错误:
基本上不用理会,继续等就好了,使用USB来调试,大概等个十来秒就可以连接上,如果用WiFi,可能要等挺久的。
如果出现error: failed to get reply to handshake packet这个错误提示,可以尝试拔掉USB线重新连接,或者重启手机来解决,当然也有另一种尝试的方案,就是先连接下自己的证书签名的APP,然后再去连接App Store下载的APP。
使用LLDB的指令b adress或br s -a address可以对地址入口打个断点。
去除启动闪屏+直播间90秒广告
1) hookTADSplashManager的splashItemForItem函数返回nil,可以去掉闪屏广告;
2.hookTADVideoViewController的viewDidAppear函数,调用其skipAdPlay函数可以跳过直播间90秒广告。
这里讲一下去掉闪屏的分析方式:
1) 直接法,通过Xcode启动APP,从UI入手,找到对应的view和控制器(nextResponder响应链),然后hook相关的函数来实现修改其逻辑。 这个方式在《iOS应用逆向工程》里讲的很清楚;
2) 间接法,所有的闪屏基本都是APP打开后先发请求去获取闪屏配置信息,然后下载闪屏内容,之后等到下次启动,检查本地有闪屏则显示,无闪屏则直接进入主页面的逻辑,而闪屏的英文是splash,所以用这个关键字在class-dump出来的头文件去搜索,会得到很多很直接的信息,我就是这么试了一下就成功的。
3) 闪屏信息通过一个接口来获取,可以block掉这个接口。
另外关于闪屏的设计,其实发现腾讯体育和腾讯视频基本是一模一样,连类名和接口名都没变,可能是一个团队做的?
破解会员才能看直播的限制
客户端会根据当前登录用户的状态来判断是否可以试看,服务器的接口会返回一个直播的链接和链接可以播放的时效(300秒),可以测试下这个链接是否一直有效:
——接口会返回一个带鉴权key的直播URL,这个链接拉流时间收到服务器限制。
步骤
1) 把链接地址抓出来看看是否能在Safari上播放;——可以播放
2) hook一下客户端对播放时间的限制,去除该限制,看看是否可以一直播放下去。——不行,服务器鉴权。 |
|