吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5791|回复: 59
收起左侧

[Web逆向] 某视频解析网址加密接口分析

  [复制链接]
wanxu 发表于 2024-1-29 13:40
本帖最后由 wanxu 于 2024-1-29 13:54 编辑

之前分享过一次帖子,是扣JS的方法来请求接口
希望各位食客给个关注,加个评论来点更新的动力

这次直接使用C#实现了他的算法,然后在分享一下他的接口时怎么请求以及解密的
用到的工具就是Fiddler和浏览器控制台,然后写了一个C#版本的软件(随手写的有BUG哈哈)
正文开始
地址是:aHR0cHM6Ly9qeC54bWZsdi5jb20v

首先打开FD,然后打开控制台抓一下包,挨个分析
image.png
这里有这样一个请求,他的请求参数有我们想看的视频并且响应是加密的
image.png
我们先分析他的请求,可以看到有个key是加密的,去控制台打一个XHR断点
image.png
可以看到成功断住,我们根据这个断点往上找加密的地方
image.png
往上找到这里的时候可以看到key=lllIIlIl,lllIIlIl=sign
先分析sign中的几个参数与结果
I111ill=时间戳,url=编码后的想看的视频的地址
image.png
可以看到时间戳拼接视频地址,然后取MD5
这个时候我们去sign中看他的逻辑即可
鼠标悬停进VM虚拟机里看sign代码
image.png
image.png
是一个AES加密的,然后传过来MD5的结果
就是KEY参数的值
这个时候可以模拟请求拿到对应的响应
结果中有两个参数是加密的,分别是url和html
我们看到同时他的响应中有一个AES_KEY和AES_IV
大胆设想他是AES加密并且同时返回key和iv
image.png
image.png
一个是url,一个是html,
这个url会返回真实视频地址,两种情况一个是301,一个是直接的视频地址
html是全集和剧的详细信息
C#的代码贴在下方,diamagnetic比较烂只是能用,没有具体优化,各位佬可以根据自己需求在优化
现在他有时候接口返回的响应有一些剧的他自己网站也播放不出来,一直卡着转圈,所以软件也没办法下载,具体哪些能下哪些不能下需要自己测试了


[C#] 纯文本查看 复制代码
using Newtonsoft.Json;
using System;
using System.IO;
using System.IO.Pipes;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace xmflv
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Hello, World!");


            Console.Write("请输入视频URL(支持腾讯视频,爱奇艺):");
            string fromUrl = Console.ReadLine();
            if (string.IsNullOrEmpty(fromUrl))
            {
                Console.WriteLine("输入url为空!");
                Console.ReadLine();
            }

            fromUrl = EncodeUrl(fromUrl);
            //Console.WriteLine(fromUrl);
            //时间戳
            long timeStamp = GenerateTimestamp();
            //Console.WriteLine(timeStamp);
            //时间戳+URL的MD5
            string plaintext = CalculateMD5Hash($"{timeStamp}{UrlDecode(fromUrl)}");
            //Console.WriteLine(plaintext);
            //请求中的key参数
            string ciphertext = Sign(plaintext);
            //Console.WriteLine(ciphertext);
            HttpHelper http = new HttpHelper();
            HttpItem item = new HttpItem()
            {
                URL = "接口地址的url",
                Method = "POST",
                Accept = "application/json, text/javascript, */*; q=0.01",
                ContentType = "application/x-www-form-urlencoded; charset=UTF-8",
                UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
                Postdata = $"wap=1&url={fromUrl}&time={timeStamp}&key={EncodeKey(ciphertext)}",
                //ProxyIp = "127.0.0.1:8888"
            };
            item.Header.Add("Origin", "地址自己抓一下");
            HttpResult result = http.GetHtml(item);
            if (result.StatusCode != System.Net.HttpStatusCode.OK)
            {
                Console.Write("请求失败!");
            }
            else
            {
                string html = result.Html;
                //Console.WriteLine(html);
                var resultDynamic = JsonConvert.DeserializeObject<dynamic>(html);
                if (!string.IsNullOrEmpty(html) && (int)resultDynamic.code == 200)
                {
                    //解密后的视频地址集合
                    var extm3u = DecryptAES((string)resultDynamic.url, (string)resultDynamic.aes_key, (string)resultDynamic.aes_iv);
                    //Console.WriteLine(extm3u);

                    //取得全集链接
                    var AllUrl = ExtractURLs(DecryptAES((string)resultDynamic.html, (string)resultDynamic.aes_key, (string)resultDynamic.aes_iv));

                    item = new HttpItem()
                    {
                        URL = RemoveSpecialCharacters(extm3u),
                        Method = "GET",
                        UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
                        Accept = "*/*",
                        //ProxyIp = "127.0.0.1:8888"
                    };
                    item.Header.Add("Origin", "地址自己抓一下");
                    result = http.GetHtml(item);
                    if (result.StatusCode == System.Net.HttpStatusCode.OK && !string.IsNullOrEmpty(result.Html))
                    {
                        html = result.Html;
                        //Console.WriteLine(html);
                        string[] lines = html.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
                        string folderPath = AppDomain.CurrentDomain.BaseDirectory + $"{resultDynamic.name}";
                        int i = 0;
                        foreach (string line in lines)
                        {
                            if (!line.StartsWith("#"))
                            {

                                //文件夹不存在则创建文件夹
                                if (!Directory.Exists(folderPath))
                                {
                                    Directory.CreateDirectory(folderPath);
                                }

                                string fileName = $"{i}.ts";
                                string filePath = Path.Combine(folderPath, fileName);

                                if (!File.Exists(filePath))
                                {
                                    bool bl = true;
                                    int j = 0;
                                    while (bl)
                                    {
                                        try
                                        {
                                            //WebProxy webProxy = new WebProxy("127.0.0.1", 8888);
                                            using (HttpClient client = new HttpClient())
                                            {
                                                if (extm3u.Contains("IP地址包含就用这个"))
                                                {
                                                    //先获取重定向的url
                                                    item = new HttpItem()
                                                    {
                                                        URL = "https://服务器地址自己抓一下/" + line,
                                                        Method = "GET",
                                                        UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
                                                        Accept = "*/*",
                                                        //ProxyIp = "127.0.0.1:8888"
                                                    };
                                                    item.Header.Add("Origin", "地址自己抓一下");
                                                    result = http.GetHtml(item);
                                                    var location = result.RedirectUrl;

                                                    using (HttpResponseMessage response = await client.GetAsync(location))
                                                    {
                                                        response.EnsureSuccessStatusCode();

                                                        using (Stream stream = await response.Content.ReadAsStreamAsync())
                                                        {
                                                            using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                                                            {
                                                                await stream.CopyToAsync(fileStream); // 将响应流保存到本地文件
                                                                bl = false;
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    //client.Timeout = TimeSpan.FromSeconds(120); // 设置超时时间为 120 秒
                                                    //HttpClient.DefaultProxy = webProxy;
                                                    //client.DefaultRequestHeaders.Add("origin", "地址自己抓一下");
                                                    string pattern = @"/([^/]+)$";
                                                    string match = Regex.Replace(extm3u, pattern, "");
                                                    string mp4Url = match + "/" + line;

                                                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(mp4Url);
                                                    request.Method = "GET";
                                                    request.Headers.Add("sec-ch-ua", "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Microsoft Edge\";v=\"120\"");
                                                    request.Headers.Add("sec-ch-ua-mobile", "?0");
                                                    request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0";
                                                    request.Headers.Add("sec-ch-ua-platform", "\"Windows\"");
                                                    request.Accept = "/";
                                                    request.Headers.Add("Origin", "地址自己抓一下");
                                                    request.Headers.Add("Sec-Fetch-Site", "cross-site");
                                                    request.Headers.Add("Sec-Fetch-Mode", "cors");
                                                    request.Headers.Add("Sec-Fetch-Dest", "empty");
                                                    request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
                                                    request.Headers.Add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
                                                    try
                                                    {
                                                        // Send the request and get the response
                                                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                                                        // Read the response content
                                                        using (var stream = response.GetResponseStream())
                                                        {
                                                            using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                                                            {
                                                                await stream.CopyToAsync(fileStream); // 将响应流保存到本地文件
                                                                bl = false;
                                                            }

                                                            response.Close();
                                                            break;
                                                        }
                                                    }
                                                    catch (WebException ex)
                                                    {
                                                        Console.WriteLine("An error occurred: " + ex.Message);
                                                    }

                                                    //using (HttpResponseMessage response = await client.GetAsync(mp4Url))
                                                    //{
                                                    //    if (response.StatusCode == HttpStatusCode.OK)
                                                    //    {

                                                    //        using (Stream stream = await response.Content.ReadAsStreamAsync())
                                                    //        {
                                                    //            using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                                                    //            {
                                                    //                await stream.CopyToAsync(fileStream); // 将响应流保存到本地文件
                                                    //                bl = false;
                                                    //                break;
                                                    //            }
                                                    //        }
                                                    //    }
                                                    //}


                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            j++;
                                            if (j > 3)
                                            {
                                                bl = false;
                                                Console.WriteLine($"3次请求地址自己抓一下{line}失败已经跳过!");
                                            }
                                        }
                                    }


                                }
                                i++;
                            }
                        }

                        CombineMP3(folderPath);
                    }
                    else
                    {
                        Console.WriteLine("请求加密接口失败!");
                    }
                }
                else
                {
                    Console.WriteLine("请求失败!" + html);
                }

            }

            Console.ReadLine();
        }

        static void CombineMP3(string folder)
        {
            string outputFilePath = $"{folder}.mp4";
            string[] mp3Files = Directory.GetFiles(folder, "*.ts"); // 获取文件夹中的所有MP3文件路径

            List<byte[]> mp3DataList = new List<byte[]>();

            List<string> sortedFiles = mp3Files.OrderBy(f => Path.GetFileNameWithoutExtension(f), new NumericFileNameComparer()).ToList();
            foreach (string filePath in sortedFiles)
            {
                byte[] mp3Data = File.ReadAllBytes(filePath); // 读取MP3文件的字节数据
                mp3DataList.Add(mp3Data);
            }

            byte[] outputData = mp3DataList.SelectMany(data => data).ToArray(); // 将所有MP3文件的字节数据合并为一个字节数组

            File.WriteAllBytes(outputFilePath, outputData); // 将字节数组写入输出文件
            Directory.Delete(folder, true);
            Console.WriteLine("合并完成,输出文件路径:" + outputFilePath);
        }


        public static string RemoveSpecialCharacters(string url)
        {
            string pattern = @"[^a-zA-Z0-9.:/?=_-]"; // 匹配非法字符的正则表达式

            return Regex.Replace(url, pattern, ""); // 去掉非法字符
        }
        public class NumericFileNameComparer : IComparer<string>
        {
            public int Compare(string x, string y)
            {
                string fileNameX = Path.GetFileNameWithoutExtension(x);
                string fileNameY = Path.GetFileNameWithoutExtension(y);

                if (fileNameX == null || fileNameY == null)
                {
                    return 0; // 如果文件名为空,则认为两个文件名相等
                }

                int numericValueX, numericValueY;
                bool successX = int.TryParse(fileNameX, out numericValueX);
                bool successY = int.TryParse(fileNameY, out numericValueY);

                if (successX && successY)
                {
                    return numericValueX.CompareTo(numericValueY);
                }
                else if (successX)
                {
                    return -1; // 如果只有 x 是数字,那么 x 小于 y
                }
                else if (successY)
                {
                    return 1; // 如果只有 y 是数字,那么 x 大于 y
                }
                else
                {
                    return string.Compare(fileNameX, fileNameY, StringComparison.Ordinal); // 如果都不是数字,则按照字符串顺序排序
                }
            }
        }


        /// <summary>
        /// 获取全集链接
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static List<string> ExtractURLs(string text)
        {
            List<string> urls = new List<string>();
            Regex regex = new Regex(@"./\?url=(.*?)'");

            MatchCollection matches = regex.Matches(text);
            foreach (Match match in matches)
            {
                string url = match.Groups[1].Value;
                urls.Add(url);
            }

            return urls;
        }
        /// <summary>
        /// 获取请求中的key
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static string Sign(string a)
        {
            // 计算MD5
            byte[] md5Bytes;
            using (var md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(a);
                md5Bytes = md5.ComputeHash(inputBytes);
            }
            string b = BitConverter.ToString(md5Bytes).Replace("-", "").ToLower();

            // 使用MD5作为密钥
            byte[] key = Encoding.UTF8.GetBytes(b);

            // 设置IV和Padding
            byte[] iv = Encoding.UTF8.GetBytes("3cccf88181408f19");
            PaddingMode padding = PaddingMode.Zeros;

            // 加密
            byte[] encryptedBytes;
            using (var aes = new AesCryptoServiceProvider())
            {
                aes.Key = key;
                aes.IV = iv;
                aes.Padding = padding;
                aes.Mode = CipherMode.CBC;

                byte[] inputBytes = Encoding.UTF8.GetBytes(a);
                using (var encryptor = aes.CreateEncryptor())
                {
                    encryptedBytes = encryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
                }
            }

            string e = Convert.ToBase64String(encryptedBytes);
            return e;
        }
        /// <summary>
        /// 时间戳+url
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        static string CalculateMD5Hash(string input)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    stringBuilder.Append(hashBytes[i].ToString("x2"));
                }

                return stringBuilder.ToString();
            }
        }
        /// <summary>
        /// 获取时间戳
        /// </summary>
        /// <returns></returns>
        static long GenerateTimestamp()
        {
            DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            TimeSpan timeSpan = DateTime.UtcNow - epoch;
            long timestamp = (long)timeSpan.TotalMilliseconds;
            return timestamp;
        }
        /// <summary>
        /// 对网址进行url编码
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        static string EncodeUrl(string str)
        {
            string encodedUrl = Uri.EscapeDataString(str);
            encodedUrl = encodedUrl.Replace("%3A", "%253A").Replace("%2F", "%252F");
            return encodedUrl;
        }
        static string EncodeKey(string str)
        {
            string encodedUrl = Uri.EscapeDataString(str);
            return encodedUrl;
        }
        public static string UrlDecode(string encodedUrl)
        {
            string decodedUrl = HttpUtility.UrlDecode(encodedUrl);
            return decodedUrl;
        }
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="encryptedText"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        static string DecryptAES(string encryptedText, string key, string iv)
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
            byte[] encryptedBytes = Convert.FromBase64String(encryptedText);

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = ivBytes;
                aesAlg.Padding = PaddingMode.Zeros;
                aesAlg.Mode = CipherMode.CBC;

                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msDecrypt = new MemoryStream(encryptedBytes))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            return srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
        }
    }
}



免费评分

参与人数 16威望 +1 吾爱币 +35 热心值 +15 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
你有往事我有酒 + 1 + 1 谢谢@Thanks!
抱歉、 + 1 用心讨论,共获提升!
Shanghanzu + 1 + 1 我很赞同!
涛之雨 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
尹铭 + 1 + 1 用心讨论,共获提升!
wincao + 2 + 1 我很赞同!
xiao智可以不帅 + 1 + 1 我很赞同!
唐小样儿 + 1 + 1 我很赞同!
awdlol233 + 1 + 1 我很赞同!
朝闻道夕死可矣 + 1 + 1 热心回复!
yjn866y + 1 + 1 谢谢@Thanks!
fathi + 1 + 1 我很赞同!
free12345 + 1 + 1 我很赞同!
greendays + 1 + 1 用心讨论,共获提升!
skyrayecfp杰 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

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

sinmu 发表于 2024-1-29 17:09
我知道怎么弄 。感谢
xhr断点.png

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
Quincy379 + 1 + 1 热心回复!

查看全部评分

 楼主| wanxu 发表于 2024-1-29 17:04
sinmu 发表于 2024-1-29 17:00
大佬,请教一下“去控制台打一个XHR断点” 这个怎么操作,开发者工具可以直接捕获所有的xhr请求和定位对应 ...

搜一搜怎么打XHR断点吧,F12-源代码-右边侧边栏里有一个xhr断点,添加网址就可以
Coldandcolder 发表于 2024-1-29 15:39
jueseman 发表于 2024-1-29 13:55
虽然看不懂,还是支持
slslsl 发表于 2024-1-29 14:15
其实按照原来js的情况来看,如果是混淆不严重的话,应该可以把其中几个比较关键的function给提取出来,然后用C#也好或者其他语言也好,应该大多都有提供对应调用执行js的方法,去调用来计算加密值即可
cuiqiqi123 发表于 2024-1-29 14:20
虽然看不懂,还是支持
aaron505 发表于 2024-1-29 14:52
大佬牛的,感谢分享经验学习
wind315_ 发表于 2024-1-29 14:54
基础知识太多,看不懂,只能纯支持
aimzhangyuting 发表于 2024-1-29 15:10
感谢楼主分享 好人长命百岁
skyrayecfp杰 发表于 2024-1-29 15:23
我在想,我们的硬件加密是不是就是这样破解掉的,被人拿着到处盈利。
mtcf 发表于 2024-1-29 15:26
强中还有强中手啊,果然是牛人
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-22 08:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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