FCEUd, Tutorial #2 (Password Generators)

Parasyte
FCEUd, Tutorial #2 (Password Generators)
[The Addams Family: Pugsley's Scavenger Hunt]

by Parasyte of DES (http://www.dragoneyestudios.net/)
v1.0 (4-30-03)



-===========---
1) Warm-Up
-===============---

   Before beginning, it's best to know what is needed in order to use this
document to it's full potential. First, you must know the very basics of
assembly programming. (The basics are simple, understand each opcode addressing
mode, and each opcode type) You must also be well versed in binary, including
binary math. Overall, not much is needed to start using FCEUd.
   For 6502 assembly documents and tutorials, check out Zophar's Domain and
ROM Hacking.com at the URLs below. As an alternative, search for
"6502 Assembly" in everyone's favorite search engine - Google.

Things you'll need:
 FCEUd (get from http://www.dragoneyestudios.net/)
 The Addams Family: Pugsley's Scavenger Hunt ROM
 6502 ASM docs, available from:
   http://www.zophar.net/
   http://www.obelisk.demon.co.uk/6502/reference.html
   http://www.romhacking.com/



-===========---
2) Finding The Password
-==============---

   The first thing you need to do when hacking password routines is finding the
entered password in RAM! This only requires a simple cheat search. Just open
the ROM, and go into the password-entry screen. From here, enter a single "1"
character (you must push the A button to actually enter the character). Then
open the FCEUd Cheats window from NES -> Cheats... With the cheats window open,
click Add Cheat to open the Cheat Console. In here, you're presented with a
cheat search, this is what we will use to find the entered password in RAM.
   When starting a cheat search, the first thing you must do is push the Reset
Search button. After that, close all the cheat windows to get back to the game.
Next, erase the entered "1" character with the B button, and enter a "2." Get
back to the cheat search and set the Filter as "O!=C," which means "Original
Value is not equal to Current Value." Push Do Search, then push Set Original To
Current, and get back to the game. Now enter about three "1" characters, so the
entered password is now "2111." Go back to the cheat search, And select the
"|O-C|==V2" filter. This means "The Difference Between Original and Current is
equal to V2." V2 is the text box to the left of the filters, you can't miss it!
Make sure V2 contains 0, because that first password character has not changed
since the last search. Push Do Search! Once again, go back to the game and
enter "Z" as the first password character.
   Now, back in the cheat search, the value has changed, so filter the search
with "O!=C." Push Do Search! Repeat the search process until you get one
possible address. I'll just cheat a bit and tell you the address is $043D.



-===========---
3) Finding The Password Verifier
-==============---

   Now we know where the entered password is held in RAM, we just need to use
this knowledge to find the password verifier routine. The routine which will
ensure the password is not just randomly entered junk!
   Open FCEUd's Debug Console with NES -> Debug, or by pushing F1. Then get
back to the game, and enter a random password, such as "2211B"

   But, before entering the last character in the password, set a breakpoint on
read (BPR) on address $043D. And we're shown that the debugger snaps
immediately, so we have to work around this. Disable the first BPR before
continuing.
   With the debugger snapped, set a breakpoint on write (BPW) on $0441, which
just so happens to be the address which holds the last password character.
Finally, enter your last password character and the debugger will snap thanks
to the second breakpoint. You can delete that one now, as it serves no more
purpose. Enable the first breakpoint you set, and hit the Run button! You will
be placed right in the password decoding routine, the one you will need to rip
in order to write your generator!

   In the disassembler window, scroll up until you come across an RTS opcode.
Luckily it's on the line directly above the PC address. This means the PC is on
the start of the routine. So copy all the ASM starting from the beginning of
the routine, and ending at the first RTS you come scross. Just paste it all
into notepad for reverse engineering!



-===========---
4) Translating 6502 to C or another Programming Language
-==============---

   This is the fun part, making the actual password generator! The first thing
I do at this point is take a quick look at the ripped assembly. I'm seeing the
familiar addresses which contain the entered password, this is a good thing.
Let's take a look at the routine in small pieces, now.

$BAC8:AD 3D 04  LDA $043D = #$01
$BACB:18        CLC
$BACC:6D 3E 04  ADC $043E = #$01
$BACF:18        CLC
$BAD0:6D 3F 04  ADC $043F = #$00
$BAD3:18        CLC
$BAD4:6D 40 04  ADC $0440 = #$00
$BAD7:18        CLC
$BAD8:69 25     ADC #$25
$BADA:29 1F     AND #$1F
$BADC:CD 41 04  CMP $0441 = #$09
$BADF:D0 3A     BNE $BB1B

   This is extremely simple code, it loads the first password character from
$043D, then adds that value to the next three password characters. This is the
most basic of all checksums, but this game does something a bit different.
After generating the checksum, it adds $25 to the value, just to offset the
checksum a bit. Finally, it masks the checksum with $1F. (The highest possible
password character value) Then it simply compares the final checksum to the
last password character. If they do not match, it branches to $BB1B.
   Checking your ripped ASM, make sure you've got $BB1B, and you wouldn't have
if you did stop copying at the first encounted RTS opcode. $BB1B contains a
very small amount of code, which simply returns with a value of -1, for error.

$BB1B:A9 FF     LDA #$FF
$BB1D:60        RTS

   Nothing to it!
   So, with all of this in mind, let's write some code to do exactly what is
done above. I'll be using C, as it's my favorite programming language.

u8 password[5]; //unsigned character array to hold entered password
chksum = ((password[0] + password[1] + password[2] + password[3] + 0x25) & 0x1F);
if (password[4] != chksum) return -1;

   Quite simple, isn't it?
   Next we'll check out the next piece of ASM, which starts to get a bit
tricky.

$BAE1:AD 3D 04  LDA $043D = #$01
$BAE4:49 0A     EOR #$0A
$BAE6:0A        ASL
$BAE7:0A        ASL
$BAE8:0A        ASL
$BAE9:0A        ASL
$BAEA:8D 3B 04  STA $043B = #$00
$BAED:AD 3E 04  LDA $043E = #$01
$BAF0:49 0F     EOR #$0F
$BAF2:4A        LSR
$BAF3:0D 3B 04  ORA $043B = #$00
$BAF6:8D 3B 04  STA $043B = #$00
$BAF9:29 02     AND #$02
$BAFB:D0 1E     BNE $BB1B

   The first password character is loaded, then it's XOR'd with $0A, and
shifted left by four. Next it's temporarily stored away, and the second
password character is loaded, then XOR'd with $0F. Finally, that value is
shifted right by one, then it's OR'd with the previously decoded value.
There's also a little check which ensures bit 1 is unset. If the bit is set,
the routine returns with an error.

u8 decode[3]; //buffer for decoded data
decode[2] = (((password[0] ^ 0x0A) << 4) | ((password[1] ^ 0x0F) >> 1));
if (decode[2] & 0x02) return 1;

   You'll see why I used an array in a moment. I usually run through these
routines a few times before translating any of it.
   The next pieces of the routine are a lot simpler, and will require a lot
less work.

$BAFD:AD 3F 04  LDA $043F = #$00
$BB00:49 05     EOR #$05
$BB02:8D 37 04  STA $0437 = #$00

   Load password character 3, XOR with $05, store it into the buffer!

decode[1] = (password[2] ^ 0x05);

   See?! So Simple!!

$BB05:AD 40 04  LDA $0440 = #$00
$BB08:49 02     EOR #$02
$BB0A:4A        LSR
$BB0B:8D 38 04  STA $0438 = #$05

   Load password character 4, XOR with $02, shift right one, store into buffer!

decode[0] = ((password[3] ^ 0x02) >> 1);

   The rest of the routine is mostly useless, so you can easily ignore it. All
it does is fill some memory with certain values.



-===========---
5) Putting It All Together
-==============---

   The last thing to do is put it all together into a program, and you have a
fully funtional password verifier. Now that's great and all, but you want the
program to generate passwords, not just verify them! How do we do this with the
code we wrote? In 9 of 10 cases, the answer is "REVERSE IT!" That is, take your
code, and rewrite it to do the exact opposite. So, for reference, here is the
completed verifier function.

u8 VerifyPass(u8 *password, u8 *buffer) {
   int chksum = ((password[0]+password[1]+password[2]+password[3]+0x25)&0x1F);
   if (password[4] != chksum) return -1:
   buffer[2] = (((password[0]^0x0A)<<4)|((password[1]^0x0F)>>1));
   if (buffer[2]&0x02) return -1;
   buffer[1] = (password[2]^0x05);
   buffer[0] = ((password[3]^0x02)>>1);
   return 0;
}

   Now reverse the operations for a generator function.

u8 GeneratePass(u8 *password, u8 *buffer) {
   if (buffer[2]&0x02) return -1;
   password[0] = ((buffer[2]>>4)^0x0A);
   password[1] = (((buffer[2]<<1)^0x0F)&0x1F);
   password[2] = (buffer[1]^0x05);
   password[3] = ((buffer[0]<<1)^0x02);
   password[4] = ((password[0]+password[1]+password[2]+password[3]+0x25)&0x1F);
   return 0;
}

   I hope you understand how I reversed the operations. Basically, do
everything in reverse, with opposites. For example, add instead of subtract.
Also notice the masking I had to do for password[1]. This code just prevents
the value from going above $1F, which is the highest possible value for a
password character.
   Now you just put it together into a nice program, and you're done!



-===========---
6) Understanding The Decoded Data
-==============---

   The secret to making your password generator useful is by understanding the
decoded password data. All I did was compare the data in the buffer to the
items and such I was given. To keep this section short, buffer[0] is the upper
digit of your lives counter, buffer[1] is the lower digit for lives, and
finally, buffer[2] contains your number of hearts, and each family member
rescued.



-===========---
7) Legal Information
-===============---

   This document is Copyright 2003 Parasyte\Dragon Eye Studios. This doument
may not be modified in any way, in part or whole without permission of the
author. Parasyte and Dragon Eye Studios are in no way affiliated with Nintendo.
Addams Family et.al and Nintendo are registered trademarks of thier respected
owners.
   Parasyte and Dragon Eye Studios are not responsible for how you use the
information contained in this document. We are not responsible for the fact
that it may eat your homework and your dog. Please remember to wipe.



EOF