NFS Undercover Save Editor v1.2
-------------------------------

1. Disclaimer

Please notice, that this tool is provided AS IS, you are using it at your
own risk. The author of this tool is not responsible for any bugs during
the gameplay process, that may be caused directly or indirectly by using
this program and for damaged save files, which you forgot to backup.
Please, always make backups of your save game files before using this program.


2. Features

This program allows you to modify some fields of the database (DB), which
is stored in your save game file. The current version can change:
 
- money amount
- unlock access to all shops, thus making all cars, parts,
  customizations etc. available for buying
- unlock access to all career races and jobs
- mark all types of races completed
- driver skills

There are also some optional features, for advanced users, such as:

- DB export and import (read in the following sections)
- checksum fixing

However there can be some side effects, which are covered in the next section.
Please, read it carefully to understand the logic of the program.


3. General information and usage

NFS Undercover is somewhat similar to NFS Carbon in sense of save data
management, as both store most of the gameplay related information in a
special database. In Carbon it was a simple text file, in Undercover - it is
a fully functional relational DB - SQLite (http://www.sqlite.org/), which
means, that modification of saved options and parameters is now as easy, as
executing an SQL query. You can read a bit more technical details about this
in a corresponding section.

Once the save file is opened, it is read into the memory completely and no
modifications to the original file are made until the "Save Changes" button
is pressed. The program can refuse to open the save file if it is damaged
(it doesn't mean that the checksums are wrong, but that the header or the file
itself is broken) or if there are no sufficient rights to open that file.
The DB is read upon file open - it is exported to the special file with unique
name in the temp directory, read and then deleted. When the changes are being
applied to the actual save file, the DB is exported again from the save file
currently loaded into memory, modified, imported back and only after all these
steps, the file on disk is overwritten with the new data. So, another reason
of failures during open/save process besides the file access problems (no free
space, security, etc.) are DB related problems (opening and modifying).

Actions related to checkboxes can't be undone (in this program) once they were
applied. When the file is loaded into the program, the DB data is checked and
these checkboxes get ticked again, if the corresponding options were applied
before. A special attention is needed for the last option because it will
reset the status of the event to "completed", regardless of it's previous
status.

"Fix Checksum" button is enabled only if the loaded save file has incorrect
checksums in it's header. When this button is pressed, the currently loaded
save file is written to disk with fixed checksums. Please, note the difference
with "Save Changes" button, which additionally applies currently selected
changes to the DB. Each one of these mentioned above buttons is disabled to
indicate the successful completion of the operation, no message is displayed.

"Import DB" button overwrites the DB of the currently loaded into memory save
file, then automatically overwrites it on the disk and reloads the data in
order to display an actual data from the new DB. "Export DB" button simply
writes the DB of the loaded save file to the specified location.

To edit driver skills check the last option. The dialog will open where you
can change the values. If the value was entered incorrectly, it will be just
skipped, thus will not change, no error will pop up. To open the dialog again
uncheck and than check again this option. Please, make sure that you didn't
clear check mark after you have made the changes, because the changes won't
be saved when you click on "Save Changes" in this case.


4. Technical information

I won't repeat myself about the layout of header that was described in my
previous NFS save editors, as it didn't change. Instead I just talk about
most important things.

First, this save editor assumes that the block containing the DB is not
moveable and starts at file offset 0x238. The DWORD at offset 0x21C holds the
size of DB block plus 0x14 (that's probably the header size). It turned out
that the DB can have a variable size, thus can expand. A wrong assumption was
made about the DB size constancy in version 1.0 of this editor, that could lead
to save file damage. The DB block is encrypted, the decryption key is located
right before the DB data, at file offset 0x228 and is 16 byte long, and is also
encrypted with constant master key, which is located in game exe. The
encryption is simple XOR but it is applied in block chaining mode and uses
MD5 hash function for key generation. I think code is much better than words,
so anybody interested can read the sources of CSaveFile class that I wrote for
this save editor. It can be downloaded from here:
http://www.nfstools.webhosting-for-free.com/CSaveFile.zip

For my experiments and tests with DB I used SQLite Expert Personal, a freeware
program available at: http://www.sqliteexpert.com/download.html
As you can see on the screenshot (DBEdit.png), the money value is in UserData
table, key 1076877135. The options with checkboxes in save editor operate on
CareerUnlocks and CareerEventTracking tables. The information about these
tables and their fields which I was able to figure out is listed at the end of
this section.

A couple of words about serials. Initially I thought about adding an option
to edit the serial into the save editor, but it turned out that the game allows
loading save files with the serial, that is different from the one, that is
stored in the registry, or even without it at all. Moreover, it will replace
the serial in save file with the one stored in the registry every time it
overwrites that save file (if there is no serial in the registry, the serial
buffer in save file is also filled with zeroes). So, this feature would be
useless in the save editor program.

Player name is no longer stored inside the save file, so it's easy to change it
by simply renaming the corresponding directory and save file.

Ok, now about the DB tables. CareerUnlocks table is the most interesting among
the others. It has the following fields:
Key   - an unique id of an object (such as racing event or wheelman level)
Type  - object type (where a value of 3 indicates shops, 2 - jobs, 1 - wheelman
        level, 0 - ordinary races such as checkpoint, sprint, etc. but also
        some jobs)
State - 0 means not available (locked), 1 - available, 2 - available new (will
        be blinking on the GPS map)
Driver skills are stored in CareerData table as a floating point CDValue (where
a value of 0.01 represents 1%) under the following CDKey:

CDKey       Skill
----------  ----------------
1048148874  Engine
3316577405  Transmission
3915205446  Nitrous
4194208498  Forced Induction
3186419145  Suspension
2493928453  Brakes
2260958773  Tires
2165616624  Earnings Bonus
3288497859  Parts Discount
2491680514  Zone Bonus

Unlocking the wheelman level is another thing, that I decided not to implement
in save editor, because it looks like the game calculates it at run-time using
some additional data, so when I've put a few 1's to the state fields to make
the level higher, it worked good only for newly created profile but 50/50 in my
real gameplay profile. Decreasing the level in real profile at level 13 brought
weird results, with level numbers of 78, 20, 53 etc. Probably the wheelman
level is somehow related to the data from CareerLogic table, but I'm not sure
about it. So I didn't put such unstable feature to the save editor.
CareerEventTracking table holds your career progress, the Rank field is the
status of the racing event (1 = winner), Flags is 4 for "completed" and 8 for
"dominated". What save editor actually does for the options with checkboxes -
it executes the following SQL queries:
1st cb: UPDATE CareerUnlocks SET State = 1 WHERE Type = 3
2nd cb: UPDATE CareerUnlocks SET State = 1 WHERE Type = 0 OR Type = 2
        UPDATE CareerEventTracking SET Rank = 1, Flags = 4 WHERE Key = 2229739021
3d  cb: UPDATE CareerEventTracking SET Rank = 1, Flags = 4
4th cb: UPDATE CareerData SET CDValue = nnn.mmm WHERE CDKey = kkk
As you can see the "unlock all career events" option, the second checkbox,
executes an additional SQL query that marks one event as completed. This is
the Showdown - final career event. Not doing so will cause the game to show
only this single event as open and ready to race and others will be
unavailable, no matter that they were unlocked.
It is also possible to modify the stats, just to make some fun, because
there is no other use of it (except the money amount):

In-game Name                    Key	        Table

Career
------
Current Cash                    1076877135  UserData (actual in-game money amount)
Total Cost To State             2955377331  CareerData
Total Zone Points               1466039711  CareerData
Pink Slip Cars                  506612467   UserData

Game
----
Total Drive Distance            3290023354  UserData (in metres)
Total Cash Earned               3128534255  UserData
Most Cost To State (1 event)    2294545711  CareerData
Highest Top Speed               1712513165  UserData (in metres per second)
Most Zone Points (1 event)      3105838030  CareerData
Total Cars Bought               358443849   UserData
Total Cars Impounded            115555055   UserData

Pursuit
-------
Longest Pursuit                 2036746550  UserData (in seconds)
Shortest Pursuit                347537910   UserData (in seconds)
Pursuits Evaded                 118225201   UserData
Times Busted                    1190648803  UserData
Infractions                     1949258289  UserData
Cops Disabled                   1494668669  UserData
Cops Disabled (1 pursuit)       2032965883  UserData
Roadblocks Dodged               3378051675  UserData
Roadblocks Dodged (1 pursuit)   4055062937  UserData
Spike Strips Dodged             1385473495  UserData
Spike Strips Dodged (1 pursuit) 2724492437  UserData

Also I made a small loader program, that can run the no-Securom version of
nfs.exe by RELOADED team, that can be downloaded from
http://gf.wiretarget.com/nfs_undercover.htm
which will patch game code at run-time so that it will dump all SQL queries
being executed to the file C:\nfs.log  It can be useful for analyzing what
actually the game does with DB during the gameplay process. The loader program
can be downloaded here: http://www.nfstools.webhosting-for-free.com/NFSLoader.zip


5. Secret codes

The secret code verification function is located at address 0x0058A6B0 in
nfs.exe. This routine takes the ascii zero-terminated string - your input,
calculates it's 32-bit hash (see SecretCodeHash()) and then searches for
that number among the 34 hard-coded secret code hashes.

int SecretCodeHash(const char *pszCode)
{
	int nHash = -1;

	for ( int i = 0; pszCode[i] != 0; ++i )
		nHash = 33*nHash+pszCode[i];

	return nHash;
}

The good news is that this hash function is very simple and produces a lot of
collisions, so it was possible to successfully bruteforce all hard-coded secret
code hashes with short length strings containing only lower case latin
characters. I've picked one of the generated secret codes for every hash,
checked the result that it produces and made the following table:

##  Hash      Code      Result
--  --------  --------  ---------
 1  0C06C9F1  zgdbyela  10000$
 2  13140E79  jxkmaze   15000$
 3  21748A76  aguetwia  Lotus Elise from NeedForSpeed.com
 4  9D3393D6  zouzzzgd  10000$
 5  6C185ACF  zawysied  Pontiac Solstice GXP from NeedForSpeed.com
 6  8324DB24  vetvlas   15000$ from T-Mobile
 7  875848AE  qfmytyda  You are in Progressive cop team (get Police vehicle)
 8  2A59FD65  deftyade  Shelby Terlingua Kit
 9  D631A75D  ftpnkby   Audi R8 from Die-Cast
10  1772D820  goosqdt   BMW M3 E92 from Die-Cast
11  B39278DA  nircagfa  Chevrolet Camaro Concept from Die-Cast
12  A03C4CFA  nsializa  Dodge Viper SRT10 from Die-Cast
13  F455C6B6  jkeoqon   Dodge Charger R/T from Die-Cast
14  A3D645D0  cmexlhld  Ford Mustang GT from Die-Cast
15  CB649D41  gamruvld  Lamborghini Murcielago LP640 from Die-Cast
16  27476579  naboatad  Lexus IS F from Die-Cast
17  E2045019  awnwjnad  Mazda Mazda3 MPS from Die-Cast
18  2C0958FE  fexifsya  Mitsubishi Lancer EVOLUTION from Die-Cast
19  4BC360A6  dotfjvvd  Nissan 240SX (S13) from Die-Cast
20  EF522507  hymuueib  Pontiac GTO from Die-Cast
21  47C7D523  fsmegdie  Porsche 911 Turbo from Die-Cast
22  7A5DEB8B  psixhfvd  Volkswagen R32 from Die-Cast
23  25CDB22F  tvrbylid  Circuit City vinyl
24  001E6F70  tylvibsd  <code disabled>
25  D5770DC7  ftfdaps   Nissan GR-R (R35) from Die-Cast (police)
26  9C9E107D  kodkupke  Porsche 911 GT2 from Die-Cast
27  925E4841  rmoodthe  Chevrolet Camaro Concept from Die-Cast (alt. paint)
28  9C0F3754  osowsubc  Dodge Charger R/T from Die-Cast (alt. paint)
29  8591F3B3  orexnag   Lexus IS F from Die-Cast (alt. paint)
30  F825F301  ypskdmee  Mitsubishi Lancer EVOLUTION from Die-Cast (alt. paint)
31  C724A0A4  slicgs    Porsche 911 GT2 from Die-Cast (alt. paint)
32  2ECEA225  xmgfoda   <code disabled>
33  000ACF53  genogtp   <code disabled>
34  0F803640  odkosrna  <code disabled>

Some positions in this table say <code disabled> - it means that the original
secret code check function in nfs.exe explicitly skips these indices, but they
are included here for the sake of completeness. Every time you enter one of
these secret codes, the game writes 1 into the Status field in the row with
corresponding CodeKey in CheatCodes table into DB. Once the 1 value has been
put there, secret code can't be reused again for that profile.


6. Credits

This program makes use of the following libraries:

	MD5 hash implementation from OpenSSL library
	http://www.openssl.org/

	SQLite database engine
	http://www.sqlite.org/

Thanks to RELOADED team for Securom-free nfs.exe. This tool would be never
created without the ability to analyse the unprotected game code.


7. Contact

The latest version of the program can be downloaded here:

	http://www.nfstools.webhosting-for-free.com/

If this free hosting is down, try to use

	http://kickme.to/coderipper

It is permanent redirect to the most recent version of all these tools in
a single archive uploaded to Rapidshare.


e-mail: code_ripper@ukr.net

(C) 2008 CoDe RiPPeR
