using System.Security.Cryptography; using System.Text; namespace dy.net.utils { public class XBogus { private readonly int?[] _array; private readonly string _character; private readonly byte[] _uaKey = { 0x00, 0x01, 0x0c }; private readonly string _userAgent; public string Params { get; private set; } public string Xb { get; private set; } public XBogus(string userAgent = "") { // 初始化 Array 数组(对应 Python 的 self.Array) _array = new int?[128]; // 数字 0-9 对应 ASCII 48-57 for (int i = 48; i <= 57; i++) _array[i] = i - 48; // 字母 A-F 对应 ASCII 65-70,映射为 10-15 for (int i = 65; i <= 70; i++) _array[i] = i - 55; // 字母 a-f 对应 ASCII 97-102,映射为 10-15 for (int i = 97; i <= 102; i++) _array[i] = i - 87; // 字符映射表 _character = "Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe="; // 用户代理,默认值与 Python 一致 _userAgent = string.IsNullOrEmpty(userAgent) ? "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0" : userAgent; } /// /// 将字符串通过 MD5 哈希转换为整数数组 /// private int[] Md5StrToArray(string md5Str) { if (!string.IsNullOrEmpty(md5Str) && md5Str.Length > 32) return md5Str.Select(c => (int)c).ToArray(); var result = new List(); for (int i = 0; i < md5Str.Length; i += 2) { if (i + 1 >= md5Str.Length) break; int? high = _array[md5Str[i]]; int? low = _array[md5Str[i + 1]]; if (high == null || low == null) result.Add(0); else result.Add(((int)high << 4) | (int)low); } return result.ToArray(); } /// /// 多轮 MD5 哈希加密 URL 参数 /// private int[] Md5Encrypt(string urlParams) { string firstMd5 = Md5(urlParams); int[] firstArray = Md5StrToArray(firstMd5); string secondMd5 = Md5(firstArray); return Md5StrToArray(secondMd5); } /// /// 计算 MD5 哈希值 /// private string Md5(object input) { int[] dataArray; switch (input) { case string str: dataArray = Md5StrToArray(str); break; case int[] arr: dataArray = arr; break; default: throw new ArgumentException("Invalid input type. Expected string or int array."); } using (var md5 = MD5.Create()) { byte[] bytes = dataArray.Select(i => (byte)(i & 0xFF)).ToArray(); byte[] hashBytes = md5.ComputeHash(bytes); return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); } } /// /// 第一次编码转换 /// private string EncodingConversion( int a, int b, int c, int e, int d, int t, int f, int r, int n, int o, int i, int _, int x, int u, int s, int l, int v, int h, int p) { var bytes = new byte[] { (byte)a, (byte)i, (byte)b, (byte)_ , (byte)c, (byte)x, (byte)e, (byte)u, (byte)d, (byte)s, (byte)t, (byte)l, (byte)f, (byte)v, (byte)r, (byte)h, (byte)n, (byte)p, (byte)o }; return Encoding.GetEncoding("ISO-8859-1").GetString(bytes); } /// /// 第二次编码转换 /// private string EncodingConversion2(int a, int b, string c) { return ((char)a).ToString() + ((char)b).ToString() + c; } /// /// RC4 加密算法 /// private byte[] Rc4Encrypt(byte[] key, byte[] data) { int[] S = Enumerable.Range(0, 256).ToArray(); int j = 0; // 初始化 S 盒 for (int i = 0; i < 256; i++) { j = (j + S[i] + key[i % key.Length]) % 256; (S[i], S[j]) = (S[j], S[i]); } // 生成密文 var encrypted = new byte[data.Length]; int i2 = 0, j2 = 0; for (int k = 0; k < data.Length; k++) { i2 = (i2 + 1) % 256; j2 = (j2 + S[i2]) % 256; (S[i2], S[j2]) = (S[j2], S[i2]); int t = (S[i2] + S[j2]) % 256; encrypted[k] = (byte)(data[k] ^ S[t]); } return encrypted; } /// /// 位运算计算 /// private string Calculation(int a1, int a2, int a3) { int x1 = (a1 & 0xFF) << 16; int x2 = (a2 & 0xFF) << 8; int x3 = x1 | x2 | (a3 & 0xFF); char c1 = _character[(x3 & 0x0FC0000) >> 18]; // 16515072 = 0x0FC0000 char c2 = _character[(x3 & 0x003F000) >> 12]; // 258048 = 0x003F000 char c3 = _character[(x3 & 0x0000FC0) >> 6]; // 4032 = 0x0000FC0 char c4 = _character[x3 & 0x3F]; return $"{c1}{c2}{c3}{c4}"; } /// /// 获取 X-Bogus 值 /// public (string Params, string Xb, string UserAgent) GetXBogus(string urlParams) { // 计算 array1 byte[] uaBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(_userAgent); byte[] rc4Ua = Rc4Encrypt(_uaKey, uaBytes); string base64Ua = Convert.ToBase64String(rc4Ua); string md5Ua = Md5(base64Ua); int[] array1 = Md5StrToArray(md5Ua); // 计算 array2(固定 MD5:d41d8cd98f00b204e9800998ecf8427e 是空字符串的 MD5) int[] array2 = Md5StrToArray(Md5(Md5StrToArray("d41d8cd98f00b204e9800998ecf8427e"))); // 计算 URL 参数的 MD5 数组 int[] urlParamsArray = Md5Encrypt(urlParams); // 时间戳和固定值 long timer = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); int ct = 536919696; // 构建 new_array var newArray = new List { 64, 0.00390625, 1, 12, urlParamsArray.Length > 14 ? urlParamsArray[14] : 0, urlParamsArray.Length > 15 ? urlParamsArray[15] : 0, array2.Length > 14 ? array2[14] : 0, array2.Length > 15 ? array2[15] : 0, array1.Length > 14 ? array1[14] : 0, array1.Length > 15 ? array1[15] : 0, (timer >> 24) & 0xFF, (timer >> 16) & 0xFF, (timer >> 8) & 0xFF, timer & 0xFF, (ct >> 24) & 0xFF, (ct >> 16) & 0xFF, (ct >> 8) & 0xFF, ct & 0xFF }; // 计算异或结果 int xorResult = (int)newArray[0]; for (int i = 1; i < newArray.Count; i++) { int b = (int)newArray[i]; xorResult ^= b; } newArray.Add(xorResult); // 拆分 array3 和 array4 var array3 = new List(); var array4 = new List(); for (int i = 0; i < newArray.Count; i++) { array3.Add((int)newArray[i]); if (i + 1 < newArray.Count) array4.Add((int)newArray[i + 1]); i++; } // 合并数组 int[] mergeArray = array3.Concat(array4).ToArray(); // 生成乱码 string encoding1 = EncodingConversion( mergeArray[0], mergeArray[1], mergeArray[2], mergeArray[3], mergeArray[4], mergeArray[5], mergeArray[6], mergeArray[7], mergeArray[8], mergeArray[9], mergeArray[10], mergeArray[11], mergeArray[12], mergeArray[13], mergeArray[14], mergeArray[15], mergeArray[16], mergeArray[17], mergeArray[18] ); byte[] encoding1Bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(encoding1); byte[] rc4Key = Encoding.GetEncoding("ISO-8859-1").GetBytes("ÿ"); byte[] rc4Encrypted = Rc4Encrypt(rc4Key, encoding1Bytes); string rc4Str = Encoding.GetEncoding("ISO-8859-1").GetString(rc4Encrypted); string garbledCode = EncodingConversion2(2, 255, rc4Str); // 计算 X-Bogus StringBuilder xbBuilder = new StringBuilder(); for (int i = 0; i < garbledCode.Length; i += 3) { if (i + 2 >= garbledCode.Length) break; int a = garbledCode[i]; int b = garbledCode[i + 1]; int c = garbledCode[i + 2]; xbBuilder.Append(Calculation(a, b, c)); } // 结果赋值 Xb = xbBuilder.ToString(); Params = $"{urlParams}&X-Bogus={Xb}"; return (Params, Xb, _userAgent); } } // 测试代码 //public class XBogusTest //{ // public static void Main() // { // string ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"; // var xb = new XBogus(ua); // string dyUrlParams = "device_platform=webapp&aid=6383&channel=channel_pc_web&sec_user_id=MS4wLjABAAAAW9FWcqS7RdQAWPd2AA5fL_ilmqsIFUCQ_Iym6Yh9_cUa6ZRqVLjVQSUjlHrfXY1Y&max_cursor=0&locate_query=false&show_live_replay_strategy=1&need_time_list=1&time_list_query=0&whale_cut_token=&cut_version=1&count=18&publish_video_strategy_type=2&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=12&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7335414539335222835&msToken=p9Y7fUBuq9DKvAuN27Peml6JbaMqG2ZcXfFiyDv1jcHrCN00uidYqUgSuLsKl1onC-E_n82m-aKKYE0QGEmxIWZx9iueQ6WLbvzPfqnMk4GBAlQIHcDzxb38FLXXQxAm"; // string tkUrlParams = "WebIdLastTime=1713796127&abTestVersion=%5Bobject%20Object%5D&aid=1988&appType=t&app_language=zh-Hans&app_name=tiktok_web&browser_name=Mozilla&browser_online=true&browser_platform=Win32&browser_version=5.0%20%28Windows%20NT%2010.0%3B%20Win64%3B%20x64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F123.0.0.0%20Safari%2F537.36&channel=tiktok_web&device_id=7360698239018452498&odinId=7360698115047851026®ion=TW&tz_name=Asia%2FHong_Kong&uniqueId=rei_toy625"; // var dyResult = xb.GetXBogus(dyUrlParams); // Console.WriteLine($"Douyin - URL: {dyResult.Params}, X-Bogus: {dyResult.Xb}, UA: {dyResult.UserAgent}"); // var tkResult = xb.GetXBogus(tkUrlParams); // Console.WriteLine($"TikTok - URL: {tkResult.Params}, X-Bogus: {tkResult.Xb}, UA: {tkResult.UserAgent}"); // } //} }