首页
社区
课程
招聘
[原创]某在线视频播放器之去广告分析
发表于: 2014-9-1 22:23 2424

[原创]某在线视频播放器之去广告分析

2014-9-1 22:23
2424
在看雪混了这么久,第一次发个帖子,技术不够,分析不到位,还望海涵。
最近忙着开学适宜瞎折腾–这两天Zero忙着视频去广告,话说广告越来越泛滥了,有的视频开通广告都超过60s了。某个视频站点的他去掉了,但是有个一直没搞定。让我帮他看看。

源码是他给我的,我没有swf反编译器。

大概看了下结构,ActionScript我没有学过。他说跟Java差不多,我也就懒得看基本语法了,直接上。先看下主文件Player.as的头吧,看看有哪些引用。
    import com.iqiyi.components.global.*;
    import com.iqiyi.components.tooltip.*;
    import com.qiyi.player.base.pub.*;
    import com.qiyi.player.base.uuid.*;
    import com.qiyi.player.core.*;
    import com.qiyi.player.core.model.def.*;
    import com.qiyi.player.core.model.utils.*;
    import com.qiyi.player.wonder.*;
    import com.qiyi.player.wonder.body.view.*;
    import com.qiyi.player.wonder.common.config.*;
    import com.qiyi.player.wonder.common.lso.*;
    import com.qiyi.player.wonder.common.pingback.*;
    import com.qiyi.player.wonder.common.sw.*;
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.system.*;
    import flash.utils.*;

看名知意,com.qiyi.player.wonder.common.config.*;引起我的注意–看看配置信息吧。两个文件FlashVarConfig.as与SystemConfig.as。SystemConfig.as没发现什么起眼的东西,但是FlashVarConfig.as中引用的xml配置文件值得研究。
package com.qiyi.player.wonder.common.config
{

    public class FlashVarConfig extends Object
    {
        public static const OWNER_PAGE:String = "page";
        public static const OWNER_CLIENT:String = "client";
        public static const OS_XP:String = "xp";
        public static const OS_WIN7:String = "win7";
        public static const OS_WIN8:String = "win8";
        public static const PAGE_OPEN_SRC_NONE:String = "0";
        public static const PAGE_OPEN_SRC_DIRECT:String = "1";
        public static const PAGE_OPEN_SRC_OTHER:String = "2";
        private static var _flashVarSource:Object;
        private static var _albumId:String = "";
        private static var _tvid:String = "0";
        private static var _vid:String = "";
        private static var _autoPlay:Boolean = true;
        private static var _isMemberMovie:Boolean = false;
        private static var _cyclePlay:Boolean = false;
        private static var _components:String = "fefff7e6";
        private static var _cupId:String = "";
        private static var _shareStartTime:int = -1;
        private static var _shareEndTime:int = -1;
        private static var _preloaderURL:String = "http://dispatcher.video.qiyi.com/dispn/player/preloader.swf";
        private static var _preloaderVipURL:String = "";
        private static var _exclusivePreloader:String = "";
        private static var _useGPU:Boolean = true;
        private static var _showBrand:Boolean = true;
        private static var _expandState:Boolean = false;
        private static var _tipDataURL:String = "http://static.qiyi.com/ext/tips/tipdata.xml";
        private static var _coop:String = "";
        private static var _owner:String = "page";
        private static var _os:String = "win7";
        private static var _adPlayerURL:String = "";
        private static var _origin:String = "";
        private static var _passportID:String = "";
        private static var _playListID:String = "";

在31行里,这个配置文件有这样一段话。并且在35行的广告播放地址也引起我的注意,稍后在分析。先看配置文件。
</item>
<!-- 正在为您播放片中广告, 可选择是否要跳过, 类别是1, 持续时间是8秒 -->
<!-- 限制条件是:  不是正在登录中的会员 -->
<!-- 每天每人次只最多显示两次这个tips -->
<item id="ToSelectWhetherToSkipPlayingMiddleAD" level="1" duration="-1" type="1">
<conditions>
<fields>
<field name="member" operator="eq" value="false"/>
</fields>
<frequency count="2">
<restrain name="day"/>
<restrain name="user"/>
</frequency>
</conditions>
<list>
<message>
<![CDATA[
正在为您播放片中广告, <a href="event:ASEvent(skipAD)"><b><u>跳过广告</u></b></a>
]]>
</message>
</list>
</item>
<!-- 提示即将跳过8秒后会显示的剧中广告, 类别是1, 持续时间是8秒 -->
<!-- 必须是登录的会员 -->
<item id="ToCancelSkipNextMiddleAD" level="1" duration="8" type="1">
<conditions>
<fields>
<field name="member" operator="eq" value="true"/>
</fields>
<frequency count="1">
<restrain name="day"/>
<restrain name="user"/>
</frequency>
</conditions>
<list>
<message>
<![CDATA[
即将为您跳过片中广告,<a href="event:ASEvent(cancelSkipAD)"><u>不再跳过</u></a>
]]>
</message>
</list>
</item>
<!--
提示版权下线, 如果还有小于7天的时间下线, 每天一个专辑一台电脑提醒一次, 类别是1, 从起始60秒开始显示, 持续时间是10秒
-->
<!-- 因为优先级很高, 前面的最高优先级是10, 所以这里把level设为11. -->
<!-- 这个tip是由signal发起的. Shawn.X  -->
<!--
《<span>#keyword#</span>》 将于  <span>#expiredTime#</span> 版权到期.
-->
<item id="NoticeThisCopyrightWillExpire" level="11" duration="10" type="1">
<conditions>

说是剧中广告,8s时间,也就是说我将其本地化,然后劫持浏览器就可以实现去广告,但是很明显,这个不是视频加载前的广告。继续翻—很枯燥的过程。

查找get adPlayerURL()  是谁调用的,向上寻找。在com\qiyi\player\wonder\plugins\ad下发现,广告播放器是以插件形式存在的,也就是还有调用,向上找,找到在com\qiyi\cupid\adplayer\CupidAdPlayer.as处CupidAdPlayer进行初始化。并且该类做了混淆处理,很可疑。
public function CupidAdPlayer(param1:CupidParam)
        {
            this.PLAYER_TIMEOUT_LENGTHS = new Array(10000, 15000);
            Log.info("init, version=" + VERSION + ", " + param1.toString());
            this._videoPlayerVersion = param1.videoPlayerVersion;
            this._videoId = param1.videoId;
            this._tvId = param1.tvId;
            this._channelId = param1.channelId;
            this._collectionId = param1.collectionId;
            this._playerId = param1.playerId;
            this._albumId = param1.albumId;
            this._userId = param1.userId;
            this._webEventId = param1.webEventId;
            this._videoEventId = param1.videoEventId;
            this._vipRight = param1.vipRight;
            this._terminal = param1.terminal;
            this._duration = param1.duration;
            this._passportId = param1.passportId;
            this._passportCookie = param1.passportCookie;
            this._passportKey = param1.passportKey;
            this._videoDefinitionId = param1.videoDefinitionId;
            if (this.isQiyiWebEx())
            {
                this._playerUrl = this.IQIYI_WEBEX_AM_URL;
            }
            else if (param1.playerUrl)
            {
                this._playerUrl = param1.playerUrl;
            }
            else
            {
                this._playerUrl = this.IQIYI_WEB_AM_URL;
            }
            if (param1.dispatcher == null)
            {
                this._dispatcher = this;
            }
            else
            {
                this._dispatcher = param1.dispatcher;
            }
            this._volume = param1.volume;
            this._videoIndex = param1.videoIndex;
            this._stageWidth = param1.stageWidth;
            this._stageHeight = param1.stageHeight;
            this._displayContainer = param1.adContainer;
            this._screenStatus = DisplayProperties.isFullScreen(this._displayContainer.stage) ? ("1") : ("0");
            this._baiduMainVideo = param1.baiduMainVideo;
            this._disablePreroll = param1.disablePreroll;
            this._disableSkipAd = param1.disableSkipAd;
            this._enableVideoCore = param1.enableVideoCore;
            this._isUGC = param1.isUGC;
            this._videoPlayerUrl = this._displayContainer.loaderInfo ? (this._displayContainer.loaderInfo.loaderURL) : ("");
            this._env = this.generateEnv();
            this.addAdPlayerEventListeners();
            return;
        }// end function

CupidAdPlayer(param1:CupidParam) <–看其调用参数,也就是上层还有在调用,其中参数一中的,一个值很引人注意,vipRight 判断是否为vip,而vip就不存在广告了,也就是说如果我在其播放器获取网站的session里的用户信息之后,在判断是否为vip的地方作出修改,导致下层被调用的时候,被误以为是vip(仅仅广告播放器认为你是vip,而其他地方不受影响)。那我们就继续向上找起吧。找着找着又回去了,又回到广告插件的目录了。com\qiyi\player\wonder\plugins\ad\view里的ADView.as,头部先是
private var _adPlayer:CupidAdPlayer;

定义了一次名为_adPlayer的CupidAdPlayer的实例,向下翻查,谁使用了_adPlayer。竟然找到了广告播放器的创建函数。
public function createAdPlayer(param1:CupidParam) : void
        {
            if (this._adPlayer)
            {
                this.unloadAdPlayer();
            }
            this._log.info("loading adplayer...");
            this._adPlayer = new CupidAdPlayer(param1);
            this._adPlayer.addEventListener(AdPlayerEvent.ADPLAYER_LOADING_SUCCESS, this.onAdLoadSuccess);
            this._adPlayer.addEventListener(AdPlayerEvent.ADPLAYER_LOADING_FAILURE, this.onAdLoadFailed);
            this._adPlayer.addEventListener(AdPlayerEvent.ADPLAYER_AD_START, this.onAdStartPlay);
            this._adPlayer.addEventListener(AdPlayerEvent.CONTROL_VIDEO_PAUSE, this.onAdAskVideoPause);
            this._adPlayer.addEventListener(AdPlayerEvent.CONTROL_VIDEO_RESUME, this.onAdAskVideoResume);
            this._adPlayer.addEventListener(AdPlayerEvent.CONTROL_VIDEO_START_LOADING, this.onAdAskVideoStartLoad);
            this._adPlayer.addEventListener(AdPlayerEvent.CONTROL_VIDEO_START, this.onAdAskVideoStartPlay);
            this._adPlayer.addEventListener(AdPlayerEvent.CONTROL_VIDEO_END, this.onAdAskVideoEnd);
            this._adPlayer.addEventListener(AdPlayerEvent.ADPLAYER_AD_BLOCK, this.onAdBlock);
            this._adPlayer.addEventListener(AdPlayerEvent.CONTROL_VIDEO_DISPLAY_AD_TIP, this.onAskVideoShowBonusTips);
            this._adPlayer.addEventListener(AdPlayerEvent.ADPLAYER_AD_VIDEO, this.onAdFlvADAction);
            this._adPlayer.load();
            return;
        }// end function

看到还可以参数传递,说明还有在调用。终于在com\qiyi\player\wonder\plugins\ad\view下的ADViewMediator.as找到了源头。他的函数最终调用是这样的
private function createADPlayer() : void
        {
            sendNotification(BodyDef.NOTIFIC_PLAYER_STOP_LOAD);
            ProcessesTimeRecord.STime_adInit = getTimer();
            var _loc_1:* = facade.retrieveProxy(PlayerProxy.NAME) as PlayerProxy;
            var _loc_2:* = facade.retrieveProxy(UserProxy.NAME) as UserProxy;
            var _loc_3:* = new CupidParam();
            _loc_3.playerUrl = FlashVarConfig.adPlayerURL;
            _loc_3.videoId = _loc_1.curActor.loadMovieParams.vid;
            _loc_3.tvId = _loc_1.curActor.loadMovieParams.tvid;
            _loc_3.channelId = _loc_1.curActor.movieModel.channelID;
            _loc_3.playerId = FlashVarConfig.cupId;
            _loc_3.albumId = _loc_1.curActor.movieModel.albumId;
            _loc_3.dispatcher = null;
            _loc_3.adContainer = this._ADView;
            _loc_3.stageWidth = GlobalStage.stage.stageWidth;
            _loc_3.stageHeight = GlobalStage.stage.stageHeight;
            _loc_3.userId = _loc_1.curActor.uuid;
            _loc_3.webEventId = UUIDManager.instance.getWebEventID();
            _loc_3.videoEventId = UUIDManager.instance.getVideoEventID();
            _loc_3.vipRight = _loc_2.userLevel != UserDef.USER_LEVEL_NORMAL ? ("1") : ("0");
            _loc_3.terminal = "iqiyiw";
            _loc_3.duration = _loc_1.curActor.movieModel.duration / 1000;
            _loc_3.passportId = _loc_2.passportID;
            _loc_3.passportCookie = _loc_2.P00001;
            _loc_3.passportKey = KeyUtils.getPassportKey(0);
            _loc_3.enableVideoCore = true;
            _loc_3.disableSkipAd = _loc_1.curActor.movieModel.forceAD;
            _loc_3.volume = Settings.instance.mute ? (0) : (Settings.instance.volumn);
            _loc_3.isUGC = UGCUtils.isUGC(_loc_1.curActor.movieModel.tvid);
            _loc_3.collectionId = FlashVarConfig.collectionID;
            _loc_3.videoDefinitionId = _loc_1.curActor.movieModel.curDefinitionInfo.type.id;
            _loc_3.videoPlayerVersion = WonderVersion.VERSION_WONDER;
            this._ADView.createAdPlayer(_loc_3);
            return;
        }// end function

_loc_3.vipRight = _loc_2.userLevel != UserDef.USER_LEVEL_NORMAL ? ("1") : ("0");

这句,判断是用户是否为vip,首先根据局部变量loc_2判断用户的级别,如果与定义的vip级别相符,就返回1。我们给他稍作修改,就成了伪vip了。
_loc_3.vipRight = _loc_2.userLevel != UserDef.USER_LEVEL_NORMAL ? ("1") : ("1");

这样在Hex里修改下就行了,测试广告成功去掉(利用Chrome的插件功能,修改播放器地址为本地的,播放参数原样传递)。

另外在com\qiyi\cupid\adplayer\model下的AdBlockedBlackScreen.as有一个本地检测函数,禁止Chrome的插件屏蔽。
 public static function isInBlacklist(param1:String) : Boolean
        {
            if (!param1)
            {
                return false;
            }
            if (StringUtils.beginsWith(param1, "chrome-extension://"))
            {
                return true;
            }
            var _loc_2:* = new URLParser(param1);
            var _loc_3:* = _loc_2.getHost();
            return HOST_BLACKLIST.indexOf(_loc_3) != -1;
        }// end function

把第二个if 的return改为false就行了。

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 1
支持
分享
最新回复 (10)
雪    币: 60
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
# 前 留名。
2014-9-1 22:46
0
雪    币: 1392
活跃值: (4867)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
3
iqiyi youku 这些播放器最多就是混淆类名,函数名。处理还是挺简单的。楼主可以试试土豆的,看看如何
2014-9-2 09:21
0
雪    币: 3343
活跃值: (1243)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
土豆有广告?还真没注意--看火影的时候没见啊。

看到你的土X的帖子了 学习
2014-9-2 09:42
0
雪    币: 53
活跃值: (734)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
不错 感谢分享
2014-9-2 11:33
0
雪    币: 341
活跃值: (138)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
7月有个手机号码不要了,开了个qiyiVIP。。。就欠费了,然后现在依旧VIP。。。。。
2014-9-2 12:15
0
雪    币: 69
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
7
可以分析下sohu的, 加密了. 有点挑战. 这些东西,研究一下去广告的规则,很快就找出来了.
2014-9-2 14:54
0
雪    币: 3343
活跃值: (1243)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
8
搜狐的已经搞定了,只是没写总结。
2014-9-2 18:02
0
雪    币: 3343
活跃值: (1243)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
9
貌似以前卡过QQ会员-- 现在还有这种用途么。。。。
2014-9-2 18:04
0
雪    币: 68
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
不明角力啊!
2014-9-2 19:09
0
雪    币: 61
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
谢谢分享
2014-9-2 20:02
0
游客
登录 | 注册 方可回帖
返回
//