A Simple Proxy Reference
While this article for the Silkroad, the concepts still apply to any game and you only need to make a couple of changes for it to work in other games. Those changes are the command line for the game and whatever is required to fake the client into thinking the original loader was used.
A Simple Silkroad Proxy Reference
The purpose of this guide is to give a simple but complete explanation of how proxies work with Silkroad. The reason this guide is being written is because a lot of people use Silkroad proxies without really understanding what they do or how they are made. Proxies are an important aspect to any packet based development because you have access to all of the data that goes on between the client and server.
Once you understand how to create a proxy, you can then develop new tools and programs on an entire new level that are otherwise not possible simply by using client patches. If you want to take development even further, you can run a proxy inside the client for a real unique setup that would allow for even more flexibility and power coupled with an injected DLL. However, that is outside the scope of this guide.
Rather than trying to go through this guide using edx33 or SR33, I have written a new simple proxy to be used. This proxy will be a final replacement for edx33 just as edx33 replaced SR33. However, the version of the proxy being shown in this guide is a “lite” version and not in a final form. It should be “good enough” to use and learn from though.
Last but not least, this guide contains a lot of text, so it’s not a practically fun read or exciting read. Rather, this guide is more like a crash course of how things work without getting into the “how to code it from scratch” aspect. The reason we don’t go step by step through programming the proxy is because it’s a programming task that will just vary based on what language you use. If you were to use C#, you’d be able to write a simple proxy using the built in networking commands rather quickly. However, you would then have to convert the Silkroad security class into C# or a compatible DLL which is not that fun.
The reason there is a lot of code is because of how C++ works. Usually, C++ projects are a lot more code than any counterparts in higher level languages. It’s one of the tradeoffs you get with the language for having a lot of power at your finger tips. Don’t be discouraged by this as much as just as how things are in the development world. Good things don’t always come in small and easy to work with packages!
If you have an interest in this topic, you will need to understand the basics of TCP. TCP is not something you just learn in a day, a month, but something you really get to understand over time or heavy study. You don’t have to know much about it for this guide, but at least know what it is!
In addition, you will need to understand how Silkroad’s security is setup. You can refer to my previous article “A Guide to Silkroad’s Security” if you do not know the basics of that concept either. Knowing how the security is setup will help in understanding how the TCP stream is processed in the proxy, but there will be more on that later.
Finally, a good working set of C++ and Visual Studio knowledge is required for this guide. Once you understand the concepts of making a proxy, you can use any language you want. However, unless you implement the Silkroad security API in another language or make a DLL out of it to use in other languages, it will not work out so nicely!
This guide is not really meant to be read from start to finish once. It’s more of something you read some, look at the code, let your brain fry, take a break, and do over and over for a while. I’ve been working with writing proxies for almost two years now and I’m still learning new and alternative designs of how to implement them efficiently. It just takes a lot of practice and struggling, so it’s not something you just do in a matter of days, weeks, or even months. As many times as I thought my code was “right”, after I learned more, I soon realized I did a lot of things wrong. Just keep that in mind as you learn more, you will go back and realize flaws in previous code.
First and foremost, proxies are not complex programs. They are really simple and usually dumb programs relatively speaking. All they do is accept connections and pass data back and forth between remote connections. For Silkroad, if not for the security bytes, you could write a really simple proxy in no time at all with very little code in a higher level language. Just keep this in mind as you are reading the guide. No matter how complex it might seem to be, in the end it is a really simple program that just requires networking domain knowledge to implement successfully.
Starting from the beginning, we need to establish how Silkroad works. First, sro_client is launched by a loader. “sro_client” will now be referred to as the “client”. The client will then connect to one of the Silkroad login servers. The Silkroad login server the client connected to will now be referred to as the “server”. Once this connection is made, the server sends data to the client and the client responds back and the communication process continues until either side terminates the communication. Easy enough, right?
At this point, we will introduce a proxy into the picture. The proxy is run from some computer the client can connect to. When the client starts, rather than connecting to the server, it simply connects to the proxy. To the client, the proxy is the server since it connected to it. It can’t tell the difference! (It could, but it would need additional programming for that.)
When the client connects to the proxy, the proxy then creates its own client to connect to the server. The reason for this is because the proxy must establish a connection to the server to be able to pass the data from the server back to the client and from the client to the server. The setup looks like this in ASCII art: Client <-> Proxy <-> Server.
Now, for simple games and programs that do not implement any security into their packets, at this point you would have complete access to the communication stream and could do whatever you wanted. You could easily inject packets in either direction, drop packets from either side, or modify packets as you wished. The power of the proxy is that since all traffic flows through it, you are in control.
For a game like Silkroad though, things are not that easy. You could still utilize this method if you wanted to log packets, but you would not be able to modify anything or drop and inject packets. For any packets that are encrypted, you would also be unable to read them yourself. This is pretty useless I think, so that is why all of my Silkroad proxies make use of the security process to give full control.
Once we add the Silkroad security processing into the proxy, we gain full control over the data stream. We are then free to do whatever we wish. For this guide, the proxy I have designed goes ahead and adds some “smart” features. If you have done any Silkroad development, you will know how the client has to send a ping packet ever 5 seconds there is no other data sent. Even though the client takes care of this for us, it is something we have to implement if we were to make a clientless.
Rather than leaving it up to the clientless programmers, we can implement the ping logic directly into our proxy so the proxy correctly pings the server so the client(less) does not have to. Pretty neat, huh? In addition, we can also add other packet processing such as the handshake, identify, version, and login packets to the proxy so all the clientless programmer has to do is send the login packet once (for ISRO) and everything else is taken care of.
What we end up with is a small but powerful program that we can use for all sorts of cool projects. Writing a clientless becomes 10x easier since all you have to do is send regular packets to the proxy and the proxy will fix them up to send to the server. Likewise the clientless will only process unencrypted packets since the proxy will decrypt them first. Of course, if anti-clientless protection is put into place like how CSRO has, then this solution is not enough unless you crack it first.
So, just to recap, the client connects to the proxy. The proxy connects to the server. The proxy sends client data to the server and server data to the client. It also decrypts and handles all of the security bytes as needed. That’s all a simple proxy does. Our proxy adds a few extra features, but that’s all there is to it!
The next bit of theory we need to cover deals with TCP, the networking protocol Silkroad and a lot of MMOs use. TCP is a protocol that is stream based, not packet based. That means when you receive data, you must know the size of the packet that it contains beforehand. This is why the size is in all packets, so the client knows how many bytes to process in the stream. Once you understand this little peculiar with TCP, then writing any proxy is not that hard. However, some games incorrectly use TCP and that is a problem you have to account for at times with your code. Silkroad uses it correctly though, so no worries here.
In order do code the TCP stream processing correctly in Silkroad, we have to first have 2 bytes available in the stream. From there we can tell if the packet is encrypted (which more packet data is required than is mentioned in the header) or if the packet is unencrypted and we have the real size. If we have an encrypted packet, we have to calculate the expected size based on the Blowfish algorithm. This topic is covered in the Silkroad Security guide. Once we decrypt our packet if it’s encrypted, we must then fix the packet size in the header so our programs have the correct size.
The proxy in itself is just another client/server program, so we can now look at what type of data the proxy needs to track for the clients that connect to it as well as the connections it creates to the remote hosts. Previously in SR33/edx33 and a previous unreleased Silkroad proxy of mine, I wrote a proxy class that was setup as a proxy object. The server would implement the remote connecting client design internally so you were only working with a single object.
That design was a bit complicated so I went to a simpler design that is shown in this proxy, which is to simply use composition to create a proxy from a server and client class. Rather than the remote client code being embedded directly into the server, I created interface functions so the client simply calls the server’s functions. This simplifies the code greatly compared to a proxy and as a result leads to a more organized design.
The proxy itself will maintain a few state variables for the local clients that connect to it such as the ping logic, the login logic, the handshake logic, and a unique ID to associate a remote client with. With a login server client is transitioning to a world server client, certain data must be passed such as the login id, name, pass, and client locale, so a wrapper structure was created to handle that.
Looking at the big picture, the proxy is its own server that will accept connections on a custom port for the login and world server emulation. It will store client data in memory for the current connection as well as copy data over to a new connection when an account goes from a login server to the world server. Finally, it will implement the basic logic for the login and world servers to handle repetitive tasks and as a result, make clientless programs easier to develop.
Phew, that’s a lot of text, but as you look through the code and read this guide, you should start being able to get a better idea of how everything is interconnected. The code should be pretty clean, but the design is not yet perfected. Even though it works great, I still want to do some more rewriting eventually to make things simpler. Proxy development is a really an incremental development process. I’ve written dozens of proxies and still working on a good design that is not only simple, but easy to maintain and use for other projects.
Attached is the complete project. This is just a “lite” version of the proxy program. It does not support plugins like my previous edx33/ SR33 projects did. However, once you understand this code, you can then look back at that code and see how the plugin logic was added. Due to limitations in the network code, only 64 connections are supported per server. While this is more than enough for Silkroad, it is something to be aware of if you plan on using the network code for other projects.
The code should not have any serious flaws in it. It does have some design issues that need to be reworked, but in terms of it working, it should just fine. I’ve tested the maximal amount of connections at once using it and never had a problem with it. Memory and CPU usage is pretty efficient too for the task. The design of the code is for a single threaded program to keep things simple. One of the things I’ve learned from edx33/SR33 is that threading over-complicates tasks like these.
In addition, the default Silkroad setup is used, so the proxy will work as-is for any Silkroad version that has not made changes to the security system or the login server packets. All you have to do is detour the client to connect to the proxy and you are set! A guide about that process will come later.
For a brief code overview:
- main.cpp – The main proxy driver code that sets up the GUI for the program. Through this GUI, users will be able to set the ports for the login and world server as well as the remote login server.
- SimpleNetwork.h/cpp – The new generic reusable network code. This is a select() based client and server implementation, so it is very simple. Only the important logic parts are commented, so expect to spend some time revering other networking information online.
- SilkroadClient.h/cpp – The Silkroad specific client class. All this does is call the appropriate server functions with its own this pointer for processing.
- SilkroadServer.h /cpp – The Silkroad specific server class. This is a base class that will handle the incoming connections as well as outgoing remote connection. The SilkroadClient objects call member functions of this class for a centralized design.
- WorldServer.h/cpp – The WorldServer implementation of the SilkroadServer. Ping, Autologin, and the handshake are handled here.
- LoginServer.h/cpp - The LoginServer implementation of the SilkroadServer. Ping, login, and the handshake are handled here.
- WorldServerObject.h/Packet.h – Helper structures.
- HandshakeApi.h/cpp – Silkroad security class.
If you read through the theory section, you should be able to account for all things mentioned in the various code files. Understand that you will not be able to just look at it and know what is going on. Sometimes it’s good to trace through to understand the flow of things, but unless you already know how to write your own proxy, understanding all of the code there might take some time. Just work through it slowly and try making your own versions when you feel you understand the concepts!
Included in the project is a compiled version for testing. Run the debug version (marked with a _d) to see the console output. The simplest testing you can do is to run the proxy and then telnet into it. The command for that would be (from a console window):
telnet localhost 16000
From there, you should see some packets being displayed, but you won't get too far since you would need to send some more packets first. However, it should be "good enough" in showing that it works! If you are on Vista or Win7, you might need to enable telnet manually. Do a good search for how this is done.
Hopefully by now, the concept of Silkroad proxies makes more sense. A Silkroad proxy acts just like a HTTP proxy except it has to do slightly more work since we are working with a complex game rather than a web server. By studying this guide and looking at the associated code, you should be able to have a more solid how a Silkroad proxy is created. This included implementation is only one possible way of accomplishing the task, there are many other approaches you could take.
That wraps up this guide. As I mentioned before, it is a lot of text and concentrated knowledge that you won’t simply read and absorb in a short period of time. From here, we have another tool at our disposal that is useful in creating more advanced development tools. This proxy will be slightly improved in the mean time and additional guides will be made to serve as companions to it. This guide is just a brief overview of the whole thing as it's an important stepping stone.
© Drew “pushedx” Benton