From 8e1ac1a3f8448c80523ccfbb4299f91724c07fc3 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sat, 8 Jul 2017 16:19:17 +0100 Subject: [PATCH] Trying to make obfuscated2 protocol work --- src/danog/MadelineProto/Connection.php | 73 +++++++++++++++++++++++++- src/danog/MadelineProto/DataCenter.php | 3 +- src/danog/MadelineProto/MTProto.php | 10 ++-- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/danog/MadelineProto/Connection.php b/src/danog/MadelineProto/Connection.php index 2e9df1a9..6301d1ab 100644 --- a/src/danog/MadelineProto/Connection.php +++ b/src/danog/MadelineProto/Connection.php @@ -41,6 +41,7 @@ class Connection extends \Volatile public $max_outgoing_id; public $proxy = '\Socket'; public $extra = []; + public $obfuscated = []; public $call_queue = []; @@ -109,8 +110,8 @@ var_dump(is_null($this->{$name})); $this->sock->setBlocking(true); $this->write(str_repeat(chr(238), 4)); break; - case 'tcp_full': + case 'tcp_full': $this->sock = new $proxy($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp')); if ($has_proxy && $this->extra !== []) { $this->sock->setExtra($this->extra); @@ -127,6 +128,49 @@ var_dump(is_null($this->{$name})); $this->out_seq_no = -1; $this->in_seq_no = -1; break; + case 'obfuscated2': + $this->sock = new $proxy($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp')); + if ($has_proxy && $this->extra !== []) { + $this->sock->setExtra($this->extra); + } + if (!$this->sock->connect($ip, $port)) { + throw new Exception("Connection: couldn't connect to socket."); + } + if (!\danog\MadelineProto\Logger::$has_thread) { + $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout); + $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout); + } + $this->sock->setBlocking(true); + do { + $random = $this->random(64); + } while (in_array(substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', str_repeat(chr(238), 4)]) || $random[0] === chr(239) || substr($random, 4, 4) === "\0\0\0\0"); + $reversed = strrev(substr($random, 8, 48)); + + $this->obfuscated = ['encryption' => new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_CTR), 'decryption' => new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_CTR)]; + $this->obfuscated['encryption']->enableContinuousBuffer(); + $this->obfuscated['decryption']->enableContinuousBuffer(); + + $this->obfuscated['encryption']->setKey(substr($random, 8, 32)); + $this->obfuscated['encryption']->setIV(substr($random, 40, 16)); + + $this->obfuscated['decryption']->setKey(substr($reversed, 0, 32)); + $this->obfuscated['decryption']->setIV(substr($reversed, 32, 16)); + + $random = substr_replace( + $random, + substr( + $this->obfuscated['encryption']->encrypt( + substr_replace($random, str_repeat(chr(239), 4), 56, 4) + ), + 56, + 8 + ), + 56, + 8 + ); + $this->write($random); + break; + case 'http': case 'https': $this->parsed = parse_url($ip); @@ -162,6 +206,7 @@ var_dump(is_null($this->{$name})); case 'tcp_full': case 'http': case 'https': + case 'obfuscated2': try { unset($this->sock); } catch (\danog\MadelineProto\Exception $e) { @@ -183,7 +228,7 @@ var_dump(is_null($this->{$name})); public function __sleep() { - return ['proxy', 'extra', 'protocol', 'ip', 'port', 'timeout', 'parsed', 'time_delta', 'temp_auth_key', 'auth_key', 'session_id', 'session_out_seq_no', 'session_in_seq_no', 'ipv6', 'incoming_messages', 'outgoing_messages', 'new_incoming', 'new_outgoing', 'max_incoming_id', 'max_outgoing_id']; + return ['proxy', 'extra', 'protocol', 'ip', 'port', 'timeout', 'parsed', 'time_delta', 'temp_auth_key', 'auth_key', 'session_id', 'session_out_seq_no', 'session_in_seq_no', 'ipv6', 'incoming_messages', 'outgoing_messages', 'new_incoming', 'new_outgoing', 'max_incoming_id', 'max_outgoing_id', 'obfuscated']; } public function __wakeup() @@ -208,6 +253,7 @@ var_dump(is_null($this->{$name})); case 'tcp_abridged': case 'tcp_intermediate': case 'tcp_full': + case 'obfuscated2': case 'http': case 'https': $wrote = 0; @@ -233,6 +279,7 @@ var_dump(is_null($this->{$name})); case 'tcp_abridged': case 'tcp_intermediate': case 'tcp_full': + case 'obfuscated2': case 'http': case 'https': $packet = ''; @@ -290,6 +337,18 @@ var_dump(is_null($this->{$name})); } return $this->read($packet_length); + + case 'obfuscated2': + $packet_length_data = $this->read(1); + $packet_length = ord($packet_length_data); + if ($packet_length < 127) { + $packet_length <<= 2; + } else { + $packet_length_data = $this->read(3); + $packet_length = unpack('V', $packet_length_data."\0")[1] << 2; + } + + return substr($this->obfuscation['decryption']->encrypt($this->read($packet_length)), 8, -4); case 'http': case 'https': $headers = []; @@ -349,6 +408,16 @@ var_dump(is_null($this->{$name})); } $this->write($step1); break; + case 'obfuscated2': + $message = "\0\0\0\0\0\0\0\0".$message."\0\0\0\0"; + $len = strlen($message) / 4; + if ($len < 127) { + $step1 = chr($len).$message; + } else { + $step1 = chr(127).substr(pack('V', $len), 0, 3).$message; + } + $this->write($this->obfuscated['encryption']->encrypt($step1)); + break; case 'http': case 'https': $this->write('POST '.$this->parsed['path']." HTTP/1.1\r\nHost: ".$this->parsed['host']."\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nContent-Length: ".strlen($message)."\r\n\r\n".$message); diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php index f570ae66..2315592c 100644 --- a/src/danog/MadelineProto/DataCenter.php +++ b/src/danog/MadelineProto/DataCenter.php @@ -46,6 +46,7 @@ var_dump(is_null($this->{$name})); $this->settings = $settings; foreach ($this->sockets as $key => $socket) { if ($socket instanceof Connection) { + $socket->old = true; $socket->close_and_reopen(); } else { unset($this->sockets[$key]); @@ -67,7 +68,7 @@ var_dump(is_null($this->{$name})); public function dc_connect($dc_number) { $this->curdc = $dc_number; - if (isset($this->sockets[$dc_number])) { + if (isset($this->sockets[$dc_number]) && !isset($this->sockets[$dc_number]->old)) { return false; } $dc_config_number = isset($this->settings[$dc_number]) ? $dc_number : 'all'; diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 83ff428f..3f1a1a9e 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -548,6 +548,10 @@ class MTProto extends \Volatile if (!isset($settings['app_info']['api_id'])) { throw new \danog\MadelineProto\Exception('You must provide an api key and an api id, get your own @ my.telegram.org'); } + /* + if ($settings['app_info']['api_id'] < 20) { + $settings['connection_settings']['all']['protocol'] = 'obfuscated2'; + }*/ switch ($settings['logger']['logger_level']) { case 'ULTRA_VERBOSE': $settings['logger']['logger_level'] = 5; break; case 'VERBOSE': $settings['logger']['logger_level'] = 4; break; @@ -591,9 +595,7 @@ class MTProto extends \Volatile public function connect_to_all_dcs() { foreach ($old = $this->datacenter->get_dcs() as $new_dc) { - if (!isset($this->datacenter->sockets[$new_dc])) { - $this->datacenter->dc_connect($new_dc); - } + $this->datacenter->dc_connect($new_dc); } $this->setup_threads(); $this->init_authorization(); @@ -740,7 +742,7 @@ class MTProto extends \Volatile public function getV() { - return 50; + return 52; } public function get_self()