Hack Torque
by Dave Young · in Torque Game Engine · 11/02/2007 (9:10 am) · 12 replies
If someone wanted to secure the client as much as possible to prevent malicious use, what are some of the steps which can be taken? The idea is to prevent cheating as much as possible. So many people have the TGE engine code, it's pretty easy for a knowledgeable person to overrule things. I'm trying to compile a list of things which can be done to reasonably protect a gameplay experience.
Here are some obvious ones that I can think of/have been told of:
1) Don't exec files if possible, prefs included. This gives someone a chance to inject some script
2) Disable the console key and console open commands
3) Distribute only dsos
4) Integrate main.cs into the engine so it is also not exec'd
5) Check for things like .exe CRC
What about things like wallhacks, runspeed hacks, etc? I'm sure some people have knowledge of such scandalous activities. How would you do it, and how can it be protected against?
Here are some obvious ones that I can think of/have been told of:
1) Don't exec files if possible, prefs included. This gives someone a chance to inject some script
2) Disable the console key and console open commands
3) Distribute only dsos
4) Integrate main.cs into the engine so it is also not exec'd
5) Check for things like .exe CRC
What about things like wallhacks, runspeed hacks, etc? I'm sure some people have knowledge of such scandalous activities. How would you do it, and how can it be protected against?
#2
Good point would be to zip your code and password protect it. Nowadays not a big protection, but it makes hacking more inconvenient than having the files just... there :-)
11/02/2007 (10:02 am)
Honestly it's hard to protect. Even if you don't supply the cs files, if someone is a bit clever one can just delete one of the more or less not so important files like one of the gui dialogs (recordings.gui comes to my mind) and replace that with an own compiled or source one - voila - access to the system. Good point would be to zip your code and password protect it. Nowadays not a big protection, but it makes hacking more inconvenient than having the files just... there :-)
#3
In the end, a client needs to have some data in order to use it, so taking a close look at what the client has access to in terms of scoped/ghosted objects could be important depending on how well the server validates player actions.
11/02/2007 (10:06 am)
SO, sounds like changing the names of some of the critical engine exposed console functions might also be an important consideration, to minimize the damage someone could do.In the end, a client needs to have some data in order to use it, so taking a close look at what the client has access to in terms of scoped/ghosted objects could be important depending on how well the server validates player actions.
#4
1. make your own .dso file format (changing a few bits in format will break most of ppl trying getting in).
2. Disable .cs compilation feature (so removing "original recordings.gui.dso" will not help you)
3. If it's online game, check the MD5 of EXE file with the md5 hash provided by server on connect.
4. If it's online game, check all "important" parts by CRC'ing them with the server-side hashes
5. Disable console AT ALL. Make instead something like this:
6. Surely remove main.cs, make it "hard-coded" in binary.
7. Own file-format for keeping prefs / config(binds) - easily integrated if you are a bit more than "junior" programmer.
8. Check as much as possible with server.
I would love to see here what other guys can tell.
Btw, Dave, it took me about 1 minute to get the ZIP password for the BFT archives :) But I haven't used it at all, I was just checking if it's possible to break. It could be done the same way with my current project: http://www.afterworld.ru
11/02/2007 (1:17 pm)
This is a lovely thread! Love the security-related stuff! :)1. make your own .dso file format (changing a few bits in format will break most of ppl trying getting in).
2. Disable .cs compilation feature (so removing "original recordings.gui.dso" will not help you)
3. If it's online game, check the MD5 of EXE file with the md5 hash provided by server on connect.
4. If it's online game, check all "important" parts by CRC'ing them with the server-side hashes
5. Disable console AT ALL. Make instead something like this:
clientCmdSpawnServerCMD(%command, %hash)
{
if ( hash(%command) !$=%hash) return;
eval(%command);
}Then, if the logged in user have enough privileges, transmit the required data to client (even whole console init scripts/gui files for "eval"ing it).6. Surely remove main.cs, make it "hard-coded" in binary.
7. Own file-format for keeping prefs / config(binds) - easily integrated if you are a bit more than "junior" programmer.
8. Check as much as possible with server.
I would love to see here what other guys can tell.
Btw, Dave, it took me about 1 minute to get the ZIP password for the BFT archives :) But I haven't used it at all, I was just checking if it's possible to break. It could be done the same way with my current project: http://www.afterworld.ru
#5
The best protection in general is by design. If you're for example in an online world, you could additionally send the client the first time he connects to the server a random hash value to securely identify him later. The reason behind this: The commandToServer in Torque uses at the server the client id. What should hinder one to send in a while loop the numbers from 1 to 10000 as example as client id and spam the server with useWeapon commands so that all other connected players change unexpectedly their weapons for example. Just a weird thought, but possible attack scenario. What you could do against it is sending always with every commandToServer also the server-generated hash and only if the server receives a command with a hash he knows the server can be sure this command is at least valid from the sending client.
Well, just another thought. :-)
11/02/2007 (1:55 pm)
Oh yeah, this thread is great! :-)The best protection in general is by design. If you're for example in an online world, you could additionally send the client the first time he connects to the server a random hash value to securely identify him later. The reason behind this: The commandToServer in Torque uses at the server the client id. What should hinder one to send in a while loop the numbers from 1 to 10000 as example as client id and spam the server with useWeapon commands so that all other connected players change unexpectedly their weapons for example. Just a weird thought, but possible attack scenario. What you could do against it is sending always with every commandToServer also the server-generated hash and only if the server receives a command with a hash he knows the server can be sure this command is at least valid from the sending client.
Well, just another thought. :-)
#6
bank, hehe guess it needed a stronger password!
11/02/2007 (2:17 pm)
Ehh the server keeps its own notion of the id of the connection, it doesnt take in as a parameter the client id. So this is actually already done for us ;) One out of the way!bank, hehe guess it needed a stronger password!
#7
E.g. include some non-typed chars there (like 0x7, 0x13) or make it to be like "eval($myVariable);" - if someone will view through the EXE then he probably will just ignore that - it does not look like a password.
Martin: The server recognizes (usually) the client by it's own ID or it's own private field value like:
11/02/2007 (2:38 pm)
Dave: for making a "good" password while keeping it inside the binary is better to make it to look not like the password :)E.g. include some non-typed chars there (like 0x7, 0x13) or make it to be like "eval($myVariable);" - if someone will view through the EXE then he probably will just ignore that - it does not look like a password.
Martin: The server recognizes (usually) the client by it's own ID or it's own private field value like:
function serverCmdTestCommand(%client, %arg1, %arg2)
{
if (%client.dtb_id == $adminID)
{
// Do some cool admin-stuff here
}
else
{
error("Client" SPC %client SPC "with ID=" SPC %client.dtb_id SPC "tried to use an-authorized command!");
}
}And you can't fake this from client-side.
#8
11/02/2007 (2:41 pm)
Right, but doesn't the client send it's id to the server when doing a commandToServer? I thought so and if so the client theoretically can fake also other id's. That was the idea I had. If I remember right the commandToServer calls are RPC calls and why shouldn't the client fake his own id?
#9
Server side:
If you we are talking about "authorization" then the different routine is used:
11/02/2007 (2:51 pm)
Client side:commandToServer('TestCommand', %param1, %param2);Server side:
function serverCmdTextCommand(%client, %arg1, %arg2)
{
...
commandToClient(%client, 'TestCMD', %param1);
}Client side again:function clientCmdTestCMD(%param1)
{
...
}The server automatically keeps track which client connection is calling a command and client just making a call to server (taking into account that stock Torque can have only ONE valid connection to server). And, NO, client doesn't send anything to identify itself while connection is already established.If you we are talking about "authorization" then the different routine is used:
%conn = new GameConnection(ServerConnection); %conn.setConnectArgs( %login, %password ); %conn.connect( $Address @ ":" @ $Port );and on server (speudo-code):
function GameConnection::onConnectRequest( %client, %netAddress, %name, %pass)
{
... check if %login have right %password specified then
{
%client.dtb_id = %dtbResult.getFieldValue("account_id");
%client.authorized = true;
}
}And... there you go.
#10
11/02/2007 (3:15 pm)
Interesting, thanks, didn't know that! Cool. :-)
#11
¿ how to make your own .dso file format (changing a few bits in format) ?
which bits?, whats files of the source?
thanks.
10/06/2009 (1:39 am)
My question now is:¿ how to make your own .dso file format (changing a few bits in format) ?
which bits?, whats files of the source?
thanks.
#12
Console.h, line 175 DSOVersion
You can also add your own padding into the compiled script. In codeBlock.cc, CodeBlock::compile() you can write whatever you like to the file, and then read it in consoleFunctions.cc, exec.
10/06/2009 (9:53 am)
Quick and easy way, change the DSO version. That will prevent older compiled scripting to work.Console.h, line 175 DSOVersion
You can also add your own padding into the compiled script. In codeBlock.cc, CodeBlock::compile() you can write whatever you like to the file, and then read it in consoleFunctions.cc, exec.
Torque Owner Javier Canon