Skip to content

Commit 98ebad3

Browse files
committed
Add TCP Intermediate obfuscated protocol
1 parent 55010e4 commit 98ebad3

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

pyrogram/connection/transport/tcp/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
from .tcp_abridged_o import TCPAbridgedO
2121
from .tcp_full import TCPFull
2222
from .tcp_intermediate import TCPIntermediate
23+
from .tcp_intermediate_o import TCPIntermediateO
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Pyrogram - Telegram MTProto API Client Library for Python
2+
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
3+
#
4+
# This file is part of Pyrogram.
5+
#
6+
# Pyrogram is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU Lesser General Public License as published
8+
# by the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# Pyrogram is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public License
17+
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
18+
19+
import logging
20+
import os
21+
from struct import pack, unpack
22+
23+
from .tcp import TCP
24+
from ....crypto.aes import AES
25+
26+
log = logging.getLogger(__name__)
27+
28+
29+
class TCPIntermediateO(TCP):
30+
RESERVED = (b"HEAD", b"POST", b"GET ", b"OPTI", b"\xee" * 4)
31+
32+
def __init__(self, proxy: dict):
33+
super().__init__(proxy)
34+
self.encrypt = None
35+
self.decrypt = None
36+
37+
def connect(self, address: tuple):
38+
super().connect(address)
39+
40+
while True:
41+
nonce = bytearray(os.urandom(64))
42+
43+
if (nonce[0] != b"\xef"
44+
and nonce[:4] not in self.RESERVED
45+
and nonce[4:4] != b"\x00" * 4):
46+
nonce[56] = nonce[57] = nonce[58] = nonce[59] = 0xee
47+
break
48+
49+
temp = bytearray(nonce[55:7:-1])
50+
51+
self.encrypt = (nonce[8:40], nonce[40:56], bytearray(1))
52+
self.decrypt = (temp[0:32], temp[32:48], bytearray(1))
53+
54+
nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64]
55+
56+
super().sendall(nonce)
57+
58+
log.info("Connected{}!".format(" with proxy" if self.proxy_enabled else ""))
59+
60+
def sendall(self, data: bytes, *args):
61+
super().sendall(
62+
AES.ctr256_encrypt(
63+
pack("<i", len(data)) + data,
64+
*self.encrypt
65+
)
66+
)
67+
68+
def recvall(self, length: int = 0) -> bytes or None:
69+
length = super().recvall(4)
70+
71+
if length is None:
72+
return None
73+
74+
length = AES.ctr256_decrypt(length, *self.decrypt)
75+
76+
data = super().recvall(unpack("<i", length)[0])
77+
78+
if data is None:
79+
return None
80+
81+
return AES.ctr256_decrypt(data, *self.decrypt)

0 commit comments

Comments
 (0)