Results 1 to 2 of 2
  1. #1
    atom0s's Avatar
    Join Date
    May 2013
    Gender
    male
    Posts
    403
    Reputation
    139
    Thanks
    104

    Creating Packet Editor / Proxy In C#

    Before We Begin...
    Please note this tutorial is for educational purposes. I am not responsible for what you do with this information. You agree by reading and using anything from this tutorial that you are solely responsible for anything you do with it. Altering packets can result in damage of the target server(s), disruption of service, and/or other major issues which can be used against you in the court of law in some areas. USE AT YOUR OWN RISK!


    Tools Required

    The list of tools we will need for this is fairly small. The main things will be noted here, if you feel you need other tools, feel free to get them as well.

    • Visual Studio 2010 (C# or full install upto you, just make sure you install C#)
    • Target application that uses TCP.
    • Possible hex editor in some cases, discussed later in this tutorial.




    Getting Started
    To begin, create a new standard Windows form project for C# in VS2010.
    File -> New -> Project -> Visual C# -> Windows -> Windows Forms Application
    You can use WPF or a console app too if you wish, GUI is not important here.


    For the sake of this tutorial I'm going to name/refer to the project as 'ExampleTcpProxy'.



    Now that we have our project created, lets make some classes that we will need during the usage of our project. So we want to add a new folder
    Right-click project in solution explorer -> Add -> New Folder
    Name this folder 'Classes'.


    Inside classes we want to add two new Class files, so:
    Right-click the 'Classes' folder -> Add -> Class -> name it 'Server.cs'
    Right-click the 'Classes' folder -> Add -> Class -> name it 'Client.cs'




    Coding The Server
    Next we want to start with coding the server, the guts of Server.cs, so open Server.cs first. As I said above this is specifically for TCP so we want to begin by using the wrappers that the .NET framework exposes for us (TcpListener) for the server.

    We will be using TcpListeners async methods to create an async server. A quick run-down of what the code below does:

    • Initialize a new instance of our Server class.
    • Prepares the default connection info.
    • Starts our server.
    • Begins listening (async) for connections to this new server.
    • When a connection is found, create an instance of our Client class.
    • Tell our client class to connect to the given remote server.
    • Begin listening for a new client.

    This does not support multiple clients though. This will simply let you keep it running and it will keep accepting the new client and dropping the previous one.


    Our server code will look like this:
    Code:
          
    // -----------------------------------------------------------------------
    // <copyright file="Server.cs" company="">
    // (c) atom0s 2012 - ExampleTcpProxy
    // </copyright>
    // -----------------------------------------------------------------------
    
    namespace ExampleTcpProxy.Classes
    {
        using System;
        using System.Net;
        using System.Net.Sockets;
        using System.Windows.Forms;
    
        /// <summary>
        /// TCP Proxy Server Implementation
        /// 
        /// </summary>
        public class Server
        {
            /// <summary>
            /// Local listening server object.
            /// </summary>
            private TcpListener m_vServer;
    
            /// <summary>
            /// Local copy of our connected client.
            /// </summary>
            private Client m_vClient;
    
            /// <summary>
            /// Default Constructor
            /// </summary>
            public Server()
            {
                // Setup class defaults..
                this.LocalAddress = IPAddress.Loopback.ToString();
                this.LocalPort = 7776;
                this.RemoteAddress = IPAddress.Loopback.ToString();
                this.RemotePort = 7777;
            }
    
            /// <summary>
            /// Starts our listen server to accept incoming connections.
            /// </summary>
            /// <returns></returns>
            public bool Start()
            {
                try
                {
                    // Cleanup any previous objects..
                    this.Stop();
    
                    // Create the new TcpListener..
                    this.m_vServer = new TcpListener(IPAddress.Parse(this.LocalAddress), this.LocalPort);
                    this.m_vServer.Start();
                    
                    // Setup the async handler when a client connects..
                    this.m_vServer.BeginAcceptTcpClient(new AsyncCallback(OnAcceptTcpClient), this.m_vServer);
                    return true;
                }
                catch (Exception ex)
                {
                    this.Stop();
                    MessageBox.Show("Exception caught inside of Server::Start\r\n" + ex.Message);
                    return false;
                }
            }
    
            /// <summary>
            /// Stops the local listening server if it is started.
            /// </summary>
            public void Stop()
            {
                // Cleanup the client object..
                if (this.m_vClient != null)
                    this.m_vClient.Stop();
                this.m_vClient = null;
    
                // Cleanup the server object..
                if (this.m_vServer != null)
                    this.m_vServer.Stop();
                this.m_vServer = null;
            }
    
            /// <summary>
            /// Async callback handler that accepts incoming TcpClient connections.
            /// NOTE:
            ///     It is important that you use the results server object to
            ///     prevent threading issues and object disposed errors!
            /// </summary>
            /// <param name="result"></param>
            private void OnAcceptTcpClient(IAsyncResult result)
            {
                // Ensure this connection is complete and valid..
                if (result.IsCompleted == false || !(result.AsyncState is TcpListener))
                {
                    this.Stop();
                    return;
                }
    
                // Obtain our server instance. (YOU NEED TO USE IT LIKE THIS DO NOT USE this.m_vServer here!)
                TcpListener tcpServer = (result.AsyncState as TcpListener);
                TcpClient tcpClient = null;
    
                try
                {
                    // End the async connection request..
                    tcpClient = tcpServer.EndAcceptTcpClient(result);
    
                    // Kill the previous client that was connected (if any)..
                    if (this.m_vClient != null)
                        this.m_vClient.Stop();
    
                    // Prepare the client and start the proxying..
                    this.m_vClient = new Client(tcpClient.Client);
                    this.m_vClient.Start(this.RemoteAddress, this.RemotePort);
                }
                catch
                {
                    System.Diagnostics.Debug.WriteLine("Error while attempting to complete async connection.");
                }
    
                // Begin listening for the next client..
                tcpServer.BeginAcceptTcpClient(new AsyncCallback(OnAcceptTcpClient), tcpServer);
            }
    
            /// <summary>
            /// Gets or sets the local address of this listen server.
            /// </summary>
            public String LocalAddress
            {
                get;
                set;
            }
    
            /// <summary>
            /// Gets or sets the local port of this listen server.
            /// </summary>
            public Int32 LocalPort
            {
                get;
                set;
            }
    
            /// <summary>
            /// Gets or sets the remote address to forward the client to.
            /// </summary>
            public String RemoteAddress
            {
                get;
                set;
            }
    
            /// <summary>
            /// Gets or sets the remote port to foward the client to.
            /// </summary>
            public Int32 RemotePort
            {
                get;
                set;
            }
        }
    }
    Coding The Client
    The client is where the main guts are of the project. This contains all the packet monitoring functions that you will want to alter and such. Keep in mind, TCP uses packet fragmentation which requires the base client/server to use their own packet protocol in order to determine when a packet has been fully received. Given that TCP ensures the packets have been received, you cannot guarantee a packet is done until the custom implementation is valid. (I'll show an example after this.)

    So the basic jist of our client is as follows:

    • Once created, initialize the internal objects.
    • When told to start, attempt to connect to the remote machine on a new socket.
    • If connected, prepare the buffer sizes, then begin listening for packets for both the server and client.

    Again, we are using async methods here too.


    Our client code looks like this:
    Code:
         
    // -----------------------------------------------------------------------
    // <copyright file="Server.cs" company="">
    // (c) atom0s 2012 - ExampleTcpProxy
    // </copyright>
    // -----------------------------------------------------------------------
    
    namespace ExampleTcpProxy.Classes
    {
        using System;
        using System.Collections.Generic;
        using System.Net;
        using System.Net.Sockets;
    
        /// <summary>
        /// TCP Proxy Client Implementation
        /// 
        /// </summary>
        public class Client
        {
            /// <summary>
            /// The maximum amount of data to receive in a single packet.
            /// </summary>
            private static Int32 MAX_BUFFER_SIZE = 2048;
    
            /// <summary>
            /// Internal client state to prevent multiple stop calls.
            /// (Helps reduce the number of unneeded exceptions.)
            /// </summary>
            private Boolean m_vIsRunning;
    
            /// <summary>
            /// Client variables.
            /// </summary>
            private Socket m_vClientSocket;
            private Byte[] m_vClientBuffer;
            private List<Byte> m_vClientBacklog;
    
            /// <summary>
            /// Server variables.
            /// </summary>
            private Socket m_vServerSocket;
            private Byte[] m_vServerBuffer;
            private List<Byte> m_vServerBacklog;
    
            /// <summary>
            /// Default Constructor
            /// </summary>
            /// <param name="sockClient"></param>
            public Client(Socket sockClient)
            {
                // Setup class defaults..
                this.m_vClientSocket = sockClient;
                this.m_vClientBuffer = new Byte[MAX_BUFFER_SIZE];
                this.m_vClientBacklog = new List<Byte>();
    
                this.m_vServerSocket = null;
                this.m_vServerBuffer = new Byte[MAX_BUFFER_SIZE];
                this.m_vServerBacklog = new List<Byte>();
            }
    
            /// <summary>
            /// Starts our proxy client.
            /// </summary>
            /// <param name="remoteTarget"></param>
            /// <param name="remotePort"></param>
            /// <returns></returns>
            public bool Start(String remoteTarget = "127.0.0.1", Int32 remotePort = 7777)
            {
                // Stop this client if it was already started before..
                if (this.m_vIsRunning == true)
                    this.Stop();
                this.m_vIsRunning = true;
    
                // Attempt to parse the given remote target.
                // This allows an IP address or domain to be given.
                // Ex:
                //      127.0.0.1
                //      derp.no-ip.org
    
                IPAddress ipAddress = null;
                try { ipAddress = IPAddress.Parse(remoteTarget); }
                catch
                {
                    try { ipAddress = Dns.GetHostEntry(remoteTarget).AddressList[0]; }
                    catch { throw new SocketException((int)SocketError.HostNotFound); }
                }
    
                try
                {
                    // Connect to the target machine on a new socket..
                    this.m_vServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    this.m_vServerSocket.BeginConnect(new IPEndPoint(ipAddress, remotePort),
                        new AsyncCallback((result) =>
                            {
                                // Ensure the connection was valid..
                                if (result == null || result.IsCompleted == false || !(result.AsyncState is Socket))
                                    return;
    
                                // Obtain our server instance. (YOU NEED TO USE IT LIKE THIS DO NOT USE this.m_vServerSocket here!)
                                Socket serverSocket = (result.AsyncState as Socket);
    
                                // Stop processing if the server has told us to stop..
                                if (this.m_vIsRunning == false || serverSocket == null)
                                    return;
    
                                // Complete the async connection request..
                                serverSocket.EndConnect(result);
    
                                // Start monitoring for packets..
                                this.m_vClientSocket.ReceiveBufferSize = MAX_BUFFER_SIZE;
                                serverSocket.ReceiveBufferSize = MAX_BUFFER_SIZE;
                                this.Server_BeginReceive();
                                this.Client_BeginReceive();
                            }), this.m_vServerSocket);
    
                    return true;
                }
                catch (ObjectDisposedException ex)
                {
                    // Process the exception as you wish here..
                }
                catch (SocketException ex)
                {
                    // Process the exception as you wish here..
                }
                catch (Exception ex)
                {
                    // Process the exception as you wish here..
                }
    
                return false;
            }
    
            /// <summary>
            /// Stops this client object.
            /// </summary>
            public void Stop()
            {
                if (this.m_vIsRunning == false)
                    return;
    
                // Cleanup the client socket..
                if (this.m_vClientSocket != null)
                    this.m_vClientSocket.Close();
                this.m_vClientSocket = null;
    
                // Cleanup the server socket..
                if (this.m_vServerSocket != null)
                    this.m_vServerSocket.Close();
                this.m_vServerSocket = null;
    
                this.m_vIsRunning = false;
            }
    
                    /// <summary>
            /// Begins an async event to receive incoming data.
            /// </summary>
            private void Client_BeginReceive()
            {
                // Prevent invalid call..
                if (!this.m_vIsRunning)
                    return;
    
                try
                {
                    this.m_vClientSocket.BeginReceive(this.m_vClientBuffer, 0, MAX_BUFFER_SIZE, SocketFlags.None, new AsyncCallback(OnClientReceiveData), this.m_vClientSocket);
                }
                catch (SocketException ex) { this.Stop(); }
                catch (Exception ex) { this.Stop(); }
            }
    
            /// <summary>
            /// Begins an async event to receive incoming data. 
            /// </summary>
            private void Server_BeginReceive()
            {
                // Prevent invalid call..
                if (!this.m_vIsRunning)
                    return;
    
                try
                {
                    this.m_vServerSocket.BeginReceive(this.m_vServerBuffer, 0, MAX_BUFFER_SIZE, SocketFlags.None, new AsyncCallback(OnServerReceiveData), this.m_vServerSocket);
                }
                catch (SocketException ex) { this.Stop(); }
                catch (Exception ex) { this.Stop(); }
            }
    
            /// <summary>
            /// Completes an async event to receive data.
            /// </summary>
            /// <param name="result"></param>
            private void OnClientReceiveData(IAsyncResult result)
            {
                // Prevent invalid calls to this function..
                if (!this.m_vIsRunning || result.IsCompleted == false || !(result.AsyncState is Socket))
                {
                    this.Stop();
                    return;
                }
    
                Socket client = (result.AsyncState as Socket);
    
                // Attempt to end the async call..
                Int32 nRecvCount = 0;
                try
                {
                    nRecvCount = client.EndReceive(result);
                    if (nRecvCount == 0)
                    {
                        this.Stop();
                        return;
                    }
                }
                catch { this.Stop(); return; }
    
                // Read the current packet..
                Byte[] btRecvData = new Byte[nRecvCount];
                Array.Copy(this.m_vClientBuffer, 0, btRecvData, 0, nRecvCount);
    
                // Send the packet to the server..
                this.SendToServer(btRecvData);
    
                // Begin listening for next packet..
                this.Client_BeginReceive();
            }
    
            /// <summary>
            /// Completes an async event to receive data.
            /// </summary>
            /// <param name="result"></param>
            private void OnServerReceiveData(IAsyncResult result)
            {
                // Prevent invalid calls to this function..
                if (!this.m_vIsRunning || result.IsCompleted == false || !(result.AsyncState is Socket))
                {
                    this.Stop();
                    return;
                }
    
                Socket server = (result.AsyncState as Socket);
    
                // Attempt to end the async call..
                Int32 nRecvCount = 0;
                try
                {
                    nRecvCount = server.EndReceive(result);
                    if (nRecvCount == 0)
                    {
                        this.Stop();
                        return;
                    }
                }
                catch { this.Stop(); return; }
    
                // Read the current packet..
                Byte[] btRecvData = new Byte[nRecvCount];
                Array.Copy(this.m_vServerBuffer, 0, btRecvData, 0, nRecvCount);
    
                // Send the packet to the client..
                this.SendToClient(btRecvData);
    
                // Begin listening for next packet..
                this.Server_BeginReceive();
            }
    
            /// <summary>
            /// Sends the given packet data to the client socket.
            /// </summary>
            /// <param name="btPacket"></param>
            public void SendToClient(byte[] btPacket)
            {
                if (!this.m_vIsRunning)
                    return;
    
                try
                {
                    this.m_vClientSocket.BeginSend(btPacket, 0, btPacket.Length, SocketFlags.None,
                        new AsyncCallback((x) =>
                        {
                            if (x.IsCompleted == false || !(x.AsyncState is Socket))
                            {
                                this.Stop();
                                return;
                            }
    
                            (x.AsyncState as Socket).EndSend(x);
                        }), this.m_vClientSocket);
                }
                catch (Exception ex) { this.Stop(); }
            }
    
            /// <summary>
            /// Sends the given packet data to the server socket.
            /// </summary>
            /// <param name="btPacket"></param>
            public void SendToServer(byte[] btPacket)
            {
                if (!this.m_vIsRunning)
                    return;
    
                try
                {
                    this.m_vServerSocket.BeginSend(btPacket, 0, btPacket.Length, SocketFlags.None,
                        new AsyncCallback((x) =>
                        {
                            if (x.IsCompleted == false || !(x.AsyncState is Socket))
                            {
                                this.Stop();
                                return;
                            }
    
                            (x.AsyncState as Socket).EndSend(x);
                        }), this.m_vServerSocket);
                }
                catch (Exception ex) { this.Stop(); }
            }
    
            /// <summary>
            /// Gets the base client socket.
            /// </summary>
            public Socket ClientSocket
            {
                get
                {
                    if (this.m_vIsRunning && this.m_vClientSocket != null)
                        return this.m_vClientSocket;
                    return null;
                }
            }
    
            /// <summary>
            /// Gets the base server socket.
            /// </summary>
            public Socket ServerSocket
            {
                get
                {
                    if (this.m_vIsRunning && this.m_vServerSocket != null)
                        return this.m_vServerSocket;
                    return null;
                }
            }
        }
    }
    Using Our Proxy
    Great now we got both the client and server coded, we can use it and test it out. In our main form (or whatever kind of project you created) just double click the form to automatically add the 'Load' event. Inside here we will put our server creation code like this:

    Code:
        
            private void Form1_Load(object sender, EventArgs e)
            {
                Server server = new Server();
                server.RemoteAddress = "your.server.here";
                server.RemotePort = 7777;
    
                server.Start();
            }
    Then you can run the project and attempt to connect to it.


    At this time, our server/client setup simply reads the packets and sends it to either the client or server. There is no altering or extended stuff being done. This is our simple base to prepare us for future altering/editing of the packets being read and such.


    Adjusting The Packet Handlers For A Given Protocol
    I will be using the game Terraria for my examples here. In this next part we will be modifying how the packets are read and handled. This will let us intercept any specific packet we wish, as well as drop the packet, edit the packet, send other packets with it, etc.

    To start lets discuss Terraria's protocol real quick. As I mentioned TCP ensures packet arrival so the coder is left to write a protocol for the packets to follow on top of the TCP protocol to ensure they are reading the proper data. Terraria does this by using the following packet format:

    Code:
    struct t_packet {
        unsigned int payload_size;
        unsigned char packet_id;
        unsigned char[payload_size] packet_data;
    };
    So we can easily tell when a packet is properly read based on the first part of the packet since it's the size. Let's begin with altering the OnClientReceiveData method. Since we know the packet layout now, we can read our packets and place them into the backlog list and process them as individual packets. So we'll rewrite the method to look like this:

    Code:
            /// <summary>
            /// Completes an async event to receive data.
            /// </summary>
            /// <param name="result"></param>
            private void OnClientReceiveData(IAsyncResult result)
            {
                // Prevent invalid calls to this function..
                if (!this.m_vIsRunning || result.IsCompleted == false || !(result.AsyncState is Socket))
                {
                    this.Stop();
                    return;
                }
    
                Socket client = (result.AsyncState as Socket);
    
                // Attempt to end the async call..
                Int32 nRecvCount = 0;
                try
                {
                    nRecvCount = client.EndReceive(result);
                    if (nRecvCount == 0)
                    {
                        this.Stop();
                        return;
                    }
                }
                catch { this.Stop(); return; }
    
                // Copy the obtained data into the backlog..
                Byte[] btRecvData = new Byte[nRecvCount];
                Array.Copy(this.m_vClientBuffer, 0, btRecvData, 0, nRecvCount);
                this.m_vClientBacklog.AddRange(btRecvData);
    
                // Process all the packets in the backlog..
                for (; ; )
                {
                    if (this.m_vClientBacklog.Count < 5)
                        break;
    
                    Int32 nPacketSize = BitConverter.ToInt32(this.m_vClientBacklog.ToArray(), 0) + 4;
                    if (this.m_vClientBacklog.Count < nPacketSize)
                        break;
    
                    Byte[] btPacket = new Byte[nPacketSize];
                    Array.Copy(this.m_vClientBacklog.ToArray(), 0, btPacket, 0, nPacketSize);
                    this.m_vClientBacklog.RemoveRange(0, nPacketSize);
    
                    // Send this packet to the server..
                    this.SendToServer(btPacket);
                }
    
                // Begin listening for next packet..
                this.Client_BeginReceive();
            }
    Now our method handles each packet by itself allowing us to easily alter the packet, drop the packet, add more packets etc. when one is received.

    Next lets do the same for the OnServerReceiveData method:
    Code:
            /// <summary>
            /// Completes an async event to receive data.
            /// </summary>
            /// <param name="result"></param>
            private void OnServerReceiveData(IAsyncResult result)
            {
                // Prevent invalid calls to this function..
                if (!this.m_vIsRunning || result.IsCompleted == false || !(result.AsyncState is Socket))
                {
                    this.Stop();
                    return;
                }
    
                Socket server = (result.AsyncState as Socket);
    
                // Attempt to end the async call..
                Int32 nRecvCount = 0;
                try
                {
                    nRecvCount = server.EndReceive(result);
                    if (nRecvCount == 0)
                    {
                        this.Stop();
                        return;
                    }
                }
                catch { this.Stop(); return; }
    
                // Copy the obtained data into the backlog..
                Byte[] btRecvData = new Byte[nRecvCount];
                Array.Copy(this.m_vServerBuffer, 0, btRecvData, 0, nRecvCount);
                this.m_vServerBacklog.AddRange(btRecvData);
    
                for (; ; )
                {
                    if (this.m_vServerBacklog.Count < 5)
                        break;
    
                    Int32 nPacketSize = BitConverter.ToInt32(this.m_vServerBacklog.ToArray(), 0) + 4;
                    if (this.m_vServerBacklog.Count < nPacketSize)
                        break;
    
                    Byte[] btPacket = new Byte[nPacketSize];
                    Array.Copy(this.m_vServerBacklog.ToArray(), 0, btPacket, 0, nPacketSize);
                    this.m_vServerBacklog.RemoveRange(0, nPacketSize);
                    
                    // Send this packet to the client..
                    this.SendToClient(btPacket);
                }
    
                // Begin listening for next packet..
                this.Server_BeginReceive();
            }
    Now we can easily do what we want to the packets before we call the SendToClient/SendToServer functions!



    Have fun!
    ~ atom0s

  2. The Following 2 Users Say Thank You to atom0s For This Useful Post:

    0haithar (02-12-2015),recnic (02-18-2015)

  3. #2
    egycnq's Avatar
    Join Date
    Sep 2018
    Gender
    male
    Posts
    202
    Reputation
    84
    Thanks
    34
    My Mood
    Amazed
    Thanks for this

Similar Threads

  1. [Release] toxy - Terraria Packet Editor / Proxy
    By atom0s in forum Terraria Hacks
    Replies: 41
    Last Post: 10-26-2014, 01:37 PM
  2. [Request] Packet Editor
    By dae67 in forum FlyFF Hacks
    Replies: 0
    Last Post: 09-06-2010, 12:41 AM
  3. [Request] Undetected Packet Editors
    By crazygamer53 in forum Combat Arms Hacks & Cheats
    Replies: 6
    Last Post: 03-16-2010, 09:01 PM
  4. XPI [Packet Editor + MS + HS Bypass] for Sale
    By Combatant in forum MapleStory Discussions
    Replies: 5
    Last Post: 01-29-2010, 12:03 PM
  5. Packet Editors
    By Anirak in forum General Hacking
    Replies: 0
    Last Post: 10-17-2009, 07:34 PM

Tags for this Thread