GEO Task Worker v2 免安装版 (含嵌入式 Python + 全部依赖)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

152 lines
4.8 KiB

# -*- coding: utf-8 -*-
import time
import random
import struct
import base64
import hmac
import hashlib
import ctypes
class _RC4:
"""
内部使用的 RC4 算法实现,还原了 Java 版本特殊的 Key Scheduling 逻辑
"""
_RC4_PK = "QrMgt8GGYI6T52ZY5AnhtxkLzb8egpFn3j5JELI8H6wtACbUnZ5cc3aYTsTRbmkAkRJeYbtx92LPBWm7nBO9UIl7y5i5MQNmUZNf5QENurR5tGyo7yJ2G0MBjWvy6iAtlAbacKP0SwOUeUWx5dsBdyhxa7Id1APtybSdDgicBDuNjI0mlZFUzZSS9dmN8lBD0WTVOMz0pRZbR3cysomRXOO1ghqjJdTcyDIxzpNAEszN8RMGjrzyU7Hjbmwi6YNK"
def __init__(self):
self.state = list(range(256))
self.x = 0
self.y = 0
self._prepare_key(self._RC4_PK)
def _prepare_key(self, key_str):
key_len = len(key_str)
j = 0
for i in range(256):
c_char_at = ord(key_str[i % key_len])
i13 = self.state[i]
j = (c_char_at + i13 + j) % 256
self.state[i], self.state[j] = self.state[j], self.state[i]
self.x = 0
self.y = 0
def rc4(self, data):
output = bytearray(len(data))
x = self.x
y = self.y
state = list(self.state)
for k in range(len(data)):
x = (x + 1) % 256
sx = state[x]
y = (y + sx) % 256
sy = state[y]
state[x], state[y] = sy, sx
idx = (state[x] + state[y]) % 256
output[k] = data[k] ^ state[idx]
return bytes(output)
class _JavaUtils:
"""
内部工具类:处理 Python 与 Java 之间的数据类型差异(大端序、溢出处理)
"""
@staticmethod
def get_bytes(val):
"""Int -> 4 bytes (Big Endian)"""
return struct.pack('>i', ctypes.c_int32(val).value)
@staticmethod
def string_hashcode(s):
"""模拟 Java String.hashCode 的溢出行为"""
h = 0
for c in s:
h = (31 * h + ord(c)) & 0xFFFFFFFF
return ctypes.c_int32(h).value
class UTDIDGenerator:
"""
UTDID 生成器主类
"""
def __init__(self):
# 初始化配置与 HMAC Key
self._init_hmac_key()
def _init_hmac_key(self):
MAX_POWER_OF_TWO = 64
OP_LOAD = 24
# 原始 Java 有符号 byte 数组
raw_b_arr2_signed = [
69, 114, 116, -33, 125, -54, -31, 86, -11, 11, -78, -96, -17, -99,
MAX_POWER_OF_TWO,
23, -95, -126, -82, -64, 113, 116, -16, -103,
OP_LOAD,
-30, 9, -39, 33, -80, -68, -78, -117, 53, 30, -122,
MAX_POWER_OF_TWO,
-104, 74, -49, 106, 85, -38, -93
]
# 转换为无符号
b_arr2 = bytearray([b + 256 if b < 0 else b for b in raw_b_arr2_signed])
# 解密出 HMAC Key
self.hmac_key = _RC4().rc4(b_arr2)
def _calc_hmac(self, data):
h = hmac.new(self.hmac_key, data, hashlib.sha1)
signature = h.digest()
return base64.b64encode(signature).decode('utf-8')
def _generate_random_imei(self):
"""生成随机的 15 位数字 IMEI"""
prefix = random.choice(['35', '86', '01', '99'])
suffix = "".join([str(random.randint(0, 9)) for _ in range(15 - len(prefix))])
return prefix + suffix
def generate(self, imei=None):
"""
生成一个 UTDID
:param imei: 可选,指定 IMEI 字符串。如果不传则自动随机生成。
:return: Base64 编码的 UTDID 字符串
"""
buffer = bytearray()
# 1. Timestamp (4 bytes)
timestamp = int(time.time())
buffer.extend(_JavaUtils.get_bytes(timestamp))
# 2. Random Int (4 bytes)
random_int = random.randint(-2147483648, 2147483647)
buffer.extend(_JavaUtils.get_bytes(random_int))
# 3. Version (1 byte) & Reserved (1 byte)
buffer.append(3)
buffer.append(0)
# 4. IMEI Hash (4 bytes)
real_imei = imei if imei else self._generate_random_imei()
imei_hash = _JavaUtils.string_hashcode(real_imei)
buffer.extend(_JavaUtils.get_bytes(imei_hash))
# 5. Checksum (4 bytes)
# 对应: hashCode(calcHmac(bytes[0:14]))
data_14 = bytes(buffer)
hmac_str = self._calc_hmac(data_14)
hmac_hash = _JavaUtils.string_hashcode(hmac_str)
buffer.extend(_JavaUtils.get_bytes(hmac_hash))
# 6. Final Base64
return base64.b64encode(buffer).decode('utf-8')
# --- 快捷单例导出 ---
# 实例化一个默认生成器,外部可以直接 import 这个对象或函数
_default_generator = UTDIDGenerator()
def generate_utdid(imei=None):
"""
快捷函数:生成 UTDID
"""
return _default_generator.generate(imei)
# if __name__ == "__main__":
# # 测试代码
# print("--- Testing UTDID Generator ---")
# print(f"Random: {generate_utdid()}")
# print(f"Fixed: {generate_utdid('865100020000000')}")