A fundamental event occurred today. But it requires a backstory.
On February 24, 2013, I created a project called TSO-SE, with the following README.md:
# TSO-SE TSO-SE ("The Sims Online Server Emulator") is not a serious project, but a curious one attempting to see just how far the game's original protocol can be cracked.
The project started with some PHP files and some documentation. I intended to upload this project to Github, but day after day inside OllyDbg I found myself repeating the phrase “Let me just finish figuring this thing out first so I can put something nice in for the initial commit”. On March 20, 2013, I successfully broke past the login screen on the official Maxis client for the TSO New & Improved trial (version 1.1097.1.0), into Select-A-Sim, and documented the results on the wiki. The process involves uploading a few PHP files on an HTTPS server, or patching the client to connect over HTTP rather than HTTPS, and specifying its hostname in the client’s ini files. The same server can allow any version of The Sims Online into Select-A-Sim, from Play Test (1.3.2.89) to the final version of EA-Land (2.1667.5.0). For the rest of the game, a new server is required, which must use the ARIES/Voltron protocol over TLS, which must be reverse engineered without the help of any decrypted packet logs.
Today, I have broken into Create-A-Sim. The implications are tremendous. I can make a pixel-perfect reconstruction of the original menus for Niotso Tech Preview 1. And I plan to finish it by the end of the summer.
Getting into Create-A-Sim was significantly more involved than Select-A-Sim. Sure, Select-A-Sim’s protocol was completely plaintext, allowing me to place a breakpoint on the cRZString::Compare() function and write down every XML tag it checked for. But more importantly, the networking code for Select-A-Sim was completely serial, and all the logic started and completed inside the same function. What has held back Create-A-Sim for so long is two issues, the first of which is fully resolved, and the second of which is ongoing.
The first issue was finding the logic that handles the server’s response. Select-A-Sim makes an HTTP request using wininet.dll’s HttpOpenRequest() function and then immediately parses the response. Aries, however, runs on its own thread. When data is discovered using Winsock, it’s decrypted into a buffer using OpenSSL, and the 12-byte header is run through an initial validation. After that, some flags are set somewhere, and the TSOClient thread eventually gets to handling the data. These unknown flags have to indicate that the data has a complete Voltron packet before the TSOClient thread handles the data, meaning hardware breakpoints did nothing until I got the header right, so it’s a chicken-and-egg problem unless you can either find the flags or get it right: in my case, the header was just three fields, so it wasn’t difficult to guess. Afterwards, back over in the TSOClient thread, the code splits into hundreds of branches: unlike Select-A-Sim, there is no single right or wrong response by the server at any given time. How do you guess which (one or more, in cascade) of these corresponds to the Server Hello message (or whatever the hell it’s waiting for)? This problem can be reworded like this: what input state will cause this output state? In theory, as cryptographic hash functions exploit, this problem may be impractical to solve. However, as the “general” logic has at least been found, the initial issue in question can be more or less checked off.
The second issue is actually equivalent to the sub-problem of the first. After finding the function that updates the progress bar (which was not easy, because the results are not drawn until far later), I discovered that I could enter Create-A-Sim by forging the HandleConnectionEstablished message ID (0x3BF7000A) onto the cTSOClientLoginRegulator message queue in place of HandleConnectionFailed (0xFBF7001B), which was already an incredible find, but I wanted more than that: I wanted to know which packets cause the game to make this step on its own. The one function in TSONetServiceSimClientD.dll that posts 0x3BF7000A (located at 0x10011320) does not have any static call references; that is, it’s looked up from a v-table. The function appears in three v-tables at the same offset of +0x74. The regular expression “call[ ]*DWORD PTR \[.*\+0x74\]” yielded 30 matches, and after removing those that supply the wrong number of arguments or an obvious non-pointer as arg1, that still left me with 22 potential candidates. And if the code uses the lea instruction or anything else to look up the function from the v-table, all 22 could be false positives. Resolving references to a function that are computed on the spot like this, in theory, reduces to the halting problem. And this could just keep going back, requiring more and more levels of analysis. What connects the path from state A to state B? This is the point where I decided to give up going backwards, and try to attack this from the other direction.
The run-time type information from EA-Land, giving a name to each Voltron packet type, and guesswork are the only things that saved me here. It turned out that sending a HostOnlinePDU was the answer to getting into Create-A-Sim.
How to do it yourself
- Make a backup of sys/gameentry.ini. Then open it with a text editor and set the “Server” field to niotso.org. If your version of TSO also has a gamedata/sys/ folder, do the same thing with the copy of gameentry.ini in that folder.
- Make a backup of sys/cityselector.ini. Then open it with a text editor and set the “ServerName” field to niotso.org. Keep “ServerPort” at 80. If your version of TSO also has a gamedata/sys/ folder, do the same thing with the copy of cityselector.ini in that folder.
Since I’d rather not pay for HTTPS hosting, you’ll have to make a binary patch to 3 DLLs using a hex editor (such as wxHexEditor, Ghex, or Frhed) to connect over HTTP. (If you decide to connect to a different server that supports HTTPS, you can skip these modifications.)
- Make a backup of authlogin.dll. Then open it with a hex editor. Replace the 5 bytes “68 00 30 C0 84″ (in version 1.1097.1.0 these appear at offset 0x8325) with “68 00 00 40 84″. Also, replace the 5 bytes “68 BB 01 00 00″ (in version 1.1097.1.0 these appear at offset 0x82AC) with “68 50 00 00 00″.
- Make a backup of TSOServiceClientD.dll. Then open it with a hex editor. Replace the 8 bytes “68 74 74 70 73 3A 2F 2F” (in version 1.1097.1.0 these appear at offset 0x923C0) with “68 74 74 70 3A 2F 2F 00″.
- Make a backup of InternetServiceD.dll. Then open it with a hex editor. Replace the 7 bytes “74 07 68 BB 01 00 00″ (in version 1.1097.1.0 these appear at offset 0x17B2) with “EB 07 68 BB 01 00 00″. Not all versions of the game contain this code (play test and EA-Land do not), so for those versions, this file should remain untouched.
The above steps have been tested to work on all five versions of the game in our possession. After these modifications, if you also wish to enter Create-A-Sim, download the TSO-SE cityserver and run it in the background. Because the city server listens on a port, Windows Firewall (if you’ve enabled it) will ask you if you want to allow it to do so; click allow.
After you have done this, launch the game through TSOClient.exe (not the updater utility) and log in with “asdf” as your username and “hjkl” as your password. When you wish to create a Sim, click the button, and when you get to the progress bar, give the cityserver the command: send hostonlinepdu.dat . If you’re curious, communications will be logged in log.dat, so take a look.
The userdata/localavatarcache folder is still being studied. As far as I can tell, the game does not even ask the server for the up-to-date avatar data before you connect to the city. Without valid data in the localavatarcache folder to begin with, you will see the “proxy” Sim shown in this screenshot. This can be solved by placing this data in your localavatarcache folder alongside the “dont_delete.txt” file. (The avatar ID I’m having the City Selection server assign is 1337, which explains the naming.)
Where I’m going next
I’ve just been accepted into electrical engineering at UT Austin. Additionally this summer, I’m starting a basic ray tracer project, going through a digital signal processing textbook, and getting my license.