13.08.2013 Views

Saving and loading games in Bundesliga Manager Professional

Saving and loading games in Bundesliga Manager Professional

Saving and loading games in Bundesliga Manager Professional

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Sav<strong>in</strong>g</strong> <strong>and</strong> <strong>load<strong>in</strong>g</strong> <strong>games</strong> <strong>in</strong> <strong>Bundesliga</strong> <strong>Manager</strong><br />

<strong>Professional</strong><br />

1 Introduction<br />

Rol<strong>and</strong> Kübert<br />

December 2010<br />

This document describes how Software 2000’s <strong>Bundesliga</strong> <strong>Manager</strong> <strong>Professional</strong><br />

(BMP), also known as The <strong>Manager</strong> <strong>in</strong> English, saves <strong>and</strong> loads <strong>games</strong>. The<br />

<strong>in</strong>-game data that is saved is encrypted <strong>and</strong> both the encryption <strong>and</strong> decryption<br />

process are described <strong>in</strong> this document.<br />

2 File format<br />

A save game <strong>in</strong> BMP is 34369 bytes long. Out of these, 37 bytes are non-payload<br />

data: the file header (34 bytes), a seed value (1 byte) <strong>and</strong> two checksums (1<br />

byte each). All the rest is payload data, that is the data used by the game itself<br />

<strong>and</strong> sav<strong>in</strong>g the player’s <strong>in</strong>formation.<br />

2.1 File header<br />

The file header consists of a 29 byte long text str<strong>in</strong>g (WeRnEr krahe & JeNs onnenBMP!),<br />

followed by 5 more bytes, of which byte 3 <strong>and</strong> 4 are always both zero. The significance<br />

of these values is yet unclear.<br />

2.2 Seed<br />

The seed value is a probably r<strong>and</strong>om value used <strong>in</strong> the encryption process. It is<br />

yet unclear how this value is determ<strong>in</strong>ed.<br />

2.3 Checksums<br />

The checksum bytes computed dur<strong>in</strong>g the encryption process <strong>and</strong> are stored at<br />

two times, once at offset 28006 <strong>and</strong> at offset 34368, the end of the file.<br />

1


2.4 Payload<br />

What the payload data conta<strong>in</strong>s is only partially known at this time. Look<br />

at https://sourceforge.net/apps/mediawiki/freebmp/<strong>in</strong>dex.php?title=<br />

MAN\_file\_format for up-to-date <strong>in</strong>formation.<br />

3 The sav<strong>in</strong>g process<br />

Savegame encryption is not overly complex, but nonetheless we firstly present<br />

an example before def<strong>in</strong><strong>in</strong>g the algorithm.<br />

3.1 An example save game<br />

The save game process starts by obta<strong>in</strong><strong>in</strong>g the seed value. For this example,<br />

let the seed value be y = 0xC3 <strong>and</strong> let the first bytes be a0a1a2a3 =<br />

0x040x050x060x07.<br />

Initially, the checksum is set to be equal to the seed value, that is<br />

.<br />

3.1.1 Encrypt<strong>in</strong>g the first byte<br />

checksum = C3<br />

The encrypted value for our unencrypted byte a = 0x04 is computed like this:<br />

aienc = (ai ⊕ y) + y%0x100<br />

That is, the current value of y is xor’d with a <strong>and</strong> then y is added to the<br />

result aga<strong>in</strong>. The result is taken mod 256, which just means that any value that<br />

does not fit <strong>in</strong> one byt is discarded. For our example, this gives the follow<strong>in</strong>g<br />

result:<br />

1<br />

a0enc = (0x04 ⊕ 0xC3) + 0xC3 = 0xC7 + 0xC3 = 0x8A<br />

As we have said, only the lowest byte of the result is used, therefore a0enc<br />

results to 0x8A.<br />

Another value, which we call z, comes <strong>in</strong>to play now. This value is a static<br />

value that is fixed to 0xD7 <strong>in</strong> BMP <strong>and</strong> that is used to compute the next value<br />

of y like this:<br />

y = y + z%100<br />

1 Obviously, the result overflows <strong>in</strong>to the next byte giv<strong>in</strong>g 0x18A as the result. However,<br />

the overflow value is never used <strong>and</strong> therefore we omit from here on.<br />

2


The new value of y is the result of the addition of the old value of y <strong>and</strong> the<br />

value of z. Once aga<strong>in</strong>, only the low byte of this computation is kept. In our<br />

case, this results <strong>in</strong> the new value of y be<strong>in</strong>g 0x9A:<br />

y + z = 0xC3 + 0XD7 = 0x9A<br />

The new checksum value is computed by add<strong>in</strong>g the unencrypted value of ai<br />

to the old checksum value (if the value exceeds one byte, only the lowest byte<br />

is reta<strong>in</strong>ed):<br />

checksum = checksum + ai = 0xC3 + 0x04 = 0xC7<br />

This concludes all computations for the first byte. As a result, the value of<br />

a0enc = 0x8A, is written to the save file.<br />

3.1.2 Encrypt<strong>in</strong>g the second byte<br />

The same process as before is now applied to the second byte, a1 = 0x05.<br />

We compute a1enc by xor<strong>in</strong>g with y, add<strong>in</strong>g y <strong>and</strong> keep<strong>in</strong>g the low byte (we<br />

omit mod 256 ):<br />

a1enc = (a1 ⊕ y) + y = (0x05 ⊕ 0x9A) + 0x9A = 0x9F + 0x9A = 0x39<br />

Therefore, a1enc = 0x39.<br />

For the new value of y, we <strong>in</strong>crease y by 0xD7, keep<strong>in</strong>g only the low byte:<br />

y = y + 0xD7 = 0x9A + 0xD7 = 0x71<br />

We <strong>in</strong>crease the checksum with the value of a1:<br />

checksum = checksum + a1 = 0xC7 + 0x05 = 0xCC<br />

This concludes all computations for the second byte. As a result, the value<br />

of a1enc = 0x39, is written to the save file.<br />

3.1.3 Encrypt<strong>in</strong>g the third byte<br />

The same process as before is now applied to the third byte, a1 = 0x06.<br />

We compute a2enc by xor<strong>in</strong>g with y, add<strong>in</strong>g y <strong>and</strong> keep<strong>in</strong>g the low byte (we<br />

omit mod 256 ):<br />

a2enc = (a2 ⊕ y) + y = (0x06 ⊕ 0x71) + 0x71 = 0x77 + 0x71 = 0xE8<br />

Therefore, a2enc = 0xE8.<br />

For the new value of y, we <strong>in</strong>crease y by 0xD7, keep<strong>in</strong>g only the low byte:<br />

y = y + 0xD7 = 0x71 + 0xD7 = 0x48<br />

3


We <strong>in</strong>crease the checksum with the value of a2:<br />

checksum = checksum + a2 = 0xCC + 0x06 = 0xD2<br />

This concludes all computations for the third byte. As a result, the value of<br />

a2enc = 0xE8, is written to the save file.<br />

3.1.4 Encrypt<strong>in</strong>g the fourth byte<br />

The same process as before is now applied to the fourth byte, a3 = 0x07.<br />

We compute a3enc by xor<strong>in</strong>g with y, add<strong>in</strong>g y <strong>and</strong> keep<strong>in</strong>g the low byte (we<br />

omit mod 256 ):<br />

a3enc = (a3 ⊕ y) + y = (0x07 ⊕ 0x48) + 0x48 = 0x4F + 0x48 = 0x97<br />

Therefore, a3enc = 0x97.<br />

For the new value of y, we <strong>in</strong>crease y by 0xD7, keep<strong>in</strong>g only the low byte:<br />

y = y + 0xD7 = 0x48 + 0xD7 = 0x1F<br />

We <strong>in</strong>crease the checksum with the value of a2:<br />

checksum = checksum + a3 = 0xD2 + 0x07 = 0xD9<br />

This concludes all computations for the third byte. As a result, the value of<br />

a3enc = 0xD9, is written to the save file.<br />

3.1.5 Encrypt<strong>in</strong>g the nth byte<br />

We refra<strong>in</strong> from giv<strong>in</strong>g more example as the process is quite clear from the 4<br />

examples above. The only special case is the first iteration, where the <strong>in</strong>itial<br />

values are set up. There are, however, two special occassions when the checksum<br />

byte is written: once at offset 28006 <strong>and</strong> once at offset 34368. The last offset is<br />

the last byte <strong>in</strong> the saved file, the other offset is some arbitrary value.<br />

3.2 The encryption algorithm<br />

The follow<strong>in</strong>g list<strong>in</strong>g shows the algorithm <strong>in</strong> k<strong>in</strong>d of pseudo-code.<br />

y = 0xC3 # Just use a f i x e d value f o r y<br />

z = 0xD7 # Use a f i x e d value f o r z as w e l l<br />

checksum = y<br />

f o r o f f s e t <strong>in</strong> range ( 0 , payload bytes ) :<br />

a dec = i n f i l e . read ( 1 )<br />

a enc = ( a dec ˆ y ) + y ) % 0x100<br />

y = ( y + z ) % 0 x100<br />

4


checksum = ( checksum + a dec ) % 0x100<br />

o u t f i l e . w r i t e ( a enc )<br />

# Write checksum bytes i f n e c e s s a r y<br />

i f o f f s e t == 27970 or o f f s e t == 34331:<br />

o u t f i l e . w r i t e ( checksum )<br />

checksum = checksum new<br />

4 The <strong>load<strong>in</strong>g</strong> process<br />

Given an encrypted game, how is the payload data extracted? This sections<br />

answers this problem by demonstrat<strong>in</strong>g how a given file is read. The file format<br />

is described <strong>in</strong> section 2, but table 4 summarizes the structure for your<br />

convenience:<br />

Offset Length Description<br />

0 34 Header<br />

34 1 Seed<br />

35 27972 Payload data, part 1<br />

28006 1 Checksum 1<br />

28007 6360 Payload data, part 2<br />

34368 1 Checksum 2<br />

The seed value, which will be labeled with the variable y <strong>in</strong> this section’s<br />

equations, is the first value that needs to be read (apart from the file header,<br />

which can be used to identify if the file is even a save game file <strong>in</strong> the correct<br />

format). Similar to section 3, we present how the algorithm works on the first<br />

four bytes of a save game.<br />

4.1 An example save game<br />

The save game process starts by obta<strong>in</strong><strong>in</strong>g the seed value from the file. For this<br />

example, let the seed value be y = 0xC3 <strong>and</strong> let the first bytes be a0a1a2a3 =<br />

0x8A0x390xE80xD9.<br />

Initially, the checksum is set to be equal to the seed value, that is<br />

.<br />

4.1.1 Decrypt<strong>in</strong>g the first byte<br />

checksum = C3<br />

The first byte is a0 = 0x8A. The decrypted value is obta<strong>in</strong>ed by the follow<strong>in</strong>g<br />

computation:<br />

5


a0dec = (a0 − y) ⊕ y)<br />

As when encod<strong>in</strong>g, only the lower 8 bits of the result are used, which means<br />

that an implicit mod 256 is applied, which we omit for the sake of clarity from<br />

the equations. If y is greater than the value of the byte to decrypt, you can<br />

assume an implicit addition of 256. The unencrypted value is:<br />

a0dec = (0x8A−0xC3)⊕0xC3 = (0x18A−0xC3)⊕0xC3 = 0xC7⊕0xC3 = 0x04<br />

As before, the value of y is <strong>in</strong>creased by a fixed value (mod 256 ), called z,<br />

which is always z = 0xD7:<br />

y = y + z = 0xC3 + 0xD7 = 0x9A<br />

The checksum is <strong>in</strong>creased by the decrypted value of a0:<br />

checksum = checksum + a0dec = 0xC3 + 0x04 = 0xC7<br />

4.1.2 Decrypt<strong>in</strong>g the second byte<br />

The second byte is a1 = 0x39, which we decrypt us<strong>in</strong>g y = 0x9A:<br />

a1dec = (0x39−0x9A)⊕0x9A = (0x139−0x9A)⊕0x9A = 0x9F ⊕0x9A = 0x05<br />

As before, the value of y is <strong>in</strong>creased by a fixed value (mod 256 ), called z,<br />

which is always z = 0xD7:<br />

y = y + z = 0x9A + 0xD7 = 0x71<br />

The checksum is <strong>in</strong>creased by the decrypted value of a1:<br />

checksum = checksum + a1dec = 0xC7 + 0x05 = 0xCC<br />

4.1.3 Decrypt<strong>in</strong>g the third byte<br />

The third byte is a2 = 0xE8, which we decrypt us<strong>in</strong>g y = 0x71:<br />

a2dec = (0xEB − 0x71) ⊕ 0x71 = 0x7A ⊕ 0x71 = 0x06<br />

As before, the value of y is <strong>in</strong>creased by a fixed value (mod 256 ), called z,<br />

which is always z = 0xD7:<br />

y = y + z = 0x71 + 0xD7 = 0x48<br />

The checksum is <strong>in</strong>creased by the decrypted value of a2:<br />

checksum = checksum + a2dec = 0xCC + 0x06 = 0xD2<br />

6


4.1.4 Decrypt<strong>in</strong>g the fourth byte<br />

The fourth byte is a3 = 0x97, which we decrypt us<strong>in</strong>g y = 0x48:<br />

a3dec = (0x97 − 0x48) ⊕ 0x48 = 0x4F ⊕ 0x48 = 0x07<br />

As before, the value of y is <strong>in</strong>creased by a fixed value (mod 256 ), called z,<br />

which is always z = 0xD7:<br />

y = y + z = 0x48 + 0xD7 = 0x1F<br />

The checksum is <strong>in</strong>creased by the decrypted value of a3:<br />

checksum = checksum + a3dec = 0xD2 + 0x07 = 0xD9<br />

4.1.5 Decrypt<strong>in</strong>g the nth byte<br />

We refra<strong>in</strong> from giv<strong>in</strong>g more example as the process is quite clear from the 4<br />

examples above. The only special case is the first iteration, where the <strong>in</strong>itial<br />

values are set up. There are, however, two special occassions when the checksum<br />

byte is read: once at offset 28006 <strong>and</strong> once at offset 34368. The last offset is the<br />

last byte <strong>in</strong> the saved file, the other offset is some arbitrary value.<br />

If the checksum is not correct, that is the file has been manipulated, the<br />

game recognizes this through the checksum, pr<strong>in</strong>ts an error message <strong>and</strong> hangs.<br />

4.2 The decod<strong>in</strong>g algorithm<br />

The follow<strong>in</strong>g list<strong>in</strong>g shows the algorithm <strong>in</strong> k<strong>in</strong>d of pseudo-code.<br />

z = 0xD7 # Use a f i x e d value f o r z<br />

# Read i n i t i a l y ( i n f i l e i s at o f f s e t 34 already )<br />

y = i n f i l e . read ( 1 )<br />

checksum = y<br />

# I t e r a t e through a l l payload bytes<br />

f o r i <strong>in</strong> range ( 0 , payload bytes ) :<br />

a enc = i n f i l e . read ( 1 )<br />

# Ignore the f i r s t <strong>and</strong> l a s t checksum byte , that i s , do not decode i t<br />

i f o f f s e t == 27971 or o f f s e t == 34333:<br />

# Skip checksum bytes at o f f s e t s 27971 <strong>and</strong> 34333<br />

e l s e :<br />

a dec = ( a enc − y ) ˆ y ) % 0x100<br />

y = ( y + z ) % 256<br />

checksum = ( checksum + a dec ) % 0x100<br />

o u t f i l e . w r i t e ( a dec )<br />

o f f s e t = o f f s e t + 1<br />

7


5 Version<br />

This file is revision number 127 from 2010-12-21 20:01:56Z, committed by rkuebert.<br />

8

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!