NFS Most Wanted Save Editor - Technical Details
A nuż komuś się przyda ;)
Po angielsku:
--------------------------------------
Technical Details
=================
If you (probably) have a wish to crate some better tools for editing savegame files for NFS Most Wanted then here is some (maybe) useful info about it.
First, about the limitations of my save editor:
- It will work only with files of 63 596 bytes in length as it seems that the game allocates all the structures directly after the alias is created but initialises them progressively during the gameplay
- Block locations are assumed non-moveable, thus the program uses constant file offsets
- Bounty can be changed for the first car only because there is no reliable way to verify that the internal structures were initialised properly and won't be overwritten later, besides the total bounty is calculated dynamically from the different locations, so there is an improvement vector ;-)
The savefile is protected aginst damage/hack with the custom variation of the CRC32 checksum and MD5 hash, however it seems the game does not make any use of CRC32 checksums, but that requires in fact a more detailed investigation.
This save editor updates all checksums anyway and besides allows you to make some changes to the save files by hand using any hex-editor and update the checksums only.
Savefile itself consists of the header, data block and MD5 hash of that data block. File layout is as follows (all fields are stored in little endian format):
---------- | -------------- | ---------- | -------------------------------------------------------------------- |
0 | magic | 4 byte | 'MC02' |
0x4 | file_length | 4 byte | total file length in bytes |
0x8 | unknown1 | 4 byte | usually 8 |
0xC | data_length1 | 4 byte | saved data length (including MD5 hash) ? |
0x10 | crc32_blk1 | 4 byte | crc32 of a 8-byte data block at offset 0x1C |
0x14 | crc32_data | 4 byte | crc32 of a saved data (offset 0x24 till the end of the file) |
0x18 | crc32_blk2 | 4 byte | crc32 of the above data (0x18 byte block from the file beginning) |
0x1C | unknown2 | 4 byte | usually 0x10D |
0x20 | data_length2 | 4 byte | following block length ? usually equal to data_length1 |
0x24 | unk_3 | 1 byte | zero (16-byte zero block) |
.... | unk_n | zero | |
0x34 | saved_data | beginning of the saved data | |
.... | .......... | data | |
0xF85C | MD5_hash | 16 byte | MD5-hash of the saved data (offset 0x34 till the end-16 bytes) |
As you can see there are 4 checksums, but it seems that the game uses only the MD5 hash to make the conclusion that the file was not altered in any way.
MD5 implementation used in this save editor was taken from the OpenSSL project sources.
EA's CRC32 algo uses a table, the sample code is following:
DWORD EAcrc32(void *pData, DWORD cbData)
{
DWORD crc32 = 0;
BYTE *pbyData = (BYTE *)pData;
if ( cbData < 4 )
return 0;
crc32 |= (*pbyData++)<<24 font="font">24>
crc32 |= (*pbyData++)<<16 font="font">16>
crc32 |= (*pbyData++)<<8 font="font">8>
crc32 |= (*pbyData++);
cbData -= 4;
crc32 = ~crc32;
while ( cbData-- )
crc32 = ((crc32<<8 crc32="crc32" crc32tab="crc32tab" pbydata="pbydata">>24];8>
return ~crc32;
}
Here is the table:
DWORD EAcrc32tab[] = {
DWORD EAcrc32(void *pData, DWORD cbData)
{
DWORD crc32 = 0;
BYTE *pbyData = (BYTE *)pData;
if ( cbData < 4 )
return 0;
crc32 |= (*pbyData++)<<24 font="font">24>
crc32 |= (*pbyData++)<<16 font="font">16>
crc32 |= (*pbyData++)<<8 font="font">8>
crc32 |= (*pbyData++);
cbData -= 4;
crc32 = ~crc32;
while ( cbData-- )
crc32 = ((crc32<<8 crc32="crc32" crc32tab="crc32tab" pbydata="pbydata">>24];8>
return ~crc32;
}
Here is the table:
DWORD EAcrc32tab[] = {
0x00000000 | 0x04C11DB7 | 0x09823B6E | 0x0D4326D9 |
0x130476DC | 0x17C56B6B | 0x1A864DB2 | 0x1E475005 |
0x2608EDB8 | 0x22C9F00F | 0x2F8AD6D6 | 0x2B4BCB61 |
0x350C9B64 | 0x31CD86D3 | 0x3C8EA00A | 0x384FBDBD |
0x4C11DB70 | 0x48D0C6C7 | 0x4593E01E | 0x4152FDA9 |
0x5F15ADAC | 0x5BD4B01B | 0x569796C2 | 0x52568B75 |
0x6A1936C8 | 0x6ED82B7F | 0x639B0DA6 | 0x675A1011 |
0x791D4014 | 0x7DDC5DA3 | 0x709F7B7A | 0x745E66CD |
0x9823B6E0 | 0x9CE2AB57 | 0x91A18D8E | 0x95609039 |
0x8B27C03C | 0x8FE6DD8B | 0x82A5FB52 | 0x8664E6E5 |
0xBE2B5B58 | 0xBAEA46EF | 0xB7A96036 | 0xB3687D81 |
0xAD2F2D84 | 0xA9EE3033 | 0xA4AD16EA | 0xA06C0B5D |
0xD4326D90 | 0xD0F37027 | 0xDDB056FE | 0xD9714B49 |
0xC7361B4C | 0xC3F706FB | 0xCEB42022 | 0xCA753D95 |
0xF23A8028 | 0xF6FB9D9F | 0xFBB8BB46 | 0xFF79A6F1 |
0xE13EF6F4 | 0xE5FFEB43 | 0xE8BCCD9A | 0xEC7DD02D |
0x34867077 | 0x30476DC0 | 0x3D044B19 | 0x39C556AE |
0x278206AB | 0x23431B1C | 0x2E003DC5 | 0x2AC12072 |
0x128E9DCF | 0x164F8078 | 0x1B0CA6A1 | 0x1FCDBB16 |
0x018AEB13 | 0x054BF6A4 | 0x0808D07D | 0x0CC9CDCA |
0x7897AB07 | 0x7C56B6B0 | 0x71159069 | 0x75D48DDE |
0x6B93DDDB | 0x6F52C06C | 0x6211E6B5 | 0x66D0FB02 |
0x5E9F46BF | 0x5A5E5B08 | 0x571D7DD1 | 0x53DC6066 |
0x4D9B3063 | 0x495A2DD4 | 0x44190B0D | 0x40D816BA |
0xACA5C697 | 0xA864DB20 | 0xA527FDF9 | 0xA1E6E04E |
0xBFA1B04B | 0xBB60ADFC | 0xB6238B25 | 0xB2E29692 |
0x8AAD2B2F | 0x8E6C3698 | 0x832F1041 | 0x87EE0DF6 |
0x99A95DF3 | 0x9D684044 | 0x902B669D | 0x94EA7B2A |
0xE0B41DE7 | 0xE4750050 | 0xE9362689 | 0xEDF73B3E |
0xF3B06B3B | 0xF771768C | 0xFA325055 | 0xFEF34DE2 |
0xC6BCF05F | 0xC27DEDE8 | 0xCF3ECB31 | 0xCBFFD686 |
0xD5B88683 | 0xD1799B34 | 0xDC3ABDED | 0xD8FBA05A |
0x690CE0EE | 0x6DCDFD59 | 0x608EDB80 | 0x644FC637 |
0x7A089632 | 0x7EC98B85 | 0x738AAD5C | 0x774BB0EB |
0x4F040D56 | 0x4BC510E1 | 0x46863638 | 0x42472B8F |
0x5C007B8A | 0x58C1663D | 0x558240E4 | 0x51435D53 |
0x251D3B9E | 0x21DC2629 | 0x2C9F00F0 | 0x285E1D47 |
0x36194D42 | 0x32D850F5 | 0x3F9B762C | 0x3B5A6B9B |
0x0315D626 | 0x07D4CB91 | 0x0A97ED48 | 0x0E56F0FF |
0x1011A0FA | 0x14D0BD4D | 0x19939B94 | 0x1D528623 |
0xF12F560E | 0xF5EE4BB9 | 0xF8AD6D60 | 0xFC6C70D7 |
0xE22B20D2 | 0xE6EA3D65 | 0xEBA91BBC | 0xEF68060B |
0xD727BBB6 | 0xD3E6A601 | 0xDEA580D8 | 0xDA649D6F |
0xC423CD6A | 0xC0E2D0DD | 0xCDA1F604 | 0xC960EBB3 |
0xBD3E8D7E | 0xB9FF90C9 | 0xB4BCB610 | 0xB07DABA7 |
0xAE3AFBA2 | 0xAAFBE615 | 0xA7B8C0CC | 0xA379DD7B |
0x9B3660C6 | 0x9FF77D71 | 0x92B45BA8 | 0x9675461F |
0x8832161A | 0x8CF30BAD | 0x81B02D74 | 0x857130C3 |
0x5D8A9099 | 0x594B8D2E | 0x5408ABF7 | 0x50C9B640 |
0x4E8EE645 | 0x4A4FFBF2 | 0x470CDD2B | 0x43CDC09C |
0x7B827D21 | 0x7F436096 | 0x7200464F | 0x76C15BF8 |
0x68860BFD | 0x6C47164A | 0x61043093 | 0x65C52D24 |
0x119B4BE9 | 0x155A565E | 0x18197087 | 0x1CD86D30 |
0x029F3D35 | 0x065E2082 | 0x0B1D065B | 0x0FDC1BEC |
0x3793A651 | 0x3352BBE6 | 0x3E119D3F | 0x3AD08088 |
0x2497D08D | 0x2056CD3A | 0x2D15EBE3 | 0x29D4F654 |
0xC5A92679 | 0xC1683BCE | 0xCC2B1D17 | 0xC8EA00A0 |
0xD6AD50A5 | 0xD26C4D12 | 0xDF2F6BCB | 0xDBEE767C |
0xE3A1CBC1 | 0xE760D676 | 0xEA23F0AF | 0xEEE2ED18 |
0xF0A5BD1D | 0xF464A0AA | 0xF9278673 | 0xFDE69BC4 |
0x89B8FD09 | 0x8D79E0BE | 0x803AC667 | 0x84FBDBD0 |
0x9ABC8BD5 | 0x9E7D9662 | 0x933EB0BB | 0x97FFAD0C |
0xAFB010B1 | 0xAB710D06 | 0xA6322BDF | 0xA2F33668 |
0xBCB4666D | 0xB8757BDA | 0xB5365D03 | 0xB1F740B4 |
};
Yep, that's all ;-)
Best regards,
CoDe RiPPeR code_ripper@ukr.net
Need For Speed Most Wanted Save Editor
----------------------------------------------
Informacje techniczne
=======================
Jeśli chciałbyś stworzyć lepsze narzędzie do edytowania zapisów stanu gry w NFS Most Wanted, to mam dla Ciebie (najprawdopodobniej) użyteczne informacje o tym programie.
Po pierwsze, o limitach w moim edytorze:
- Program działa tylko z plikami o długości 63 596 bajtów. Gra tworzy alias o takim rozmiarze na początku rozgrywki i stopniowo wypełnia je, w miarę postępów poczynionych w grze.
- (*) Lokacje bloków są z założenia nieruchome, więc program wykorzystuje stałe przesunięcia plików
- (*) Notowania mogą być zmienione tylko dla pierwszego samochodu ponieważ nie ma niezawodnego sposobu na sprawdzenie, czy wewnętrzne struktury zostały zainicjowane prawidłowo i nie będą nadpisane później. Poza całkowitymi notowaniami oblicza się dynamicznie z różnych miejsc, więc jest ulepszenie wektora ;-)
Zapisy gry są chronione przeciwko znieszczeniom/zhakowaniu o dodatkową odmianę sum kontrolnych CRC32 i hash MD5. Wydaje mi się jednak, że gra nie używa sum kontrolnych CRC32, ale trzebaby było to dokładnie sprawdzić.
Ten program aktualizuje wszystkie sumy kontrolne. Poza tym pozwala dokonać pewnych zmian ręcznie używając dowolnego hex-edytora i aktualizując tylko sumy kontrolne.
Zapis składa się z nagłówka, bloku danych i hash'u MD5 tego bloku. Układ plików jest następujący (wszystkie pola są zapisywane w formacie "little endian" (cienkokońcowość)):
------------ | -------------- | ----------- | ------------------------------------------------------------------- |
0 | magic | 4 bajty | 'MC02' |
0x4 | file_length | 4 bajty | Całkowita długość pliku w bajtach |
0x8 | unknown1 | 4 bajty | zazwyczaj 8 |
0xC | data_length1 | 4 bajty | Zapisana długość danych (włączając hash MD5)? |
0x10 | crc32_blk1 | 4 bajty | Crc32 z 8-bajtowego bloku danych o przesunięciu 0x1C |
0x14 | crc32_data | 4 bajty |
Crc32 z zapisanych danych (przesunięcie 0x24 aż do końca pliku)
|
0x18 | crc32_blk2 | 4 bajty | Crc32 z powyższych danych (0x18 bajtów od początku pliku) |
0x1C | unknown2 | 4 bajty | Zazwyczaj 0x10D |
0x20 | data_length2 | 4 bajty | Po długości bloku? Zwykle równa się data_length1 |
0x24 | unk_3 | 1 bajty | Zero (16-byte zero block) |
.... | unk_n | Zero | |
0x34 | saved_data | Początek zapisywania danych | |
.... | .......... | Dane | |
0xF85C | MD5_hash | 16 bajtów | MD5-hash z zapisanych danych (przesunięcie 0x34 do końca 16 bajtu) |
Jak widać istnieją 4 sumy kontrolne, jednak wydaje się, że gra wykorzystuje tylko hash MD5 do sprawdzenia czy plik nie został zmodyfikowany w jakikolwiek sposób.
Implementacja MD5 została zaczerpnięta z projektu OpenSSL.
EA's CRC32 algorytm wykorzystuje tabelę, przykładowy kod jest następujący:
DWORD EAcrc32(void *pData, DWORD cbData)
{
DWORD crc32 = 0;
BYTE *pbyData = (BYTE *)pData;
if ( cbData < 4 )
return 0;
crc32 |= (*pbyData++)<<24 font="font">24>
crc32 |= (*pbyData++)<<16 font="font">16>
crc32 |= (*pbyData++)<<8 font="font">8>
crc32 |= (*pbyData++);
cbData -= 4;
crc32 = ~crc32;
while ( cbData-- )
crc32 = ((crc32<<8 crc32="crc32" crc32tab="crc32tab" pbydata="pbydata">>24];8>
return ~crc32;
}
Tu jest tabela:
DWORD EAcrc32tab[] = {
0x00000000 | 0x04C11DB7 | 0x09823B6E | 0x0D4326D9 |
0x130476DC | 0x17C56B6B | 0x1A864DB2 | 0x1E475005 |
0x2608EDB8 | 0x22C9F00F | 0x2F8AD6D6 | 0x2B4BCB61 |
0x350C9B64 | 0x31CD86D3 | 0x3C8EA00A | 0x384FBDBD |
0x4C11DB70 | 0x48D0C6C7 | 0x4593E01E | 0x4152FDA9 |
0x5F15ADAC | 0x5BD4B01B | 0x569796C2 | 0x52568B75 |
0x6A1936C8 | 0x6ED82B7F | 0x639B0DA6 | 0x675A1011 |
0x791D4014 | 0x7DDC5DA3 | 0x709F7B7A | 0x745E66CD |
0x9823B6E0 | 0x9CE2AB57 | 0x91A18D8E | 0x95609039 |
0x8B27C03C | 0x8FE6DD8B | 0x82A5FB52 | 0x8664E6E5 |
0xBE2B5B58 | 0xBAEA46EF | 0xB7A96036 | 0xB3687D81 |
0xAD2F2D84 | 0xA9EE3033 | 0xA4AD16EA | 0xA06C0B5D |
0xD4326D90 | 0xD0F37027 | 0xDDB056FE | 0xD9714B49 |
0xC7361B4C | 0xC3F706FB | 0xCEB42022 | 0xCA753D95 |
0xF23A8028 | 0xF6FB9D9F | 0xFBB8BB46 | 0xFF79A6F1 |
0xE13EF6F4 | 0xE5FFEB43 | 0xE8BCCD9A | 0xEC7DD02D |
0x34867077 | 0x30476DC0 | 0x3D044B19 | 0x39C556AE |
0x278206AB | 0x23431B1C | 0x2E003DC5 | 0x2AC12072 |
0x128E9DCF | 0x164F8078 | 0x1B0CA6A1 | 0x1FCDBB16 |
0x018AEB13 | 0x054BF6A4 | 0x0808D07D | 0x0CC9CDCA |
0x7897AB07 | 0x7C56B6B0 | 0x71159069 | 0x75D48DDE |
0x6B93DDDB | 0x6F52C06C | 0x6211E6B5 | 0x66D0FB02 |
0x5E9F46BF | 0x5A5E5B08 | 0x571D7DD1 | 0x53DC6066 |
0x4D9B3063 | 0x495A2DD4 | 0x44190B0D | 0x40D816BA |
0xACA5C697 | 0xA864DB20 | 0xA527FDF9 | 0xA1E6E04E |
0xBFA1B04B | 0xBB60ADFC | 0xB6238B25 | 0xB2E29692 |
0x8AAD2B2F | 0x8E6C3698 | 0x832F1041 | 0x87EE0DF6 |
0x99A95DF3 | 0x9D684044 | 0x902B669D | 0x94EA7B2A |
0xE0B41DE7 | 0xE4750050 | 0xE9362689 | 0xEDF73B3E |
0xF3B06B3B | 0xF771768C | 0xFA325055 | 0xFEF34DE2 |
0xC6BCF05F | 0xC27DEDE8 | 0xCF3ECB31 | 0xCBFFD686 |
0xD5B88683 | 0xD1799B34 | 0xDC3ABDED | 0xD8FBA05A |
0x690CE0EE | 0x6DCDFD59 | 0x608EDB80 | 0x644FC637 |
0x7A089632 | 0x7EC98B85 | 0x738AAD5C | 0x774BB0EB |
0x4F040D56 | 0x4BC510E1 | 0x46863638 | 0x42472B8F |
0x5C007B8A | 0x58C1663D | 0x558240E4 | 0x51435D53 |
0x251D3B9E | 0x21DC2629 | 0x2C9F00F0 | 0x285E1D47 |
0x36194D42 | 0x32D850F5 | 0x3F9B762C | 0x3B5A6B9B |
0x0315D626 | 0x07D4CB91 | 0x0A97ED48 | 0x0E56F0FF |
0x1011A0FA | 0x14D0BD4D | 0x19939B94 | 0x1D528623 |
0xF12F560E | 0xF5EE4BB9 | 0xF8AD6D60 | 0xFC6C70D7 |
0xE22B20D2 | 0xE6EA3D65 | 0xEBA91BBC | 0xEF68060B |
0xD727BBB6 | 0xD3E6A601 | 0xDEA580D8 | 0xDA649D6F |
0xC423CD6A | 0xC0E2D0DD | 0xCDA1F604 | 0xC960EBB3 |
0xBD3E8D7E | 0xB9FF90C9 | 0xB4BCB610 | 0xB07DABA7 |
0xAE3AFBA2 | 0xAAFBE615 | 0xA7B8C0CC | 0xA379DD7B |
0x9B3660C6 | 0x9FF77D71 | 0x92B45BA8 | 0x9675461F |
0x8832161A | 0x8CF30BAD | 0x81B02D74 | 0x857130C3 |
0x5D8A9099 | 0x594B8D2E | 0x5408ABF7 | 0x50C9B640 |
0x4E8EE645 | 0x4A4FFBF2 | 0x470CDD2B | 0x43CDC09C |
0x7B827D21 | 0x7F436096 | 0x7200464F | 0x76C15BF8 |
0x68860BFD | 0x6C47164A | 0x61043093 | 0x65C52D24 |
0x119B4BE9 | 0x155A565E | 0x18197087 | 0x1CD86D30 |
0x029F3D35 | 0x065E2082 | 0x0B1D065B | 0x0FDC1BEC |
0x3793A651 | 0x3352BBE6 | 0x3E119D3F | 0x3AD08088 |
0x2497D08D | 0x2056CD3A | 0x2D15EBE3 | 0x29D4F654 |
0xC5A92679 | 0xC1683BCE | 0xCC2B1D17 | 0xC8EA00A0 |
0xD6AD50A5 | 0xD26C4D12 | 0xDF2F6BCB | 0xDBEE767C |
0xE3A1CBC1 | 0xE760D676 | 0xEA23F0AF | 0xEEE2ED18 |
0xF0A5BD1D | 0xF464A0AA | 0xF9278673 | 0xFDE69BC4 |
0x89B8FD09 | 0x8D79E0BE | 0x803AC667 | 0x84FBDBD0 |
0x9ABC8BD5 | 0x9E7D9662 | 0x933EB0BB | 0x97FFAD0C |
0xAFB010B1 | 0xAB710D06 | 0xA6322BDF | 0xA2F33668 |
0xBCB4666D | 0xB8757BDA | 0xB5365D03 | 0xB1F740B4 |
};
Tak, to wszystko ;-)
Pozdrawiam,
CoDe RiPPeR code_ripper@ukr.net
Brak komentarzy:
Prześlij komentarz