PDA

View Full Version : GameMon ERL Encryption (Based on rev 834)


nForce
28th September 2006, 08:01
The version of GameGuard for the game I've been targetting was bumped up to 834. As a result I've decided to take a look at whats changed in the ERL encryption process.

Interestingly enough they took a bit of a smarter approach this time. Indeed they still use a byte by byte encryption algorithm with a single 32bit key along with a static key table. However, this time the initial key is being encrypted with the RSA algorithm. Unfortunately this is asymetric encryption, and even though we can easily obtain the public key, we can only use it to encrypt data. The private key is required for decryption of this initial key.

Yet there is a weak point in this system. If we can obtain the initial key before it is encrypted, we can easily decrypt the current sessions ERL log file.

I have provided some example code bellow:

BOOL WINAPI HookCryptEncrypt
(
HCRYPTKEY hKey,
HCRYPTHASH hHash,
BOOL Final,
DWORD dwFlags,
BYTE* pbData,
DWORD* pdwDataLen,
DWORD dwBufLen
)
{
LogCryptData ( ( const char * ) pbData, dwBufLen );

DCryptEncrypt * OriginalFunction = ( DCryptEncrypt * ) m_hkCryptEncrypt->OriginalFunction ();

BOOL bReturnValue = OriginalFunction
(
hKey,
hHash,
Final,
dwFlags,
pbData,
pdwDataLen,
dwBufLen
);

return bReturnValue;
}

void LogCryptData ( const char * szData, unsigned long nSize )
{
if ( nSize == 64 )
{
ofstream ofsKeyFile ( _T ( "KeyFile.dat" ), ios::binary );
if ( ofsKeyFile.is_open () )
{
ofsKeyFile.write ( szData, 4 );
ofsKeyFile.close ();
}
}
}

Now that we have the key in clear text, we can simply plug it into the reverse engineered byte by byte decryption algorithm.

/************************************************** **********************************
* Project: ERL (Type3) Decryptor *
* *
* Copyright (C) 2006 by nForce *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
************************************************** **********************************/

#include <iostream>
#include <fstream>

using namespace std;

int main ( int nArguments, const char * szArguments [] )
{
static const unsigned long nKeyTable [] =
{
0x4E626C2E, 0x83A3A023,
0x29C9E1E8, 0x0E8E828C,
0xD2D416C6, 0x080B0B03,
0x70314171, 0x1A0A1218,
0x39497178, 0x89818809
};

if ( nArguments > 2 )
{
std::string sOutput ( szArguments [ 1 ] );
std::string sKeyFile ( szArguments [ 2 ] );
ifstream ifsTargetFile ( sOutput.c_str (), ios::binary );
ifstream ifsKeyFile ( sKeyFile.c_str (), ios::binary );

if ( ( ifsTargetFile.is_open () ) &&
( ifsKeyFile.is_open () ) )
{
sOutput.append ( ".dec" );
ofstream ofsOutputFile ( ( sOutput.c_str () ) );

if ( ofsOutputFile.is_open () )
{
unsigned long nCryptoKey;
ifsKeyFile.read ( ( ( char * ) ( & nCryptoKey ) ), 4 );
if ( ! ifsKeyFile.fail () )
{
unsigned long nKeyIndex = ( ( nCryptoKey & 0xff00ffff ) % ( sizeof ( nKeyTable ) / sizeof ( ( * nKeyTable ) ) ) );
nCryptoKey ^= nKeyTable [ nKeyIndex ];

ifsTargetFile.seekg ( 68 );
if ( ! ifsTargetFile.fail () )
{
while ( ifsTargetFile.good () )
{
nCryptoKey *= 3;
nCryptoKey = ( ( nCryptoKey ^ ( ( nCryptoKey >> ( ( ( ( nCryptoKey >> 24 ) % 17 ) + 8 ) & 0xff ) ) & 0xff ) ) + 1 );

unsigned char nEncryptedByte;
ifsTargetFile.get ( ( * ( char * ) ( & nEncryptedByte ) ) );
nEncryptedByte ^= ( ( ( char ) ( nCryptoKey & 0xff ) ) + 46 );
ofsOutputFile.put ( ( * ( char * ) ( & nEncryptedByte ) ) );
}
}
}
else
{
cout << "Key file reading failure!" << endl;
}
}
else
{
cout << "Unable to open " << sOutput.c_str () << " for output!" << endl;
}

ofsOutputFile.close ();
}
else
{
if ( ! ifsTargetFile.is_open () )
cout << "Unable to open " << sOutput.c_str () << " for input!" << endl;
if ( ! ifsKeyFile.is_open () )
cout << "Unable to open " << sKeyFile.c_str () << " for input!" << endl;
}

ifsTargetFile.close ();
ifsKeyFile.close ();
}
else
{
cout << "Syntax Error!" << endl
<< "Syntax: " << szArguments [ 0 ] << " <Erl File> <Key File>" << endl;
}

return 0;
}

Note: I leave the process of actually hooking the CryptEncrypt function exported from AdvAPI32 in GameMon to the reader.

nForce
28th September 2006, 21:44
I thought I might as well attach the compiled form of the decryption application.

Shard
28th September 2006, 22:24
Awesome work! I can't try it at the moment but I'm sure it will work perfectly. :)

temp2
29th September 2006, 11:51
Interestingly enough they took a bit of a smarter approach this time. Indeed they still use a byte by byte encryption algorithm with a single 32bit key along with a static key table. However, this time the initial key is being encrypted with the RSA algorithm. Unfortunately this is asymetric encryption, and even though we can easily obtain the public key, we can only use it to encrypt data. The private key is required for decryption of this initial key.

Yet there is a weak point in this system. If we can obtain the initial key before it is encrypted, we can easily decrypt the current sessions ERL log file.


Superb work nForce. Prior to your previous decryption I had anticipated that they were doing something like this with a public and private key on erl files … clearly they were not. Even more interesting that their encryption can be defeated this way and thank you for sharing the source code

Last1life
4th October 2006, 10:02
thats nice

SunBeam
4th October 2006, 22:03
There is an actual loop to the process of decoding the data in-memory. Been sniffing around MapleStory.exe in raw format, and it seems that there are 2 sections where GameGuard : 1. reads the data and encrypts it using that key table and 2. writes the same data (WriteFile) using a 'modified' table. One of the keys is replaced with 1 (mov eax, 1) After that, comes the old XOR with 55h. I believe it's the second key that gets replaced.

More analysis soon to be posted.

Good job, nForce ;)

andyroo
5th October 2006, 17:56
so...does this mean u can decrypt right now? or u might b able 2...

Sami_cool10
5th October 2006, 22:32
cnt we sue them for puting trojan like stuff in our computers?

Predat0r
5th October 2006, 23:32
nope, cant sue anything they do you agree to all of this when u sign up for maplestory or whatever game you play that has GG.

MMaI
6th October 2006, 00:10
one short and simple question, where do I find the Key File for input into the compiled program?

You dont need to explain how command line works, I just want to know what the key file is.

Thank you in advance, not in the least place f0or releasing this great tool [thumbs up]

stimmedcow
10th October 2006, 23:30
one short and simple question, where do I find the Key File for input into the compiled program?

You dont need to explain how command line works, I just want to know what the key file is.

I'd assume you get the key file from the first half of nForce's post - you have to hook the EncryptDecrypt function in the AdvAPI32.dll file.

Once that is done, the hook function logs the key before it is encrypted and you have your "key file".

MMaI
12th October 2006, 19:07
kk thanks, I didnt understand that step right I think

pursuit11
21st January 2007, 13:18
I'd assume you get the key file from the first half of nForce's post - you have to hook the EncryptDecrypt function in the AdvAPI32.dll file.

Once that is done, the hook function logs the key before it is encrypted and you have your "key file".

How do you go about that?

frogger
21st January 2007, 16:04
I'd like to know... what valuable information you can obtain from those log files? I was only trying to emulate a server for GG but I'm open for any different approaches...

pursuit11
23rd January 2007, 11:34
The information id like to recieve from the log files, is the server s ip address.

game: flyff

frogger
23rd January 2007, 13:14
Do you know WPE pro? Just attach it to GG and it will log all IPs GG is connecting to.

pursuit11
25th January 2007, 09:50
ive tried that.... and sometimes... SOMETIMES... it is able to pull ips.... i was only able to pull 2 unique ips aside from my own...
38.112.59.140 & 38.112.59.146 ive tried editing my host files to those ips and it seems not to affect gg or the game itself.... any ideas?

frogger
25th January 2007, 18:58
I don't believe you can edit your hosts file like that. The hosts file is there so the PC doesn't have to connect to a DNS server in order to resolve a sites IP address. So I think you can only map an address to an IP, like that:

66.102.9.104..........www.google.com

And NOT

127.0.0.1...............66.102.9.104


p.s. Another good packet sniffer is ethereal.