• Hey, guest user. Hope you're enjoying GameParadise! Have you considered registering for an account? Come join us and add your take to the daily discourse.

How to create Gateway Cheat Codes

 
 
1712645277545.png

Gateway cheats seem like magic. How can a seemingly random string of numbers give us infinite lives in Super Mario 3D Land or make us invincible? It's simple. They access our machines RAM that holds our game information and manipulate bytes to do what we want. They can be viewed as a very rudimentary form of programming language, but one that is mighty powerful.

In this "quick" guide I am going to explain the different code types that are implemented in the Gateway cheat engine, what the codes do and how we construct them. In order to understand the codes and prevent any misunderstandings we need to define the terminology first, so here's a list of words that I will be using throughout the tutorial. I will also be giving alternative terminology that might be used in other areas of computing, but for the sake of this tutorial we are going to stick with the terminology that is marked in bold.

Note beforehand: We are going to be dealing a lot with hexadecimal numbers when creating codes (base 16). Since we mainly use the decimal system in our daily lives we will have to calculate between decimal and hexadecimal (or vice versa) quite often. Whenever I am using a hexadecimal number, it will be denoted by a leading '0x'. This will help us to not confuse hexadecimal values that look like decimal values (like 0x10 for example) with their decimal sibbling (10). So when you see a regular number like '10', that will be decimal. If it's 0x10, it's hexadecimal (0x10 = 16, fyi). 0b will be used for denoting binary numbers (only used in the 16-bit conditional codes).


Code: A code consists of various parameters. Parameters are 'code type', 'address', 'value', 'offset' 'mask' and 'data register'. A code is split into two 8-digit strings separated by a space.

Code Type: Determines what the code does. The first digit of a code determines the code type, note that some code types (like the D codes) can be further split into secondary code types, which will be determined by the second digit of the code. Gateway supports 28 different code types, 27 of which gateway has documented.

Address: the games memory is laid out in bytes, each byte represented by an individual address and performing a specific task within the games memory. We can precisely define which byte we want to manipulate by telling the Gateway cheat engine the exact address of the byte. I common computer terminology an address is often called 'offset', but we are going to need that term for something else so we will be calling addresses strictly by the name 'address'.

Value: This is the value of a specific byte in the games memory. For example the address that holds your ammount of lives in Super Mario 3D Land has a value corresponding to this number. Often called 'data'. To avoid confusion with the 'data register' only the term 'value' will be used.

Offset: Since the first digit of a code line is always reserved we might – depending on the code type – not be able to enter an 8-digit address into a code. If the address we want is more than 7 digits, we need to set the offset to a value that, when added to the address paramter, adds up to our correct 8-digit address we want to manipulate.

Mask: Only used in 16-bit conditional instructions. It allows us to 'mask' individual bits in the condition – comparable to wildcards. This will be clearly explained at the 16-bit conditional section.

Data register: a specific register that can hold a value and add to that value. By default it is 0x0 but we can set it to any value we want or load a value from any address. Specific code types are used for loading a value from an address or writing the value within the data register to an address.


So without further ado, here are the code types:

Memory Writes:
parameters: address (XXXXXXX), value (YY, YYYY, YYYYYYYY)
To write an address higher than 0xFFFFFFF, you need to set an offset using code Type 0xD3. The offset gets added to the address parameter to determine the final address we want to manipulate. See Code type 0xD3 for further instructions.

The memory write codes are split into three code types. Which code type is used depends on the value you want to write. One byte can hold 256 values, two bytes can hold 256² values, four bytes can hold 256^4 values, including 0. So the maximum value a write instruction can write is:

8-bit : 255
16-bit: 65.535
32-bit: 4.294.967.295
If the game stores a value as 8-bit, doing a 16-bit or 32-bit write to the address might break the game or manipulate other values of the game that we might not intent to change. As an example, „Legend of Zelda: Tri Force Heroes" stores the ammount of the items we have in 70 consecutive bytes, so doing a 16-bit write to such an address will also modify the item next to the one we wanted to change. So be carefull to only manipulate as little as neccessary, but as much as required.

0XXXXXXX YYYYYYYY – 32bit write to [XXXXXXX + offset]
writes the 32-bit value we specify to the given address. This manipulates four bytes starting at the given address. Two 16-bit writes can be used with the same result, endianness has to be taken into account. See Note at the end of the tutorial about endianness.

1XXXXXXX 0000YYYY – 16bit write to [XXXXXXX + offset]
writes the 16-bit value we specify to the given address. This manipulates two bytes starting at the given address. Two 16-bit writes can replace a 32-bit write, however endianness has to be taken into account. See Note at the end of the tutorial about endianness.

2XXXXXXX 000000YY – 8bit write to [XXXXXXX + offset]
writes the 8-bit value we specify to the given address. This manipulates a single byte. Two 8-bit writes can replace a 16-bit write, however endianness has to be taken into account. See Note at the end of the tutorial about endianness.

Examples:
03BA110C 01CD5F99 – writes the value 0x1CD5F99 (30.236.569) to the address 0x3BA110C. Manipulates the bytes at addresses 0x3BA110C, 0x3BA110D, 0x3BA110E and 0x3BA110F.

13BA110C 00005F99 – writes the value 0x5F99 (24.473) to the address 0x3BA110C. Manipulates the bytes at addresses 0x3BA110C and 0x3BA110D.

23BA110C 00000099 – writes the value 0x99 (153) to the address 0x3BA110C. Manipulates only the byte at addresses 0x3BA110C.

Conditional 32bit codes:
parameters: address (XXXXXXX), value (YYYYYYYY)

Conditional codes allow us to compare the value of an address to the value we provide as a parameter. If the condition is true execution continues at the next code line. If false, execution will jump to the next terminator code (Code type 0xD0 and 0xD2) and continue from there. Conditionals can be nested. The code does not manipulate the games memory on it's own, it needs to be followed by a code that does the manipulation (a 32-bit write for example).


3XXXXXXX YYYYYYYY – Less Than (YYYYYYYY < [XXXXXXX + offset])
If the value at the specified address is less than the value we provide, continue the instruction.

4XXXXXXX YYYYYYYY – Greater Than (YYYYYYYY > [XXXXXXX + offset])
If the value at the specified address is greater than the value we provide, continue the instruction.

5XXXXXXX YYYYYYYY – Equal To (YYYYYYYY == [XXXXXXX + offset])
If the value at the specified address is equal to the value we provide, continue the instruction.

6XXXXXXX YYYYYYYY – Not Equal To (YYYYYYYY != [XXXXXXX + offset])
If the value at the specified address is not euqal to the value we provide, continue the instruction.

Examples:
33BA110C 00000063 – if the value at address 0x3BA110C is less than 0x63 (99), execute next line.
03BA110C 01CD5F99 – sets the value at address 0x03BA110C to 30.236.569
D0000000 00000000 – ends the if instruction and continue code exection without the conditional.

63BA110C 00000063 – if the value at address 0x3BA110C is anything other than 0x63 (99), execute next line.
03BA110C 01CD5F99 – sets the value at address 0x03BA110C to 30.236.569
D0000000 00000000 – ends the if instruction and continue code exection without the conditional.

Conditional 16bit deref + write codes:
parameters: address (XXXXXXX), value (YYYY), mask (ZZZZ)
Even though Gateway calls them write codes, according to the Datel trainer toolkit manual for the AR DS and my trials these do not write to the location. It needs to be followed by a code that does the manipulation (a 16-bit write for example). The mask parameter allows us to mask out specific bits of the 16 bit value for the condition. If the mask is set to 0x0000 the code will behave exactly like the conditional 32-bit codes (Code types 0x03-0x06).

7XXXXXXX ZZZZYYYY – Less Than
If the masked value at the specified address is less than the masked value we provide, continue the instruction.

8XXXXXXX ZZZZYYYY – Greater Than
If the masked value at the specified address is greater than the masked value we provide, continue the instruction.

9XXXXXXX ZZZZYYYY – Equal To
If the masked value at the specified address is equal to the masked value we provide, continue the instruction.

AXXXXXXX ZZZZYYYY – Not Equal To
If the masked value at the specified address is not equal to the masked value we provide, continue the instruction.

Understanding masks is a bit tricky and from the top of my head I can't really think of a reasonable practical use of a masked conditional but i'll try my best to explain them. If you think you can provide a clearer explanation of masks, feel free to post it, I can insert it here if you like.

Masks work on a binary/bit level. A mask of 0x0000 will translate to 0b00000000 00000000 (space added for better readability), 0xFFFF will translate to 0b11111111 11111111. Any bit set to 1 will be ignored when comparing the value at the address provided with the value we pass in the code.

Let's say when our character does a regular jump the value at address 0x03BA110C changes to 0x25 but when we do a running jump it changes to 0x15. Address 0x03BA110E determines the gravity and we want to set it to zero every time we jump, regardless if we made a regular jump or a running jump. A code 93BA110C 00000005 (mask = 0x0000) would only be true for a regular jump, not a running jump. Thats why we want to mask out any bits that we consider irrelevant for our condition. To do that we have to translate 0x25 and 0x15 to binary first:

0b00000000 00100101 = 0x25
0b00000000 00010101 = 0x15

we want the condition to be true whenever the value ends with 0x5 so we translate that to binary:

0b00000000 00000101 = 0x5

we mask out all the bits that we do not care about with a 0b1 and convert it to hexadecimal

0b11111111 11111000 = 0xFFF8

This mask will only take the last 3 bits of the value and compare it to the last three bytes of our value that we pass in the code. So in our example, whenever the last three binary digits of our value matches 0b101 (0x5) the condition holds true and we continue to the next code line. If it is false we jump to the next 0xD0 or 0xD2 code.

Examples:
93BA110C 00000005 – if the value at address 0x03BA110C is exactly 0x5 execute next line. True only for 0x5
13BA110E 00000001 – sets the value at address 0x03BA110E to 1
D0000000 00000000 - ends the if instruction and continue code exection without the conditional.


93BA110C FFF80005 – if the masked value at address 0x03BA110C is 0x5 execute next line. True for 0x5, 0x15, 0x25 etc. (but also 0xD, 0x1D, 0x2D etc.)
13BA110E 00000001 – sets the value at address 0x03BA110E to 1
D0000000 00000000 - ends the if instruction and continue code exection without the conditional.

Offset Codes:

Since for a lot of codes only a 7-digit address can be parsed we often need to add an offset to that address parameter to determine the final address. We have a few types of codes dealing with offsets. The rule is always: address parameter + offset = destination address.

D3000000 XXXXXXXX – set offset to immediate value
parameters: offset (XXXXXXXX)

This will set the offset to an immediate value we pass in the code. This value gets added to any address parameter in all other code types to result in the destination address so in order to write to addresses with 8-digits it is necessary to set an offset. It is also quite common to set the offset to the destination address and work with the address parameter 0x0000000 in all other codes. This method, in my opinion, has a few advantages so in my codes you will usually see me declaring an offset everytime, even if it would not be necessary.

Examples:
D3000000 10000000 – sets the offset to 0x10000000
23BA110E 00000063 – writes a 8-bit value of 0x63 (99) to the address at 0x13BA110E (0x10000000 + 0x3BA110E = 0x13BA110E)

The same code can also be written like this:

D3000000 13BA110E – sets the offset to 0x13BA110E
20000000 00000063 – writes a 8-bit value of 0x63 (99) to the address at 0x13BA110E (0x13BA110E + 0x00000000 = 0x13BA110E)

As you can see, this allows you to see the address more clearly than the first method. Which method you prefer is up to you, both methods are correct and valid.

DC000000 XXXXXXXX – Adds an value to the current offset
parameters: value (XXXXXXXX)

This code type allows you to increase the offset by the hexadecimal value you provide. This is particularly useful in combination with the loop code (see code type 0xC0) to manipulate a lot of addresses laid out in a repeating pattern with only a few lines of code.

Examples:
D3000000 13BA110C – sets the offset to 0x13BA110C
20000000 00000063 – writes an 8-bit value of 0x63 (99) to the address at 0x13BA110C (0x13BA110C + 0x00000000 = 0x13BA110C)
DC000000 00000002 – increases the offset by 0x2, Offset is now 0x13BA110E
20000000 00000063 – writes an 8-bit value of 0x63 (99) to the address at 0x13BA110E (0x13BA110E + 0x00000000 = 0x13BA110E)

BXXXXXXX 00000000 – offset = *(xxx)
parameters: address (XXXXXXX)

This code type allows us to load a 32-bit value from the address we provide (+ any offset we might have set before) into the offset register, replacing the current offset. This allows us to use pointers in our code. For a tutorial on how to find pointers, see http://www.maxconsole.com/maxcon_forums/threads/293146-Finding-Pointer-Codes-With-Gateway-RAM-Dump (thanks to @json,for pointing towards that tutorial)

Example:
D3000000 13BA110C – sets the offset to 0x13BA110C
B0000000 00000000[COLOR=][/COLOR] – loads the 32-bit value at address 0x13BA110C into the offset register, replacing our current offset. So if the value at 0x13BA110C is 0x368F39C3, this will be our new offset (Note: when viewing hex values in a hex editor on your pc or the gateway cheat menu, take endianness into account!)
20000000 00000063 – writes an 8-bit value of 0x63 (99) to the address at 0x368F39C3 (0x368F39C3 + 0x00000000 = 0x368F39C3)

Loop Code:
C0000000 YYYYYYYY – Sets the repeat value to 'YYYYYYYY'

parameters: number of loops (YYYYYYYY)

This code allows us to repeat the following block of codes as often as we need it to. When code type 0xD1 or 0xD2 is hit, the loop number will decrease by 0x1 and start again. Combined with other codes we can manipulate a huge array of addresses with just a few lines of code.

Example:
D3000000 13BA110C – sets the offset to 0x13BA110C
C0000000 00000032 – repeat the following instructions 0x32 (50) times
20000000 00000063 – writes an 8-bit value of 0x63 (99) to the address at 0x13BA110C (0x13BA110C + 0x00000000 = 0x13BA110C)
DC000000 00000002 – increases the offset by 0x2, Offset is now 0x13BA110E
D1000000 00000000 – decrease loop counter by 0x1, jump back to the previous 0xC0 code.

So instead of manipulating 50 addresses one by one, our loop does automatically set the value of every other address to 0x63 (99)

Terminator Codes
D0000000 00000000 – End If instruction
This code ends the current conditional cod instruction. For examples see the section about conditional codes

D1000000 00000000 – End repeat instruction
This code decreases the current loop counter by one and returns code execution to the last 0xC0 code. See Loop code for examples.

D2000000 00000000 – end code instruction. (not documented by team gateway)

This code decreases the current loop counter by one and returns code execution to the last 0xC0 code. It also ends any conditional blocks. It also clears the current offset and any value you might have written to the data register. It is recommended to use this as final code terminator before starting a new code.


Data Register Codes:
The data register allows us copy a value from an address and manipulate it before writing it back to an address (either the same address or any other one). The data register is always 32-bit, we can decide on the "bit-ness" during the write instructions. If not set or loaded by any code, it will be 0x0.

D5000000 XXXXXXXX – Sets the data register to XXXXXXXX
parameters: value (XXXXXXXX)

This code allows us to set the content of the data register to any arbitrary value we want.


D9000000 XXXXXXXX – (32bit) sets data to [XXXXXXXX+offset]
parameter: address (XXXXXXXX)

This will load the 32-bit value from the address provided (also taking the offset into account) and store it in the data register.


DA000000 XXXXXXXX – (16bit) sets data to [XXXXXXXX+offset] & 0xffff
parameter: address (XXXXXXXX)

This will load the 16-bit value from the address provided (also taking the offset into account) and store it in the data register.


DB000000 XXXXXXXX – (8bit) sets data to [XXXXXXXX+offset] & 0xff
parameter: address (XXXXXXXX)

This will load the 8-bit value from the address provided (also taking the offset into account) and store it in the data register.


D4000000 XXXXXXXX – Adds XXXXXXXX to the data register
parameters: value (XXXXXXXX)

This code simply adds the value we pass to the data register.


D6000000 XXXXXXXX – (32bit) [XXXXXXXX+offset] = data ; offset += 4
parameters: address (XXXXXXXX)

This code writes the current content of the data register to the address provided (taking the offset into account) as a 32-bit value. After the write it automatically increases the current offset by 0x4.


D7000000 XXXXXXXX – (16bit) [XXXXXXXX+offset] = data & 0xffff ; offset += 2
parameters: address (XXXXXXXX)

This code writes the current content of the data register to the address provided (taking the offset into account) as a 16-bit value. After the write it automatically increases the current offset by 0x2.


D8000000 XXXXXXXX – (8bit) [XXXXXXXX+offset] = data & 0xff ; offset++
parameters: address (XXXXXXXX)

This code writes the current content of the data register to the address provided (taking the offset into account) as a 8-bit value. After the write it automatically increases the current offset by 0x1.

Example for data register usage:
D3000000 13BA110C – sets the current offset to 0x13BA110C
D5000000 413C0000 – sets the data register to 0x413C0000
C0000000 0000002B – start a loop and execute it 0x2B (43) times
D6000000 00000000 – Write the data register to address 0x13BA110C and increase the offset by 0x4. New offset is now 0x13BA1110. Data register remains 0x413C0000
D1000000 00000000 – decreases the loop count by 0x1 and returns to the 0xC0 line above. When the loop count is at 0x0, execution continues at the next code line.
D3000000 13BA178C – sets the current offset to 0x13BA178C
C0000000 0000002B - start a loop and execute it 0x2B (43) times
D6000000 00000000 – write the data register to address 0x13BA178C and increases the offset by 0x4. New offset is now 0x13BA1790. Data register remains 0x413C0000
D2000000 00000000 – decreases the loop counter by 0x1, returns to the previous 0xC0 code. As soon as loop counter is 0x0, it clears the data and offset register, both return to 0x0,

Special Codes:

DD000000 XXXXXXXX – if KEYPAD has value XXXXXXXX execute next block
parameters: keypad value

This code allows us to activate codes only as soon as a button combo is pressed. This is great for creating codes that can be enabled "on demand" by pressing the button combo that corresponds with the value we pass. Each button corresponds to a specific hexadecimal value. We just add any values of the buttons we want to be pressed for the button to activate. Let's assume we want to press L+R+Start+Select, we just add 0x200, 0x300, 0x8 and 0x4. The result is 0x50C

So by putting the line DD000000 0000050C in front of our code we will have to press the buttons to activate the code. The gateway cheat engine seems to be very sensitive about the button presses so sometimes the code will execute multiple times with even the shortest of a press of the button combo. See the following list for the available keys and their corresponding values. New 3DS exclusive buttons (ZL, ZR, C-Stick) are currently not available.

0x1 A
0x2 B
0x4 Select
0x8 Start
0x10 Right
0x20 Left
0x40 Up
0x80 Down
0x100 R
0x200 L
0x400 X
0x800 Y

EXXXXXXX YYYYYYYY - Patch Code
Parameters: address (XXXXXXX), Number of Bytes (YYYYYYYY)

This code type was introduced in gateway 3.6.2, but the implementation is a bit iffy. I believe Gateway may have botched this one up slightly. This code writes YYYYYYYY bytes from the list of following values (an example will make this a bit clearer, please bear with me) starting at the address (+offset we might have set). Where this code gets a bit iffy is the endianness it treats the list of values to write:

D3000000 32C825A4 - sets the current offset to 0x32C825A4
E0000000 00000008 - write the following list of 08 (0x10) bytes to the addresses 0x32C825A4 onwards
44332211 88776655 - this is the part the code goes iffy. 0x11 is the value that gets written to 0x32C825A4, 0x22 gets written to 0x32C825A5, 0x55 to 0x32C825A8, 0x66 to 0x32C825A9 etc.

Logic would usually dictate that it should not treat the list as individual 32-bit strings but simply a stream of bytes to write, but it does. So this code is to be used very carefully as to write the proper value to the addresses we want. It's not broken per se, it's just a bit tricky to bend your mind around the stream of bytes.

The 0xE code type will also disable code type detection for YY of bytes in the code list. I.e. in the above example the line following E0000000 00000008 would simply be interpreted as a list of values, not an 0x4 (32-bit 'greater than' conditional) code type.

Footnote about endianness:

If you looked at a RAM dump of the 3DS - either in the built in hex editor or your PC - you might have noticed that when looking at a value at an address the values our codes write do not seem to match up. Thi is because the 3DS RAM is laid out in little endian, our codes are written in big endian. When we take the 32-bit big endian value 11223344 the cheat engine will split these up into four bytes, 11 22 33 44 then start by writing the least significant byte (44) to the address we want. then writes the next byte (33) to the following address. For further clarifcation, check the Wikipedia entry about endianness. For the sake of this guid:

When you pass the value 1A2B3C4D in a code, it'll show up as 4D 3C 2B 1A in RAM. The value will be correct, though.

Changelog:

19.01.2016: fixed code types 0x3, 0x4, 0x7 and 0x8.
26.01.2016: added code type 0xE - patch code.
About author
admin
Avid gamer.

Comments

There are no comments to display.
 

Nintendo 3DS information

Author
Chad Waliser
Article read time
12 min read
Views
1,673
Last update

More in Nintendo 3DS

More from Chad Waliser

Back
Top