• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Resource Using Cheat Engine with Dolphin

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Cheat Engine is a disassembler/debugger/memory editing GUI that works with little-endian x86/x64 architectures.

As a free program, it comes with a wealth of surprisingly powerful features that can be used for the purpose of reversing; a lot of which do not work with Dolphin (to the best of my knowledge.)

To sum up what I know about why (as quickly as I can: )
  • The base address used for GALE01 in Cheat Engine doesn't match up to the mapped regions used in the emulation, transposing all perceived addresses by a fixed amount.
  • Gamecube/Dolphin uses a big-endian PowerPC architecture, making the disassembler and all of its features useless (inside of the emulation, at least.) The endian difference also causes the byte order of any readable floats words and hwords to appear backwards.
Despite these issues, Cheat Engine is pretty dang flexible and can be set up in a way that revives some of the dead features. Specifically, its memory editing/searching toolset can be very useful in place of Dolphin’s cumbersome equivalent.

This might be a serious boon to any code writers out there looking for some tools to supplement their memory browsing experience--but it may also benefit anyone just looking to reverse file data or learn more about Melee mechanics in general.

I plan to make some additional posts after this guide about some specific examples of how Cheat Engine can be used. I should also make a note that while my examples will be for Melee, this can be used for a lot more than just Melee/Dolphin.

So let’s set up Cheat Engine:

---

Step 1 - Get It
Download Cheat Engine. I recommend the portable version, which you don't even need to install. It’s also got a github if you’d like to noodle with the source.

Open it up and click on the flashing icon for a prompt to select your running Dolphin process.


Note that I’m using 64-bit Cheat Engine and 64-bit Dolphin, so if you’re using a 32-bit system the addresses that show up in the following steps will probably look quite different.

---

Step 2 - View ALL THE RAM
Enable MEM_MAPPED regions in your scan settings so that the program can see emulated RAM.



If you'd really like to make sure you’ve got it working, do a string search for “GALE01” from the main window before and after checking this option, like so:


The addresses may differ, and the amount might not be the same; but you should see an increase in the “found” count. Notice that none of these are from address 80000000 like they are in the emulation. We fix that in the next step~

---

Step 3 - GALE01 (in A Minor)
Download emurpm.zip (an addon written by Dark Byte) and extract its contents into the autorun folder of your Cheat Engine directory.

This adds an indispensable menu item called “Emulator Memory” to the main menu bar, which allows you to adjust the base memory address used by Cheat Engine when looking at a process. I’ve only recently learned about this, and using CE without it is a sort of hell.

In every case I’ve seen of 64-bit Dolphin 4.0+ the base address for logical cached RAM appears to be represented by 0x7FFF0000 in Cheat Engine. There are other possible ranges that can be used, but I’ve found some of them to be inconsistent and haven’t had any trouble with this location across versions--so I assume it is the start of the logical cached region.

Try these settings if you’re using Dolphin 4.0+


If you’re using an older version of Dolphin, the address we’re looking for doesn’t even appear to be static and must be referenced with a pointer. You might have luck with settings similar to what I use for this old fastlog build, which I often rely on for memory check breakpoints and live browsing of the disassembler. If this doesn’t work, you’ll have to hunt for the appropriate pointer by studying GALE01 locations via scan (or update Dolphin.)


Now, if you choke your scan to a range of 0x80000000 to 0x81800000 from the settings in the main window, you should find the one GALE01 to rule them all when performing the search from the previous step :



Note that you might get some garbage GALE01 locations within this choked range--which are normal--so long as the first result is 0x80000000

---

Step 4 - Avoid Little-Endian Values
This one’s the dagger in the heart of most of the memory-related features in Cheat Engine, and there’s no way (that I know of, at this time) to completely eliminate it.

It is however very easy to eliminate most occurrences of little-endian bias by using the AOB (array of byte) data type when given the option; which ignores endian formats altogether.

In addition, you can install custom big-endian data types that will work with scans and the “cheats table” RAM watch. You may just rely on AOB data types for this, but these are particularly useful for big-endian floats and copying easily-pastable pointers.

These are are a courtesy of mgr.inz.Player and Dark Byte from the Cheat Engine forum:
Code:
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)

TypeName:
db '2 Byte Big Endian',0

ByteSize:
dd 2

//The convert routine should hold a routine that converts the data to an integer (in eax)
//function declared as: stdcall int ConvertRoutine(unsigned char *input);
//Note: Keep in mind that this routine can be called by multiple threads at the same time.
ConvertRoutine:
//jmp dllname.functionname
[64-bit]
//or manual:
//parameters: (64-bit)
//rcx=address of input
xor eax,eax
mov ax,[rcx] //eax now contains the bytes 'input' pointed to
xchg ah,al //convert to big endian

ret
[/64-bit]

[32-bit]
//jmp dllname.functionname
//or manual:
//parameters: (32-bit)
push ebp
mov ebp,esp
//[ebp+8]=input
//example:
mov eax,[ebp+8] //place the address that contains the bytes into eax
mov ax,[eax] //place the bytes into eax so it's handled as a normal 4 byte value
and eax,ffff //cleanup
xchg ah,al //convert to big endian

pop ebp
ret 4
[/32-bit]

//The convert back routine should hold a routine that converts the given integer back to a row of bytes (e.g when the user wats to write a new value)
//function declared as: stdcall void ConvertBackRoutine(int i, unsigned char *output);
ConvertBackRoutine:
//jmp dllname.functionname
//or manual:
[64-bit]
//parameters: (64-bit)
//ecx=input
//rdx=address of output
//example:
xchg ch,cl //convert the little endian input into a big endian input
mov [rdx],cx //place the integer the 4 bytes pointed to by rdx

ret
[/64-bit]

[32-bit]
//parameters: (32-bit)
push ebp
mov ebp,esp
//[ebp+8]=input
//[ebp+c]=address of output
//example:
push eax
push ebx
mov eax,[ebp+8] //load the value into eax
mov ebx,[ebp+c] //load the address into ebx

//convert the value to big endian
xchg ah,al

mov [ebx],ax //write the value into the address
pop ebx
pop eax

pop ebp
ret 8
[/32-bit]
Code:
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)

TypeName:
db '4 Byte Big Endian',0

ByteSize:
dd 4

//The convert routine should hold a routine that converts the data to an integer (in eax)
//function declared as: stdcall int ConvertRoutine(unsigned char *input);
//Note: Keep in mind that this routine can be called by multiple threads at the same time.
ConvertRoutine:
//jmp dllname.functionname
[64-bit]
//or manual:
//parameters: (64-bit)
//rcx=address of input
xor eax,eax
mov eax,[rcx] //eax now contains the bytes 'input' pointed to
bswap eax //convert to big endian

ret
[/64-bit]

[32-bit]
//jmp dllname.functionname
//or manual:
//parameters: (32-bit)
push ebp
mov ebp,esp
//[ebp+8]=input
//example:
mov eax,[ebp+8] //place the address that contains the bytes into eax
mov eax,[eax] //place the bytes into eax so it's handled as a normal 4 byte value

bswap eax

pop ebp
ret 4
[/32-bit]

//The convert back routine should hold a routine that converts the given integer back to a row of bytes (e.g when the user wats to write a new value)
//function declared as: stdcall void ConvertBackRoutine(int i, unsigned char *output);
ConvertBackRoutine:
//jmp dllname.functionname
//or manual:
[64-bit]
//parameters: (64-bit)
//ecx=input
//rdx=address of output
//example:
bswap ecx //convert the little endian input into a big endian input
mov [rdx],ecx //place the integer the 4 bytes pointed to by rdx

ret
[/64-bit]

[32-bit]
//parameters: (32-bit)
push ebp
mov ebp,esp
//[ebp+8]=input
//[ebp+c]=address of output
//example:
push eax
push ebx
mov eax,[ebp+8] //load the value into eax
mov ebx,[ebp+c] //load the address into ebx

//convert the value to big endian
bswap eax

mov [ebx],eax //write the value into the address
pop ebx
pop eax

pop ebp
ret 8
[/32-bit]
Code:
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)
alloc(UsesFloat,4)

TypeName:
db 'Float Big Endian',0
ByteSize:
dd 4
UsesFloat:
db 01

ConvertRoutine:
[32-bit]
push ebp
mov ebp,esp
mov eax,[ebp+8] //place the address that contains the bytes into eax
mov eax,[eax]   //place the bytes into eax
bswap eax
pop ebp
ret 4
[/32-bit]

[64-bit]
//rcx=address of input
mov eax,[rcx] //eax now contains the bytes 'input' pointed to
bswap eax
ret
[/64-bit]

ConvertBackRoutine:
[32-bit]
push ebp
mov ebp,esp
//[ebp+8]=input
//[ebp+c]=address of output
push eax
push ebx
mov eax,[ebp+8] //load the value into eax
mov ebx,[ebp+c] //load the address into ebx
bswap eax
mov [ebx],eax //write the value into the address
pop ebx
pop eax

pop ebp
ret 8
[/32-bit]

[64-bit]
//ecx=input
//rdx=address of output
bswap ecx
mov [rdx],ecx //place the integer the 4 bytes pointed to by rdx
ret
[/64-bit]

To install them, paste the AA scripts into the text prompt that appears when right clicking the “Value Type” dropdown box from the main scan window settings:



The custom types can then be selected as a part of a scan, or defined when entering an address on the cheats table.

---

Now you can use Cheat Engine as an alternative to Dolphin’s cheat search, memory tab, and RAM watch features!


As you’ve seen, the Cheat Search (“Scan”) in Cheat Engine is readily available as an integrated part of the main GUI. If you followed all of step 4, you’ve also seen that the value types are programmable, which brings some interesting possibilities to the table.

By default, the AOB data type can be used with an arbitrary length (I believe it also supports 4-bit nibbles.) This can be used to copy bytes from a hex editor and search for them as part of a loaded file in RAM during runtime. Combined with Dolphin breakpoints, this is very helpful for exploring how data is instantiated. Try it with .dat headers~

---


The “Cheats Table”--which you might think of as similar in function to Dolphin’s RAM watch--is actually the root of many features in Cheat Engine. Since the disassembler doesn’t work with PPC, I don’t think the debugger delivers any justice to most of the features normally offered by it. In addition, pointers are hardcoded as 64-bit little-endian, making what would have probably been the greatest feature of this setup a total dud.

Even so, it’s a great way to keep track of values (especially big endian floats!)

And not everything is broken; you can still save your cheats tables as XML-based “CT” files and recover them later; assign memory edits to hotkeys, freeze values and quite a bit more. I believe it’s even possible to assign Lua scripts and AA scripts to entries on the cheats table.

---


My absolute favorite feature of Cheat Engine is the simple Memory View. It can’t use custom data types, so it’s limited to byte alignment when used with Dolphin; however this conveniently makes it look and feel just like a hex editor.

It’s not though; it’s an animated interactive RAM dump that you can read/write to and save addresses from as a part of your cheats table, and it floats around in a resizable window. It hosts many hidden features in Cheat Engine, some of which I haven’t fully explored; my favorite of which just makes another Memory View~ You can create as many instances of these things as you want!

---

I'll go into more depth at a later date, if I can. There are a lot of ways to use these tools to explore Melee.

I’m pretty keen on learning more about how to make use of these Lua exposures, as well as how to write AA scripts. I’d really love to find even more ways to make Cheat Engine useful for big-endian data (and maybe even with PPC.)

A final note: I stumbled upon this fascinating github project (by Yoshifan) a long time ago, back before I had a clue about any of this stuff. I believe it has the potential to easily create trainer-like GUI tools for memory editing in Dolphin. I found it to work well with Melee back when I played with it, though I didn’t venture to do much. It’s outdated at this point, however the utilities in this file helped me understand how simple it is to deal with endian problems, and inspired me to write a tool (in PPC) that allowed me to use some of the pointer features in Cheat Engine in a limited way. I’m rewriting it now with MCM so that it can be installed as a DOL mod.
 
Last edited:

DRGN

Technowizard
Moderator
Premium
Joined
Aug 20, 2005
Messages
2,175
Location
Sacramento, CA
Great guide! Well-written, full of info, and easy to follow. This is really interesting stuff. I feel like I've been in the dark ages when it comes to how I test structure & value changes (which has been basically just boot the game and see if it works or what changes). The plethora of pictures & gyfs add a lot and make it really nice to follow too.

Although this is powerful, especially to be able to rapidly test things, I think that its uses probably aren't too obvious until you really get into it. Adding a section in the beginning to explain what this can be used to do and why it's useful might help a lot, especially to those just getting into modding. It would also serve as a tl;dr for those who might have otherwise moved on because they didn't quite understand right away what the potential here was.
 

ItsYaBoii

Smash Rookie
Joined
May 4, 2020
Messages
11

So this part doesn't work for me, but I have no idea how to find the correct one to get only one "GALE01" to appear?

you’ll have to hunt for the appropriate pointer by studying GALE01 locations
How do we study the locations? what are we looking for? I have 561 addresses with GALE01
 
Last edited:

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423

So this part doesn't work for me, but I have no idea how to find the correct one to get only one "GALE01" to appear?



How do we study the locations? what are we looking for? I have 561 addresses with GALE01
Aldelaro explains the problem in detail in this thread. Basically, Dolphin now handles virtually mapped memory in a way that breaks the ability to view it in CE like this. You can use his Memory Engine program as a suitable alternative to CE.

I don't know exactly when the patch broke this functionality, but I know that this old version of 5.0 Dolphin still works with the Emulator Memory offset in CE, and I still use it from time to time.
 

ItsYaBoii

Smash Rookie
Joined
May 4, 2020
Messages
11
Aldelaro explains the problem in detail in this thread. Basically, Dolphin now handles virtually mapped memory in a way that breaks the ability to view it in CE like this. You can use his Memory Engine program as a suitable alternative to CE.

I don't know exactly when the patch broke this functionality, but I know that this old version of 5.0 Dolphin still works with the Emulator Memory offset in CE, and I still use it from time to time.
Thanks bro I'll use that version of Dolphin with CE then.

I also do use that dolphin memory engine you linked but the problem is it doesn't have dissect structures and generate pointer maps like in CE and I don't know how to navigate without these tools yet.
 
Top Bottom