Register by 10/16 for $250 off the on-site price.
Build the future of communications.
Start building for free

Intro to ROM/RAM hacking: Building an SMS powered Game Genie with Lua and Python

mariobanner

Old video games are notorious for being insanely difficult. As a child I was astonished to discover a magical item appropriately named Game Genie that allowed me to beat certain games. “Cheating” to make games easier was great, but some Game Genie codes made things more fun rather than just providing infinite lives. Some of these codes manipulated the games in absurdly interesting ways such as making all enemies throw hammers in Super Mario Bros.

hammer_cheat.gif
As a hacker, I love doing crazy things with code not only because it’s fun but because it’s a great way to learn new things. I was ecstatic to discover that many video game emulators offer an API for the Lua programming language granting access to all sorts of functionality like saving states and editing the game’s memory. Imagine opening these classic games up to the power of the Internet. Today we are going to do just that by using the memory manipulation API to build a Game Genie that operates via text messaging with Twilio.

Power Ups that we will need

  • A version of the FCEUX Nintendo emulator that has Lua API access. We will be using the 2.2.2 Windows binary. You can also use other emulators as long as they have the same Lua API. The same code should work for Visual Boy Advance(gameboy games), SNES9X(SNES games) and others.
  • Wine to run Windows applications if you are a Linux or Mac user like me. Unfortunately right now, the Lua API and debugging tools are more commonly found on Windows versions of these emulators.
  • A free Twilio account and one Twilio phone number with SMS capabilities.
  • Python with the Flask and Twilio libraries installed. These can be installed with pip.
  • A ROM file for The Legend of Zelda that we will use for testing purposes. If you own the game there are devices you can buy online that allow you to use the ROM file from your cartridge.
  • An insatiable hunger for manipulating old school video games and bringing them to life with the power of the internet.

And so, our journey begins

Experienced adventurers know that the first step on a quest is stocking up for dangers that lie ahead. This is true whether you are item shopping in Corneria before heading out to battle Garland or if you are a hacker trying to setup your environment for a new project.

The first item in our inventory will be our emulator of choice, FCEUX. Download FCEUX and extract the files to a directory of your choosing where our project will live. If you are a Windows user then you’re good to go. Linux or Mac uses will need to install Wine. If you are a Mac user with Homebrew installed, then you can also use your terminal to get Wine (you also need to install XQuartz as a dependency as shown below). You may need to run brew update before installation.

brew install caskroom/cask/brew-cask
brew cask install Caskroom/cask/xquartz
brew install wine

Now that we are well-equipped, let’s sling some Lua code to fend off our enemies. Open a new file called “nesms.lua” in your favorite text editor. Let’s write some code to take over the emulator’s execution.

-- Infinite loop to take control over frame advancing.
while true do
  emu.message('Hello World!') -- Print hello world to the screen on every frame
  emu.frameadvance() -- This essentially tells FCEUX to keep running
end

emu.frameadvance() tells the emulator to advance exactly one frame which is the basic unit of time on an NES. The emulator usually does this itself, but allows our script to do whatever we want before each frame is rendered.

Now it’s time to open up FCEUX with Wine. If you installed it with brew or another package manager, you can navigate to the directory where fceux.exe is sitting and run wine fceux.exe otherwise you can double click the file itself. You need to be playing a game for code to run. So open up your Legend of Zelda ROM and run your code by clicking “File -> Lua -> New Lua Script Window” and navigating to the script.

HelloWorld.gif

Victory.gif

Cue the famous victory fanfare as we have won our first battle. These experience points will be useful. Now that we know how to get Lua code to execute let’s cut to the chase and get to the real hacking.

Jump higher, punch harder, live forever

gamegenie.gif
Our Hello World script is nice but it’s hardly as magical as my childhood experiences with the Game Genie. Let’s dig into some of the basic tools we’ll need to emulate Game Genie’s functionality. FCEUX comes with a host of awesome debugging utilities. One of the most important things in this toolbox is a hex editor. With this we can look at the contents of the game’s memory in the form of hexadecimal addresses and values.

The hex editor is the main tool that ROM hackers use to open up a game’s Read Only Memory and edit the hex values to change what is in the game. Cleverly editing memory addresses can result in some crazy gameplay modifications or even completely new games. Let’s open the hex editor and see what we can do with it.

All of the two digit hex numbers you see represent a value in the game’s RAM at a specific location. You can change any value to see what happens in-game. You can also search for specific consecutive values. Check out this example to see the hex editor in action to find the bytes corresponding to the timer in Super Mario Bros and then changing the time to zero to kill Mario.

hexediting.gif

ROM hacking can be a pretty daunting task. We are about to discover that you don’t need to be an expert to do some really cool stuff.

ROM represents the unchanging contents of what you’d find on a game’s cartridge whereas RAM represents the actual memory of the game as the program is running. Changes made to RAM appear immediately allowing you to make real time changes. There are NES RAM maps here and here that will tell you which memory addresses correspond to specific things in-game.

Let’s try to mimic the Game Genie by “enhancing” games with Lua scripts. As an example, let’s mess around with one of my all time favorites, the original Legend of Zelda. Using this RAM map we will edit certain values to make some funky stuff happen.

Open up a new file in your text editor and add some of these one liner example scripts to change RAM values and see what happens. You will need to have your Legend of Zelda ROM running in FCEUX have a new game started for these scripts to work.

-- Change the current music to the dungeon music
-- 0x0600 is the memory address to play music
-- 0x40 is the value representing the dungeon theme.
memory.writebyte(0x0600, 0x40)

-- Give Link the sword without even entering the cave
-- 0x0657 is the memory address for Links current sword
-- 0x01 is the value representing the regular sword
memory.writebyte(0x0657, 0x01)

-- Give Link a bunch of rupees
-- 0x066D is the memory address for your current number of rupees
-- 0xFF is the maximum number of rupees(255)
memory.writebyte(0x066D, 0xFF)

It’s dangerous to go alone…

You’ve seen what we can do with a bit of Lua. But it is getting lonely in here so let’s equip ourselves. Instead of a sword, our weapon will be the power to communicate with other programming languages. I am not a very good Lua developer, but I love me some Python. Wouldn’t it be rad to manipulate the game’s memory with Python instead?

Our Lua scripts run in an environment provided by the emulator but we can open them to the outside world in a couple of different ways. We could use sockets or implement an HTTP server, but let’s just use text files for now.

Hop back to “nesms.lua” and add a function for reading text files:

-- A function to read text files
function read_file (filename)
    input = io.open(filename, 'r') -- Open this file with the read flag.
    io.input(input) -- Set the input that the io library will read from.
    input_content = io.read() -- Read the contents of the file.
    io.close(input) -- Close the file.

    return input_content
end

We’ll use this function in our frame loop to listen for changes in two text files: “address.txt” and “value.txt” On every frame advance we will read a hexadecimal string from each of these files and write the contents of value.txt to the memory location in address.txt. Let’s add this to nesms.lua as well.

-- A function to read text files
function read_file (filename)
    input = io.open(filename, "r") -- Open this file with the read flag.
    if input ~= nil then
      io.input(input) -- Set the input that the io library will read from.
      input_content = io.read() -- Read the contents of the file.
      io.close(input) -- Close the file.
    end

    return input_content
end

prev_address = '' -- Variable to keep track of the address.
prev_value = '' -- Variable to keep track of the value.

-- Infinite loop to take control over frame advancing.
while true do
  address = read_file('address.txt')
  value = read_file('value.txt')

  -- Only write to memory if the value has changed.
  if address ~= prev_address or value ~= prev_value then
    hex_address = tonumber(address, 16)
    hex_value = tonumber(value, 16)

    -- Check to see if the entered strings are valid.
    if hex_address == nil or hex_value == nil then
      emu.message('Invalid address or value. Please use valid hex numbers.')
    else
      memory.writebyte(hex_address, hex_value) -- Base 16 for hex values
      emu.message(address..': '..value) -- Print address and value being changed.
    end
  end

  prev_address = address -- Update the address to keep track of changes.
  prev_value = value -- Update the value to keep track of changes.
  emu.frameadvance() -- This essentially tells FCEUX to keep running.
end

Let’s see if this code works. Run the new version of our script in your emulator and throw some hex numbers in them using the previously linked RAM maps for your game of choice. Let’s try another Zelda example:

  1. Load your Zelda ROM if it was not already open. Get past the file select screen and make sure you have Link on the overworld.
  2. Open “address.txt” and write “0600” (and nothing else) in the text file.
  3. Open “value.txt” and write “40” (and nothing else) in the text file.
  4. Save both files and run “nesms.lua” in FCEUX.
  5. Listen to the music change to the dungeon tune.

“Get equipped” with Twilio and FlaskGetEquippedWithTwilioMegaman2.png

Now we can receive input from other programs including the terminal output from Dr. Wily’s robots. The idea is to leave our nesms.lua script running and manipulate the game’s memory whenever those text files change. Let’s make this way cooler by setting up a Twilio phone number that will receive text messages with memory addresses and values to write to these text files.

First you need to create a Twilio account if you haven’t before and purchase a phone number. We will set up a Flask app to receive requests from Twilio once we configure our number. Here’s how you buy a phone number:

buy-a-twilio-number.gif

In order to receive messages, let’s make a web app on our local machine that will respond to HTTP requests. We will use the Flask web framework for Python because it’s lightweight and easy to get running. First install Flask and Twilio using pip. We’ll do it in a virtualenv to avoid messing with anything else on your machine. If you’re unfamiliar with pip and virtualenv you can check out this awesome guide to setting up your Python environment.

Navigate to your project’s directory, create a virtualenv and activate it.

virtualenv venv
source venv/bin/activate

Then install Flask and Twilio so we can write some code.

pip install flask
pip install twilio==5.7.0

Open a file called “app.py” in the same directory as your Lua script and try this out:

from flask import Flask, request

app = Flask(__name__)


@app.route('/', methods=['GET'])
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

Now that we have a hello world Flask app, lets run it:

python app.py

Visit http://localhost:5000 on a web browser to make sure things are working.

Let’s make a route in our app to respond to the webhook Twilio sends when messages are received. We will expect messages in the form of a four digit hex address and a two digit hex value separated by a space. This will involve using Twilio’s Python library to generate some TwiML to respond to the message.

from flask import Flask, request
from twilio.twiml import Response

app = Flask(__name__)


@app.route('/', methods=['POST'])
def sms_reply():
    # Retrieve the body of the text message.
    message_body = request.form['Body']
    print(message_body)

    # Create a TwiML response object to respond to the text message.
    resp = Response()
    message_response = 'Message received! Manipulating memory now.'
    error_message = ('Please enter a 4 digit hex address and a 2 digit '
                     'hex value separated by a space. '
                     'For example: "066D FF"')

    # Create a list of all words in the message body.
    message_list = message_body.split(' ')

    # Create a regex for matching hex Strings.
    hex_pattern = re.compile('^[0-9a-fA-F] $')

    # Make sure the message is in the right format.
    if not len(message_list) == 2:
        message_response = error_message
    else:
        # The first word should be the hex address.
        address = message_list[0]

        # The second word should be the hex value to write to the address.
        value = message_list[1]

        # Check to see if the address and value are valid hexadecimal numbers.
        if hex_pattern.match(address) and hex_pattern.match(value):
            # Write the address and value to their respective text files.
            with open('address.txt', 'w') as f:
                f.write(address)

            with open('value.txt', 'w') as f:
                f.write(value)
        else:
            message_response = error_message

    resp.message(message_response)
    return str(resp)

if __name__ == '__main__':
    app.run(host='0.0.0.0')

Now we need to expose our local environment to the Internet so Twilio can see our web app. Ngrok is a great tool for this. I would explain how ngrok works, but my buddy Kevin already wrote an awesome (and thematically relevant) post detailing this process. Once you have ngrok set up, you can run it to listen to the port that your Flask application is running on, which in our case is the default 5000.

You should see a screen that looks like this with a generated link that we can visit to access our Flask app:

ngrok.png

We need to add this URL to our Twilio phone number in the account phone numbers dashboard so Twilio knows to send us an HTTP request when a text is received.

twilio_dashboard.png

Your phone number is configured, your Flask server is listening for text messages and your emulator is running with our Lua script listening to these text files. We can finally shoot a message to this Twilio number to make some real time changes to the game you are playing.

To keep with our example from earlier open up your Zelda ROM in the emulator and make sure all of your code is running. Text “0600 10” to your Twilio number and this should change the music to the ending credits theme.

Here is an example of a message being received and making changes to Super Mario Bros to show that this works with any game.

mario_dies.gif

But our princess is in another castle

Here’s a twist: We didn’t just implement a Game Genie. You may have noticed that all of these arbitrary hex values don’t look like those beloved 8 character codes of days long past. All of this was just having fun hacking with low level memory manipulations.

With the actual Game Genie, the gamer enters a 6 or 8 digit code of seemingly arbitrary letters. This goes through a cipher and is translated to a hex address and value. The Game Genie hardware intercepts the memory reads from the game console and responds with the value that the code represents. Here is a pretty good explanation of this process with example bits of C code.

The Game Genie works by intercepting reads to the ROM. It actually isn’t messing with the RAM like we were. But idea is still the same: manipulating memory locations in the game and replacing the contents with different values to get the results we want. The Lua API actually gives us a way to bypass manually doing this. We can interact with Game Genie codes directly using emu.addgamegenie

Sure we can directly add Game Genie cheats to our emulator but aren’t you glad you learned the basics of hex editing and RAM manipulation first? The journey is satisfying in the same way that playing through every level of Mario is despite the princess only being in the last castle. But now let’s get through that final castle by adding the ability to accept Game Genie codes directly via SMS. Hop back into nesms.lua and make these changes:

function read_file (filename)
  input = io.open(filename, "r") -- Open this file with the read flag.
  if input ~= nil then
    io.input(input) -- Set the input that the io library will read from.
    input_content = io.read() -- Read the contents of the file.
    io.close(input) -- Close the file.

    return input_content
  end

  return nil
end

prev_address = '' -- Variable to keep track of the address.
prev_value = '' -- Variable to keep track of the value.
prev_cheat = '' -- Variable to keep track of game genie codes.

-- Infinite loop to take control over frame advancing.
while true do
  address = read_file('address.txt')
  value = read_file('value.txt')
  cheat = read_file('cheat.txt')

  -- Only write to memory if the value has changed.
  if address ~= prev_address or value ~= prev_value then
    hex_address = tonumber(address, 16) -- Base 16 for hex values
    hex_value = tonumber(value, 16)

    -- Check to see if the entered strings are valid.
    if hex_address == nil or hex_value == nil then
      emu.message('Invalid address or value. Please use valid hex numbers.')
    else
      memory.writebyte(hex_address, hex_value)
      emu.message(address..': '..value) -- Print address and value being changed.
    end
  end

  -- Only add a game genie code if the file exists and has changed.
  if cheat ~= prev_cheat and cheat ~= nil then
    -- The emulator will already display a message if the code is invalid.
    cheat_added = emu.addgamegenie(cheat) -- Add our new Game Genie code.
    if cheat_added then -- cheat_added will be true if the code was valid.
      emu.message('Cheat added: '..cheat) -- Print address and value being changed.
    end
  end

  prev_address = address -- Update the address to keep track of changes.
  prev_value = value -- Update the value to keep track of changes.
  prev_cheat = cheat -- Update the cheat code to keep track of changes.
  emu.frameadvance() -- This essentially tells FCEUX to keep running.
end

Now our Lua script is checking cheat.txt to see if any new Game Genie codes have been added. Let’s take care of the rest by hopping back into our app.py and adding this to the Flask app:

import re

from flask import Flask, request
from twilio.twiml import Response

app = Flask(__name__)


@app.route('/', methods=['POST'])
def sms_reply():
    # Retrieve the body of the text message.
    message_body = request.form['Body']
    print(message_body)

    # Create a TwiML response object to respond to the text message.
    resp = Response()
    message_response = 'Message received! Manipulating memory now.'
    error_message = ('Please enter a 4 digit hex address and a 2 digit '
                     'hex value separated by a space. '
                     'For example: "066D FF"')

    # Create a list of all words in the message body.
    message_list = message_body.split(' ')

    # Create a regex for matching hex Strings.
    hex_pattern = re.compile('^[0-9a-fA-F] $')

    # Check to see if the message is in the right format for Game Genie codes.
    if len(message_body) == 6 or len(message_body) == 8:
        # FCEUX will determine if the code is invalid by default.
        with open('cheat.txt', 'w') as f:
            f.write(message_body)
    # Make sure the message is in the right format.
    elif not len(message_list) == 2:
        message_response = error_message
    else:
        # The first word should be the hex address.
        address = message_list[0]

        # The second word should be the hex value to write to the address.
        value = message_list[1]

        # Check to see if the address and value are valid hexadecimal numbers.
        if hex_pattern.match(address) and hex_pattern.match(value):
            # Write the address and value to their respective text files.
            with open('address.txt', 'w') as f:
                f.write(address)

            with open('value.txt', 'w') as f:
                f.write(value)
        else:
            message_response = error_message

    resp.message(message_response)
    return str(resp)

if __name__ == '__main__':
    app.run(host='0.0.0.0')

And with this we should be done. Run our Flask app and our Lua script again and try texting “IZLZZZ” to your Twilio number while playing Zelda. This will make it so that when you walk into walls, enemies appear. This may not end well for Link.

gamegeniecheat.gif

The morning sun has vanquished the horrible night

When hacking old games I feel the excitement I felt in my younger days using Game Genie to have fun with my Nintendo cartridges. Now that we’ve went over the basics of ROM/RAM hacking, I hope you can derive this same enjoyment. Like Simon Belmont as the sun rises and his hostile enemies disappear, you are now able to equip yourself. With a small Lua script running in your emulator you can hack classic games using any programming language. There are endless possibilities now that we’ve hooked up old video games to the power of the Internet.

You can:

  • Have Mario send phone calls to your ex.
  • Exchange Bitcoin for rupees in Zelda.
  • Have Mike Tyson order you a pizza.

What crazy ideas can you think of?

a_winner_is_you.png

Check out the entire documentation for the FCEUX Lua API to get started on your own hacks. If you are curious about more of the hex editing stuff you can also see their hex editing guide.

I cannot wait to see what awesome emulator extensions you build. Drop me a line if you have any questions or if you just want to show off your hack.

Sign up and start building
Not ready yet? Talk to an expert.