Skip to content

Version Check

FeroxFoxxo edited this page Oct 20, 2023 · 29 revisions

Getting Started

So what is the verChk protocol? Let's have a look:

  1. Install ILSpy from the following link:
  1. Open the MQ -> game -> MQ_Data -> Managed folder as shown below.

  2. Press control + A to select all games in the folder

  3. Open ILSpy, delete everything in the "Assemblies" panel and drag the new assemblies into the application.

image

So, what are the functions of these assemblies? Let's have a rundown of the most important:

  • For the game logic; Assembly-CSharp
  • For the chat code; Crisp.AutoSuggest
  • To handle incoming/outgoing game protocols; A2mCore
  • For handing the socket connection that A2mCore relies on, as well as system protocols; SmartFoxClient
  • For some specialised protocols like portals; Thrift

Looking into what makes a protocol

If we look into ILSpy, we can see that this protocol is handled in the SmartFox assembly (as is common for System protocols) by searching for it, by looking up "verChk" and switching the mode to "constant" (a string). Feel free to double-click this, and you'll exactly what goes into "building" this protocol:

image

As we want to respond to this 'verChk' protocol, which we can extrapolate is (likely) related to checking the version of the game (based on the majVersion etc variables in the code sending the protocol), what is the client looking to be returned by us to continue executing the game code? (i.e., so it isn't stuck on the loading screen).

Well... let's continue further!

First, how would the client process the protocol? Using the information we know about the assemblies, let's think about how these might work together to handle incoming data:

  1. SmartFoxClient receives the protocol from the server and processes it, finding the name and type of the protocol
  2. A2mCore is then handed the processed response, formatting incoming data specifically to that protocol's requirements
  3. Assembly-CSharp finally handles this formatted data, which it runs the game logic for.

As I previously mentioned, this is a system protocol. We can see this, as the message (msg) type (t) is set to system (sys). A lot of reverse engineering is guessing what these variables might mean. In this context, these variable names make sense.

Typically, protocols in this XML format are system protocols.

image

We can guess that SmartFox has something to do with handling this protocol. A couple of ways to find this mystery method to handle verChk's response can be found below:

  • We could look through all the methods in SmartFox's assembly to find the method we might be after.
  • In the search-mode "method", look for something in SmartFox relating to "XML" and "receive".
  • A smarter way of doing this is to search for "msg t" in search mode "constant" (which are the arguments in the sent protocol), which the client might also look for as part of incoming protocols.

TLDR; There are countless ways to problem-solve your way to these methods! Doing so, we land on the method below:

image

From this, we can glean the following information:

  • It first loads up the XML
  • It gets the type of the protocol (sys for system, xt for external - we'll talk about this one later)
  • It handles the message according to the type of protocol it is

If we look at the class, we can see a few other related methods. A protocol can either be in the format of:

  • XML, likely if it's a system protocol, surrounded by '<' and '>'.
  • JSON (unlikely), surrounded by '{' and '}'.
  • STR, with each argument split by '%'.

image

For example, if we click on MSG_STR in the above screenshot, we can see this information listed at the top of the class.

image

We can see where these are used by right-clicking, pressing "Analyse", and opening the "Used by" tab. Alternatively, we can also find where XML Received is called by, using the same method.

image

Message Handlers

So, what are these messageHandlers? Let's click on it and take a look.

image

As it seems to be a table/list, there must be some code that adds to this list. By right-clicking and pressing "Analyse", we can see, as this is a variable, it is both read and assigned. Assigning the list is unlikely to have any interesting information, as it's simply where the variable is created. What looks more interesting, is the 'AddMessageHandler' method.

image

If we open this up, we can see it takes a key and handler and adds it to this list.

image

Such, we might need to dig a layer deeper. By pressing the right arrow on your keyboard, or clicking the '+' button to the left, let's see where this method is called.

image

From here, we can see that it's used by SetupMessageHandlers. This looks more like it! Taking a peek into the method, we can tell two "message handlers" are added - sysHandler (system, sys) and extHandler (external, xt).

image

From the above image, we can see these are both of type IMessageHandler. If we look into this interface, we can find it has that initial HandleMessage method from XMLReceived!

image

Let's take a look at the HandleMessage from SysHandler. Here, we can see all the incoming system protocols. These are the most fundamental protocols for the game and are all in this one location. Often, the client will be expecting the same type of protocol to the server that it expects back. Taking a look at the list, what is the most likely protocol it wants received?

image

The ApiOK Protocol

We can guess that, if it's running a version check where - if you've noticed - it contains a version 'v' of 154, it might be checking if the API version matches the game's.

image

This makes sense, given the error message of ApiKO (KO, being the inverse of OK)

image

Note, Nothing is done with the xml parameter in this method.

If we follow DispatchEvent (if we inspect/analyze runInQueueMode it's always false) to _DispatchEvent and search for that "OnConnection", we meet the following code.

image

We can further see if we analyze onConnection, it takes us to a delegate. Delegates are used to call code from other assemblies.

image

Investigating OnConnectionDelegate, we can see it calls code in A2M core. Given what we know about the assembly, this makes sense.

image

If we were to follow this all the way down, it would take us to the next protocol that's sent. We'll see this once we program this response for 'verChk'!

Programming verChk

Before we start, I want to preface the information mentioned above as something you'll get used to over time. It is this process of reverse engineering that we'll use to understand this project. Simply, we are: searching for related methods/variables, analyzing them, and following their code down to find what we want. Understanding the specific variables/functions is key, but the basic implementation of this problem-solving will help you get to where you want to go.

Now, onto the programming!

To create a response to a protocol, we attach it to a class. Where the class goes depends on which type of protocol it is. For system protocols, this is the "Protocols.System" project, in the "[xml] System" folder.

Right-click this folder -> Add -> New Item -> Class

The class' name follows a specific template, to ensure consistency. This can be seen as follows:

[protocolName] SentProtocolMethod

image

For instance, based on the verChk's method, we'd call it:

[verChk] HandleSocketConnection

We then format the class as follows to clean it up. We:

  1. Change the class' name to what we set SentProtocolMethod to
  2. Set the class to public
  3. Remove unnecessary imports

As such, it goes from this:

image

To this:

image

Much cleaner! Now we can write our protocol.

If this is a system protocol, we need to extend the class by SystemProtocol. If this is an external protocol (xt), we extend it by ExternalProtocol.

In doing so, we see the class is now underlined in red. If we hover over it, we see it's missing some important methods I've written that are part of the class - similar to the HandleMessage method we saw earlier.

image

We can press the lightbulb icon and "Implement abstract class" to add what's missing.

image

Here, we need to set the ProtocolName - "verChk" - and in Run, we can write the code replying to the protocol.

What we know we need to reply with, from our analysis of ApiOK/KO:

  • We need to check the version given to us through the protocol
  • Then send a system XML with apiOK/KO based on whether the client's version matches the server's

One way we could do this is to always reply with "apiOK", if we know we're only going to use the same version of the client. As XMLs are always used for SYS protocols, using the SendXML method (part of the BaseProtocol class that SysProtocol extends - if you control + click on the class in Visual Studio, you can follow it down to this method.

image

Note: We saw above that the 'xml' passed into ApiOK isn't used anywhere, hence why 'message' is empty.

Let's run the game and see what happens next!

image

Here we can see:

  • the incoming verChk protocol
  • the outgoing apiOk protocol we just wrote
  • a new protocol called rndK, also of type 'system'

As you might notice, this is new! Next, we'll look into how to implement this protocol.

However; think - are we done with this protocol?

No! We're given the version that we don't check, and it will never fail the version check as a result.

If we check how this is implemented on the 'main' branch, we see the following:

image

What does this do?

  • Gets the version from the xmlDoc. XmlDocument is a class as part of the internal C# library. I won't explain how the node query is written, as there are plenty of resources online. For example, https://zetcode.com/csharp/xmldocument/
  • Sends the XML, with the protocol type as apiOK if version equals SmartFoxClient.GetVersion().Replace(..), else; apiKO

Any class you need can be injected into your protocol by:

  • Setting the variable to public
  • Adding 'getters' and 'setters' ( {get;set;} )

This class is injected in Server.Reawakened -> Reawakened.cs in the AddServices method.

image

  • The Server.Reawakened class is where the majority of the server's game logic is stored.

Why are we using GetVersion from the class?

image

If we see where the majVersion etc. variables from verChk's HandleSocketConnection are used, it's also found in GetVersion().

image image

As these are very similar, if we remove the '.'s, the value of GetVersion will be the same as HandleSocketConnection. By checking against this, we can ensure that the SmartFoxClient and other dependencies of our server matches that of the game that's trying to connect.

Hopefully, that makes sense! Let's move on to the next protocol c:

MQReawakened Wiki

Development

Developer Tutorials

System Protocols:

External Protocols (TO DO):

Entities (TO DO):

  • Init Data
  • Sync Events

Miscellaneous (TO DO):

  • Console Commands
  • Timers
  • XMLs
  • Web
Clone this wiki locally