Circumventing Terraria’s security

Almost two years ago I decided to learn a bit more about how CLR manages reflectivity, anonymous types and so on. It turned out that helpful documentation about CLR internals were few and far between. So I started my own disassembler in an attempt to learn more. Today, I’m going to use that disassembler to circumvent Terraria’s security. Why? Because it’s fun 🙂

First things first, we want to be able to modify the abilities of our character (life, mana, objects, etc..). It’s quite obvious that information is being stored under \My Documents\My games\Terraria\Players\ however, the file has been enciphered and any modification would result in a useless file. Therefore, the application should have a way to decipher it, modify it and then encipher it again.

I’ve started by looking the types. To be honest I was expecting to find something like Terraria.Crypto or something like that, however, this is what I’ve found:

Just looking to that there is no obvious place to look at. Instead of spending a lot of time blindly looking for anything related with cryptography, I’ve tried something else. If the file that stores the player’s information is enciphered, the type Terraria.Player looks like a good place to put the code to deal with that:

The last two methods are really interesting: EncryptFile and DecryptFile. Both have two string arguments… the original file and the resulting file? Let’s try the assumption and execute DecryptFile over one the saved players:

If everything has been successful, we should be able to read the saved player. Here is the difference; the left is the decrypted file, the right the original one:

That’s it. Now we can execute DecryptFile to get the info, modify what we want and then, execute EncryptFile to encrypt it. Obviously, the DecryptFile is under a format we know nothing about… but c’mon, you can make some sense out of it.

For example, after every item, there is a number that represent the number (Int32) of items of that type the player has. 0x12 is the current life (Int32) and 0x16 is the maximum life (Int32), 0x1A is the current mana (Int32) and 0x1E the maximum mana (Int32).

Ok, the process is manual and error prone… or am I the only one who writes big-endian? But you can write a simple tool to perform this changes for you if you like 🙂

Go back to top