NitroPacker is an open source, cross-platform utility for packing and unpacking Nintendo DS ROMs. It also can apply ASM hacks to both ARM9 and overlay files.
This code was written primarily by Ermelber and Gericom. Jonko has ported it to .NET 8.0 and made modifications to make it cross-platform and has added a number of features since the project was open sourced.
The primary purpose of NitroPacker is to pack and unpack NDS ROMs.
To unpack a ROM with NitroPacker, run the following command:
NitroPacker unpack -r PATH/TO/ROM.nds -o PATH/TO/UNPACK/DIRECTORY -p PROJECT_NAME
Replace the capitalized arguments with:
PATH/TO/ROM.nds
– the path to the Nintendo DS ROM you want to unpackPATH/TO/UNPACK/DIRECTORY
– the path to the directory you want to unpack the ROM toPROJECT_NAME
– the name of the project file that will be created on unpack (can be anything but usually should be the name of the game)
This command will unpack all the game's files and place them in the specified directory. The ROM's file system will go in the data
subdirectory, while
any overlays present will be placed in the overlay
subdirectory. The main ARM9 and ARM7 binaries will be placed in the root directory. Additionally, the created project file contains a bunch of metadata about the ROM, such as the ROM header, the overlay table, and the banner.
In order to disassemble or patch arm9.bin, you'll need it to be decompressed. If the arm9 binary is compressed, you can append the -d
flag to the above command to decompress it, e.g.
NitroPacker unpack -r PATH/TO/ROM.nds -o PATH/TO/UNPACK/DIRECTORY -p PROJECT_NAME -d
NitroPacker can only pack a directory that was previously unpacked with NitroPacker (or something structured exactly like that). To pack a ROM, run the following command:
NitroPacker pack -p PATH/TO/PROJECT_FILE.xml -r PATH/TO/OUTPUT_ROM.nds
The project file is expected to be in a directory with ARM9 and ARM7 binaries as well as the data and overlay subdirectories mentioned previously. If the ARM9 binary was decompressed previously, you will need to add -c
in order to compress it at this stage.
NitroPacker can also be used as a powerful tool to apply assembly hacks, but this functionality is a bit more complicated.
As mentioned above, NitroPacker relies on other programs to help with the assembling your hacks, namely, devkitARM and Make. DevkitARM is distributed
by devkitPro and can be downloaded from their website. They have a graphical installer for Windows (for which you need only select the NDS workloads)
and a package manager for Mac/Linux (for which you can run the command dkp-pacman -S nds-dev
to install devkitARM).
On Linux distros, Make can be installed from the package manager (e.g. sudo apt install make
). On macOS, you can use brew. On Windows, the easiest way to install it is with Chocolatey, where the command is choco install make
.
If either of these options presents a challenge for you or doesn't work for some reason, you can instead opt to use the alternate method of assembling
the code in Docker containers. After installing Docker Desktop or the Docker engine, ensure the engine
is running. Then, when calling NitroPacker, ensure you pass -d
followed by the Docker tag you want to use. If you're not sure which one to use,
we recommend choosing latest
. See devkitpro/devkitarm on DockerHub for more details.
You will need to move the unpacked arm9.bin
to a different directory with a specific structure:
src
overlays
main_HEXOVERLAYNUM
– the name here corresponds to the name of the overlay in the unpackedoverlay
directoryreplSource
– a directory containing subdirectories with instructions to be directly replaced in the specified overlayHEXLOCATION
– the location of an instruction to replaceHEXLOCATION.s
– a source file containing an instruction to replace at the specifiedHEXLOCATION
source
– a directory containing source files to append to the specified overlayfile.s
– ARM assembly source files that will be assembled and appended to the overlayfile.c
– C source files that will be compiled and appended to the overlayfile.cpp
– C++ source file that will be compiled and appended to the overlayfile.s.override
– a source file that will be assembled only if--override-suffix "override"
is passed to NitroPacker (and will replacefile.s
in that case)
symbols.x
– an editable symbols file that allows for naming specific offsets for use in specified overlay's source files
linker.x
– boilerplate linker file for overlaysMakefile
– boilerplate Makefile for overlays
replSource
– a directory containing subdirectories with instructions to be directly replaced in the ARM9HEXLOCATION
– the location of an instruction to replaceHEXLOCATION.s
– a source file containing an instruction to replace at the specifiedHEXLOCATION
source
– a directory contianing source files to append to the ARM9file.s
– ARM assembly source files that will be assembled and appended to the ARM9file.c
– C source files that will be compiled and appended to the ARM9file.cpp
– C++ source file that will be compiled and appended to the ARM9file.s.override
– a source file that will be assembled only if--override-suffix "override"
is passed to NitroPacker (and will replacefile.s
in that case)
arm9.bin
– the main ARM9 – must be copied in from the unpacked ROM directory.clang-format
– boilerplate CLang format filelinker.x
– boilerplate linker file for ARM9Makefile
– boilerplate Makefile for ARM9symbols.x
– an editable symbols file that allows for naming specific offsets for use in ARM9 source files
This directory structure should be copied from the asm_sample
directory in this repo. A fully fleshed-out example can be found in the ChokuretsuTranslationBuild repository.
Additionally, prior to assembling the ARM9, you will need to find the arena lo offset. This value can be found by searching for 0x37F8000
in the ROM.
IDA or Ghidra should be used to search for this value. Once you find it, you'll want to go back a few values until you see an offset that has a value
between 0x20C0000 and 0x20F0000 (typically, although it could be higher or lower!) – the offset (not the value) is the arena lo offset.
It will most likely be followed by two subroutines that look like:
MOV R0, R0,LSL#2
ADD R0, R0, #0x2700000
ADD R0, R0, #0xFF000
STR R1, [R0,#0xDC4]
BX LR
...
MOV R0, R0,LSL#2
ADD R0, R0, #0x2700000
ADD R0, R0, #0xFF000
STR R1, [R0,#0xDA0]
BX LR
Finally, source files may have any valid ARM assembly. To hook into a function and create a branch link to your code, the following format should be used:
ahook_02061344:
CODE_HERE
bx lr
This method will replace the instruction at 0x02061344 with a BL to your code.
Once this directory has been constructed, source files have been created, the arena lo offset determined, and the ARM9 has been copied in, the following commands may be used:
To assemble the hacked ARM9, run the following command:
NitroPacker patch-arm9 -i PATH/TO/SRC/DIRECTORY -o PATH/TO/OUTPUT/DIRECTORY -p PROJECT_FILE -a ARENA_LO_OFFSET [-d DOCKER_TAG]
The project file you need to supply is the one created by unpacking the ROM with NitroPacker. The project file is only needed for determining the ARM9's RAM address; if you would rather specify this address manually, you may use -r RAM_ADDRESS
instead.
This will assemble the hacks and append them to arm9.bin
, then copy the ARM9 to the output directory (which should be the directory you will then run
the pack
command on).
Note: To be able to use the patch-arm9
command, the arm9.bin
must be decompressed. See the Unpacking
section for more information on how to do this.
To patch the overlays, run the following command:
NitroPacker patch-overlays -i PATH/TO/ORIGINAL/OVERLAY/DIRECTORY -o PATH/TO/PATCHED/OVERLAY/DIRECTORY -s PATH/TO/OVERLAY/SOURCE -r PATH/TO/PROJECT/FILE [-d DOCKER_TAG]
To build the project from source, ensure .NET 8 is installed. After you have installed .NET, you should be able
to simply run dotnet build
from the terminal within the root directory and it will build the NitroPacker executable. You can also
open the solution in Visual Studio, Rider, or another IDE and build it from there.