javaminecraftpacket

Received Packets don't match Minecrafts Protocol-wiki Packets


I'm trying to code a proxy for Minecraft which should intercept packages sent between the client and server. I got the proxy working but the packet IDs I received don't seem to match the packet IDs in the Protocol wiki.

For example: if a player/an entity moves, the client should sent this packet to the server (I think). This packet start with the ID: 0x2C. The actual packet I got when the player moves is: 1B 00 14 C0 11 76 EE 76 F6 9B C0 40 55 40 00 00 00 00 00 BF FD 0E DF A6 AD 79 0F 01 which has the packet ID: (0x)1B.

Another example: if an player breaks a block, the client should sent this packet to the server (I think). This packet start with the ID: 0x07. THe actual packet I got when the player breaks a block is: 03 00 2F 00 which has the packet ID (0x)03.

I'm clearly doing something wrong but I'm not sure if this is because I'm refering to the wrong packets or that there is some to decrypt this. Note that I'm running my server on offline_mode so there should be any authentication from Microsoft/Mojang and thus no encryption.

For anyone who's wondering, here's my code:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

public class MinecraftProxy {
    private static final String SERVER_HOST = "localhost";  // Replace with your actual server host
    private static final int SERVER_PORT = 25565;  // Replace with your actual server port

    public static void main(String[] args) throws IOException {
        ServerSocket proxyServerSocket = new ServerSocket(55555);  // Proxy server port

        while (true) {
            Socket clientSocket = proxyServerSocket.accept();
            Socket serverSocket = new Socket(SERVER_HOST, SERVER_PORT);

            // Create separate threads to handle client-to-server and server-to-client communication
            Thread clientToServerThread = new Thread(() -> copyStreams(clientSocket, serverSocket, "Client to Server"));
            Thread serverToClientThread = new Thread(() -> copyStreams(serverSocket, clientSocket, "Server to Client"));

            clientToServerThread.start();
            serverToClientThread.start();
        }
    }

    private static void copyStreams(Socket inputSocket, Socket outputSocket, String direction) {
        try {
            InputStream inputStream = inputSocket.getInputStream();
            OutputStream outputStream = outputSocket.getOutputStream();

            byte[] buffer = new byte[4096];
            int bytesRead;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                byte[] packet = Arrays.copyOf(buffer, bytesRead);

                // Print the packet being sent or received
                if (direction.equals("Client to Server")) {
                    System.out.println("Packet Sent: " + bytesToString(packet));
                } else {
                    // System.out.println("Packet Received: " + bytesToString(packet));
                }

                // Data is being received from inputSocket (client) and sent to outputSocket (server)
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
            }

            // Input stream closed, so close the output stream and sockets as well
            outputStream.close();
            inputSocket.close();
            outputSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String bytesToString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString();
    }
}

Solution

  • The first byte seems to correspond to the rest of the packet's length. The second byte for some reason will always be 00. The third byte will be the packet's ID.

    For example the third byte of my first example is: 14. This corresponds to this packet which indeed contains the player position. The only difference is that this packet is server-bound instead of client-bound.

    The third byte of my second example is: 2F. This corresponds to this packet instead of a block-breaking packet. Now that I think of it, this is far more logical since when breaking a block, the player swings it arm. Here of-course the packet is also server-bound instead of client-bound.