blurite / rsprox

RuneScape local proxy server that intercepts and records all the traffic.
MIT License
24 stars 12 forks source link

RSProx #1

Closed Z-Kris closed 1 month ago

Z-Kris commented 2 months ago

Introduction

RSProx will be a project that wraps around existing clients and records all incoming and outgoing traffic in a similar fashion to the commonly used event inspector. The difference here is that this project works for all java clients, as well as the desktop C++ client.

Problems

This project has to overcome numerous hurdles in order to be simple to use, and actually function as intended.

ISAAC Seed

The first hurdle that we need to overcome is that of the ISAAC seed. The client generates said seed through a SecureRandom instance, which is then written into a buffer that is encrypted with a 4096-bit RSA. It's currently impossible to crack such RSAs or even come close to it, so anything of that nature is out of the question.

The solution here comes in the form of patching and proxying. If we replace the original RSA key in the client with one that we generated on our own, allowing us get both the public and the private key, we can decrypt said block of data at the proxy, grab the necessary information and re-encrypt it with the original RSA key that the client was going to use, writing the information on to the OSRS servers as if nothing happened. Afterwards, we can simply maintain an ISAAC key pair at the proxy the same way the client does. We must ensure that the proxy remains in synchronization with the client at all times, though this is a minor problem.

World Selection

The second hurdle comes in the form of world selection. The client always uses the same port - 43594 - for all of the worlds it connects to. There is an alternative port of 443 if the primary fails, but we can ignore this for all intents and purposes here, as it is rarely ever used to begin with. The primary problem here is the proxy will have no knowledge of the world you selected.

The solution here involves patching and maintaining a separate world list that the client connects to. This separate world list will be updated frequently by a separate server that grabs the latest world list and re-encodes it with different IPs - those of unique local hosts. Rather than the IP being of world 1 being http://oldschool1.runescape.com/, we would replace it with 127.0.1.1. For world 2, we would replace http://oldschool1.runescape.com/ with 127.0.2.1 and so on, effectively saturating the localhost IP space with ~300 IPs that the proxy will listen to. The proxy will use this localhost IP to determine the actual world that the client is attempting to connect to.

World Hopping

The third hurdle is world hopping. As the server transmits the exact world IP and information that the client will be connecting to, our current concept does not work for it.

The solution here requires intercepting and modifying the LOGOUT_TRANSFER packet at the proxy level. The server will transfer the original LOGOUT_TRANSFER packet with the IP that it intended you to connect to, but the proxy will intercept it before writing it to the client, decoding it, remapping the original IP and re-encoding. The client will simply get the unique localhost IP that corresponds to that specific IP that the server requested.

Base Client

The tool here needs to patch a client. We do not wish to lock the people to a specific client as we did with the old Event Inspector tool. The solution should support different existing clients.

In order to avoid locking people onto a specific client, this tool would initially open up as a simple window that allows you to select a specific client you wish to use. This would look up existing RuneLite installation, as well as your C++ installation. Additionally, it would offer a selection window for a specific jar that one could choose. The tool would then attempt to patch the RSA, worldlist and jav_config strings automatically. All of these strings can be identified uniquely across all clients (unless the client is heavily modified to scatter the information). As long as the patching process works, the proxy tool will work with that client.

Packet Processing

In order for this entire application to function, the tool must support decoding packets in both directions, as well as encoding a couple specific cases. This allows us to log traffic in both directions. Based on RSProt project, we can see that roughly 40-50% of all the packets in both directions are consistent across revisions - these would not need to be modified ever. The remaining 50-60% however would have to be updated each revision. We can copy the client-to-server decoders from RSProt, but the server-to-client decoders must be written explicitly in this tool, exactly how the client does them. I expect the entire process of updating all the packets both directions to take no more than about two hours.

Packet Logging

In addition to being processed, we need to actually log the data in the packets. This should always be done in two forms:

Binary Logging

This logging involves storing the entire session in a binary file that contains the raw bytes of all the packets as they originally were. The binary file would contain a header which provides us the information we need to properly identify it, such as the world type (free, members, beta, PvP, etc), the world id, revision, ISAAC seed, etc.

Text Logging

An alternative to binary logging is text-based logging. This is more in line with the traditional event inspector. A public API would be provided for the logging implementation, allowing developers to provide their own preferred logging structure for the packets. Each individual packet would be configurable, as well as the overall style of the logs (spacing, metadata and so on).

Crowdsourcing

An additional side-goal of this project is to create a large archive of crowdsourced gameplay data from OldSchool RuneScape. We can accomplish this by having an optional step (with a simple way to opt in/out of it) to upload the session to a public database. The database would be publicly accessible by anyone to grab the data. All confidential information is erased before it ever leaves the user's local PC.

Storage Format

One of the problems with crowdsourcing comes in the form of storage format. While we could just store it in a sanitized text format, it doesn't provide users with the option of downloading the logs in their preferred format. In order to accomplish this, we need to do data sanitization at the proxy end before it ever gets written to the server, for security concerns. All private messages, incoming and outgoing, will be starred out. Whenever the bank pin interface is opened, some state will be marked down indicating "the next input integer that follows will be a bank pin". When that next input integer is received, and the marker is set, the value will be replaced from the actual pin (e.g. 1367) with the value 0. In doing so, we ensure the confidentiality of anyone using the tool. Usernames, friend list contents and clan messages will not be excluded however, as this has too much possibility of false-positives. There's also the question of where to draw the line if that were to happen - dms, names, clans, public messages, all player names, etc. Rather not deal with names at all.

Header

Below is a table of what all the binary blob's header needs to contain: Property Value Type
Header Version Int
Revision Int
Login Timestamp Long
World Id Int
World Flags Int
World Location Int
World Host String
World Activity String
Display Name String
Local Player Index Int
Account Hash Long
ISAAC Seed IntArray
Client Name String
Cache CRC IntArray

Packets

Packets will additionally also contain their own header, however this header only contains the epoch time millisecond of when the packet was received. While it is possible to infer the semi-accurate timestamp based on SERVER_TICK_END packets, this provides best accuracy there is, especially during login when the client is spammed with hundreds of packets and multiple ticks essentially merge into one. The packet payload here contains the opcode, the variable-size (if applicable) as well as the actual data transmitted. The data will remain in the obfuscated format according to the respective revision. In a few rare cases, sanitization will occur where some bytes get replaced for privacy reasons.

Property Value Type
Timestamp Long
Payload ByteArray

Bad Actors

Another problem is bad actors. Anyone can create fake data and upload it to the server. If this ever becomes a problem, we need to come up with some authorization process to ensure only valid data gets to the public server.

Live Logging

The current event inspector offers a UI that lets players see traffic live as it happens. Given the popularity of it, it should be offered along the other external logging options. This would be an opt-in UI that the user can open at any moment, offering logs in the format of the user's choice. It's possible we can make this into an API and allow users to customize the UI to their own liking.

ultraviolet-jordan commented 2 months ago

Looks good to me

Tyluur commented 2 months ago

Well written, good work.