Created additional documentation for setup and basic how-tos

This commit is contained in:
Hexalotl
2024-01-19 18:18:12 -08:00
parent f6a2187b0f
commit 0b7ee5560e
22 changed files with 270 additions and 2 deletions
+9 -2
View File
@@ -17,7 +17,7 @@ Use `--recursive` when cloning to have ppcdis in the repository.
### Docker
1. Dump a copy of the game and extract **main.dol** and **foresta.rel.szs**.
1. [Dump a copy of the game](./docs/extract_game.md) and extract **main.dol** and **foresta.rel.szs**.
2. Decompress **foresta.rel.szs** with yaz0 found in *tools/* (`yaz0 -d foresta.rel.szs foresta.rel`).
3. Place **main.dol** and **foresta.rel** in *dump/*.
4. Place **forest_1st.arc** and **forest_2nd.arc** in *dump/*.
@@ -32,7 +32,7 @@ Use `--recursive` when cloning to have ppcdis in the repository.
> ️ When building manually from a work directory originally used for Docker, you will need to run `sudo ninja -t clean` for the build to execute properly.
1. Dump a copy of the game and extract **main.dol** and **foresta.rel.szs**.
1. [Dump a copy of the game](./docs/extract_game.md) and extract **main.dol** and **foresta.rel.szs**.
2. Decompress **foresta.rel.szs** with yaz0 found in *tools/* (`yaz0 -d foresta.rel.szs foresta.rel`).
3. Place **main.dol** and **foresta.rel** in *dump/*.
4. Place **forest_1st.arc** and **forest_2nd.arc** in *dump/*.
@@ -53,6 +53,13 @@ Use `--recursive` when cloning to have ppcdis in the repository.
12. Run `python3 configure.py`.
13. Run `python3 build.py`.
## Quick Guides
- [Dumping Game Files](./docs/extract_game.md)
- [Ghidra Setup](./docs/ghidra_setup.md)
- [Generating Decomp Context](./docs/generating_decomp_context.md)
- [Ghidra Basics](./docs/ghidra_basics.md)
- [Decomp Basics](./docs/decomp_basics.md)
## Credits
- jamchamb, Cuyler36, NWPlayer123 and fraser125 for past documentation of Animal Crossing.
+59
View File
@@ -0,0 +1,59 @@
# Decompilation Basics And Tips
## Determining Slice Boundaries
When adding in a new Translation Unit (TU) you currently need to manually calculate the addresses for the TU's section boundaries. You can determine the boundaries for a new TU by using the [symbol map files extracted from the game](./extract_game.md) and adding an offset to the addresses.
If using the symbol map, search for `<TU_NAME>.o` to find each applicable section, its start address and end address (usually the address of the next address with a different TU name attached to it). Note that some TUs may or may not have certain sections. You can determine this by searching through the symbol map and noting which sections are found.
The address offsets to add for each section in `foresta.rel` are:
| Section | Offset | Usage |
|------------|--------------|--------------------|
| `.text:` | `0x803702A8` | Code |
| `.rodata:` | `0x80641260` | Const data |
| `.data:` | `0x8064D500` | Non-const data |
| `.bss:` | `0x8125A7C0` | Uninitialized data |
Once the boundaries have been determined, paste them into the [slices file](../config/rel_slices.yml). You will then have to re-run the [configuration script](../configure.py) after modifying the file.
> ### Example (ac_dummy.c)
>
> #### Symbol Map
>~~~
> ...
> 00052540 000024 00052540 1 .data ac_dummy.o
> 00052540 000024 00052540 4 Dummy_Profile ac_dummy.o
> 00052568 0002a0 00052568 1 .data m_all_grow_ovl.o
> ...
> 0019f590 000010 0019f590 1 .text ac_dummy.o
> 0019f590 000004 0019f590 4 Dummy_Actor_ct ac_dummy.o
> 0019f594 000004 0019f594 4 Dummy_Actor_dt ac_dummy.o
> 0019f598 000004 0019f598 4 Dummy_Actor_draw ac_dummy.o
> 0019f59c 000004 0019f59c 4 Dummy_Actor_move ac_dummy.o
> 0019f5a0 005b84 0019f5a0 1 .text m_all_grow_ovl.o
> ...
>~~~
> #### Calculation
>~~~
> .data start: (0x00052540 + 0x8064D500) = 0x8069FA40
> .data end: (0x00052568 + 0x8064D500) = 0x8069FA68
>
> .text start: (0x0019F590 + 0x803702A8) = 0x8050F838
> .text end: (0x0019F5a0 + 0x803702A8) = 0x8050F848
>~~~
> #### Final
>~~~
>ac_dummy.c:
> .data: [0x8069FA40, 0x8069FA68]
> .text: [0x8050F838, 0x8050F848]
>~~~
## Generating Assembly Text File
To use sites such as [decomp.me](https://decomp.me) or [m2c](https://simonsoftware.se/other/m2c.html) you will need to paste in the assembly code you wish to match. The easiest way to get the assembly is by first generating an assembly text file with symbols included. To create this file run the following command at the root of the repository:
~~~console
python3 tools/ppcdis/disassembler.py config/rel.yml build/rel_labels.pickle build/rel_relocs.pickle rel.s -m config/symbols.yml
~~~
This will generate a `rel.s` file. Once generated open the file and search for the name of the function you wish to match and copy the assembly listed in the file for that function.
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

+51
View File
@@ -0,0 +1,51 @@
# Game Files Extraction
As this repository does **not** contains any game assets you will first need to extract files from an existing copy of the game.
This repository support the US version of Animal Crossing:
- `GAFE01`: Rev 0 (USA) `sha1: 2d2b1fa3883f49af779ce9ca133db3be17be8f32`
## Dolphin Emulator
Files can be extracted from a copy of the game using [Dolphin Emulator](https://dolphin-emu.org/). Use the following steps to extract the necessary files:
1. Install Dolphin onto your computer.
2. Place your copy of Animal Crossing into your Dolphin game directory.
3. Right-click on the Animal Crossing entry and select "Properties".
![Dolphin Properties](./doc_assets/dolphin_properties.png)
4. Select the "File System" tab at the top of the opened dialog.
5. Right-click on the disc.
6. Select "Extract Entire Disc".
![Dolphin Extract](./doc_assets/dolphin_extract.png)
7. Select a convenient folder to extract to.
## WIT
Alternatively you can extract the necessary game files using [WIT](https://wit.wiimm.de/). Follow these steps to extract the necessary files:
1. Download the archive appropriate to your OS and architecture.
2. Extract the contents of the archive. Follow the installation instructions included in the `INSTALL.txt` file.
3. Once installed run the following command:
~~~~console
wit EXTRACT <PATH_TO_GAME_COPY> <PATH_TO_OUPUT_FOLDER>
~~~~
## Extracted Files
Once files have been extracted you will need to copy the following files into the `dump/` folder at the root of the repository:
- `main.dol`
- `forest_1st.arc`
- `forest_2nd.arc`
- `foresta.rel.szs`
Make sure to rename `main.dol` to `static.dol`.
You will also need to decompress `foresta.rel.szs` using `yaz0` found in `tools/` using the following command:
~~~~console
yaz0 -d foresta.rel.szs foresta.rel
~~~~
It is recommended that you also copy the following symbol maps for reference:
- `foresta.map`
- `static.map`
+35
View File
@@ -0,0 +1,35 @@
# Decompilation Context
In order to use tools such as [decomp.me](https://decomp.me/), [m2c](https://simonsoftware.se/other/m2c.html), or [Ghidra](https://ghidra-sre.org/) more effectively you will need to generate a "context" file that contains all of the necessary functions and structures needed to properly parse extracted blocks.
To help make this easier you can use the [`decompctx.py`](../tools/decompctx.py) script located inside of the `tools/` folder. This script recursively includes and expands all of the header files used by the specified file.
## Generating Context
In order to generate the context for a given file run the following command:
~~~console
./tools/decompctx.py <PATH_TO_C_FILE>
~~~
This will generate a `ctx.h` file at the root of the project. You can then copy the content of this file to the tool of your choice.
The script attempts to use the `N64_SDK` environment path variable for the necessary [ultralib](https://github.com/decompals/ultralib) header files. If this environment variable has not been set, or if you'd like to use an alternative SDK path, a path can be provided by using the `--n64-sdK` flag (see below).
If generating context for Ghidra or m2c, use the `--ghidra` or `--m2c` respectively as those tools require specific changes to be made to the generated context.
## Tool Arguments
You can modify the output of the context by passing in specific arguments. Some tools may require specific options to be turned on or off. For convenience certains tools have flags that automatically set these options.
| Argument | Description |
|-----------------------------|----------------------------------------------------------------------|
| `--ghidra` | Outputs Ghidra-friendly context. |
| `--m2c` | Outputs m2c-friendly context. |
| `-o` | Specifies a specific path to output the context file to. |
| `-r` | If the context file should be output relative to the source file. |
| `--n64-sdk` | Specify the top-level path of the N64 SDK. |
| `--strip-attributes` | If `__attribute__(())` usages should be stripped. |
| `--strip-at-address` | Strips out `AT_ADDRES()` and `:` uses. |
| `--convert_binary_literals` | Converts binary literals (0bxxxx) to decimal format. |
| `--clipboard` | Copies the contents of the generated context file to your clipboard. |
## Preprocessor Arguments
`decompctx.py` uses [pcpp](https://pypi.org/project/pcpp/) to preprocess and expand the header files used by the file argument. `decompctx.py` will automatically pass arguments to `pcpp`. For a list of additional preprocessor arguments you can use, please refer to the [pcpp page](https://github.com/ned14/pcpp).
+28
View File
@@ -0,0 +1,28 @@
# Ghidra Basics And Tips
## Redefinitions
The following operations require you to have structs and typedefs imported into Ghidra via a [context file](./generating_decomp_context.md) or created manually.
### Editing Function Signatures
You can change the signature of a function inside of Ghidra by right-clicking on a function's name and selecting "Edit Function Signature". Editing the signature allows you to change the return type, and add/edit any arguments that may be missing or incorrect.
![Ghidra Edit Function Signature](./doc_assets/ghidra_edit_function_signature.png)
### Renaming Variables
When reverse engineering a function it is often helpful to rename variables from their default names to more human-readable names. To do so click on the variable name and then either right-click and select "Rename Variable" or press the `L` key. Type in the new desired name and press "OK".
![Ghidra Rename Variable](./doc_assets/ghidra_rename_variable.png)
### Retyping Variables
Ghidra often mistypes variables when first importing and analyzing the game's binary file. As you use Ghidra you can retype variables in order to give you a better and more accurate decompile. To retype a variable, click on the variable's name **NOT** the variables type. Then either right-click and select "Retype Variable" or press `Ctrl + L`.
![Ghidra Retype Variable](./doc_assets/ghidra_retype_variable.png)
In the dialog that comes up select the type you want to change to.
![Ghidre Type Selection Dialog](./doc_assets/ghidra_data_type_dialog.png)
### Retyping Data
You can also retype data to known structs by selecting the piece of data's name in the "Listing" view. Then either right-click and choose `Data->Choose Data Type` or press `T`. Select the data type you wish to apply. You may get a warning that it will clear existing data. If you are confident that the selected data type is correct you can click "Yes".
![Ghidra Choose Data Type](./doc_assets/ghidra_choose_data_type.png)
+88
View File
@@ -0,0 +1,88 @@
# Ghidra Setup
[Ghidra](https://github.com/NationalSecurityAgency/ghidra) is a cross-platform, open-source program that can be used to help reverse engineer compiled code.
## Installing Ghidra
To install Ghidra, follow the [instruction on their project page](https://github.com/NationalSecurityAgency/ghidra?tab=readme-ov-file#install). This involves installing the listed requirements and downloading an archived release for your OS.
## Installing Ghidra GameCube Loader Plugin
To properly import and analyze the [game files you extracted](./extract_game.md) you will need to install the [Ghidra GameCube Loader Plugin](https://github.com/Cuyler36/Ghidra-GameCube-Loader).
Follow the steps below to install the plugin:
1. [Download an archived release](https://github.com/Cuyler36/Ghidra-GameCube-Loader/releases) of the plugin appropriate for the version of Ghidra you are using. Do not decompress the `.zip` file.
2. Navigate to the folder where Ghidra was installed.
3. Copy the plugin `.zip` file to `<Ghidra install directory>/Extensions/Ghidra/`
4. Start Ghidra.
5. Select `File->Install Extensions`.
![Install Extensions](./doc_assets/ghidra_install_extensions.png)
6. Make sure the checkbox next to `GameCubeLoader` is checked.
![Check Extension](./doc_assets/ghidra_install_extensions_window.png)
7. Press "OK".
# Importing Binaries
With both Ghidra and the GameCube Loader plugin installed you can now import the binaries extracted from the game for analysis. To do so follow the steps below:
1. Create a new Ghidra Project.
2. Select `File->Import File`.
![Ghidra Import File Dropdown](./doc_assets/ghidra_import_file.png)
3. Select one of the binary files you extracted: `foresta.rel.szs` or `static.dol`.
4. In the Import dialog, make sure that `Nintendo GameCube/Wii Binary` is selected for the format. Click OK.
![Ghidra Import Dialog](./doc_assets/ghidra_import_dialog.png)
5. After import is complete, find the binary in the project view. Open it by double clicking it.
6. Upon opening the file, you will get a prompt to analyze the file. Select "Yes".
7. On the Analyzer window, make sure that the `(GameCube/Wii) Program Analyzer` is checked. Click OK.
![Ghidra Analyze Dialog](./doc_assets/ghidra_analyze_dialog.png)
8. Wait for the analyzer to finish running.
The analyzer will import symbols for some of the functions, structs, and data used in the game. These symbols make it easier to reverse engineer code by giving us hints as to what specific functions do and help us match our code closer to the original code.
## Importing Context
You can optionally import a [context file](generating_decomp_context.md) to help populate Ghidra with structs and typedefs used in our reverse-engineered C code. This allows us to redefine function signatures and retype variables.
1. [Generate your context file](./generating_decomp_context.md) or copy your context from an existing source such as a [decomp.me](https://decomp.me/) scratch.
2. Got to `File->Parse C Source`.
![Parse C Source](./doc_assets/ghidra_parse_c_source.png)
3. On the Parse C Source dialog, press the green "+" button in the "Source files to parse" section.
![Parse C Source Dialog](./doc_assets/ghidra_parse_c_dialog.png)
4. Select the context file you wish to import. Please note that it has to have the `.h` extension.
5. Press the "Parse to program" button at the bottom of the dialog.
### Special Modifications
> :warning: Due to Ghidra's C parser not properly parsing certain attributes, some additional modifications will need to be made.
#### Struct Aligments
The Ghidra C parser does not properly parse alignments specified by the `_Alignas()` keyword or the `__attribute__((aligned()))` attribute. After importing your context, search for any uses of the `_Alignas()` or `__attribute__((aligned()))` and make note of the structs using them and the aligment values for each.
An example of a structure that would need to be fixed can be seen below:
~~~C
typedef struct original_texture_s {
u8 data[(32 * (32 / 2))];
} __attribute__((aligned(32))) mNW_original_tex_c;
~~~
In the above case, `mNW_original_tex_c` is aligned to `32` bytes. However, when imported to Ghidra, it will have an alignment of `1`. To fix the alignment follow these steps:
1. Open your project in Ghidra.
2. Navigate to the "Data Tpe Manager".
3. Search for the struct you need to re-align.
4. Right-click on the struct name and select "Edit".
![Data Manager Struct](./doc_assets/ghidra_data_manager_struct_edit.png)
5. Near the bottom of the Struct Editor dialog, look for `align (minimum)`. Select the middle option to manually enter the alignment. Please note that this is in hexadecimal, so be sure to convert any number to hex first.
![Struct Editor Dialog](./doc_assets/ghidra_struct_editor_dialog.png)
6. Hit the save button near the top of the dialog, or close the dialog and press "Yes" when prompted to save the changes to the struct.