+---------------------------------------------------------+
| Reverse Engineering of Casltevania II's Password System |
| by Kingshriek (Dean Fehlau) |
| email: kingshriek at yahoo dot com |
+---------------------------------------------------------+
1. Introduction
This document contains a reverse engineering of the password system in the US
version of Castlevania II: Simon's Quest (CV2). I'm not sure if the system is
the same in the European version. The Japanese release,
Akumajou Dracula: Noroi no Fuuin was a Famicom Disk System game and saves
directly to disk so no password system was needed.
It is assumed that the reader is familiar with binary and hexidecimal notation
and is comfortable converting both to and from decimal notation. It is also
assumed that the reader is familiar with basic logic operations (and, or, xor,
left shift, right shift). It will also be helpful if the reader has some
familiarity with 6502 assembly and how the CPU RAM is organized.
The CV2 password saves the following information :
1. Simon's experience level
2. Number of game days that have elapsed
3. Quantity of garlic and laurels
4. Possession of quest items - Dracula's body parts and crystals
5. Possession of other items - garlic, laurels, magic cross, silk bag
6. Possession of use items - stake, flame, diamond, holy water, 3 daggers
7. The whip that is in possession
The terms "quest items", "other items", and "use items" will be used throughout
the document. Please see the next section for an exact listing of what each
category entails. The information above has been split up in this manner
because each one of the seven categories corresponds to a byte that makes up
the base password.
2. Notation
Before the password system can be discussed, the reader needs to be familiar
with the notation used in the document.
$zz or $zzzz - memory address ($xx is a zero-page address)
0xzz - value in hexidecimal
Operators (in order of precedence):
+ , - Addition, Subtraction
<< , >> Left Shift, Right Shift <-------- done first
& Logical AND
^ Logical XOR
| Logical OR <-------- done last
3. How the password in generated
Before we get into the password generation algorithm, we need to know where and
how the game stores the seven categories of information listed above in memory.
Generally, for items that are stored by a single bit, a value of 1 means the
item is in possession and a value of 0 means the item is not.
The adressess for this information are as follows:
$004A - use items
bits (from highest order to lowest)
7 - not used, keep set to 0
6 - Oak Stake
5 - Holy Flame
4 - Diamond
3 - Holy Water
2 - Golden Dagger
1 - Silver Dagger
0 - Dagger
$004C - quantity of laurels (max. 8)
$004D - quantity of garlic (max. 8)
$0083 - time elapsed in game days (max. 9)
$008B - Simon's level (max. 6)
$0091 - quest items
bits (from highest order to lowest)
7 - not used, keep set to 0
6 - Blue Crystal ---+
+--- set both to get the Red Crystal
5 - White Crystal ---+
4 - Dracula's Ring
3 - Dracula's Nail
2 - Dracula's Eye
1 - Dracula's Heart
0 - Dracula's Rib
$0092 - other items
bits (from highest order to lowest)
7-4 - not used, keep set to 0
3 - Garlic
2 - Laurels
1 - Magic Cross
0 - Silk Bag
$0434 - whip (takes on values between 0 and 4)
0 - Leather Whip
1 - Thorn. Whip
2 - Chain Whip
3 - Morning Star
4 - Flame Whip
Now we can begin with the generation algorithm. The password generation code
begins at $AF21 in RAM. First, the game stores the contents of all the
above addresses into the address range $0520-$0526. It does this in the
following manner:
$0520 = $8B ; Simon's experience level
$0521 = $83 ; Time elapsed in game days
$0522 = $4C | $4D << 4 ; # of garlic and laurels (see note below)
$0523 = $91 ; quest items
$0524 = $92 ; other items
$0525 = $4A ; use items
$0526 = $0434 ; whip
note: # of garlic is stored in the upper 4 bytes of $522 whereas # of
laurels is stored in the lower 4 bytes
Next, checksums are computed and stored in $0527-$0528.
For randomization, the password generated uses a value from a counter that
updates on every frame (the counter increments by 0x01 and goes through all
values 0x00-0xFF). The address of this counter is $1D. A "random" value
used in password generation is stored in $0529 after some intermediate
calculations, which are stored at $04F7 and $04F6.
The randomizer uses a lookup table for the upper 4 bytes of the $0529 byte.
The lower 4 bytes of $0529 is the same as the lower 4 bytes of the counter
value. Only a single counter value is used for the calculation of $04F7 and
$04F6 values.
The lookup table begins at $AF19 and is 8 bytes long.
$AF19 - $AF20
$AF10: xx xx xx xx xx xx xx xx xx 00 01 02 03 04 01 02
$AF20: 03 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
Next, the data in $0530-$53F is modified based on the random values
generated previously. Here, another look-up table is used -- this
one containing 2-byte memory address stored with the lower-order
byte first. Start at $B228 and add to the address itself the value
at $04F6 shifted left by 1. The address found in the look-up table
is stored at $10 and $11 with the same byte order. The table begins
at $B228 and is 32 bytes long.
$B228 - $B247
$B220: xx xx xx xx xx xx xx xx 48 B2 56 B2 64 B2 72 B2
$B230: 80 B2 8E B2 9C B2 AA B2 B8 B2 C6 B2 D4 B2 E2 B2
$B240: F0 B2 FE B2 0C B3 1A B3 xx xx xx xx xx xx xx xx
At each address listed in the table above is a series of 14 bytes
used to XOR with the data at values $0530-$053D.
Finally, to get the actual bytes that correspond to the actual
password, add 1 to each of the bytes in the range $0530-$053F.
Store these values at $0540-$054F.
Now, all we need to know is the correspondence between the bytes
in $0540-$054F and the characters used in the password. Here is
a table that shows the correspondence:
A - 0x01 K - 0x0B U - 0x15 4 - 0x1F
B - 0x02 L - 0x0C V - 0x16 5 - 0x20
C - 0x03 M - 0x0D W - 0x17 6 - 0x21
D - 0x04 N - 0x0E X - 0x18 7 - 0x22
E - 0x05 O - 0x0F Y - 0x19 8 - 0x23
F - 0x06 P - 0x10 Z - 0x1A 9 - 0x24
G - 0x07 Q - 0x11 0 - 0x1B
H - 0x08 R - 0x12 1 - 0x1C
I - 0x09 S - 0x13 2 - 0x1D
J - 0x0A T - 0x14 3 - 0x1E
The final password is the 16 characters given by the
correspondence in the table above in the same order as the bytes
in $0540 - $054F.
4. How the password is verified
Now that we know how to generate a password, lets go in reverse and
see how the game verifies user-inputted passwords. The password
verification code begins at $AD18 in RAM.
Using the character-hex value traslation table above, the inputted
password is translated into its hexidecimal equivalent and stored in
$0540-$054F. Next, subtract 1 from each value and store the result in
$0530-$053F respectively.
For the password to be valid, $527 and $528 should be equal to the
checksums as computed in the password generation code. The game
stores these values temporarily at $0E and $0F.
$0E = $0527
$0F = $0528
The game now computes the checksums as in the generation code.
If $0527 = $0E and $0528 = $0F, then all is good. If not, the
password is invalid.
A few more validations are necessary before the password is finally
okayed. What are they? If you guessed the bounds on the base values
at $0520-$0526, you are absolutely correct!
The bounds are as follows:
$0520 must be < 0x07
$0523 must be < 0x80
$0524 must be < 0x10
$0525 must be < 0x80
$0526 must be < 0x05
$0521 & 0x0F must be < 0x0A
($0521 & 0xF0) >> 4 must be < 0x0A
$0522 & 0x0F must be = 0x09
($0522 & 0xF0) >> 4 must be < 0x09
If all these checks are successful, the password is validated and the
game loads the bytes $0520-$526 into the respective places in memory.
5. Closing Notes
What is presented here is hopefully and complete and fully correct explanation
of how Castlevania II's password system is generated and verified; however, it
is most likely that I missed something or didn't explain something clearly. If
I'm missing something, or if something in this guide is incorrect or badly
explained, feel free to email me at kingshriek at yahoo dot com. Corrections,
additions, and constructive criticism will be greatly appreciated. Also, any
worthy additions added to a future version of this document will be duly
credited to the information provider.