def build( cls, uin: int, seq: int, command_name: str, session_id: bytes, body_type: int, body: Union[bytes, Packet], key: bytes, extra_data: bytes = b"", ) -> "UniPacket": data = Packet().write_with_length( struct.pack(">I", len(command_name) + 4), command_name.encode(), struct.pack(">I", len(session_id) + 4), session_id, struct.pack(">I", len(extra_data) + 4), extra_data, offset=4, ) data.write_with_length(body, offset=4) return cls().write_with_length( struct.pack(">IBIB", 0xB, body_type, seq, 0), struct.pack(">I", len(str(uin)) + 4), str(uin).encode(), qqtea_encrypt(bytes(data), key), offset=4, )
def decode_response(cls, uin: int, seq: int, ret_code: int, command_name: str, data: bytes) -> "OICQResponse": """Decode login response and wrap main info of the response. Note: Source: oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswd Args: uin (int): User QQ seq (int): Sequence number of the response packet. ret_code (int): Return code of the response. command_name (str): Command name of the response. data (bytes): Payload data of the response. Returns: LoginSuccess: Login success. NeedCaptcha: Captcha image needed. AccountFrozen: Account is frozen. DeviceLocked: Device lock detected. TooManySMSRequest: Too many SMS messages were sent. DeviceLockLogin: More login packet needed. UnknownLoginStatus: Unknown login status. OICQResponse: Invalid login response. """ if ret_code != 0 or not data: return OICQResponse(uin, seq, ret_code, command_name) data_ = Packet(data) sub_command, status, _tlv_bytes = ( data_.start().uint16().uint8().offset(2).remain().execute()) _tlv_map = TlvDecoder.decode(_tlv_bytes) if status == 0: return LoginSuccess(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) elif status == 2: return NeedCaptcha(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) elif status == 40: return AccountFrozen(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) elif status == 160 or status == 239: return DeviceLocked(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) elif status == 162: return TooManySMSRequest(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) elif status == 204: return DeviceLockLogin(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) else: return UnknownLoginStatus(uin, seq, ret_code, command_name, sub_command, status, _tlv_map)
def t512(cls, data: bytes) -> Dict[str, Any]: data_ = Packet(data) offset = 0 length = data_.read_uint16() offset += 2 ps_key_map: Dict[str, bytes] = {} pt4_token_map: Dict[str, bytes] = {} for _ in range(length): domain_length = data_.read_uint16(offset) offset += 2 domain = data_.read_bytes(domain_length, offset).decode() offset += domain_length key_length = data_.read_uint16(offset) offset += 2 ps_key = data_.read_bytes(key_length, offset) offset += key_length token_length = data_.read_uint16(offset) offset += 2 ps4_token = data_.read_bytes(token_length, offset) offset += token_length ps_key_map[domain] = ps_key pt4_token_map[domain] = ps4_token return {"ps_key_map": ps_key_map, "pt4_token_map": pt4_token_map}
def parse( cls, data: Union[bytes, bytearray], key: bytes, d2key: bytes, session_key: bytes, ) -> "IncomingPacket": if not isinstance(data, Packet): data = Packet(data) packet_type, encrypt_type, flag3, uin, payload = ( data.start().uint32().uint8().uint8().string(4, 4).remain().execute()) if packet_type not in [0xA, 0xB]: raise ValueError( f"Invalid packet type. Expected 0xA / 0xB, got {packet_type}.") if flag3 != 0: raise ValueError(f"Invalid flag3. Expected 0, got {flag3}.") try: uin = int(uin) except ValueError: uin = 0 if encrypt_type == 0: pass elif encrypt_type == 1: payload = Packet(qqtea_decrypt(bytes(payload), d2key)) elif encrypt_type == 2: payload = Packet(qqtea_decrypt(bytes(payload), bytes(16))) else: raise ValueError( f"Invalid encrypt type. Expected 0 / 1 / 2, got {encrypt_type}." ) if not payload: raise ValueError(f"Data cannot be none.") # offset = 0 # sso_head_length = payload.read_int32(offset) - 4 # offset += 4 offset = 4 sso_frame = payload[offset:] return cls.parse_sso_frame(sso_frame, encrypt_type, key, session_key, uin=uin)
def t106( cls, sso_version: int, app_id: int, sub_app_id: int, app_client_version: int, uin: int, salt: int, password_md5: bytes, guid: bytes, tgtgt_key: bytes, ip: bytes = bytes(4), save_password: bool = True, login_type: int = 1, # password login ) -> "Packet[()]": key = md5( Packet.build(password_md5, bytes(4), struct.pack(">I", salt or uin))).digest() body = Packet.build( struct.pack( ">HIIIIQ", 4, # tgtgt version cls._random_int32(), sso_version, app_id, app_client_version, uin or salt, ), struct.pack(">I", int(time.time())), ip, struct.pack(">?", save_password), struct.pack(">16s", password_md5), tgtgt_key, struct.pack(">I?", 0, bool(guid)), guid or struct.pack( ">IIII", cls._random_int32(), cls._random_int32(), cls._random_int32(), cls._random_int32(), ), struct.pack(">II", sub_app_id, login_type), cls._pack_lv(str(uin).encode()), struct.pack(">H", 0), # not found in source ) data = qqtea_encrypt(bytes(body), key) return cls._pack_tlv(0x106, data)
def t130(cls, data: bytes) -> Dict[str, Any]: """Decode tlv 130 data. Data: * time_diff (int): time difference between server and local. * ip_address (bytes(4)): may be server ip Note: Source: oicq.wlogin_sdk.tlv_type.tlv_t130 """ data_ = Packet(data) return { "time_diff": data_.read_int32(offset=2) - int(time.time()), "ip_address": data_.read_bytes(4, offset=6), }
def build( cls, uin: int, body_type: int, body: Union[bytes, Packet], ksso_version: int = 0xA, key: Optional[bytes] = None, extra_data: bytes = b"", ) -> "CSsoDataPacket": """Build CSSOPacket head and append body. Packet body was encrypted in `CSSOData::serialize`. Note: Source: `CSSOHead::serialize_verFull` """ return cls().write_with_length( Packet.build( struct.pack(">IB", ksso_version, body_type), struct.pack(">I", len(extra_data) + 4), extra_data, bytes([0]), struct.pack(">I", len(str(uin)) + 4), str(uin).encode(), qqtea_encrypt(bytes(body), key) if key else body, ), offset=4, )
def t144( cls, imei: bytes, bootloader: str, proc_version: str, codename: str, incremental: str, fingerprint: str, boot_id: str, android_id: str, baseband: str, inner_version: str, os_type: bytes, os_version: bytes, network_type: int, sim_info: bytes, apn: bytes, is_guid_from_file_null: bool, is_guid_available: bool, is_guid_changed: bool, guid_flag: int, build_model: bytes, guid: bytes, build_brand: bytes, tgtgt_key: bytes, ) -> "Packet[()]": return cls._pack_tlv( 0x144, qqtea_encrypt( bytes( Packet.build( struct.pack(">H", 5), # tlv count cls.t109(imei), cls.t52d( bootloader, proc_version, codename, incremental, fingerprint, boot_id, android_id, baseband, inner_version, ), cls.t124(os_type, os_version, network_type, sim_info, apn), cls.t128( is_guid_from_file_null, is_guid_available, is_guid_changed, guid_flag, build_model, guid, build_brand, ), cls.t16e(build_model), )), tgtgt_key, ), )
def encrypt( self, data: Union[bytes, Packet], key: Union[bytes, Packet] ) -> Packet: return Packet.build( struct.pack(">H", len(self.ticket)), self.ticket, qqtea_encrypt(bytes(data), bytes(key)), )
def parse_sso_frame( cls, sso_frame: Union[bytes, bytearray], encrypt_type: int, key: bytes, session_key: bytes, **kwargs, ) -> "IncomingPacket": if not isinstance(sso_frame, Packet): sso_frame = Packet(sso_frame) seq, ret_code, extra, command_name, session_id, data = ( sso_frame.start().uint32().int32().bytes_with_length(4, 4).string( 4, 4).bytes_with_length(4, 4).remain().execute()) if not data: return cls( seq=seq, ret_code=ret_code, extra=extra, command_name=command_name, session_id=session_id, data=bytes(), **kwargs, ) compress_type, compressed_data = data.start().int32().remain().execute( ) decompressed_data: bytes if compress_type == 0: # data_length = sso_frame.read_int32(offset) # if data_length == len(sso_frame) - offset or data_length == len( # sso_frame # ) - offset - 4: # decompressed_data = sso_frame[offset + 4:] # else: # decompressed_data = sso_frame[offset + 4:] decompressed_data = compressed_data[4:] elif compress_type == 1: decompressed_data = zlib.decompress(compressed_data[4:]) elif compress_type == 8: decompressed_data = compressed_data[4:] else: raise ValueError(f"Unknown compression type, got {compress_type}.") if encrypt_type == 2: decompressed_data = cls.parse_oicq_body(decompressed_data, key, session_key) return cls( seq=seq, ret_code=ret_code, extra=extra, command_name=command_name, session_id=session_id, data=decompressed_data, **kwargs, )
def __init__( self, uin: int, seq: int, ret_code: int, command_name: str, sub_command: int, status: int, _tlv_map: Dict[int, Any], ): super().__init__(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) self.sms_phone = None self.verify_url = _tlv_map.get(0x204, b"").decode() or None self.message = _tlv_map.get(0x17E, b"").decode() or None self.rand_seed = _tlv_map.get(0x403) self.t104 = _tlv_map.get(0x104) self.t174 = _tlv_map.get(0x174) if self.t174: t178 = Packet(_tlv_map[0x178]) self.sms_phone = t178.start().string(4).execute()[0]
def __init__( self, uin: int, seq: int, ret_code: int, command_name: str, sub_command: int, status: int, _tlv_map: Dict[int, Any], ): super().__init__(uin, seq, ret_code, command_name, sub_command, status, _tlv_map) self.t104 = _tlv_map[0x104] self.captcha_image = bytes() self.captcha_sign = bytes() self.verify_url = _tlv_map.get(0x192, b"").decode() if 0x165 in _tlv_map: data = Packet(_tlv_map[0x165]) sign, image = (data.start().bytes_with_length( 2, 4).remain().execute()) self.captcha_sign = sign[2:] self.captcha_image = bytes(image)
def encrypt( cls, data: Union[bytes, Packet], key: Union[bytes, Packet] ) -> Packet: return Packet.build( struct.pack(">BB", 2, 1), key, struct.pack( ">HHH", 305, 1, # oicq.wlogin_sdk.tools.EcdhCrypt.sKeyVersion len(cls.client_public_key), ), cls.client_public_key, qqtea_encrypt(bytes(data), cls.share_key), )
def parse_oicq_body(cls, data: Union[bytes, bytearray], key: bytes, session_key: bytes) -> bytes: """Parse incoming OICQ packet. Note: Source: oicq.wlogin_sdk.request.oicq_request.b Args: data (Union[bytes, Packet]): OICQ data. key (bytes): Random key. session_key (bytes): Siginfo wt_session_ticket_key. Raises: ValueError: Flag error or unknown encrypt type. Returns: bytes: Decode data. """ if not isinstance(data, Packet): data = Packet(data) flag, encrypt_type, body = (data.start().uint8().offset( 12).uint16().offset(1).remain().execute()) if flag != 2: raise ValueError( f"Invalid OICQ response flag. Expected 2, got {flag}.") body = body[:-1] if encrypt_type == 0: try: return qqtea_decrypt(bytes(body), ECDH.share_key) except Exception: return qqtea_decrypt(bytes(body), key) elif encrypt_type == 3: return qqtea_decrypt(bytes(body), session_key) elif encrypt_type == 4: # seems not used # data = qqtea_decrypt(bytes(body), ECDH.share_key) # ... raise NotImplementedError else: raise ValueError(f"Unknown encrypt type: {encrypt_type}")
def t400( cls, g: bytes, uin: int, guid: bytes, dpwd: bytes, app_id: int, sub_app_id: int, rand_seed: bytes, _version: int = 1, ) -> "Packet[()]": data = Packet.build( struct.pack(">HQ", _version, uin), guid, dpwd, struct.pack(">III", app_id, sub_app_id, int(time.time())), rand_seed, ) return cls._pack_tlv(0x400, qqtea_encrypt(bytes(data), g))
def decode( cls, data: Union[bytes, bytearray], offset: int = 0, tag_size: int = 2, ) -> Dict[int, Any]: if not isinstance(data, Packet): data = Packet(data) result: Dict[int, bytes] = {} while offset + tag_size <= len(data): tag: int if tag_size == 1: tag = data.read_int8(offset) offset += 1 elif tag_size == 2: tag = data.read_int16(offset) offset += 2 elif tag_size == 4: tag = data.read_int32(offset) offset += 4 else: raise ValueError( f"Invalid tag size. Expected 1 / 2 / 4, got {tag_size}.") if tag == 255: return result length = data.read_uint16(offset) offset += 2 value = data.read_bytes(length, offset) offset += length futher_decode = getattr(cls, f"t{tag:x}", None) if futher_decode: value = futher_decode(value) result[tag] = value return result
def t199(cls, data: bytes) -> Dict[str, Any]: """Decode tlv 199 data. Data: * open_id (bytes) * pay_token (bytes) Note: Source: oicq.wlogin_sdk.tlv_type.tlv_t199 """ data_ = Packet(data) offset = 0 id_length = data_.read_uint16(offset) offset += 2 + id_length token_length = data_.read_uint16(offset) return { "open_id": data_.read_bytes(id_length, 2), "pay_token": data_.read_bytes(token_length, offset + 2), }
def t125(cls, data: bytes) -> Dict[str, Any]: """Decode tlv 125 data. Data: * open_id (bytes) * open_key (bytes) Note: Source: oicq.wlogin_sdk.tlv_type.tlv_t125 """ data_ = Packet(data) offset = 0 id_length = data_.read_uint16(offset) offset += 2 + id_length key_length = data_.read_uint16(offset) return { "open_id": data_.read_bytes(id_length, 2), "open_key": data_.read_bytes(key_length, offset + 2), }
def t200(cls, data: bytes) -> Dict[str, Any]: """Decode tlv 200 data. Data: * pf (bytes) * pf_key (bytes) Note: Source: oicq.wlogin_sdk.tlv_type.tlv_t200 """ data_ = Packet(data) offset = 0 pf_length = data_.read_uint16(offset) offset += 2 + pf_length key_length = data_.read_uint16(offset) return { "pf": data_.read_bytes(pf_length, 2), "pf_key": data_.read_bytes(key_length, offset + 2), }
def t11a(cls, data: bytes) -> Dict[str, Any]: """Decode tlv 11a data. Data: * face (bytes(2)) * age (int) * gender (int) * nick (str) Note: Source: oicq.wlogin_sdk.tlv_type.tlv_t11a """ data_ = Packet(data) return { "face": data_.read_bytes(2), "age": data_.read_uint8(offset=2), "gender": data_.read_uint8(offset=3), "nick": data_.read_bytes(data_.read_uint8(offset=4), offset=5).decode(), }
async def _handle_login_response(self, response: Command, try_times: int = 1) -> LoginSuccess: if not isinstance(response, OICQResponse): raise RuntimeError("Invalid login response type!") if not isinstance(response, UnknownLoginStatus): raise ApiResponseError( response.uin, response.seq, response.ret_code, response.command_name, ) if isinstance(response, LoginSuccess): logger.info(f"{self.nick}({self.uin}) 登录成功!") await self._init() return response elif isinstance(response, NeedCaptcha): if response.verify_url: logger.info(f"登录失败!请前往 {response.verify_url} 获取 ticket") raise LoginSliderNeeded(response.uin, response.verify_url) elif response.captcha_image: logger.info(f"登录失败!需要根据图片输入验证码") raise LoginCaptchaNeeded(response.uin, response.captcha_image, response.captcha_sign) else: raise LoginException( response.uin, response.status, "Cannot get verify_url or captcha_image from the response!", ) elif isinstance(response, AccountFrozen): logger.info("账号已被冻结!") raise LoginAccountFrozen(response.uin) elif isinstance(response, DeviceLocked): msg = "账号已开启设备锁!" if response.sms_phone: msg += f"向手机{response.sms_phone}发送验证码 " if response.verify_url: msg += f"或前往{response.verify_url}扫码验证" logger.info(msg + ". " + str(response.message)) raise LoginDeviceLocked( response.uin, response.sms_phone, response.verify_url, response.message, ) elif isinstance(response, TooManySMSRequest): logger.info("验证码发送频繁!") raise LoginSMSRequestError(response.uin) elif isinstance(response, DeviceLockLogin): if try_times: seq = self.next_seq() packet = encode_login_request20( seq, self._key, self._session_id, self._ksid, self.uin, self._t104, self._siginfo.g, ) response = await self.send_and_wait(seq, "wtlogin.login", packet) return await self._handle_login_response( response, try_times - 1) else: raise LoginException( response.uin, response.status, "Maximum number of login attempts exceeded!", ) elif isinstance(response, UnknownLoginStatus): t146 = response._tlv_map.get(0x146) t149 = response._tlv_map.get(0x149) if t146: packet_ = Packet(t146) msg = packet_.start(4).string(2).execute()[0] elif t149: packet_ = Packet(t149) msg = packet_.start(2).string(2).execute()[0] else: msg = "" logger.info(f"未知的登录返回码 {response.status}! {msg}") raise LoginException(response.uin, response.status, "Unknown login status.")
def _pack_tlv(cls, type: int, *data: Union[bytes, bytearray]) -> "Packet[()]": return Packet(struct.pack(">HH", type, sum(map(len, data)))).write(*data)
def encode_login_request20( seq: int, key: bytes, session_id: bytes, ksid: bytes, uin: int, t104: bytes, g: bytes, ) -> Packet: """Build device lock login request packet. Called in ``oicq.wlogin_sdk.request.WtloginHelper.GetStWithoutPasswd``. command id: ``0x810 = 2064`` sub command id: ``20`` command name: ``wtlogin.login`` Note: Source: oicq.wlogin_sdk.request.p Args: seq (int): Packet sequence. key (bytes): 16 bits key used to decode the response. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. t104 (bytes): T104 response data. g (bytes): md5 of (guid + dpwd + t402). Returns: Packet: Login packet. """ COMMAND_ID = 2064 SUB_COMMAND_ID = 20 COMMAND_NAME = "wtlogin.login" SUB_APP_ID = APK_INFO.sub_app_id BITMAP = APK_INFO.bitmap SUB_SIGMAP = APK_INFO.sub_sigmap LOCAL_ID = 2052 # oicq.wlogin_sdk.request.t.v data = Packet.build( struct.pack(">HH", SUB_COMMAND_ID, 4), # packet num TlvEncoder.t8(LOCAL_ID), TlvEncoder.t104(t104), TlvEncoder.t116(BITMAP, SUB_SIGMAP), TlvEncoder.t401(g), ) oicq_packet = OICQRequest.build_encoded(uin, COMMAND_ID, ECDH.encrypt(data, key), ECDH.id) sso_packet = CSsoBodyPacket.build( seq, SUB_APP_ID, COMMAND_NAME, DEVICE.imei, session_id, ksid, oicq_packet, ) # encrypted by 16-byte zero. Reference: ``CSSOData::serialize`` packet = CSsoDataPacket.build(uin, 2, sso_packet, key=bytes(16)) return packet
def encode_login_request2_captcha( seq: int, key: bytes, session_id: bytes, ksid: bytes, uin: int, captcha: str, sign: bytes, t104: bytes, ) -> Packet: """Build submit captcha request packet. Called in ``oicq.wlogin_sdk.request.WtloginHelper.CheckPictureAndGetSt``. command id: ``0x810 = 2064`` sub command id: ``2`` command name: ``wtlogin.login`` Note: Source: oicq.wlogin_sdk.request.n Args: seq (int): Packet sequence. key (bytes): 16 bits key used to decode the response. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. captcha (str): Captcha image result. sign (bytes): Signature of the captcha. t104 (bytes): TLV 104 data. Returns: Packet: Login packet. """ COMMAND_ID = 2064 SUB_COMMAND_ID = 2 COMMAND_NAME = "wtlogin.login" SUB_APP_ID = APK_INFO.sub_app_id BITMAP = APK_INFO.bitmap SUB_SIGMAP = APK_INFO.sub_sigmap LOCAL_ID = 2052 # oicq.wlogin_sdk.request.t.v data = Packet.build( struct.pack(">HH", SUB_COMMAND_ID, 4), # packet num TlvEncoder.t2(captcha.encode(), sign), TlvEncoder.t8(LOCAL_ID), TlvEncoder.t104(t104), TlvEncoder.t116(BITMAP, SUB_SIGMAP), ) oicq_packet = OICQRequest.build_encoded(uin, COMMAND_ID, ECDH.encrypt(data, key), ECDH.id) sso_packet = CSsoBodyPacket.build( seq, SUB_APP_ID, COMMAND_NAME, DEVICE.imei, session_id, ksid, oicq_packet, ) # encrypted by 16-byte zero. Reference: ``CSSOData::serialize`` packet = CSsoDataPacket.build(uin, 2, sso_packet, key=bytes(16)) return packet
def encode_login_request9( seq: int, key: bytes, session_id: bytes, ksid: bytes, uin: int, password_md5: bytes, ) -> Packet: """Build main login request packet. Called in ``oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswd``. command id: ``0x810 = 2064`` sub command id: ``9`` command name: ``wtlogin.login`` Note: Source: oicq.wlogin_sdk.request.k Args: seq (int): Packet sequence. key (bytes): 16 bits key used to decode the response. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. password_md5 (bytes): User QQ password md5 hash. Returns: Packet: Login packet. """ COMMAND_ID = 2064 SUB_COMMAND_ID = 9 COMMAND_NAME = "wtlogin.login" APK_ID = APK_INFO.apk_id APK_VERSION = APK_INFO.version APK_SIGN = APK_INFO.apk_sign APK_BUILD_TIME = APK_INFO.build_time APP_ID = APK_INFO.app_id SUB_APP_ID = APK_INFO.sub_app_id APP_CLIENT_VERSION = 0 SDK_VERSION = APK_INFO.sdk_version SSO_VERSION = APK_INFO.sso_version BITMAP = APK_INFO.bitmap MAIN_SIGMAP = APK_INFO.main_sigmap SUB_SIGMAP = APK_INFO.sub_sigmap GUID_SRC = 1 GUID_CHANGE = 0 GUID_FLAG = 0 GUID_FLAG |= GUID_SRC << 24 & 0xFF000000 GUID_FLAG |= GUID_CHANGE << 8 & 0xFF00 CAN_WEB_VERIFY = 130 # oicq.wlogin_sdk.request.k.K LOCAL_ID = 2052 # oicq.wlogin_sdk.request.t.v IP_BYTES: bytes = ipaddress.ip_address(DEVICE.ip_address).packed NETWORK_TYPE = (DEVICE.apn == "wifi") + 1 data = Packet.build( struct.pack(">HH", SUB_COMMAND_ID, 23), # packet num TlvEncoder.t18(APP_ID, APP_CLIENT_VERSION, uin), TlvEncoder.t1(uin, int(time.time()), IP_BYTES), TlvEncoder.t106( SSO_VERSION, APP_ID, SUB_APP_ID, APP_CLIENT_VERSION, uin, 0, password_md5, DEVICE.guid, DEVICE.tgtgt, ), TlvEncoder.t116(BITMAP, SUB_SIGMAP), TlvEncoder.t100(SSO_VERSION, APP_ID, SUB_APP_ID, APP_CLIENT_VERSION, MAIN_SIGMAP), TlvEncoder.t107(), # TlvEncoder.t108(KSID), # null when first time login # TlvEncoder.t104(), TlvEncoder.t142(APK_ID), TlvEncoder.t144( DEVICE.imei.encode(), DEVICE.bootloader, DEVICE.proc_version, DEVICE.version.codename, DEVICE.version.incremental, DEVICE.fingerprint, DEVICE.boot_id, DEVICE.android_id, DEVICE.baseband, DEVICE.version.incremental, DEVICE.os_type.encode(), DEVICE.version.release.encode(), NETWORK_TYPE, DEVICE.sim.encode(), DEVICE.apn.encode(), False, True, False, GUID_FLAG, DEVICE.model.encode(), DEVICE.guid, DEVICE.brand.encode(), DEVICE.tgtgt, ), TlvEncoder.t145(DEVICE.guid), TlvEncoder.t147(APP_ID, APK_VERSION.encode(), APK_SIGN), # TlvEncoder.t166(1), # TlvEncoder.t16a(), TlvEncoder.t154(seq), TlvEncoder.t141(DEVICE.sim.encode(), NETWORK_TYPE, DEVICE.apn.encode()), TlvEncoder.t8(LOCAL_ID), TlvEncoder.t511([ "tenpay.com", "openmobile.qq.com", "docs.qq.com", "connect.qq.com", "qzone.qq.com", "vip.qq.com", "gamecenter.qq.com", "qun.qq.com", "game.qq.com", "qqweb.qq.com", "office.qq.com", "ti.qq.com", "mail.qq.com", "mma.qq.com", ]), # com.tencent.mobileqq.msf.core.auth.l # TlvEncoder.t172(), # TlvEncoder.t185(1), # when sms login, is_password_login == 3 # TlvEncoder.t400(), # null when first time login TlvEncoder.t187(DEVICE.mac_address.encode()), TlvEncoder.t188(DEVICE.android_id.encode()), TlvEncoder.t194(DEVICE.imsi_md5) if DEVICE.imsi_md5 else b"", TlvEncoder.t191(CAN_WEB_VERIFY), # TlvEncoder.t201(), TlvEncoder.t202(DEVICE.wifi_bssid.encode(), DEVICE.wifi_ssid.encode()), TlvEncoder.t177(APK_BUILD_TIME, SDK_VERSION), TlvEncoder.t516(), TlvEncoder.t521(), TlvEncoder.t525(TlvEncoder.t536([])), # TlvEncoder.t318() # not login in by qr ) oicq_packet = OICQRequest.build_encoded(uin, COMMAND_ID, ECDH.encrypt(data, key), ECDH.id) sso_packet = CSsoBodyPacket.build( seq, SUB_APP_ID, COMMAND_NAME, DEVICE.imei, session_id, ksid, oicq_packet, ) # encrypted by 16-byte zero. Reference: ``CSSOData::serialize`` packet = CSsoDataPacket.build(uin, 2, sso_packet, key=bytes(16)) return packet
def encode_login_request8( seq: int, key: bytes, session_id: bytes, ksid: bytes, uin: int, t104: bytes, t174: bytes, ) -> Packet: """Build sms request packet. Called in ``oicq.wlogin_sdk.request.WtloginHelper.RefreshSMSData``. command id: ``0x810 = 2064`` sub command id: ``8`` command name: ``wtlogin.login`` Note: Source: oicq.wlogin_sdk.request.r Args: seq (int): Packet sequence. key (bytes): 16 bits key used to decode the response. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. t104 (bytes): TLV 104 data. t174 (bytes): TLV 174 data. Returns: Packet: Login packet. """ COMMAND_ID = 2064 SUB_COMMAND_ID = 8 COMMAND_NAME = "wtlogin.login" SMS_APP_ID = 9 SUB_APP_ID = APK_INFO.sub_app_id BITMAP = APK_INFO.bitmap SUB_SIGMAP = APK_INFO.sub_sigmap GUID_SRC = 1 GUID_CHANGE = 0 GUID_FLAG = 0 GUID_FLAG |= GUID_SRC << 24 & 0xFF000000 GUID_FLAG |= GUID_CHANGE << 8 & 0xFF00 LOCAL_ID = 2052 # oicq.wlogin_sdk.request.t.v data = Packet.build( struct.pack(">HH", SUB_COMMAND_ID, 6), # packet num TlvEncoder.t8(LOCAL_ID), TlvEncoder.t104(t104), TlvEncoder.t116(BITMAP, SUB_SIGMAP), TlvEncoder.t174(t174), TlvEncoder.t17a(SMS_APP_ID), TlvEncoder.t197(), ) oicq_packet = OICQRequest.build_encoded(uin, COMMAND_ID, ECDH.encrypt(data, key), ECDH.id) sso_packet = CSsoBodyPacket.build( seq, SUB_APP_ID, COMMAND_NAME, DEVICE.imei, session_id, ksid, oicq_packet, ) # encrypted by 16-byte zero. Reference: ``CSSOData::serialize`` packet = CSsoDataPacket.build(uin, 2, sso_packet, key=bytes(16)) return packet
def encode_exchange_emp_15( seq: int, session_id: bytes, uin: int, g: bytes, dpwd: bytes, no_pic_sig: bytes, encrypted_a1: bytes, rand_seed: bytes, wt_session_ticket: bytes, wt_session_ticket_key: bytes, ) -> Packet: """Build exchange emp request packet. command id: ``0x810 = 2064`` sub command id: ``15`` command name: ``wtlogin.exchange_emp`` Note: Source: oicq.wlogin_sdk.request.aa Args: seq (int): Packet sequence. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. g (bytes): Siginfo g. dpwd (bytes): Siginfo dpwd. no_pic_sig (bytes): Siginfo no pic sig. encrypted_a1 (bytes): Siginfo Encrypted A1. rand_seed (bytes): Siginfo random seed. wt_session_ticket (bytes): Siginfo session ticket. wt_session_ticket_key (bytes): Siginfo session ticket key. Returns: Packet: Exchange emp packet. """ COMMAND_ID = 2064 SUB_COMMAND_ID = 15 COMMAND_NAME = "wtlogin.exchange_emp" APK_ID = APK_INFO.apk_id APK_VERSION = APK_INFO.version APK_SIGN = APK_INFO.apk_sign APK_BUILD_TIME = APK_INFO.build_time APP_ID = APK_INFO.app_id SUB_APP_ID = APK_INFO.sub_app_id APP_CLIENT_VERSION = 0 SDK_VERSION = APK_INFO.sdk_version SSO_VERSION = APK_INFO.sso_version BITMAP = APK_INFO.bitmap MAIN_SIGMAP = APK_INFO.main_sigmap SUB_SIGMAP = APK_INFO.sub_sigmap GUID = DEVICE.guid GUID_SRC = 1 GUID_CHANGE = 0 GUID_FLAG = 0 GUID_FLAG |= GUID_SRC << 24 & 0xFF000000 GUID_FLAG |= GUID_CHANGE << 8 & 0xFF00 LOCAL_ID = 2052 # oicq.wlogin_sdk.request.t.v IP_BYTES: bytes = ipaddress.ip_address(DEVICE.ip_address).packed NETWORK_TYPE = (DEVICE.apn == "wifi") + 1 data = Packet.build( struct.pack(">HH", SUB_COMMAND_ID, 24), TlvEncoder.t18(APP_ID, APP_CLIENT_VERSION, uin), TlvEncoder.t1(uin, int(time.time()), IP_BYTES), TlvEncoder._pack_tlv(0x106, encrypted_a1), TlvEncoder.t116(BITMAP, SUB_SIGMAP), TlvEncoder.t100(SSO_VERSION, APP_ID, SUB_APP_ID, APP_CLIENT_VERSION, MAIN_SIGMAP), TlvEncoder.t107(), # TlvEncoder.t108(KSID), # null when first time login TlvEncoder.t144( DEVICE.imei.encode(), DEVICE.bootloader, DEVICE.proc_version, DEVICE.version.codename, DEVICE.version.incremental, DEVICE.fingerprint, DEVICE.boot_id, DEVICE.android_id, DEVICE.baseband, DEVICE.version.incremental, DEVICE.os_type.encode(), DEVICE.version.release.encode(), NETWORK_TYPE, DEVICE.sim.encode(), DEVICE.apn.encode(), False, True, False, GUID_FLAG, DEVICE.model.encode(), DEVICE.guid, DEVICE.brand.encode(), DEVICE.tgtgt, ), TlvEncoder.t142(APK_ID), # TlvEncoder.t112(), TlvEncoder.t145(DEVICE.guid), # TlvEncoder.t166(1), TlvEncoder.t16a(no_pic_sig), TlvEncoder.t154(seq), TlvEncoder.t141(DEVICE.sim.encode(), NETWORK_TYPE, DEVICE.apn.encode()), TlvEncoder.t8(LOCAL_ID), TlvEncoder.t511([ "tenpay.com", "openmobile.qq.com", "docs.qq.com", "connect.qq.com", "qzone.qq.com", "vip.qq.com", "gamecenter.qq.com", "qun.qq.com", "game.qq.com", "qqweb.qq.com", "office.qq.com", "ti.qq.com", "mail.qq.com", "mma.qq.com", ]), # com.tencent.mobileqq.msf.core.auth.l TlvEncoder.t147(APP_ID, APK_VERSION.encode(), APK_SIGN), # TlvEncoder.t172(), TlvEncoder.t177(APK_BUILD_TIME, SDK_VERSION), TlvEncoder.t400(g, uin, GUID, dpwd, 1, APP_ID, rand_seed), TlvEncoder.t187(DEVICE.mac_address.encode()), TlvEncoder.t188(DEVICE.android_id.encode()), TlvEncoder.t194(DEVICE.imsi_md5) if DEVICE.imsi_md5 else b"", # TlvEncoder.t201(), TlvEncoder.t202(DEVICE.wifi_bssid.encode(), DEVICE.wifi_ssid.encode()), TlvEncoder.t516(), TlvEncoder.t521(), TlvEncoder.t525(TlvEncoder.t536([])), ) session = EncryptSession(wt_session_ticket) oicq_packet = OICQRequest.build_encoded( uin, COMMAND_ID, session.encrypt(data, wt_session_ticket_key), session.id, ) packet = UniPacket.build(uin, seq, COMMAND_NAME, session_id, 2, oicq_packet, key=bytes(16)) return packet