Using the Disassembly - X-Hax/SADXModdingGuide GitHub Wiki

Getting started with the Disassembly

image

Table of contents

  1. Introduction

    1.1 What is the disassembly?

    1.2 Understand the difference between Source Code and Disassembly

  2. Requirements

  3. Using IDA

    3.1 Navigation on IDA

    3.2 Getting a function call address

  4. Finding an Address

  5. Going further

Introduction

When it comes to making DLL mods, you will often have to use the disassembly of the game. Sometimes to take a look at how the game does something, sometimes to get an address to edit the game code, or even just to mess around. Although nowadays most game use C++, both Adventure games were coded in C since it was pretty common for early 3D game to do that.

In this guide, we will learn the basic of how to explore the disasembly of the game with some tips here and there. This tutorial assume you already have some basic knowledge in C, so you could at least understand a bit how that works. If you don't, please use Google and learn the basic first; at least variable, functions, conditions, array and loop. No need to be a programmer or a pro at all, just try to get the main idea of those things I listed. Just for reference, my first mod was the SADX Randomizer and I had basically 0 knowledge in C. So yeah, if I can do it, you can do it.

Worth to specify, this guide was made with SADX in mind, but the same logic applies for SA2.

What is the disassembly?

Often confused with "source code", the disassembly is basically compiled code which can be viewed with tools like Ghidra or IDA. Those tools will show you the compiled code in the Assembly language (ASM). Thankfully, IDA and Ghidra both have a way to show you "pseudo code", which is basically a translation of the ASM in C. Now, that translation is very far from perfect and it is not rare when those software show you something wrong. The tools are often used to make a decompilation of a function and sometimes even the full game, we then talk about "Reverse engineering".

Understand the difference between Source Code and Disassembly

The source code is the original code in C that the dev originally wrote (in that case Sonic Team). This code is easy to understand as you have the original names the developers used, with comments and so on. Unfortunately, we do not have that. It is very rare when you get that from a game, usually we talk about "leaked source code". So, that leads us the second option: using the disassembly.

The disassembly is compiled code which adds a ton of optimisations and those make the whole thing already more annoying to understand. But it get worse, because all the variables, functions name and struct just become memory addresses instead of the original names the dev used. Basically, imagine that you had a book, but all the chapters content have encrypted text and you have to guess yourself what they are talking about, until you can eventually understand most of the book. Sounds pretty annoying right? And how do you even do that?

Well, it all comes with research and patience. Tools like Cheat Engine can be helpful to find and understand what an address does. That address can lead to a function, and then eventually you can figure out what the game is doing at this specific part.

Thankfully SADX had years of research already and thanks to some awesome modders like MainMemory and SonicFreak, many things got figured out, so you aren't doing this blindly. Alright, let's see how to set up that.

Requirements

Using IDA

In order to use the disassembly, you will need IDA as mentioned at the beginning of this guide. Once you have it installed, start it and then do file -> open -> sonic.idb After a bit of waiting, it eventually shows the thing.

image

Wow what is that? Pretty scary right? Don't worry, we will see the pseudo-code in a bit and everything will become much easier.

Navigation on Ida

First, here's a bit of basic. On your left, you have a list with ALL the functions of the game:

image

If you double click on one of them, it will show you its content. Additionally, you can directly jump to a function by typing its address which we will do in a bit.

But, how do you get an address of a function you may ask?

First, if you take a look at "SADXFunctions.h" and "SADXVariables.h" in the Programming folder of SADX, you will see a ton of addresses that you can simply copy and paste there to navigate in the disassembly.

image

Then on IDA, if you press G, it will open the "Jump to address" feature, which is really useful if you want to quickly navigate to something. Let's give it a shot, press G, and type 425BE0 then press Enter.

Now we're here.

image

Pay attention to the "AddRings" on top. You just jumped to the function that give rings to the player. Now that's where the magic happen, press TAB or F5 andddddddd....

image

Boom! Wow, actual C language! Much easier to understand, right? So, from now on, when you are reading the ASM like you were 2 min ago, just press TAB or F5 to show the pseudo-code. Remember though, it only works if you are on a function, if you are currently looking at variables or arrays, this won't show up pseudo-code.

Getting a function call address

Ok, so now you are in this function, here's some stuff you can do. First, you can click on the name of the function on top and press X. It will show you a window like this.

image

This list reference the function we currently are. In other words, IDA is showing you every place where the game is calling the "AddRings" function. Those are also called "Function Call". It can be useful during some research or when you want to edit a specific part of the code. For example, if you double click on "FiveRingsPowerup" it will lead you to the function that gives rings to the player when you hit a 5 rings Item Box.

image

And now you are in the function that gives 5 rings to the player.

image

You can click on "AddRings(5)", then press tab to go back to the ASM view.

image

You should now see the address of the function call, which is 4D6C52. Getting a function call address can be useful to edit the game code so you can either hook the address of the call to make the game read your own code, OR you can nop the call so the game will skip that part. That way, you can prevent the game to give rings when you hit a 5 rings item box and ONLY for this item box and not every ring in the game. It is important to understand the difference. We will see how to edit the game code in a different guide.

Press tab again to go back to the pseudo-code view so we can see the FiveRingsPowerUp function again. You can notice that the game call different functions inside that function.

image

For example here it checks if you are playing Gamma and if so, play a different sound. Note that you can also press X on those functions here to see where they are called. If you do it on "GetCurrentCharacterID" you will see it's used in countless place for obvious reason. You can also press X on global variables and arrays to see where the game uses them.

And with that you can explore the disassembly and get lost easily.

Sometimes, you will find a function that isn't labeled at all like, the one at 425C50 (IDA will call those sub_XXXX). A good habit here is to click on the name of that function and then press N to give it a name of what you think it is. You can also do that on global arrays and variables.

Going back to the "AddRings" function: this kind of situation was easy because you can easily get the address of "AddRings" as it was listed in SADXFunctions.h. However, what if... you don't know the address that you want?

Let's find out how to find an address/function.

Finding an Address

For this part, you will need Cheat Engine. Not to cheat no, but to do some research, this is a very powerful tool when it comes to that.

Once you have it, open Cheat Engine, then open SA Mod Manager (previously SADX Mod Manager) and use Test Spawn to boot on Emerald Coast Act 1.

image

Once SADX is open, go back to Cheat Engine and do "File -> Open Process" and pick sonic.exe (Sonic Adventure)

image

You now successfully attached sonic.exe to Cheat Engine. That way we will be able to see and edit the game memory.

So, let's pretend we want to find in the code where the game gives Sonic a new life. We gonna open the Cheat Engine Table that we downloaded earlier. File -> Load (ctrl + o) then pick sonic.ct

You should see something like that:

image

Scroll down a bit, the table and look for the "Lives" address.

image

Now here's where the magic starts: Right click on lives -> "Find out what writes to this address". Then press Yes when it asks this:

image

Cheat Engine is now currently looking at everything that will change your life counter, from death to getting a new life.

If you play Emerald Coast for a bit, you can grab a new life after the first CheckPoint.

Once you grab it, go back to Cheat Engine and you should now have a window showing this:

image

Hm? What is this? Well Jack, this is the address that gave a life to Sonk. You can copy it and paste it in the disassembly.

image

And then...

image

Wow would you look at that? We found the function where the game sets and remove a life to Sonk.

Going further

Now you know how to do basic navigation on IDA, how to get a function call from reference and how to find an address with Cheat Engine. In a different guide, we will learn how to edit all of that to do more fancy stuff. Using WriteCall to hook a function, or WritaData to edit memory.

The best way to learn is to experiment yourself and watch other people code of what they did. Most modders upload their code on GitHub so you can study that. I personally learned C mostly by reading SADX disassembly and reading other people code, although I had to get the basic of C from a guide first.