| 1 | # path: f2/utils/abogus.py |
| 2 | |
| 3 | #!/usr/bin/env python |
| 4 | # -*- encoding: utf-8 -*- |
| 5 | """ |
| 6 | @Description:abogus.py |
| 7 | @Date :2024/06/16 11:21:14 |
| 8 | @Author :JohnserfSeed |
| 9 | @version :0.0.3 |
| 10 | @License :Apache License 2.0 |
| 11 | @Github :https://github.com/johnserf-seed |
| 12 | @Mail :support@f2.wiki |
| 13 | ------------------------------------------------- |
| 14 | Change Log : |
| 15 | 2024/06/16 17:27:47 - Create ABogus algorithm & black style |
| 16 | 2024/06/16 17:27:47 - Limit custom ua late open source full version |
| 17 | 2024/07/08 21:50:12 - Open the full version of the custom UA |
| 18 | 2025/03/05 155:55:42 - Perf Post Method Generate |
| 19 | ------------------------------------------------- |
| 20 | """ |
| 21 | |
| 22 | import random |
| 23 | import time |
| 24 | from typing import Callable, Dict, List, Union |
| 25 | |
| 26 | from gmssl import func, sm3 |
| 27 | |
| 28 | |
| 29 | class StringProcessor: |
| 30 | """ |
| 31 | StringProcessor 类用于计算ABogus算法中所需的字符串处理方法。 |
| 32 | 包括字符串和 ASCII 码之间的转换、无符号右移运算等。 |
| 33 | |
| 34 | 类方法: |
| 35 | |
| 36 | to_ord_str(s: str) -> str: |
| 37 | 将字符串转换为 ASCII 码字符串。 |
| 38 | |
| 39 | to_ord_array(s: str) -> List[int]: |
| 40 | 将字符串转换为 ASCII 码列表。 |
| 41 | |
| 42 | to_char_str(s: str) -> str: |
| 43 | 将 ASCII 码列表转换为字符串。 |
| 44 | |
| 45 | to_char_array(s: str) -> List[int]: |
| 46 | 将字符串转换为 ASCII 码列表。 |
| 47 | |
| 48 | js_shift_right(val: int, n: int) -> int: |
| 49 | 实现 JavaScript 中的无符号右移运算。 |
| 50 | |
| 51 | generate_random_bytes(length: int = 3) -> str: |
| 52 | 生成一组伪随机字节字符串,用于混淆数据。 |
| 53 | |
| 54 | 使用示例: |
| 55 | ```python |
| 56 | # 将字符串转换为 ASCII 码字符串 |
| 57 | ord_str = StringProcessor.to_ord_str("Hello, World!") |
| 58 | print(ord_str) |
| 59 | |
| 60 | # 将字符串转换为 ASCII 码列表 |
| 61 | ord_array = StringProcessor.to_ord_array("Hello, World!") |
| 62 | print(ord_array) |
| 63 | |
| 64 | # 将 ASCII 码列表转换为字符串 |
| 65 | char_str = StringProcessor.to_char_str(ord_array) |
| 66 | print(char_str) |
| 67 | |
| 68 | # 将字符串转换为 ASCII 码列表 |
| 69 | char_array = StringProcessor.to_char_array("Hello, World!") |
| 70 | print(char_array) |
| 71 | |
| 72 | # 实现 JavaScript 中的无符号右移运算 |
| 73 | shifted_val = StringProcessor.js_shift_right(10, 2) |
| 74 | print(shifted_val) |
| 75 | |
| 76 | # 生成一组伪随机字节字符串 |
| 77 | random_bytes = StringProcessor.generate_random_bytes(3) |
| 78 | print(random_bytes) |
| 79 | ``` |
| 80 | """ |
| 81 | |
| 82 | @staticmethod |
| 83 | def to_ord_str(s: str) -> str: |
| 84 | """ |
| 85 | 将字符串转换为 ASCII 码字符串 (Convert a string to an ASCII code string). |
| 86 | |
| 87 | Args: |
| 88 | s (str): 输入字符串 (Input string). |
| 89 | |
| 90 | Returns: |
| 91 | str: 转换后的 ASCII 码字符串 (Converted ASCII code string). |
| 92 | """ |
| 93 | return "".join([chr(i) for i in s]) |
| 94 | |
| 95 | @staticmethod |
| 96 | def to_ord_array(s: str) -> List[int]: |
| 97 | """ |
| 98 | 将字符串转换为 ASCII 码列表 (Convert a string to a list of ASCII codes). |
| 99 | |
| 100 | Args: |
| 101 | s (str): 输入字符串 (Input string). |
| 102 | |
| 103 | Returns: |
| 104 | List[int]: 转换后的 ASCII 码列表 (Converted list of ASCII codes). |
| 105 | """ |
| 106 | return [ord(char) for char in s] |
| 107 | |
| 108 | @staticmethod |
| 109 | def to_char_str(s: str) -> str: |
| 110 | """ |
| 111 | 将 ASCII 码列表转换为字符串 (Convert a list of ASCII codes to a string). |
| 112 | |
| 113 | Args: |
| 114 | s (str): ASCII 码列表 (List of ASCII codes). |
| 115 | |
| 116 | Returns: |
| 117 | str: 转换后的字符串 (Converted string). |
| 118 | """ |
| 119 | return "".join([chr(i) for i in s]) |
| 120 | |
| 121 | @staticmethod |
| 122 | def to_char_array(s: str) -> List[int]: |
| 123 | """ |
| 124 | 将字符串转换为 ASCII 码列表 (Convert a string to a list of ASCII codes). |
| 125 | |
| 126 | Args: |
| 127 | s (str): 输入字符串 (Input string). |
| 128 | |
| 129 | Returns: |
| 130 | List[int]: 转换后的 ASCII 码列表 (Converted list of ASCII codes). |
| 131 | """ |
| 132 | return [ord(char) for char in s] |
| 133 | |
| 134 | @staticmethod |
| 135 | def js_shift_right(val: int, n: int) -> int: |
| 136 | """ |
| 137 | 实现 JavaScript 中的无符号右移运算 (Implement the unsigned right shift operation in JavaScript). |
| 138 | |
| 139 | Args: |
| 140 | val (int): 输入值 (Input value). |
| 141 | n (int): 右移位数 (Number of bits to shift right). |
| 142 | |
| 143 | Returns: |
| 144 | int: 右移后的值 (Value after right shift). |
| 145 | """ |
| 146 | return (val % 0x100000000) >> n |
| 147 | |
| 148 | @staticmethod |
| 149 | def generate_random_bytes(length: int = 3) -> str: |
| 150 | """ |
| 151 | 生成一组伪随机字节字符串,用于混淆数据 (Generate a pseudo-random byte string to obfuscate the data). |
| 152 | |
| 153 | Args: |
| 154 | length (int): 生成的字节序列长度 (Length of the byte sequence to generate). |
| 155 | |
| 156 | Returns: |
| 157 | str: 生成的伪随机字节字符串 (Generated pseudo-random byte string). |
| 158 | """ |
| 159 | |
| 160 | def generate_byte_sequence() -> List[str]: |
| 161 | _rd = int(random.random() * 10000) |
| 162 | return [ |
| 163 | chr(((_rd & 255) & 170) | 1), |
| 164 | chr(((_rd & 255) & 85) | 2), |
| 165 | chr((StringProcessor.js_shift_right(_rd, 8) & 170) | 5), |
| 166 | chr((StringProcessor.js_shift_right(_rd, 8) & 85) | 40), |
| 167 | ] |
| 168 | |
| 169 | result = [] |
| 170 | for _ in range(length): |
| 171 | result.extend(generate_byte_sequence()) |
| 172 | |
| 173 | return "".join(result) |
| 174 | |
| 175 | |
| 176 | class CryptoUtility: |
| 177 | """ |
| 178 | CryptoUtility 类用于提供加密和编码的工具方法,包括 SM3 哈希、添加盐值、Base64 编码和 RC4 加密等。 |
| 179 | |
| 180 | 类属性: |
| 181 | salt (str): 加密盐值 (Encryption salt). |
| 182 | base64_alphabet (List[str]): 自定义 Base64 字符表 (Custom Base64 alphabet). |
| 183 | |
| 184 | 类方法: |
| 185 | sm3_to_array(input_data: Union[str, List[int]]) -> List[int]: |
| 186 | 计算请求体的 SM3 哈希值,并将结果转换为整数数组。 |
| 187 | |
| 188 | add_salt(param: str) -> str: |
| 189 | 为字符串参数添加盐值。 |
| 190 | |
| 191 | process_param(param: Union[str, List[int]], add_salt: bool) -> Union[str, List[int]]: |
| 192 | 处理输入参数,根据需要添加盐值。 |
| 193 | |
| 194 | params_to_array(param: Union[str, List[int]], add_salt: bool = True) -> List[int]: |
| 195 | 获取输入参数的哈希数组。 |
| 196 | |
| 197 | transform_bytes(bytes_list: List[int]) -> str: |
| 198 | 对输入的字节列表进行加密/解密操作,返回处理后的字符串。 |
| 199 | |
| 200 | base64_encode(input_string: str, selected_alphabet: int = 0) -> str: |
| 201 | 使用自定义字符表对输入字符串进行 Base64 编码。 |
| 202 | |
| 203 | abogus_encode(abogus_bytes_str: str, selected_alphabet: int) -> str: |
| 204 | 对输入的字节字符串进行自定义 Base64 编码,并添加位移和填充。 |
| 205 | |
| 206 | rc4_encrypt(key: bytes, plaintext: str) -> bytes: |
| 207 | 使用 RC4 算法加密数据。 |
| 208 | |
| 209 | 使用示例: |
| 210 | ```python |
| 211 | # 计算请求体的 SM3 哈希值 |
| 212 | sm3_hash = CryptoUtility.sm3_to_array("Hello, World!") |
| 213 | print(sm3_hash) |
| 214 | |
| 215 | # 为字符串参数添加盐值 |
| 216 | salted_param = CryptoUtility.add_salt("Hello, World!") |
| 217 | print(salted_param) |
| 218 | |
| 219 | # 获取输入参数的哈希数组 |
| 220 | hash_array = CryptoUtility.params_to_array("Hello, World!") |
| 221 | print(hash_array) |
| 222 | |
| 223 | # 对输入的字节列表进行加密/解密操作 |
| 224 | encrypted_str = CryptoUtility.transform_bytes([72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]) |
| 225 | print(encrypted_str) |
| 226 | |
| 227 | # 使用自定义字符表对输入字符串进行 Base64 编码 |
| 228 | base64_str = CryptoUtility.base64_encode("Hello, World!") |
| 229 | print(base64_str) |
| 230 | |
| 231 | # 对输入的字节字符串进行自定义 Base64 编码,并添加位移和填充 |
| 232 | abogus_str = CryptoUtility.abogus_encode("Hello, World!", 0) |
| 233 | print(abogus_str) |
| 234 | |
| 235 | # 使用 RC4 算法加密数据 |
| 236 | key = b"key" |
| 237 | plaintext = "Hello, World!" |
| 238 | ciphertext = CryptoUtility.rc4_encrypt(key, plaintext) |
| 239 | print(ciphertext) |
| 240 | ``` |
| 241 | """ |
| 242 | |
| 243 | def __init__(self, salt: str, custom_base64_alphabet: List[str]): |
| 244 | """ |
| 245 | 初始化 CryptoUtility 类 |
| 246 | Initialize the CryptoUtility class. |
| 247 | |
| 248 | Args: |
| 249 | salt (str): 加密盐值 (Encryption salt). |
| 250 | custom_base64_alphabet (List[str]): 自定义 Base64 字符表 (Custom Base64 alphabet). |
| 251 | """ |
| 252 | self.salt = salt |
| 253 | self.base64_alphabet = custom_base64_alphabet |
| 254 | |
| 255 | # fmt: off |
| 256 | self.big_array = [ |
| 257 | 121, 243, 55, 234, 103, 36, 47, 228, 30, 231, 106, 6, 115, 95, 78, 101, 250, 207, 198, 50, |
| 258 | 139, 227, 220, 105, 97, 143, 34, 28, 194, 215, 18, 100, 159, 160, 43, 8, 169, 217, 180, 120, |
| 259 | 247, 45, 90, 11, 27, 197, 46, 3, 84, 72, 5, 68, 62, 56, 221, 75, 144, 79, 73, 161, |
| 260 | 178, 81, 64, 187, 134, 117, 186, 118, 16, 241, 130, 71, 89, 147, 122, 129, 65, 40, 88, 150, |
| 261 | 110, 219, 199, 255, 181, 254, 48, 4, 195, 248, 208, 32, 116, 167, 69, 201, 17, 124, 125, 104, |
| 262 | 96, 83, 80, 127, 236, 108, 154, 126, 204, 15, 20, 135, 112, 158, 13, 1, 188, 164, 210, 237, |
| 263 | 222, 98, 212, 77, 253, 42, 170, 202, 26, 22, 29, 182, 251, 10, 173, 152, 58, 138, 54, 141, |
| 264 | 185, 33, 157, 31, 252, 132, 233, 235, 102, 196, 191, 223, 240, 148, 39, 123, 92, 82, 128, 109, |
| 265 | 57, 24, 38, 113, 209, 245, 2, 119, 153, 229, 189, 214, 230, 174, 232, 63, 52, 205, 86, 140, |
| 266 | 66, 175, 111, 171, 246, 133, 238, 193, 99, 60, 74, 91, 225, 51, 76, 37, 145, 211, 166, 151, |
| 267 | 213, 206, 0, 200, 244, 176, 218, 44, 184, 172, 49, 216, 93, 168, 53, 21, 183, 41, 67, 85, |
| 268 | 224, 155, 226, 242, 87, 177, 146, 70, 190, 12, 162, 19, 137, 114, 25, 165, 163, 192, 23, 59, |
| 269 | 9, 94, 179, 107, 35, 7, 142, 131, 239, 203, 149, 136, 61, 249, 14, 156 |
| 270 | ] |
| 271 | # fmt: on |
| 272 | |
| 273 | @staticmethod |
| 274 | def sm3_to_array(input_data: Union[str, List[int]]) -> List[int]: |
| 275 | """ |
| 276 | 计算请求体的 SM3 哈希值,并将结果转换为整数数组 (Calculate the SM3 hash value of the request body and convert the result to an array of integers). |
| 277 | |
| 278 | Args: |
| 279 | input_data (Union[str, List[int]]): 输入数据 (Input data). |
| 280 | |
| 281 | Returns: |
| 282 | List[int]: 哈希值的整数数组 (Array of integers representing the hash value). |
| 283 | """ |
| 284 | # 如果输入是字符串,则将其编码为字节数组 |
| 285 | if isinstance(input_data, str): |
| 286 | input_data_bytes = input_data.encode("utf-8") |
| 287 | else: |
| 288 | input_data_bytes = bytes(input_data) # 将 List[int] 转换为字节数组 |
| 289 | |
| 290 | # 将字节数组转换为适合 sm3.sm3_hash 函数处理的列表格式 |
| 291 | hex_result = sm3.sm3_hash(func.bytes_to_list(input_data_bytes)) |
| 292 | |
| 293 | # 将十六进制字符串结果转换为十进制整数列表 |
| 294 | return [int(hex_result[i : i + 2], 16) for i in range(0, len(hex_result), 2)] |
| 295 | |
| 296 | def add_salt(self, param: str) -> str: |
| 297 | """ |
| 298 | 为字符串参数添加盐值 (Add salt to the string parameter). |
| 299 | |
| 300 | Args: |
| 301 | param (str): 输入字符串 (Input string). |
| 302 | |
| 303 | Returns: |
| 304 | str: 添加盐值后的字符串 (String with added salt). |
| 305 | """ |
| 306 | return param + self.salt |
| 307 | |
| 308 | def process_param(self, param: Union[str, List[int]], add_salt: bool) -> Union[str, List[int]]: |
| 309 | """ |
| 310 | 处理输入参数,根据需要添加盐值 (Process input parameter and add salt if needed). |
| 311 | |
| 312 | Args: |
| 313 | param (Union[str, List[int]]): 输入参数 (Input parameter). |
| 314 | add_salt (bool): 是否添加盐值 (Whether to add salt). |
| 315 | |
| 316 | Returns: |
| 317 | Union[str, List[int]]: 处理后的参数 (Processed parameter). |
| 318 | """ |
| 319 | if isinstance(param, str) and add_salt: |
| 320 | param = self.add_salt(param) |
| 321 | return param |
| 322 | |
| 323 | def params_to_array(self, param: Union[str, List[int]], add_salt: bool = True) -> List[int]: |
| 324 | """ |
| 325 | 获取输入参数的哈希数组 (Get the hash array of the input parameter). |
| 326 | |
| 327 | Args: |
| 328 | param (Union[str, List[int]]): 输入参数 (Input parameter). |
| 329 | add_salt (bool): 是否添加盐值 (Whether to add salt). |
| 330 | |
| 331 | Returns: |
| 332 | List[int]: 哈希数组 (Hash array). |
| 333 | """ |
| 334 | processed_param = self.process_param(param, add_salt) |
| 335 | return self.sm3_to_array(processed_param) |
| 336 | |
| 337 | def transform_bytes(self, bytes_list: List[int]) -> str: |
| 338 | """ |
| 339 | 对输入的字节列表进行加密/解密操作,返回处理后的字符串 (Encrypt/decrypt the input byte list and return the processed string). |
| 340 | |
| 341 | Args: |
| 342 | bytes_list (List[int]): 输入的字节列表 (Input byte list). |
| 343 | |
| 344 | Returns: |
| 345 | str: 处理后的字符串 (Processed string). |
| 346 | """ |
| 347 | # 将字节列表转换为字符字符串 |
| 348 | bytes_str = StringProcessor.to_char_str(bytes_list) |
| 349 | result_str = [] |
| 350 | index_b = self.big_array[1] |
| 351 | initial_value = 0 |
| 352 | # `value_e` is populated at the end of each loop iteration (see |
| 353 | # below) and consumed at the top of the NEXT iteration's `else` |
| 354 | # branch (index > 0). The index==0 branch doesn't read it, so |
| 355 | # static analysis can't tell that it's always defined before |
| 356 | # first use. Pre-declare 0 here to silence F821 without changing |
| 357 | # runtime behaviour — the 0 is overwritten on iteration 0 before |
| 358 | # any `else` branch runs. |
| 359 | value_e = 0 |
| 360 | |
| 361 | for index, char in enumerate(bytes_str): |
| 362 | if index == 0: |
| 363 | initial_value = self.big_array[index_b] |
| 364 | sum_initial = index_b + initial_value |
| 365 | |
| 366 | self.big_array[1] = initial_value |
| 367 | self.big_array[index_b] = index_b |
| 368 | else: |
| 369 | sum_initial = initial_value + value_e |
| 370 | |
| 371 | char_value = ord(char) |
| 372 | sum_initial %= len(self.big_array) |
| 373 | value_f = self.big_array[sum_initial] |
| 374 | encrypted_char = char_value ^ value_f |
| 375 | result_str.append(chr(encrypted_char)) |
| 376 | |
| 377 | # 交换数组元素 |
| 378 | value_e = self.big_array[(index + 2) % len(self.big_array)] |
| 379 | sum_initial = (index_b + value_e) % len(self.big_array) |
| 380 | initial_value = self.big_array[sum_initial] |
| 381 | self.big_array[sum_initial] = self.big_array[(index + 2) % len(self.big_array)] |
| 382 | self.big_array[(index + 2) % len(self.big_array)] = initial_value |
| 383 | index_b = sum_initial |
| 384 | |
| 385 | return "".join(result_str) |
| 386 | |
| 387 | def base64_encode(self, input_string: str, selected_alphabet: int = 0) -> str: |
| 388 | """ |
| 389 | 使用自定义字符表对输入字符串进行 Base64 编码 (Encode the input string using a custom Base64 alphabet). |
| 390 | |
| 391 | Args: |
| 392 | input_string (str): 输入字符串 (Input string). |
| 393 | selected_alphabet (int): 选择的自定义 Base64 字符表索引 (Selected custom Base64 alphabet index). |
| 394 | |
| 395 | Returns: |
| 396 | str: 编码后的字符串 (Encoded string). |
| 397 | """ |
| 398 | |
| 399 | # 将输入字符串转换为ASCII码的二进制形式 |
| 400 | binary_string = "".join(["{:08b}".format(ord(char)) for char in input_string]) |
| 401 | |
| 402 | # 补全二进制字符串使其长度为6的倍数 |
| 403 | padding_length = (6 - len(binary_string) % 6) % 6 |
| 404 | binary_string += "0" * padding_length |
| 405 | |
| 406 | # 将二进制字符串分割为6位一组 |
| 407 | base64_indices = [int(binary_string[i : i + 6], 2) for i in range(0, len(binary_string), 6)] |
| 408 | |
| 409 | # 根据自定义字符表生成输出字符串 |
| 410 | output_string = "".join( |
| 411 | [self.base64_alphabet[selected_alphabet][index] for index in base64_indices] |
| 412 | ) |
| 413 | |
| 414 | # 添加等号填充,使符合 Base64 编码规范 |
| 415 | output_string += "=" * (padding_length // 2) |
| 416 | |
| 417 | return output_string |
| 418 | |
| 419 | def abogus_encode(self, abogus_bytes_str: str, selected_alphabet: int) -> str: |
| 420 | """ |
| 421 | 对输入的字节字符串进行自定义 Base64 编码,并添加位移和填充 (Encode the input byte string using a custom Base64 alphabet, and add shifts and padding). |
| 422 | |
| 423 | Args: |
| 424 | abogus_bytes_str (str): 输入的字节字符串 (Input byte string). |
| 425 | selected_alphabet (int): 选择的自定义 Base64 字符表索引 (Selected custom Base64 alphabet index). |
| 426 | |
| 427 | Returns: |
| 428 | str: 编码后的字符串 (Encoded string). |
| 429 | """ |
| 430 | abogus = [] |
| 431 | |
| 432 | for i in range(0, len(abogus_bytes_str), 3): |
| 433 | if i + 2 < len(abogus_bytes_str): |
| 434 | n = ( |
| 435 | (ord(abogus_bytes_str[i]) << 16) |
| 436 | | (ord(abogus_bytes_str[i + 1]) << 8) |
| 437 | | ord(abogus_bytes_str[i + 2]) |
| 438 | ) |
| 439 | elif i + 1 < len(abogus_bytes_str): |
| 440 | n = (ord(abogus_bytes_str[i]) << 16) | (ord(abogus_bytes_str[i + 1]) << 8) |
| 441 | else: |
| 442 | n = ord(abogus_bytes_str[i]) << 16 |
| 443 | |
| 444 | for j, k in zip(range(18, -1, -6), (0xFC0000, 0x03F000, 0x0FC0, 0x3F)): |
| 445 | if j == 6 and i + 1 >= len(abogus_bytes_str): |
| 446 | break |
| 447 | if j == 0 and i + 2 >= len(abogus_bytes_str): |
| 448 | break |
| 449 | abogus.append(self.base64_alphabet[selected_alphabet][(n & k) >> j]) |
| 450 | |
| 451 | abogus.append("=" * ((4 - len(abogus) % 4) % 4)) |
| 452 | return "".join(abogus) |
| 453 | |
| 454 | @staticmethod |
| 455 | def rc4_encrypt(key: bytes, plaintext: str) -> bytes: |
| 456 | """ |
| 457 | 使用 RC4 算法加密数据 (Encrypt data using the RC4 algorithm). |
| 458 | |
| 459 | Args: |
| 460 | key (bytes): 加密密钥 (Encryption key). |
| 461 | plaintext (str): 明文数据 (Plaintext data). |
| 462 | |
| 463 | Returns: |
| 464 | bytes: 加密后的数据 (Encrypted data). |
| 465 | """ |
| 466 | S = list(range(256)) |
| 467 | j = 0 |
| 468 | for i in range(256): |
| 469 | j = (j + S[i] + key[i % len(key)]) % 256 |
| 470 | S[i], S[j] = S[j], S[i] |
| 471 | |
| 472 | i = j = 0 |
| 473 | ciphertext = [] |
| 474 | for char in plaintext: |
| 475 | i = (i + 1) % 256 |
| 476 | j = (j + S[i]) % 256 |
| 477 | S[i], S[j] = S[j], S[i] |
| 478 | K = S[(S[i] + S[j]) % 256] |
| 479 | ciphertext.append(ord(char) ^ K) |
| 480 | |
| 481 | return bytes(ciphertext) |
| 482 | |
| 483 | |
| 484 | class BrowserFingerprintGenerator: |
| 485 | """ |
| 486 | BrowserFingerprintGenerator 用于生成模拟的浏览器指纹信息,用于在不同浏览器环境中进行测试和数据采集。 |
| 487 | |
| 488 | 类属性: |
| 489 | browsers (Dict[str, Callable[[], str]]): 浏览器类型和生成浏览器指纹的映射关系。 |
| 490 | |
| 491 | 方法: |
| 492 | generate_fingerprint(browser_type="Edge"): |
| 493 | 根据指定的浏览器类型生成浏览器指纹。 |
| 494 | |
| 495 | generate_chrome_fingerprint(): |
| 496 | 生成 Chrome 浏览器指纹。 |
| 497 | |
| 498 | generate_firefox_fingerprint(): |
| 499 | 生成 Firefox 浏览器指纹。 |
| 500 | |
| 501 | generate_safari_fingerprint(): |
| 502 | 生成 Safari 浏览器指纹。 |
| 503 | |
| 504 | generate_edge_fingerprint(): |
| 505 | 生成 Edge 浏览器指纹。 |
| 506 | |
| 507 | _generate_fingerprint(platform="Win32"): |
| 508 | 根据给定的参数生成浏览器指纹字符串。 |
| 509 | |
| 510 | 使用示例: |
| 511 | ```python |
| 512 | chrome_fp = BrowserFingerprintGenerator.generate_fingerprint("Chrome") |
| 513 | print(chrome_fp) |
| 514 | ``` |
| 515 | """ |
| 516 | |
| 517 | @classmethod |
| 518 | def generate_fingerprint(cls, browser_type: str = "Edge") -> str: |
| 519 | """ |
| 520 | 根据指定的浏览器类型生成浏览器指纹。 (Generate a browser fingerprint based on the specified browser type.) |
| 521 | |
| 522 | Args: |
| 523 | browser_type (str): 浏览器类型 (Browser type). |
| 524 | |
| 525 | Returns: |
| 526 | str: 生成的浏览器指纹字符串 (Generated browser fingerprint string). |
| 527 | """ |
| 528 | cls.browsers: Dict[str, Callable[[], str]] = { |
| 529 | "Chrome": cls.generate_chrome_fingerprint, |
| 530 | "Firefox": cls.generate_firefox_fingerprint, |
| 531 | "Safari": cls.generate_safari_fingerprint, |
| 532 | "Edge": cls.generate_edge_fingerprint, |
| 533 | } |
| 534 | return cls.browsers.get(browser_type, cls.generate_chrome_fingerprint)() |
| 535 | |
| 536 | @classmethod |
| 537 | def generate_chrome_fingerprint(cls) -> str: |
| 538 | return cls._generate_fingerprint(platform="Win32") |
| 539 | |
| 540 | @classmethod |
| 541 | def generate_firefox_fingerprint(cls) -> str: |
| 542 | return cls._generate_fingerprint(platform="Win32") |
| 543 | |
| 544 | @classmethod |
| 545 | def generate_safari_fingerprint(cls) -> str: |
| 546 | return cls._generate_fingerprint(platform="MacIntel") |
| 547 | |
| 548 | @classmethod |
| 549 | def generate_edge_fingerprint(cls) -> str: |
| 550 | return cls._generate_fingerprint(platform="Win32") |
| 551 | |
| 552 | @staticmethod |
| 553 | def _generate_fingerprint(platform: str) -> str: |
| 554 | """ |
| 555 | 根据给定的参数生成浏览器指纹字符串。 (Generate a browser fingerprint string based on the given parameters.) |
| 556 | |
| 557 | Args: |
| 558 | platform (str): 操作系统平台 (Operating system platform). |
| 559 | |
| 560 | Returns: |
| 561 | str: 生成的浏览器指纹字符串 (Generated browser fingerprint string). |
| 562 | """ |
| 563 | inner_width = random.randint(1024, 1920) |
| 564 | inner_height = random.randint(768, 1080) |
| 565 | outer_width = inner_width + random.randint(24, 32) |
| 566 | outer_height = inner_height + random.randint(75, 90) |
| 567 | screen_x = 0 |
| 568 | screen_y = random.choice([0, 30]) |
| 569 | size_width = random.randint(1024, 1920) |
| 570 | size_height = random.randint(768, 1080) |
| 571 | avail_width = random.randint(1280, 1920) |
| 572 | avail_height = random.randint(800, 1080) |
| 573 | |
| 574 | fingerprint = ( |
| 575 | f"{inner_width}|{inner_height}|{outer_width}|{outer_height}|" |
| 576 | f"{screen_x}|{screen_y}|0|0|{size_width}|{size_height}|" |
| 577 | f"{avail_width}|{avail_height}|{inner_width}|{inner_height}|24|24|{platform}" |
| 578 | ) |
| 579 | return fingerprint |
| 580 | |
| 581 | |
| 582 | class ABogus: |
| 583 | """ |
| 584 | ABogus 类用于生成 ABogus 参数。 |
| 585 | |
| 586 | 类属性: |
| 587 | array1 (List[int]): 加密请求体 (Encrypted request body). |
| 588 | array2 (List[int]): 加密请求头 (Encrypted request header). |
| 589 | array3 (List[int]): 加密 UA (Encrypted User-Agent). |
| 590 | aid (int): AID 值 (AID value). |
| 591 | pageId (int): 页面 ID (Page ID). |
| 592 | salt (str): 加密盐值 (Encryption salt). |
| 593 | options (List[int]): 请求选项 (Request options). |
| 594 | ua_key (bytes): UA 加密密钥 (UA encryption key). |
| 595 | character (str): 自定义 Base64 字符表 (Custom Base64 alphabet). |
| 596 | character2 (str): 自定义 Base64 字符表 (Custom Base64 alphabet). |
| 597 | character_list (List[str]): 自定义 Base64 字符表列表 (List of custom Base64 alphabets). |
| 598 | crypto_utility (CryptoUtility): 加密工具类 (Encryption utility). |
| 599 | user_agent (str): 自定义 UA (Custom User-Agent). |
| 600 | browser_fp (str): 浏览器指纹 (Browser fingerprint). |
| 601 | sort_index (List[int]): 排序索引 (Sort index). |
| 602 | sort_index_2 (List[int]): 排序索引 (Sort index). |
| 603 | |
| 604 | 说明: |
| 605 | options 参数用于指定请求的类型,GET 请求使用 [0, 1, 8],POST 请求使用 [0, 1, 14]。14兼容8,POST同样可以编码params,故写死。 |
| 606 | (The options parameter is used to specify the type of request. GET requests use [0, 1, 8], and POST requests use [0, 1, 14]. 14 is compatible with 8, and POST can also encode params, so it is hardcoded.) |
| 607 | |
| 608 | 方法: |
| 609 | encode_data(data: str, alphabet_index: int = 0) -> str: |
| 610 | 使用指定的字符表对数据进行 Base64 编码 (Encode the data using the specified Base64 alphabet). |
| 611 | |
| 612 | generate_abogus(params: str, request: str = "") -> str: |
| 613 | 生成 ABogus 参数 (Generate the ABogus parameter). |
| 614 | |
| 615 | 使用示例: |
| 616 | ```python |
| 617 | # 生成 ABogus 参数,置空使用默认 UA 和浏览器指纹 |
| 618 | abogus = ABogus(user_agent="xxx", fp="xxx") |
| 619 | abogus_param = abogus.generate_abogus("device_platform=webapp&aid=6383&channel=channel_pc_web&aweme_id=7380308675841297704……省略……") |
| 620 | print(abogus_param[1]) |
| 621 | ``` |
| 622 | """ |
| 623 | |
| 624 | def __init__( |
| 625 | self, |
| 626 | fp: str = "", |
| 627 | user_agent: str = "", |
| 628 | options: List[int] = [0, 1, 14], |
| 629 | ): |
| 630 | self.aid = 6383 |
| 631 | self.pageId = 0 # 1.0.1.19 -> 6241 |
| 632 | self.salt = "cus" # 1.0.1.19 -> 加密盐 # dhzx |
| 633 | self.boe = False |
| 634 | self.ddrt = 8.5 |
| 635 | self.ic = 8.5 |
| 636 | self.paths = [ |
| 637 | "^/webcast/", |
| 638 | "^/aweme/v1/", |
| 639 | "^/aweme/v2/", |
| 640 | "/v1/message/send", |
| 641 | "^/live/", |
| 642 | "^/captcha/", |
| 643 | "^/ecom/", |
| 644 | ] |
| 645 | self.array1 = [] # 加密请求体 |
| 646 | self.array2 = [] # 加密请求头 为空 |
| 647 | self.array3 = [] # 加密UA |
| 648 | self.options = options # GET [0, 1, 8] POST [0, 1, 14] |
| 649 | self.ua_key = b"\x00\x01\x0e" # ua加密key |
| 650 | |
| 651 | self.character = "Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe" |
| 652 | self.character2 = "ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe" |
| 653 | self.character_list = [self.character, self.character2] # 自定义base64字符表 |
| 654 | |
| 655 | self.crypto_utility = CryptoUtility(self.salt, self.character_list) # 加密工具类 |
| 656 | |
| 657 | self.user_agent = ( |
| 658 | user_agent |
| 659 | if user_agent is not None and user_agent != "" |
| 660 | else "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0" |
| 661 | ) # 自定义ua,为空则设置一个默认ua |
| 662 | |
| 663 | self.browser_fp = ( |
| 664 | fp |
| 665 | if fp is not None and fp != "" |
| 666 | else BrowserFingerprintGenerator.generate_fingerprint("Edge") |
| 667 | ) # 自定义浏览器指纹,为空则生成Edge指纹 |
| 668 | |
| 669 | # fmt: off |
| 670 | self.sort_index = [ |
| 671 | 18, 20, 52, 26, 30, 34, 58, 38, 40, 53, 42, 21, 27, 54, 55, 31, 35, 57, 39, 41, 43, 22, 28, |
| 672 | 32, 60, 36, 23, 29, 33, 37, 44, 45, 59, 46, 47, 48, 49, 50, 24, 25, 65, 66, 70, 71 |
| 673 | ] |
| 674 | self.sort_index_2 = [ |
| 675 | 18, 20, 26, 30, 34, 38, 40, 42, 21, 27, 31, 35, 39, 41, 43, 22, 28, 32, 36, 23, 29, 33, 37, |
| 676 | 44, 45, 46, 47, 48, 49, 50, 24, 25, 52, 53, 54, 55, 57, 58, 59, 60, 65, 66, 70, 71 |
| 677 | ] |
| 678 | # fmt: on |
| 679 | |
| 680 | def encode_data(self, data: str, alphabet_index: int = 0) -> str: |
| 681 | """ |
| 682 | 使用指定的字符表对数据进行 Base64 编码 (Encode the data using the specified Base64 alphabet). |
| 683 | |
| 684 | Args: |
| 685 | data (str): 输入数据 (Input data). |
| 686 | alphabet_index (int): 自定义字符表索引 (Custom alphabet index). |
| 687 | |
| 688 | Returns: |
| 689 | str: 编码后的数据 (Encoded data). |
| 690 | """ |
| 691 | return self.crypto_utility.abogus_encode(data, alphabet_index) |
| 692 | |
| 693 | def generate_abogus(self, params: str, body: str = "") -> tuple: |
| 694 | """ |
| 695 | 生成 abogus 参数 (Generate the ABogus parameter). |
| 696 | |
| 697 | Args: |
| 698 | params (str): 请求参数 (Request parameters). |
| 699 | body (str): 请求体,GET接口则为空 (Request body, empty for GET interfaces). |
| 700 | |
| 701 | Returns: |
| 702 | tuple: params 生成的 abogus 参数 和 ua (ABogus parameter generated by params and ua). |
| 703 | """ |
| 704 | ab_dir = { |
| 705 | 8: 3, # 固定 |
| 706 | 15: { |
| 707 | "aid": self.aid, |
| 708 | "pageId": self.pageId, |
| 709 | "boe": self.boe, |
| 710 | "ddrt": self.ddrt, |
| 711 | "paths": self.paths, |
| 712 | "track": {"mode": 0, "delay": 300, "paths": []}, |
| 713 | "dump": True, |
| 714 | "rpU": "", |
| 715 | }, |
| 716 | 18: 44, |
| 717 | 19: [1, 0, 1, 0, 1], |
| 718 | 66: 0, # 固定 |
| 719 | 69: 0, # 固定 |
| 720 | 70: 0, # 固定 |
| 721 | 71: 0, # 固定 |
| 722 | } |
| 723 | |
| 724 | # 开始加密时间 |
| 725 | start_encryption = int(time.time() * 1000) |
| 726 | |
| 727 | # params参数加盐加密 |
| 728 | array1 = self.crypto_utility.params_to_array(self.crypto_utility.params_to_array(params)) |
| 729 | array2 = self.crypto_utility.params_to_array(self.crypto_utility.params_to_array(body)) |
| 730 | array3 = self.crypto_utility.params_to_array( |
| 731 | self.crypto_utility.base64_encode( |
| 732 | StringProcessor.to_ord_str( |
| 733 | self.crypto_utility.rc4_encrypt(self.ua_key, self.user_agent) |
| 734 | ), |
| 735 | 1, |
| 736 | ), |
| 737 | add_salt=False, |
| 738 | ) |
| 739 | |
| 740 | # 结束加密时间 |
| 741 | end_encryption = int(time.time() * 1000) |
| 742 | |
| 743 | # 插入加密开始时间 |
| 744 | ab_dir[20] = (start_encryption >> 24) & 255 |
| 745 | ab_dir[21] = (start_encryption >> 16) & 255 |
| 746 | ab_dir[22] = (start_encryption >> 8) & 255 |
| 747 | ab_dir[23] = start_encryption & 255 |
| 748 | ab_dir[24] = int(start_encryption / 256 / 256 / 256 / 256) >> 0 |
| 749 | ab_dir[25] = int(start_encryption / 256 / 256 / 256 / 256 / 256) >> 0 |
| 750 | |
| 751 | # 插入请求头配置 |
| 752 | ab_dir[26] = (self.options[0] >> 24) & 255 |
| 753 | ab_dir[27] = (self.options[0] >> 16) & 255 |
| 754 | ab_dir[28] = (self.options[0] >> 8) & 255 |
| 755 | ab_dir[29] = self.options[0] & 255 |
| 756 | |
| 757 | # 插入请求方法 |
| 758 | ab_dir[30] = int(self.options[1] / 256) & 255 |
| 759 | ab_dir[31] = (self.options[1] % 256) & 255 |
| 760 | ab_dir[32] = (self.options[1] >> 24) & 255 |
| 761 | ab_dir[33] = (self.options[1] >> 16) & 255 |
| 762 | |
| 763 | # 插入请求头加密 |
| 764 | ab_dir[34] = (self.options[2] >> 24) & 255 |
| 765 | ab_dir[35] = (self.options[2] >> 16) & 255 |
| 766 | ab_dir[36] = (self.options[2] >> 8) & 255 |
| 767 | ab_dir[37] = self.options[2] & 255 |
| 768 | |
| 769 | # 插入请求体加密 |
| 770 | ab_dir[38] = array1[21] |
| 771 | ab_dir[39] = array1[22] |
| 772 | # 插入body加密 |
| 773 | ab_dir[40] = array2[21] |
| 774 | ab_dir[41] = array2[22] |
| 775 | # 插入ua加密 |
| 776 | ab_dir[42] = array3[23] |
| 777 | ab_dir[43] = array3[24] |
| 778 | |
| 779 | # 插入加密结束时间 |
| 780 | ab_dir[44] = (end_encryption >> 24) & 255 |
| 781 | ab_dir[45] = (end_encryption >> 16) & 255 |
| 782 | ab_dir[46] = (end_encryption >> 8) & 255 |
| 783 | ab_dir[47] = end_encryption & 255 |
| 784 | ab_dir[48] = ab_dir[8] |
| 785 | ab_dir[49] = int(end_encryption / 256 / 256 / 256 / 256) >> 0 |
| 786 | ab_dir[50] = int(end_encryption / 256 / 256 / 256 / 256 / 256) >> 0 |
| 787 | |
| 788 | # 插入固定值 |
| 789 | ab_dir[51] = (self.pageId >> 24) & 255 |
| 790 | ab_dir[52] = (self.pageId >> 16) & 255 |
| 791 | ab_dir[53] = (self.pageId >> 8) & 255 |
| 792 | ab_dir[54] = self.pageId & 255 |
| 793 | ab_dir[55] = self.pageId |
| 794 | ab_dir[56] = self.aid |
| 795 | ab_dir[57] = self.aid & 255 |
| 796 | ab_dir[58] = (self.aid >> 8) & 255 |
| 797 | ab_dir[59] = (self.aid >> 16) & 255 |
| 798 | ab_dir[60] = (self.aid >> 24) & 255 |
| 799 | |
| 800 | # 插入浏览器指纹 |
| 801 | ab_dir[64] = len(self.browser_fp) |
| 802 | ab_dir[65] = len(self.browser_fp) |
| 803 | |
| 804 | # 获取 ab_dir 中 sort_index 的值 |
| 805 | sorted_values = [ab_dir.get(i, 0) for i in self.sort_index] |
| 806 | |
| 807 | # 将浏览器指纹转换为 ASCII 码列表 |
| 808 | edge_fp_array = StringProcessor.to_char_array(self.browser_fp) |
| 809 | |
| 810 | # 将浏览器指纹长度的低 8 位作为异或值 |
| 811 | ab_xor = (len(self.browser_fp) & 255) >> 8 & 255 |
| 812 | |
| 813 | # 进行异或计算 |
| 814 | for index in range(len(self.sort_index_2) - 1): |
| 815 | if index == 0: |
| 816 | ab_xor = ab_dir.get(self.sort_index_2[index], 0) |
| 817 | ab_xor ^= ab_dir.get(self.sort_index_2[index + 1], 0) |
| 818 | |
| 819 | sorted_values.extend(edge_fp_array) |
| 820 | sorted_values.append(ab_xor) |
| 821 | |
| 822 | abogus_bytes_str = ( |
| 823 | StringProcessor.generate_random_bytes() |
| 824 | + self.crypto_utility.transform_bytes(sorted_values) |
| 825 | ) |
| 826 | |
| 827 | abogus = self.crypto_utility.abogus_encode(abogus_bytes_str, 0) |
| 828 | params = "%s&a_bogus=%s" % (params, abogus) |
| 829 | return (params, abogus, self.user_agent, body) |
| 830 | |
| 831 | |
| 832 | if __name__ == "__main__": |
| 833 | # 24/06/16 晚点开源自定义ua |
| 834 | # 24/07/08 支持自定义ua和浏览器指纹 |
| 835 | # 24/11/15 完成1.0.1.19版本abogus算法,择日开源 |
| 836 | # 25/03/05 修复POST请求参数加密错误,修补环境 |
| 837 | |
| 838 | user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0" |
| 839 | chrome_fp = BrowserFingerprintGenerator.generate_fingerprint("Edge") |
| 840 | abogus = ABogus(user_agent=user_agent, fp=chrome_fp) |
| 841 | |
| 842 | # GET |
| 843 | url = "https://www.douyin.com/aweme/v1/web/aweme/detail/?" |
| 844 | params = "device_platform=webapp&aid=6383&channel=channel_pc_web&sec_user_id=MS4wLjABAAAArDVBosPJF3eIWVEFp0szuJ-e1V_-rK0ieJeWwpE77E8&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&from_user_page=1&update_version_code=170400&pc_client_type=1&pc_libra_divert=Windows&support_h265=1&support_dash=0&version_code=290100&version_name=29.1.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=131.0.0.0&browser_online=true&engine_name=Blink&engine_version=131.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" |
| 845 | body = "" |
| 846 | print(url + abogus.generate_abogus(params=params, body=body)[0]) |
| 847 | |
| 848 | # POST |
| 849 | url = "https://www.douyin.com/aweme/v2/web/aweme/stats/?" |
| 850 | params = "device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&pc_libra_divert=Windows&update_version_code=170400&support_h265=1&support_dash=0&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=131.0.0.0&browser_online=true&engine_name=Blink&engine_version=131.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" |
| 851 | body = "aweme_type=0&item_id=7467485482314763572&play_delta=1&source=0" |
| 852 | print(url + abogus.generate_abogus(params=params, body=body)[0]) |
| 853 | |
| 854 | # # 测试生成100个abogus参数 和 100个指纹所需时间 |
| 855 | # start = time.time() |
| 856 | # for _ in range(100): |
| 857 | # abogus.generate_abogus(params=params, body=body) |
| 858 | # end = time.time() |
| 859 | # print("生成100个abogus参数和指纹所需时间:", end - start) # 生成100个abogus参数和指纹所需时间: 2.203000783920288 |
| 860 | |
| 861 | # start = time.time() |
| 862 | # for _ in range(100): |
| 863 | # BrowserFingerprintGenerator.generate_fingerprint("Chrome") |
| 864 | # end = time.time() |
| 865 | # print("生成100个指纹所需时间:", end - start) # 生成100个指纹所需时间: 0.00400090217590332 |
| 866 |