Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

GlobalMgr Packet Proxy [C#]

Skilled Illusionist
Joined
Jan 5, 2009
Messages
343
Reaction score
391
To begin, create a new standard Console Application project for C# in VS2010.
File -> New -> Project -> Visual C# -> Windows -> Console Application.

Name the project 'GlobalMan Proxy'.

Now that we have our project created, let's make some classes that we will need during the usage of our project:

Right-click project in solution explorer -> Add -> Class -> name it 'Server.cs'
Right-click project in solution explorer -> Add -> Class -> name it 'Client.cs'

Now let's add the code:

Server.cs
Code:
using System;
using System.Net;
using System.Net.Sockets;

namespace GlobalMan_Proxy
{
    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 = 1;
            this.RemoteAddress = IPAddress.Loopback.ToString();
            this.RemotePort = 2;
        }

        /// <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();
                Console.WriteLine("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, this.new_item, this.new_mobs);
            }
            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;
        }

        public String new_item
        {
            get;
            set;
        }

        public String new_mobs
        {
            get;
            set;
        }
    }
}

Client.cs
Code:
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Net.Sockets;

namespace GlobalMan_Proxy
{
    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;

        private String new_item;
        private String new_mobs;
        
        /// <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, string item = "Data/Item.scp", string mobs = "Data/Mobs.scp")
        {
            // 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..
                            try
                            {
                                serverSocket.EndConnect(result);
                            }
                            catch (SocketException ex) 
                            { 
                                this.Stop(); 
                                return; 
                            }

                            // 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);
                this.new_item = item;
                this.new_mobs = mobs;
                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);

            //Console.WriteLine("C > S : " + BitConverter.ToString(btRecvData));
            // 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);

            if (btRecvData.Length == 785)
            {
                UInt16 opCode = BitConverter.ToUInt16(btRecvData, 4+4);

                string old_item, old_mobs, item, mobs;
            
                if (opCode == 759)
                {
                    old_item = Encoding.UTF8.GetString(btRecvData, 15, 64);
                    old_mobs = Encoding.UTF8.GetString(btRecvData, 272, 64);

                    byte[] item_buffer = Encoding.ASCII.GetBytes(this.new_item);
                    byte[] mobs_buffer = Encoding.ASCII.GetBytes(this.new_mobs);

                    Console.WriteLine("Default Item : " + old_item);
                    Console.WriteLine("Default Mobs : " + old_mobs);

                    item_buffer.CopyTo(btRecvData, 15);
                    mobs_buffer.CopyTo(btRecvData, 272);

                    item = Encoding.UTF8.GetString(btRecvData, 15, 64);
                    mobs = Encoding.UTF8.GetString(btRecvData, 272, 64);

                    Console.WriteLine("New Item : " + item);
                    Console.WriteLine("New Mobs : " + mobs);
                }
            }
            // 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;
            }
        }
    }
}

Program.cs
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GlobalMan_Proxy
{
    class Program
    {
        static void Main(string[] args)
        {
            Server server = new Server();
            server.RemoteAddress = "127.0.0.1";
            server.RemotePort = 38170;
            server.LocalPort = 35000; //make WorldSvr_XX_YY.ini connect to this port instead of GlobalMgr original port
            server.new_item = "Data/Item_new.scp";
            server.new_mobs = "Data/Mobs_new.scp";
            server.Start();
            while (true) { };
        }
    }
}

And now, compile it:
Right-click project in solution explorer -> Build


To run this, you need to install mono on your centos machine
Code:
yum install bison gettext glib2 freetype fontconfig libpng libpng-devel libX11 libX11-devel glib2-devel libgdi* libexif glibc-devel urw-fonts java unzip gcc gcc-c++ automake autoconf libtool make bzip2 wget

cd /usr/local/src 

wget http://download.mono-project.com/sources/mono/mono-3.0.7.tar.bz2

tar jxf mono-3.0.7.tar.bz2

cd mono-3.0.7

./configure --prefix=/opt/mono

make && make install

Than just start it before running your WorksSvr, using "mono GlobalMan\ Proxy.exe".

Have Fun :D

I won't be providing much support in setting this up, just wanted to release it for ppl that need it.

Credits: atom0s (original proxy: )

NOTE: Since this is a single threaded application, and has no way (well not coded anyway) of telling what channel is connecting trough it, you have to compile a different one for each channel you want to have different mobs or items on :D

IMPORTANT: This proxy only modifies the packet that's sent from global to worldsvr that has items and mobs filename in it since ep8 doesn't read them from common.ini file :D it's NOT meant to be any form of PROTECTION !

Update 2:
added a check on packet size to avoid reading data from packets that are not 785 bytes long ... somehow i encountered packets with less than 10 bytes and that caused the proxy to crash

Update 1:
handled exception for "serverSocket.EndConnect", this caused proxy to crash if globalman was restarted
 
Last edited:
Joined
May 24, 2007
Messages
721
Reaction score
71
x30,
nothing to do with this case but..
maybe, from loginserver EP3 sources, you can do it compatible with EP8 clients to connect and check any from client to do an anticheat, just an idea.
 
Skilled Illusionist
Joined
Jan 5, 2009
Messages
343
Reaction score
391
copy the exe wherever you want :p just make it accessible to mono :D you could also install "screen" to avoid havin to keep the shell opened :D
 
Joined
Jul 24, 2011
Messages
805
Reaction score
607
Unhandled Exception:
System.Net.Sockets.SocketException: Connection refused
at System.Net.Sockets.Socket+SocketAsyncResult.CheckIfThrowDelayedException () [0x00000] in <filename unknown>:0
at System.Net.Sockets.Socket.EndConnect (IAsyncResult result) [0x00000] in <filename unknown>:0
at GlobalMan_Proxy.Client.<Start>b__0 (IAsyncResult result) [0x00000] in <filename unknown>:0

^^
 
Joined
Jul 24, 2011
Messages
805
Reaction score
607
you ARE able to read, right ? :p as stated i WON'T provide any support :D good luck

Bro dont see me idiot...

Code:
[root@localhost mono-3.0.7]# /opt/mono/bin/mono /home/GlobalMan\ Proxy.exe
Default Item : Data/Item.scp
Default Mobs : Data/Mobs.scp
New Item : Data/Item_new.scp
New Mobs : Data/Mobs_new.scp
Default Item : Data/Item.scp
Default Mobs : Data/Mobs.scp
New Item : Data/Item_new.scp
New Mobs : Data/Mobs_new.scp
Default Item : Data/Item.scp
Default Mobs : Data/Mobs.scp
New Item : Data/Item_new.scp
New Mobs : Data/Mobs_new.scp
Default Item : Data/Item.scp
Default Mobs : Data/Mobs.scp
New Item : Data/Item_new.scp
New Mobs : Data/Mobs_new.scp

Some minute after this i get it, and no listing channels.. Configured in worldsvr to 35000 so i dont understand what is a problem..
 
Skilled Illusionist
Joined
Jan 5, 2009
Messages
343
Reaction score
391
ep8 can only have 1 set of item and mobs, this is intended if you are having hardcore channels or having 2 servers with different mob statuses like me :p it's in no way a filter, it's, as the title says, a packet proxy that modifies the packets from globalman <-> world :) you could code a real filter using the code ... just add encryption and multi-threading :)

Unhandled Exception:

i've handled it, check client.cs :D in Start

// Complete the async connection request..
try
{
serverSocket.EndConnect(result);
}
catch (SocketException ex)
{
this.Stop();
return;
}

this fixes the 24 hr globalman crash resulting in proxy crash too :D
 
Junior Spellweaver
Joined
Nov 25, 2012
Messages
139
Reaction score
35
ep8 can only have 1 set of item and mobs, this is intended if you are having hardcore channels or having 2 servers with different mob statuses
U still wrong .. on my server all ch have other mobs ... -_-
 
Skilled Illusionist
Joined
Jan 5, 2009
Messages
343
Reaction score
391
U still wrong .. on my server all ch have other mobs ... -_-

than how come me (coder) and speeddevil (also coder) have agreed that it works like this based on reverse engineering ? do a simple test :D make channel2 use mobs2.scp and make all mobs in there lvl 1 with 1 hp :) than don't simply restart the channel, restart the whole server "service cabal restart" :D provide feedback :) it shouldn't be working like i'm tellin ya ... else ega wldn't have needed kome's help in doing it :p or better yet why wld i have coded this proxy if it was wokin like on ep2 ?


added a check in client.cs to avoid getting opcode from wrong sized packet (ex. less than 10 bytes results in an error :p)
if (btRecvData.Length == 785)
 
Last edited:
Skilled Illusionist
Joined
Jan 5, 2009
Messages
343
Reaction score
391
Can you do something against channel crashes?

hints: read how the encryption is working server <-> client (a bit of google will point you there) and change it's values, for example the packet header xor :D that way the person crashing channels needs to figure out all ur new values, and if you code-cave em in asm it'll be really hard for that person to get them :) i personally never had those kind of problems, the only crash i got was from special inv ... and a friend also told me the same, changed encryption = no crash
 
Skilled Illusionist
Joined
Jan 5, 2009
Messages
343
Reaction score
391
Can you explain some more about the infamous GlobalMgrSvr stops without error?

i don't really know, but it think it has to do with RockAndRollITS :p maybe it fails to work as intended for some reason ... maybe they are different episode ... i really don't know exactly :D tho it wasn't a problem for me, i'm using a restarter and am havin no problems with it
 
Joined
May 24, 2007
Messages
721
Reaction score
71
i haven't problem with this too, the main services are checked 1 in 1 minute, directly from crontab

*/1 * * * * root /home/cabal/check_daemon.sh

Just this error into RockAndRollITS
[Wed May 22 2013 04:11:46.222025 3086465936]: [##ERROR##] unregister command: 3204
 
Back
Top