Skip to content

Instantly share code, notes, and snippets.

@hanbule
Forked from Frago9876543210/DisableEncryption.cpp
Created June 13, 2021 00:09
Show Gist options
  • Save hanbule/f8619eb1514bc0aa2ca574dff70e821b to your computer and use it in GitHub Desktop.
Save hanbule/f8619eb1514bc0aa2ca574dff70e821b to your computer and use it in GitHub Desktop.
MCBE network debugger
#include <modloader/statichook.h>
#include <dlfcn.h>
#include <string>
static auto handshake = (size_t) dlsym(dlopen(nullptr, RTLD_LAZY), "_ZTV29ServerToClientHandshakePacket") + 0x10;
struct Packet { size_t vt; };
struct LoginPacket;
struct ClientToServerHandshakePacket;
struct NetworkIdentifier;
struct ServerNetworkHandler {
void handleClientToServerHandshake(NetworkIdentifier const &, ClientToServerHandshakePacket const &);
};
TInstanceHook(void, _ZN20ServerNetworkHandler11handleLoginERK17NetworkIdentifierRK11LoginPacket, ServerNetworkHandler, NetworkIdentifier const &nid, LoginPacket const &packet) {
original(this, nid, packet);
ClientToServerHandshakePacket *pk = nullptr;
handleClientToServerHandshake(nid, *pk);
}
TClasslessInstanceHook(void, _ZN12PacketSender19sendToPrimaryClientERK17NetworkIdentifierRK6Packet, NetworkIdentifier const &nid, Packet const &packet) {
if (packet.vt != handshake)
original(this, nid, packet);
}
TClasslessInstanceHook(void, _ZN20EncryptedNetworkPeer16enableEncryptionERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, std::string const &token) {}
<?php
declare(strict_types=1);
namespace Frago9876543210\PacketStealer {
/** @noinspection PhpIncludeInspection */
require_once "vendor/autoload.php";
use pocketmine\network\mcpe\NetworkCompression;
use pocketmine\network\mcpe\PacketStream;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\PacketPool;
use raklib\protocol\{ACK, AdvertiseSystem, ConnectedPing, ConnectedPong, ConnectionRequest,
ConnectionRequestAccepted, Datagram, DisconnectionNotification, EncapsulatedPacket, IncompatibleProtocolVersion,
NACK, NewIncomingConnection, OpenConnectionReply1, OpenConnectionReply2, OpenConnectionRequest1,
OpenConnectionRequest2, Packet, UnconnectedPing, UnconnectedPingOpenConnections, UnconnectedPong};
use raklib\server\UDPServerSocket;
use raklib\utils\InternetAddress;
class Proxy extends UDPServerSocket{
/** @var Address */
private $serverAddress;
/** @var Address */
private $clientAddress;
/** @var bool */
private $sessionCreated = false;
/** @var Datagram[][] */
private $splitPackets = [];
public function __construct(Address $bindAddress, Address $serverAddress){
RakNetPool::init();
PacketPool::init();
parent::__construct($bindAddress);
$this->serverAddress = $serverAddress;
while(true){
$this->tick();
}
}
public function tick() : void{
if($this->readPacket($buffer, $source, $port) !== false){
if(($packet = RakNetPool::getPacket($buffer)) !== null){
$this->handlePacket($packet, new Address($source, $port));
}
}
}
private function handlePacket(Packet $packet, Address $address) : void{
if(!$this->sessionCreated){
if($packet instanceof UnconnectedPing){
$this->clientAddress = $address;
$this->sendToServer($packet);
}elseif($packet instanceof UnconnectedPong){
$this->sendToClient($packet);
}elseif($packet instanceof OpenConnectionRequest1){
$this->clientAddress = $address;
$this->sessionCreated = true;
$this->sendToServer($packet);
}
}else{
if($packet instanceof Datagram){
$this->handleDatagram($packet);
}
if($this->serverAddress->equals($address)){
$this->sendToClient($packet);
}else{
$this->sendToServer($packet);
}
}
}
private function handleDatagram(Datagram $datagram) : void{
foreach($datagram->packets as $pk){
$this->handleEncapsulatedPacket($pk);
}
}
private function handleEncapsulatedPacket(EncapsulatedPacket $packet) : void{
if($packet->hasSplit && ($packet = $this->handleSplit($packet)) === null){
return;
}
if($packet->buffer !== "" && $packet->buffer{0} === "\xfe"){
$this->handleBatch($packet->buffer);
}
}
private function handleSplit(EncapsulatedPacket $packet) : ?EncapsulatedPacket{
if($packet->splitCount >= 128 or $packet->splitIndex >= 128 or $packet->splitIndex < 0){
return null;
}
if(!isset($this->splitPackets[$packet->splitID])){
if(count($this->splitPackets) >= 4){
return null;
}
$this->splitPackets[$packet->splitID] = [$packet->splitIndex => $packet];
}else{
$this->splitPackets[$packet->splitID][$packet->splitIndex] = $packet;
}
if(count($this->splitPackets[$packet->splitID]) === $packet->splitCount){
$pk = new EncapsulatedPacket;
$pk->buffer = "";
$pk->reliability = $packet->reliability;
$pk->messageIndex = $packet->messageIndex;
$pk->sequenceIndex = $packet->sequenceIndex;
$pk->orderIndex = $packet->orderIndex;
$pk->orderChannel = $packet->orderChannel;
for($i = 0; $i < $packet->splitCount; ++$i){
$pk->buffer .= $this->splitPackets[$packet->splitID][$i]->buffer;
}
$pk->length = strlen($pk->buffer);
unset($this->splitPackets[$packet->splitID]);
return $pk;
}
return null;
}
private function handleBatch(string $payload) : void{
try{
$stream = new PacketStream(NetworkCompression::decompress(substr($payload, 1)));
}catch(\Exception $e){
return;
}
while(!$stream->feof()){
$this->handleDataPacket(PacketPool::getPacket($stream->getString()));
}
}
private function getClassName(object $class) : ?string{
try{
return (new \ReflectionClass($class))->getShortName();
}catch(\ReflectionException $e){
return null;
}
}
private function handleDataPacket(DataPacket $packet) : void{
echo $this->getClassName($packet) . PHP_EOL;
}
private function sendToServer(Packet $packet) : void{
$this->writePacket($packet->buffer, $this->serverAddress->ip, $this->serverAddress->port);
}
private function sendToClient(Packet $packet) : void{
$this->writePacket($packet->buffer, $this->clientAddress->ip, $this->clientAddress->port);
}
}
class Address extends InternetAddress{
public function __construct(string $address, int $port, int $version = 4){
parent::__construct(gethostbyname($address), $port, $version);
}
}
class RakNetPool{
/** @var Packet[] */
private static $pool = [];
public static function init(){
self::registerPacket(new ACK);
self::registerPacket(new AdvertiseSystem);
self::registerPacket(new ConnectedPing);
self::registerPacket(new ConnectedPong);
self::registerPacket(new ConnectionRequest);
self::registerPacket(new ConnectionRequestAccepted);
self::registerPacket(new DisconnectionNotification);
self::registerPacket(new IncompatibleProtocolVersion);
self::registerPacket(new NACK);
self::registerPacket(new NewIncomingConnection);
self::registerPacket(new OpenConnectionReply1);
self::registerPacket(new OpenConnectionReply2);
self::registerPacket(new OpenConnectionRequest1);
self::registerPacket(new OpenConnectionRequest2);
self::registerPacket(new UnconnectedPing);
self::registerPacket(new UnconnectedPingOpenConnections);
self::registerPacket(new UnconnectedPong);
}
/**
* @param Packet $packet
*/
public static function registerPacket(Packet $packet) : void{
self::$pool[$packet::$ID] = clone $packet;
}
/**
* @param string $buffer
* @return null|Packet
*/
public static function getPacket(string $buffer) : ?Packet{
$packet = isset(self::$pool[($pid = ord($buffer{0}))]) ? clone self::$pool[$pid] : new Datagram;
if(!$packet instanceof Packet || ($packet instanceof Datagram && $pid >= 0x8f)){
return null;
}
$packet->setBuffer($buffer);
try{
@$packet->decode();
}catch(\Throwable $e){
return null;
}
return $packet;
}
}
/** @noinspection PhpUnhandledExceptionInspection */
throw new \Exception("DO NOT FORGET REPLACE IP!");
/** @noinspection PhpUnreachableStatementInspection */
new Proxy(new Address("0.0.0.0", 19134), new Address("192.168.x.x", 19132));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment