Example #1
0
 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,
     )
Example #2
0
    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)
Example #3
0
    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}
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
    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),
        }
Example #7
0
    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,
        )
Example #8
0
 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,
         ),
     )
Example #9
0
 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)),
     )
Example #10
0
    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,
        )
Example #11
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.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]
Example #12
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)
Example #13
0
 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),
     )
Example #14
0
    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}")
Example #15
0
 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))
Example #16
0
    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
Example #17
0
    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),
        }
Example #18
0
    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),
        }
Example #19
0
    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),
        }
Example #20
0
    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(),
        }
Example #21
0
    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.")
Example #22
0
 def _pack_tlv(cls, type: int, *data: Union[bytes,
                                            bytearray]) -> "Packet[()]":
     return Packet(struct.pack(">HH", type, sum(map(len,
                                                    data)))).write(*data)
Example #23
0
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
Example #24
0
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
Example #25
0
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
Example #26
0
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
Example #27
0
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