Hello, forum. I'm trying to write a server emulator for R2 Online. I do it in C#.
Programm.cs
You must be registered to see links
And Client.cs
You must be registered to see links
I only partially parsed the package in the buffer Post array. Found in it ip and port of the server and the client.The client writes no error about missing server, but nothing happens.Please explain what to do next.
I don't know how to deal with the structure of TCP packet... I find in packet - ip`s and ports.. And I know the encryption method - XOR.I don't know how to combine it. And what will be the difference between my server and another?Server emulator is a software that emulates an existing server for a specific client. The code you shared is just a simple TCP server as well as client. If you are writing your own client then it is not an emulator. You need to really understand the game structure in order to build an emulator. It will take lot of time and creativity to do it. You need start capturing game packets while playing, figure out encryption used (if any). Once you have enough data try writing a simple server which replays the exact same packet and see if client works. From there you need to start implementing each and every functionality yourself which might take years! Good luck to you sir :8:
I don't know how to deal with the structure of TCP packet... I find in packet - ip`s and ports.. And I know the encryption method - XOR.I don't know how to combine it. And what will be the difference between my server and another?
What is it ? where were these opcodes found?Look at some example emulators likeYou must be registered to see links
What is it ? where were these opcodes found?
You must be registered to see links
This is the bytes in the captured packets?That's found by capturing and understanding packets!
private static MainServer server = new MainServer();
static void Main(string[] args)
{
try
{
server.Startup();
server.Run();
}
catch (Exception ex)
{
// log the error
}
server.Shutdown();
}
public class MainServer
{
#region Constants
const int STATE_CLOSE = 0;
const int STATE_LOGIN = 1;
const int STATE_PLAYING = 2;
const int REQUESTS_PER_MIN = 60;
#endregion Constasnts
#region Fields
protected int m_nPort = 12345;
protected string m_strHost = "0.0.0.0";
protected bool m_bRunning = false;
protected Thread m_mainThread = null;
protected object m_objLock = new object();
protected Socket m_serverSocket = null;
protected Dictionary<Socket, ClientSocket> m_dicConnections = new Dictionary<Socket, ClientSocket>();
protected ConcurrentQueue<NetworkMessage> m_messageQueue = new ConcurrentQueue<NetworkMessage>();
protected AutoResetEvent m_evWaitForPendingMessages = new AutoResetEvent(false);
#endregion Fields
internal void Startup()
{
AutoResetEvent evWqaitForThreadToStart = new AutoResetEvent(false);
m_mainThread = new Thread(new ParameterizedThreadStart(MessageHandlerThread));
m_mainThread.Start(evWqaitForThreadToStart);
evWqaitForThreadToStart.WaitOne();
m_serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPAddress host = IPAddress.Parse(m_strHost);
IPEndPoint iep = new IPEndPoint(host, m_nPort);
m_serverSocket.Bind(iep);
m_serverSocket.Listen(2);
}
internal void Shutdown()
{
// stop running client thread
m_bRunning = false;
m_evWaitForPendingMessages.Set();
m_mainThread.Join();
// close server connections and disconnect existing clients
m_serverSocket.Close();
foreach (var key in m_dicConnections.Keys)
{
m_dicConnections[key].Disconnect();
}
m_dicConnections.Clear();
}
private void MessageHandlerThread(object obj)
{
m_bRunning = true;
AutoResetEvent evWqaitForThreadToStart = obj as AutoResetEvent;
evWqaitForThreadToStart .Set();
while (m_bRunning)
{
if (m_messageQueue.Count == 0)
{
m_evWaitForPendingMessages.WaitOne();
}
NetworkMessage netMsg = null;
m_messageQueue.TryDequeue(out netMsg);
if (netMsg == null)
{
continue;
}
switch (netMsg.Index)
{
// process network messages
default:
break;
}
}
// Shutting down
m_bRunning = false;
}
public void Run()
{
while (m_bRunning)
{
ListenForConnctions();
ManageInputData();
ManageOutputData();
// sleep 100 ms, suggest use a proper management of CPU overhead
Thread.Sleep(100);
}
}
private void ManageInputData()
{
// Make a copy
ArrayList copyList = new ArrayList();
foreach (var key in m_dicConnections.Keys)
{
copyList.Add(m_dicConnections[key].Socket);
}
if(copyList.Count == 0)
{
return;
}
Socket.Select(copyList, null, null, 0);
for (int nSocket = 0; nSocket < copyList.Count; nSocket++)
{
Socket socket = copyList[nSocket] as Socket;
ClientSocket client = m_dicConnections[socket];
if (client == null)
{
continue;
}
if (client.State == STATE_LOGIN)
{
client.LoginRequest++;
if (client.LoginRequest > REQUESTS_PER_MIN)
{
client.Disconnect();
m_dicConnections.Remove(socket);
continue;
}
}
if (client.Receive() <= 0)
{
client.Disconnect();
m_dicConnections.Remove(socket);
continue;
}
while (client.InputQueue.Count > 0)
{
NetworkMessage netMsg = client.InputQueue.Dequeue();
if (netMsg == null)
{
continue;
}
m_messageQueue.Enqueue(netMsg);
m_evWaitForPendingMessages.Set();
}
}
}
private void ManageOutputData()
{
List<Socket> socketsToDisconnect = new List<Socket>();
for (int nIndex = 0; nIndex < m_dicConnections.Count; nIndex++)
{
Socket socket = m_dicConnections.ElementAt(nIndex).Key;
ClientSocket client = m_dicConnections.ElementAt(nIndex).Value;
if (client.State == STATE_CLOSE || client.Send() <= 0)
{
client.Disconnect();
socketsToDisconnect.Add(socket);
continue;
}
}
for (int nIndex = 0; nIndex < socketsToDisconnect.Count; nIndex++)
{
Socket socket = socketsToDisconnect[nIndex];
m_dicConnections.Remove(socket);
}
}
private void ListenForConnctions()
{
try
{
ArrayList copyList = new ArrayList();
copyList.Add(m_serverSocket);
Socket.Select(copyList, null, null, 0);
if (copyList.Count == 0)
{
return;
}
Socket socket = m_serverSocket.Accept();
ClientSocket client = new ClientSocket(socket);
client.State = STATE_LOGIN;
m_dicConnections[socket] = (client);
}
catch (Exception ex)
{
// Socket error
}
}
}
public class ClientSocket
{
#region Constants
protected const int READ_DATA_SIZE = 1024;
#endregion Constants
#region Fields
protected int m_nState = 0;
protected int m_nLoginRequest = 0;
protected byte[] m_data = new byte[READ_DATA_SIZE];
protected Socket m_socket = null;
// input and output Message Queue
protected Queue<NetworkMessage> m_inputQueue = new Queue<NetworkMessage>();
protected Queue<NetworkMessage> m_outputQueue = new Queue<NetworkMessage>();
#endregion Fields
#region Constructors
public ClientSocket(Socket socket)
{
m_socket = socket;
}
#endregion Constructors
#region Properties
public Socket Socket { get { return m_socket; } }
public Queue<NetworkMessage> InputQueue { get { return m_inputQueue; } }
public Queue<NetworkMessage> OutputQueue { get { return m_outputQueue; } }
public int State
{
get { return m_nState; }
set { m_nState = value; }
}
public int LoginRequest
{
get { return m_nLoginRequest; }
set { m_nLoginRequest = value; }
}
#endregion Properties
public void Disconnect()
{
m_socket.Close();
}
public int Receive()
{
int nSize = m_socket.Receive(m_data);
if (nSize <= 0)
{
m_nState = 0; // 0 - STATE_CLOSE
return nSize;
}
// Process network packets / packets(there could be multiple packets)
// Also use a buffer on the client to read partial packets
bool bStop = false;
while (!bStop)
{
int nMsgIndex = -1;
//..
NetworkMessage netMsg = new NetworkMessage(nMsgIndex);
// Add network data
// ...
m_inputQueue.Enqueue(netMsg);
}
return nSize;
}
public int Send()
{
int nResult = 0;
int nQueueSize = m_outputQueue.Count;
for (int nIndex = 0; nIndex < nQueueSize; ++nIndex)
{
NetworkMessage netMsg = m_outputQueue.Dequeue();
int nMsgSize = m_socket.Send(netMsg.RawData);
if (nMsgSize <= 0)
{
return nMsgSize;
}
nResult += nMsgSize;
}
return nResult;
}
}
can you give me NetworkMessage class pleaseYou should avoid using a multi-threaded approach, because it will get slow with the number of connections:
Main
PHP:private static MainServer server = new MainServer(); static void Main(string[] args) { try { server.Startup(); server.Run(); } catch (Exception ex) { // log the error } server.Shutdown(); }
Main Server:
PHP:public class MainServer { #region Constants const int STATE_CLOSE = 0; const int STATE_LOGIN = 1; const int STATE_PLAYING = 2; const int REQUESTS_PER_MIN = 60; #endregion Constasnts #region Fields protected int m_nPort = 12345; protected string m_strHost = "0.0.0.0"; protected bool m_bRunning = false; protected Thread m_mainThread = null; protected object m_objLock = new object(); protected Socket m_serverSocket = null; protected Dictionary<Socket, ClientSocket> m_dicConnections = new Dictionary<Socket, ClientSocket>(); protected ConcurrentQueue<NetworkMessage> m_messageQueue = new ConcurrentQueue<NetworkMessage>(); protected AutoResetEvent m_evWaitForPendingMessages = new AutoResetEvent(false); #endregion Fields internal void Startup() { AutoResetEvent evWqaitForThreadToStart = new AutoResetEvent(false); m_mainThread = new Thread(new ParameterizedThreadStart(MessageHandlerThread)); m_mainThread.Start(evWqaitForThreadToStart); evWqaitForThreadToStart.WaitOne(); m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress host = IPAddress.Parse(m_strHost); IPEndPoint iep = new IPEndPoint(host, m_nPort); m_serverSocket.Bind(iep); m_serverSocket.Listen(2); } internal void Shutdown() { // stop running client thread m_bRunning = false; m_evWaitForPendingMessages.Set(); m_mainThread.Join(); // close server connections and disconnect existing clients m_serverSocket.Close(); foreach (var key in m_dicConnections.Keys) { m_dicConnections[key].Disconnect(); } m_dicConnections.Clear(); } private void MessageHandlerThread(object obj) { m_bRunning = true; AutoResetEvent evWqaitForThreadToStart = obj as AutoResetEvent; evWqaitForThreadToStart .Set(); while (m_bRunning) { if (m_messageQueue.Count == 0) { m_evWaitForPendingMessages.WaitOne(); } NetworkMessage netMsg = null; m_messageQueue.TryDequeue(out netMsg); if (netMsg == null) { continue; } switch (netMsg.Index) { // process network messages default: break; } } // Shutting down m_bRunning = false; } public void Run() { while (m_bRunning) { ListenForConnctions(); ManageInputData(); ManageOutputData(); // sleep 100 ms, suggest use a proper management of CPU overhead Thread.Sleep(100); } } private void ManageInputData() { // Make a copy ArrayList copyList = new ArrayList(); foreach (var key in m_dicConnections.Keys) { copyList.Add(m_dicConnections[key].Socket); } if(copyList.Count == 0) { return; } Socket.Select(copyList, null, null, 0); for (int nSocket = 0; nSocket < copyList.Count; nSocket++) { Socket socket = copyList[nSocket] as Socket; ClientSocket client = m_dicConnections[socket]; if (client == null) { continue; } if (client.State == STATE_LOGIN) { client.LoginRequest++; if (client.LoginRequest > REQUESTS_PER_MIN) { client.Disconnect(); m_dicConnections.Remove(socket); continue; } } if (client.Receive() <= 0) { client.Disconnect(); m_dicConnections.Remove(socket); continue; } while (client.InputQueue.Count > 0) { NetworkMessage netMsg = client.InputQueue.Dequeue(); if (netMsg == null) { continue; } m_messageQueue.Enqueue(netMsg); m_evWaitForPendingMessages.Set(); } } } private void ManageOutputData() { List<Socket> socketsToDisconnect = new List<Socket>(); for (int nIndex = 0; nIndex < m_dicConnections.Count; nIndex++) { Socket socket = m_dicConnections.ElementAt(nIndex).Key; ClientSocket client = m_dicConnections.ElementAt(nIndex).Value; if (client.State == STATE_CLOSE || client.Send() <= 0) { client.Disconnect(); socketsToDisconnect.Add(socket); continue; } } for (int nIndex = 0; nIndex < socketsToDisconnect.Count; nIndex++) { Socket socket = socketsToDisconnect[nIndex]; m_dicConnections.Remove(socket); } } private void ListenForConnctions() { try { ArrayList copyList = new ArrayList(); copyList.Add(m_serverSocket); Socket.Select(copyList, null, null, 0); if (copyList.Count == 0) { return; } Socket socket = m_serverSocket.Accept(); ClientSocket client = new ClientSocket(socket); client.State = STATE_LOGIN; m_dicConnections[socket] = (client); } catch (Exception ex) { // Socket error } } }
Client
PHP:public class ClientSocket { #region Constants protected const int READ_DATA_SIZE = 1024; #endregion Constants #region Fields protected int m_nState = 0; protected int m_nLoginRequest = 0; protected byte[] m_data = new byte[READ_DATA_SIZE]; protected Socket m_socket = null; // input and output Message Queue protected Queue<NetworkMessage> m_inputQueue = new Queue<NetworkMessage>(); protected Queue<NetworkMessage> m_outputQueue = new Queue<NetworkMessage>(); #endregion Fields #region Constructors public ClientSocket(Socket socket) { m_socket = socket; } #endregion Constructors #region Properties public Socket Socket { get { return m_socket; } } public Queue<NetworkMessage> InputQueue { get { return m_inputQueue; } } public Queue<NetworkMessage> OutputQueue { get { return m_outputQueue; } } public int State { get { return m_nState; } set { m_nState = value; } } public int LoginRequest { get { return m_nLoginRequest; } set { m_nLoginRequest = value; } } #endregion Properties public void Disconnect() { m_socket.Close(); } public int Receive() { int nSize = m_socket.Receive(m_data); if (nSize <= 0) { m_nState = 0; // 0 - STATE_CLOSE return nSize; } // Process network packets / packets(there could be multiple packets) // Also use a buffer on the client to read partial packets bool bStop = false; while (!bStop) { int nMsgIndex = -1; //.. NetworkMessage netMsg = new NetworkMessage(nMsgIndex); // Add network data // ... m_inputQueue.Enqueue(netMsg); } return nSize; } public int Send() { int nResult = 0; int nQueueSize = m_outputQueue.Count; for (int nIndex = 0; nIndex < nQueueSize; ++nIndex) { NetworkMessage netMsg = m_outputQueue.Dequeue(); int nMsgSize = m_socket.Send(netMsg.RawData); if (nMsgSize <= 0) { return nMsgSize; } nResult += nMsgSize; } return nResult; } }
public class NetworkMessage
{
protected const int READ_DATA_SIZE = 1024;
protected int m_nIndex = 0;
protected byte[] m_buffer = new byte[READ_DATA_SIZE];
protected MemoryStream m_stream = null;
private ClientSocket m_socket;
public NetworkMessage(int nIndex)
{
m_nIndex = nIndex;
m_stream = new MemoryStream(m_buffer);
}
public ClientSocket Socket
{
get { return m_socket; }
set { m_socket = value; ; }
}
public int Index
{
get { return m_nIndex; }
}
public byte[] Buffer
{
get { return m_buffer; }
}
public int Read(byte[] buffer, int nSize)
{
return m_stream.Read(buffer, 0, nSize);
}
public void Write(byte[] buffer, int nSize)
{
m_stream.Write(buffer, 0, nSize);
}
}
I'm using Socket Sniffer for sniffing out packets sent by client (It is possible if the game doesn't have a GameGuard or Anti-Sniffing shields,etc,etc). But, you can use WireShark(pretty powerful) or Socket Sniffer(easy interface with attaching the client.exe process into the software and sniff the s*** out of it, of course, pretty sure every packet you'll see is encrypted.. or maybe not if you are lucky).
Ha! Very nice tool, mate! Good job!Or he can use this tool I madeYou must be registered to see links
Ha! Very nice tool, mate! Good job!