某艺apk破解去广告详解

查看 98|回复 9
作者:jcode   
APK自取地址:
https://jcode.lanzoul.com/ijWdM0p40i4h
密码:78nd        
我也是2月底工作之余才开始接触逆向这个板块,缘由是因为梦幻西游有个记账本的工具软件,需要购买注册码,就跟着教程小试牛刀,破解过去了。
(E语言编写的工具包确实足够简单,比较容易破解)
        
    再到后来,开始想着看看手机软件相关的,接触到安卓逆向后,发现安卓源码也是Java写的,这不是我的本职工作吗,顿时兴趣就更大了。就开始入
坑,破解。
        
    回归正题,我们来讲一下iqiyi的主要破解去广告思路。
    ​   当我们拿到1个apk文件,第一件事是什么,不是安装apk,而是去看一下AndroidMainfest.xml文件中,了解一下大概有哪些Activity。
    ​   观察应用启动的Acitivity顺序(先从主入口切入Main)
    ​   从应用显示的关键环节的关键字全局搜索代码,找到切入点(关于该点,我后面做更多介绍)
    ​   定位到关键逻辑,进行代码修改。
      
    理想和现实总是处于对立面的,上面的思路针对破解一些简单的小软件是不成问题的,但是针对比较复杂的客户端/软件就显得不是那么回事了。我参
照上述方法,解决了首屏启动的广告加载问题,但是针对视频播放时长达30-90s的广告却是无能为力。针对于客户端软件常用的一些命名规则:XXXConfig-
配置类信息,XXXProxy-代{过}{滤}理工具类(很重要,尤其是Java)。在解决播放广告时,我第一时间想到的就是这个config类,通过查找,找到com.iqiyi
.video.qyplayersdk.model.QYPlayerADConfig这个配置类中有很多配置项,初次尝试通过修改部分项true/false,并未能成功。基于Java开发的本能,一
下子就想到了Proxy这个动态代{过}{滤}理的想法,再通过搜索,找到了com.iqiyi.video.qyplayersdk.player.QYMediaPlayerProxy这个类,初次进去这个
类,因为里面的方法很多,也没办法确定具体是哪个类去控制的广告,也是以失败告终。
      
    晚上下班回家之后,硬啃源码,通过登录会员账号/不登录的方式,把整个PlayerActivity的onCreate()的所有子方法都看了个遍,同时通过debug,对
比在某些节点,某些数据的差异。最终将入口定位在了QYMediaPlayerProxy类中的performBigCorePlayback(PlayData playData, PlayerInfo playerInfo,
String str)方法下的else分支中,会员/非会员/不登录走的是2个分支,大概这里的方法就是初始化一个广告id,如果是会员,那么该id=0,非会员,就会调
用后台接口,获取几个随机id(这也是大家为什么看的广告能更替的原因)。那么这里让非会员不去获取广告id,即为0就过去了。
  
  在本次破解过程中,也踩了不少坑,player相关的realPlay、doPlay、play等方法也看了个遍。针对本次的客户端破解尝试,做几点总计:
    针对复杂客户端,尽量不采用关键字搜索的方式去破解,因为复杂的客户端代码都是有设计思想的,具有结构化、配置化的特征的。尽量采用动态调试
的方法追踪调用链路。
        
    ​提高英文水平,比如player代表播放器、ad代表广告等,这样你在看混淆后的源码才有机会能猜到入口。
        
    ​先想再干,就拿这一次举例子,客户端的广告功能,肯定不是v1.0的时候就存在的,也是后期商业化过程中不断新增的功能,那么复杂化的代码肯定不
可能是通过简单的if/else就能搞定的,如果是这样,那么这个软件离倒闭也不远了。播放器的核心功能就是播放视频,这是他的核心功能,如果是初期有的
功能,可能是可以通过新增if/else解决的,但是,对于经过几个大版本间隔后的大功能,是不太可能的,那么这里就体现到了动态代{过}{滤}理的强大之处
了,它是用来干嘛的呢,简单理解就是在核心功能上,可以任意扩展别的功能。
        
    所以,想对于安卓逆向深挖的同学们,还是需要去学习一下Java基础,不然有些思路确实是很难想到的。--------------------------------------------------------------------------分割线,接上面,贴源码-----------------------------------------------------------------------------------------------------
​               
1.首屏广告的破解
package com.qiyi.video.speaker.activity;
import
    ...
/* loaded from: classes.dex */
public class PlayerActivity extends aux implements aux.con {
    /* JADX WARN: Can't fix incorrect switch cases order, some code will duplicate */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void handleVoiceMessage(VoiceMessageEvent voiceMessageEvent) {
                ...
           try {
                        ...
              // ad打头的基本都是广告相关的
              switch (msg.hashCode()) {
                                  case -1502088746:
                    if (msg.equals("ad_volume_resume")) {
                        c2 = 22;
                        break;
                    }
                    c2 = 65535;
                    break;
                                 case -1152274405:
                    if (msg.equals("ad_skip")) {
                        c2 = 19;
                        break;
                    }
                    c2 = 65535;
                    break;
              }
               // 这里观察发现 c2为0时,是属于正常播放的,所以这里修改办法为将上述c2都赋值为0,首屏广告就解决了
              switch (c2) {
                case 0:
                    play();
                    return;
                                ...
              }
    }
}
2.播放视频时的广告
package com.iqiyi.video.qyplayersdk.player;
import
    ...
/* loaded from: classes2.dex */
public class QYMediaPlayerProxy implements com.iqiyi.video.qyplayersdk.player.a.com1, com.iqiyi.video.qyplayersdk.player.a.com3, com.iqiyi.video.qyplayersdk.player.a.com5, com.iqiyi.video.qyplayersdk.player.a.con {
         ...
     //performBigCorePlayback 这个方法有3个,注意是三个参数的这个
     private void performBigCorePlayback(PlayData playData, PlayerInfo playerInfo, String str) {
        int i;
        com.iqiyi.video.qyplayersdk.f.con conVar = this.mDoPlayInterceptor;
        if (conVar != null && conVar.e(playerInfo)) {
            com.iqiyi.video.qyplayersdk.g.aux.d("PLAY_SDK", TAG, "DoPlayInterceptor is intercept!");
            lpt5 lpt5Var = this.mInvokerQYMediaPlayer;
            if (lpt5Var == null) {
                return;
            }
            lpt5Var.amX();
        } else if (this.mPlayerInfo == null) {
        } else {
            // 这里就是去除广告的核心,注意i这个参数
            org.qiyi.android.coreplayer.d.com7.beginSection("QYMediaPlayerProxy.performBigCorePlayback");
            if (com.iqiyi.video.qyplayersdk.player.data.b.nul.A(playerInfo) || playData == null) {
                // 会员账号登陆走的是这里
                i = 0;
            } else {
                // 非会员/不登陆走的是这里
                com.iqiyi.video.qyplayersdk.cupid.data.model.com9 a2 = com.iqiyi.video.qyplayersdk.cupid.util.con.a(playData, playerInfo, false, this.mPlayerRecordAdapter, 0);
                a2.eV(isIgnoreFetchLastTimeSave());
                // 它会去后台获取广告的id
                int generateCupidVvId = CupidAdUtils.generateCupidVvId(a2, playData.getPlayScene());     
                com.iqiyi.video.qyplayersdk.cupid.com4 com4Var = this.mAd;
                if (com4Var != null) {
                    com4Var.la(generateCupidVvId);
                }
                org.qiyi.android.coreplayer.d.aux.boe();
                // 最后把id赋值给了i,所以这里的破解核心就是更换条件不走else,或者在这里最后,强制把i的值赋成0
                i = generateCupidVvId;
            }
            com.iqiyi.video.qyplayersdk.core.data.model.com1 a3 = com.iqiyi.video.qyplayersdk.core.data.a.aux.a(this.mSigt, i, playData, playerInfo, str, this.mControlConfig);
            com.iqiyi.video.qyplayersdk.g.aux.d("PLAY_SDK", TAG, " performBigCorePlayback QYPlayerMovie=", a3);
            this.mPlayerInfo = new PlayerInfo.Builder().copyFrom(playerInfo).extraInfo(new PlayerExtraInfo.Builder().copyFrom(playerInfo.getExtraInfo()).sigt(a3.getSigt()).build()).build();
            notifyPlayerInfoChanged();
            if (!isNeedNetworkInterceptor(playerInfo)) {
                if (playData == null || (TextUtils.isEmpty(playData.getPlayAddress()) && (TextUtils.isEmpty(playData.getTvId()) || "0".equals(playData.getTvId())))) {
                    PlayerExceptionTools.report(0, 0.1f, "1", com.iqiyi.video.qyplayersdk.player.data.b.con.i(playData));
                }
                com.iqiyi.video.qyplayersdk.core.com1 com1Var = this.mPlayerCore;
                if (com1Var != null) {
                    com1Var.setVideoPath(a3);
                    this.mPlayerCore.ahF();
                }
            }
            org.qiyi.android.coreplayer.d.com7.endSection();
        }
    }
}

               

广告, 功能

无缝壁布_墙纸_   

感谢分享,下载备用!

[color=]            
   macOS High Sierra 【版本 10.13.6 ◆
iMac (21.5-inch, Mid 2010

  iMac (21.5-inch, Mid 2010)【处理器 3.2 GHz Intel Core i3  内存 8 GB 1333 MHz DDR3 图形卡 AMD Radeon HD 6450 512 MB]  】
  Intel(R)Core(TM)CPU【I3-550ks @ 3.2 GHz】
18285413047   

欢迎大佬们交流指正。
jcode
OP
  

建议帖子格式在搭配MD修改下,逆向过程附图片效果会更好了。
jcode
OP
  


GenW 发表于 2023-3-2 18:27
建议帖子格式在搭配MD修改下,逆向过程附图片效果会更好了。

感谢指正,下班回家后编辑一下
莫问刀   

面向切面编程是吧,以后想在哪里加广告直接切进去就行了,原方法都不带改的
guibin   

感谢给出了关键函数,但是重要的寻找过程没有,哈哈
JohnDragon   

喜欢这样的资源,多谢多谢
byyyya   

直接K掉这个视频平台  那个广告确实太恶心了
byyyya   

非常好的资源~~感谢分享~~
您需要登录后才可以回帖 登录 | 立即注册

返回顶部