Skip to content

Random Key

FeroxFoxxo edited this page Oct 20, 2023 · 30 revisions

So, now what?

A new protocol has appeared! Let's break down what we know from this, based on what we've seen in verChk:

image

  • It's a system protocol - as 't' (type) is set to 'sys'
  • It's in an XML format, common to system protocols
  • Its 'action', the protocol name, is 'rndK' - recall the 'version checking' protocol was 'verChk', what could 'rndK' mean?
  • There is nothing between the tags - unlike verChk, which had the version

So, where do we go from here?

If we open ILSpy and search for 'rndK', two results come up. Usually, searching for the protocol you've received is a good idea as it will, at least, give you added information from the function sending the data.

  • Remember to set the search mode to 'Constant' - this will look for the value in any strings etc. The next common is 'Types and Members', which will look for the value in any method or class names.

image

Here, we can see the function is called 'GetRandomKey' - indicating it may want one sent back from the server in return. If you hover over 'Send', the 'message' attribute is set to string.Empty - explaining why the body tags have nothing in them.

However; you've probably noticed there's one other method that comes up - in the 'HandleMessage' method of SysHandler!

Recall, what was the method in this class for?

  • SysHandler is the IMessageHandler for system protocols
  • HandleMessage is IMessageHandler's method that's called on data received

It is not uncommon to see the sent protocol from the client have the same name as what it expects in return! However; be careful:

  • This is not always the case - we saw this with 'verChk' and 'apiOk/Ko'.
  • The client may even want multiple protocols sent back in return, not just one.

Where to go from here?

If we scroll down the list of system protocols, we can see what runs on 'rndK' being received.

image

We can see that HandleRandomKey runs on rndK, let's have a look at that method to understand what we need to send!

image

We can break this method into three parts:

  • It gets the 'node' - the contents in between the tags - of 'k', which in turn is inside the 'body' tags. I.E., <body><k>NODE</k></body>
  • It adds this 'node', a string, to a table with the ID of 'key'
  • This table is then dispatched to the 'OnRandomKey' method.

Since we know this is the only thing required of HandleRandomKey, we could test it by writing some sample code. As we are the only person connecting, we can presume this key doesn't have to be unique. A good start could be to return a bunch of gibberish as the key and see what happens!

Making the method

Think, to make the class name:

  • What is the protocol name?
  • What is the protocol method that sends this?

Remember to:

  • Write system protocol classes in the following format: [protocolName] SentProtocolMethod
  • Extend it by SystemProtocol
  • Implement all the methods/variables that are auto-filled

Hint: What is 'GetRandomKey'? What is 'rndK'?

Remember when writing the method for this:

  • There is no data sent, so we don't need to use the xmlDoc
  • The SendXml method takes two parameters - the 'protocol name', and the 'protocol message'
  • The XML consists of special characters like '<' and '>' - for whichever randomized key we write, we should avoid the use of these to prevent conflict

Note: MQR writes the 'protocol message' inside body tags already. Such, all we need to write is the XML found between the <body> tags.

  • Stuck? Look at the breakdown above, particularly the format that it uses to get the 'node'.

If you run the game with the code you wrote, you should see a new protocol pop up. This is the 'login' protocol and the subject of the next tutorial!

image

If you are stuck, here's the code I wrote:

image

Think, is there something we're forgetting?

Well, we don't actually know what this key is used for!

If we follow 'OnRandomKey', which is dispatched by _DispatchEvent in SmartFoxClient (see the previous tutorial for more info on this!), we can see it invokes the delegate 'onRandomKey' with the variable we attach to 'key' - our sent random key!

image

If we trace 'OnRandomKeyDelegate', as we did prior, we can see that it's initialized by A2m's ConnectionManager in two places

  • The constructor, where the method 'OnSFSRandomKey' is combined
  • 'RemoveEventListeners', where it is removed

image

What occurs in this method? Well, we can look for it in this ConnectionManager!

image

As we can glean if it:

  • Receives a random key and
  • The game's state is waiting for the random key

Then it:

  • Sets the '_secretKey' to our random 'key'
  • Runs the code for login

This explains why we're receiving the login protocol after sending the random key!

So, let's see where this '_secretKey' is used by analyzing it:

image

As we can see, it's read in:

  • Our OnSFSRandomKey method previously seen, where it logs the random key.
  • DoLogin, called by OnSFSRandomKey

So, how does DoLogin use the randomly generated key?

It doesn't! Nope, seriously. That's it. At the top of the method, it immediately sets it to null.

image

Why it does this? I don't know. Redundant code, I guess.

You see this a lot in MQ. It's just... not that well written. You can even find usernames and passwords for external databases embedded in the client code. I am floored there was no major data breach. I can't stress this enough, if you're going into programming, never do this. It's dumb. Go search for it in ILSpy, if you don't believe me.

Okay, whatever, I still want to write functional code to handle this

I get you! Perhaps in earlier iterations, this variable is used. So, in the main branch, I implemented the following:

image

RandomKeyGenerator is of type IService, which is automatically injected into the Service Provider via DI (dependency injection). Please check the guide on the side panel for more information.

It is a class I've written, which takes a class to relate the key to, as well as the key itself, and finally generates a random value, which we send to the client. Internally, its data structure looks like:

image

Please check RandomKeyGenerator's code for more information. If you are using it, please set the identifying type/class to something unique, or you will run into conflicts.

By doing netState.ToString() - of which, NetState(s) contain all the connecting client's information/communication code - we get the IP Address of the connected client. Such, the GetRandomKey method gets/generates a code identified by the client's IP Address (netState.GetString()) in the dictionary identified by the type 'NetState'.

  • The type here is arbitrary, but it allows this one class to handle multiple lists of randomly generated variables.
  • Attaching it to an arbitrary type/class means we can have multiple of the same key attached to different randomized values, so long as they're differentiated by this.
  • Will we ever run into retrieving based on the same key? Probably not. If it does, would it have even mattered? I doubt it. Is it still a good idea to do? Absolutely, considering this random value was (seemingly) used in cryptography. Writing it this way now goes a long way in the future, when it's deployed in production, as we are less likely to need to go back, find, and fix bad code, with it being more difficult to make changes live.

Again, this class, RandomKeyGenerator, is all code that I've written, so please take a poke into it to learn more!

  • Keep in mind this class I've written is almost never used, so don't worry if you didn't understand that blurb.

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