吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 340|回复: 0
上一主题 下一主题
收起左侧

[Android 原创] 某网站视频接口漏洞分析

[复制链接]
跳转到指定楼层
楼主
xww2652008969 发表于 2026-3-8 01:49 回帖奖励

1.前言

之前在百度发现某网站aHR0cHM6Ly93d3cuYmlsaWJpbGkuY29tLw== android有个版本不需要vip可以使用观看高画质,然后想看看是谁家高人破解的,也没有源代码,就自己分析了

2.逆向工具

frida jadx

3.逆向记录

3.1 旧版抓包

通过抓包发现接口playurl.v1.PlayURL/PlayView返回数据是二进制,然后二进制查看一下又

有明显的视频流,很奇怪就hook 解码了,直接hook okhttp的构建请求函数,然后查看调用就发现app.playurl.v1.PlayURLMoss.executePlayView()方法,返回结构体很蒙圈,然后问下ai说是grpc的, 百度了一下服务器是rpc结构体,然后github上刚好找到proto文件,

3.2 新版抓包

通过上面方法找到接口app.playerunite.v1.Player/PlayViewUnite 也找到proto文件(后面也会逆向出文件了)

3.3 分析逻辑

playurl.v1.PlayURL/PlayView多次测试发现这个接口不会验证vip信息直接返回高画质视频流

直接上逻辑代码吧  playViewRequest PlayViewReply proto编译的 (备注:我需要c#做机器人然后c#grpc把我弄炸了直接模拟http吧)

    private static async Task<Dictionary<long, string>?> RequestPlayView(long aid, long cid)
    {
        var playViewUnitedata = new Dictionary<long, string>();
        var playViewRequest = new PlayViewReq
        {
            Aid = aid,
            Cid = cid,
            Qn = 125,
            Fnver = 0,
            Fnval = 4048,     
            Download = 2,
            ForceHost = 0,
            Fourk = false,
            Spmid = "main.ugc-video-detail.0.0",
            FromSpmid = "tm.recommend.0.0",
            TeenagersMode = 0,
            PreferCodecType = CodeType.Code265,
            Business = Business.Unknown,
            VoiceBalance = 1
        };

        var requestData = playViewRequest.ToByteArray();
        var requestLength = BitConverter.GetBytes(requestData.Length);
        Array.Reverse(requestLength);

        var grpcPayload = new byte[1].Concat(requestLength).Concat(requestData).ToArray();

        var request = new HttpRequestMessage(HttpMethod.Post,
            "https://app.bilibili.com/bilibili.app.playurl.v1.PlayURL/PlayView");
        AddGrpcHeaders(request);

        request.Content = new StreamContent(new MemoryStream(grpcPayload));
        request.Content.Headers.Add("Content-Type", "application/grpc");
        var res = await Client.SendAsync(request);
        try
        {
            var resdata = await res.Content.ReadAsByteArrayAsync();
            var viewReply = PlayViewReply.Parser.ParseFrom(resdata.AsSpan(5));
            foreach (var video in viewReply.VideoInfo.StreamList)
            {
                Console.WriteLine(video.StreamInfo.Quality);
                if (video.DashVideo != null)
                    playViewUnitedata.TryAdd(video.StreamInfo.Quality, video.DashVideo.BaseUrl);
            }

            if (playViewUnitedata.Count <= 0) return null;
            playViewUnitedata.TryAdd(0, viewReply.VideoInfo.DashAudio[0].BaseUrl);
            return playViewUnitedata;
        }
        catch (Exception e)
        {
            Console.WriteLine("解析失败");
            return null;
        }
    }

4 机器人很麻烦 有没有更简单的

有的有的, 直接hook 写xp模块

代码很乱我就用frida的了


Java.perform(function () {
    var PlayerMoss = Java.use("com.bapis.bilibili.app.playerunite.v1.PlayerMoss");
    var PlayViewReq = Java.use("com.bapis.bilibili.app.playurl.v1.PlayViewReq");
    var PlayURLMoss = Java.use("com.bapis.bilibili.app.playurl.v1.PlayURLMoss");
    var CodeType = Java.use("com.bapis.bilibili.app.playurl.v1.CodeType");

    var PlayersharedStream = Java.use("com.bapis.bilibili.playershared.Stream");
    var PlayersharedStreamInfo = Java.use("com.bapis.bilibili.playershared.StreamInfo");
    var PlayersharedDashVideo = Java.use("com.bapis.bilibili.playershared.DashVideo");
    var PlayersharedDashItem = Java.use("com.bapis.bilibili.playershared.DashItem");

    PlayerMoss.executePlayViewUnite.implementation = function (req) {

        var vod = req.vod_.value;
        var aid = vod.aid_.value;
        var cid = vod.cid_.value;

        var builder = PlayViewReq.newBuilder();
        builder.setAid(aid);
        builder.setCid(cid);
        builder.setQn(125);
        builder.setFnver(0);
        builder.setFnval(4048);
        builder.setDownload(0);
        builder.setForceHost(0);
        builder.setSpmid("main.ugc-video-detail.0.0");
        builder.setFromSpmid("tm.recommend.0.0");
        builder.setTeenagersMode(0);
        builder.setVoiceBalance(0);

        var codec = CodeType.valueOf("CODE265");
        builder.setPreferCodecType(codec);

        var playViewReq = builder.build();

        var moss = PlayURLMoss.$new("IGNORED", 443, null, 4, null);
        var PlayViewreply = moss.executePlayView(playViewReq).getVideoInfo();

        var result = this.executePlayViewUnite(req);
        result.getVodInfo().clearStreamList();

        var playurllistsize = PlayViewreply.getStreamListCount();

        for (var i = 0; i < playurllistsize; i++) {

            var oldStream = PlayViewreply.getStreamList(i);
            var oldInfo = oldStream.getStreamInfo();
            var oldDash = oldStream.getDashVideo();

            // ===== Stream Builder(基于原始 stream)=====
            var newstr = PlayersharedStream.newBuilder();

            // ===== StreamInfo Builder =====
            var newinfo = PlayersharedStreamInfo.newBuilder();

            newinfo.setAttribute(0);
            newinfo.setQuality(oldInfo.getQuality());
            newinfo.setFormat(oldInfo.getFormat());
            newinfo.setDescription(oldInfo.getDescription());
            newinfo.setErrCodeValue(0);
            newinfo.setNeedVip(false);
            newinfo.setNeedLogin(false);
            newinfo.setIntact(true);
            newinfo.setNoRexcode(oldInfo.getNoRexcode());
            newinfo.setNewDescription(oldInfo.getNewDescription());
            newinfo.setDisplayDesc(oldInfo.getDisplayDesc());
            newinfo.setSuperscript(oldInfo.getSuperscript());
            newinfo.setVipFree(false);
            newinfo.setSubtitle(oldInfo.getSubtitle());
            newinfo.setSupportDrm(oldInfo.getSupportDrm());

            // ===== DashVideo Builder =====
            var newDashVideo = PlayersharedDashVideo.newBuilder();

            newDashVideo.setBaseUrl(oldDash.getBaseUrl());
            newDashVideo.setBandwidth(oldDash.getBandwidth());
            newDashVideo.setCodecid(oldDash.getCodecid());
            newDashVideo.setMd5(oldDash.getMd5());
            newDashVideo.setSize(oldDash.getSize());
            newDashVideo.setAudioId(oldDash.getAudioId());
            newDashVideo.setNoRexcode(oldDash.getNoRexcode());
            newDashVideo.setFrameRate(oldDash.getFrameRate());
            newDashVideo.setWidth(oldDash.getWidth());
            newDashVideo.setHeight(oldDash.getHeight());
            newDashVideo.setWidevinePssh(oldDash.getWidevinePssh());

            // ===== 写回 Stream =====
            newstr.setStreamInfo(newinfo.build());
            newstr.setDashVideo(newDashVideo.build());

            result.getVodInfo().addStreamList(newstr.build());
        }

        // ===== DashAudio(DashItem)=====
        for (var i = 0; i < PlayViewreply.getDashAudioCount(); i++) {
            var oldDash = PlayViewreply.getDashAudio(i);
            var newDash = PlayersharedDashItem.newBuilder();

            newDash.setId(oldDash.getId());
            newDash.setBaseUrl(oldDash.getBaseUrl());
            newDash.setBandwidth(oldDash.getBandwidth());
            newDash.setCodecid(oldDash.getCodecid());
            newDash.setMd5(oldDash.getMd5());
            newDash.setSize(oldDash.getSize());
            newDash.setFrameRate(oldDash.getFrameRate());
            newDash.setWidevinePssh(oldDash.getWidevinePssh());

            result.getVodInfo().addDashAudio(newDash.build());
        }

        console.log(result.getVodInfo());
        return result;
    };
});

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
zhoushengzhi + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-3-10 02:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表