Skip to content

ROM Hacking Notes

AlaryVanEeckhout edited this page Apr 26, 2026 · 63 revisions

Useful external tools for NDS ROM Hacking

Specs Info

Emulating

Modifying

  • Crystaltile2 (Translation incomplete, can be unstable and crash at times, but still very much usable and extremely useful)
  • Tinke (old, no longer supported. more info on the linked page)

Reverse-Engineering

  • Ghidra with the NTRGhidra Extension
  • No$GBA (Interface is not the best, but it somewhat works. A GBA and NDS emulator with breakpoints and other essential debugging features.)
  • Nitro Debugger (it's old and lacks clarity in how you're supposed to make it work)

Info on file types

  • BIN: Binary file. Default file type. Used to store any kind of data(from code to graphics to dialogue text).
  • SDAT: Sound Data file. Can be opened with VGMTrans (MKDS Course Modifier shows SSEQ instructions and can play individual SWAV files within SWAR files. CrystalTile2 can also open it, but has less features. More info here).
  • VX: movie file. Has not been entirely decoded yet (the actimagine package can now decode and re-encode the video (not audio) properly enough to be read by the game without any problems. here is an interesting read on the format)

Mega Man ZX Advent only

  • NBFC: Nitro Basic File Character
  • NBFP: Nitro Basic File Palette
  • SRL: self-contained ROM. Contains ndsheader, arm9, arm7, bit-filled fnt, and banner.
  • AHX: audiovisual effect file.

File Structures (WIP)

Bin files have a header with data such as the amount of pointers (referred to here and in the editor as "Entry Count") and the pointers (4 bytes each: 3 bytes for relative address, 4th byte being an lz10 compression indicator with a value of 0x80 if compressed and 0x00 otherwise), followed by the End-Of-File pointer allowing us to determine file size.

Dialogue file

This kind of file is named with "m_" or "talk_" at the start,
then a letter depending on what kind of dialogue it is (ex = extra, gd = guardian, hn = hunter, m = mission, q= quest, sys = system, tw = town),
a two-digit number representing when the dialogue appears chronologically,
two letters indicating the language (en or jp),
and a number based on the version of the story (1 = Vent/Grey, 2 = Aile/Ashe)
At 0x00: File size
At 0x02: Header size
From 0x04 to 0x04 + 2*Header size: pointers to dialogue text

Font file

At 0x00: Char width (must be an even number)
At 0x02: Char height
At 0x04: Indexing space (the amount of space each char takes up in file)
At 0x08: Char count (Info never directly used; =file size/indexing space)
At 0x0C: File size
At 0x10: Unused string (probably the path of the source bitmap file before it was converted to bin)

Level file

At 0x00: Entry Count (mostly 7, but 3 for Debug Room)
At 0x04: pointer to level data (comprssed)
At 0x08: pointer to gfx table
At 0x0C: pointer to palette table
At 0x10: pointer to ??? (background/sky related?)
At 0x14: pointer to animated palettes
At 0x18: pointer to level data for radar scope (the same for Model PX and LX, comprssed)
At 0x1C: pointer to End-Of-File

Level data

At 0x00: pointer to meta-tile definition
At 0x04: pointer to meta-tile collisions
At 0x08: pointer to screen definitions (how meta-tiles are placed in each unique screen of the stage; Each screen is 16x12 meta-tiles, each meta-tile is stored in one word)

Graphics Table

Chunks of 16 bytes
At 0x00: relative pointer to start of graphic
At 0x04: data size, oam_tile_indexing, oam_tile_offset
At 0x08: ???
At 0x0C: relative pointer to end of data
At 0x10: 00 00 08 00

Palette Table

At 0x00: Entry Count
From 0x04 To 0x04 + 4*EntryCount: pointer to palette header

Palette Header

The data at 0x04 and 0x08 is used to represent each palette (Palettes are stored in BGR15 format)
At 0x00: Palette count
At 0x04: ID of palette (?)
At 0x08: pointer to palette

Level overlay

Overlays are compressed with BLZ (Backwards LZ10). The level related overlays (from 43 to 116 in ZX) contain data for entity placement, screen layout on each layer, camera scroll modes, and additional screen-related parameters. The structure of the levels is seemingly the same as in Rockman Zero 3

Entity Slots

From 0x00 to End: 12-byte Entry (attr: 1 byte, kind: 1 byte, subkind: 1 byte, role: 1 byte, modifier: 1 byte, unknown: 7 bytes)

Entity Coordinates

At 0x00: 0x80000000 0x8000 0x0000
From 0x08 to End-0x08: 8-byte Entry (x: 4 bytes, y: 2 bytes, slotID: 2 bytes)
At End: 0x7FFFFFFF 0x7FFF 0x0000

Screen layout

At 0x00: Real width (determines used layout space)
At 0x01: skip (?)
At 0x02: width (determines how screens wrap)
At 0x03: height
From 0x04 to 0x04 + width*height: screen ID

Pointer table

The most important structure in the overlay. Has pointers to essentially everything background-related in the file.
Unfortunately, the table is not at the start of the overlay, and there are no pointers to it in the file. Instead, the main ARM9 file contains a list of pointers to those tables. Note: in both ARM9 and overlays, pointers are in RAM instead of being relative to ROM.

At 0x00: ???
At 0x04: pointer to first table
At 0x08: pointer to tileset/screenset name
At 0x0C: 00 00 00 00
At 0x10: pointer to main layer screen layout
At 0x14: pointer to background (?) screen layout
At 0x18: pointer to far background (?) screen layout
At 0x1C: pointer to foreground (?) screen layout
At 0x20: pointer to radar screen layout
At 0xC8: pointer to tileset offset (?) map
At 0xEC: pointer to unknown table (has pointer to outside of overlay)
At 0xF0: pointer to screen behavior (?) map
At 0xF4: pointer to camera scroll screen layout

Model file

Contains packed geometry commands

At 0x00: Entry Count
From 0x04 to 0x04 + 4*Entry Count: pointers to 3D models
At 0x04 + 4*Entry Count: File size

Model Header

At 0x00: Name Count (?)
From 0x04 to 0x04 + 0x4C*Name Count: Name string (0x40 bytes), ??? (0x4 bytes), ptr to geometry (0x4 bytes), geometry data size (0x4 bytes)
At 0x04 + 0x4C*Name Count: 3D data

OAM file

At 0x00: Entry Count
From 0x04 to 0x04 + 4*Entry Count: pointers to OAM sections
At 0x04 + 4*Entry Count: File size

OAM Section

At 0x00: pointer to OAM Table
At 0x04: pointer to Animation Table
At 0x08: pointer to Palette Table
At 0x0C: pointer to ???

OAM Table

At 0x00: 04 00 00 00 (constant 4-byte value)
At 0x04: pointer to OAM (2 bytes)
At 0x06: Object count
At 0x07: Graphic Section ID

OAM

Shapes are Square (1x1, 2x2, 4x4, 8x8), Wide (2x1, 4x1, 4x2, 8x4) and Tall (1x2, 1x4, 2x4, 4x8).
The exact dimensions are selected using sizeIndex.
At 0x00-0x01: Tile ID (0x000 to 0x3FF)
At 0x01: Tile attributes (0x04 = horizontal flip, 0x08 = vertical flip, & 0x30 = sizeIndex, & 0xC0 = shape)
At 0x02: X position
At 0x03: Y position

Animation Table

At 0x00: 04 00 00 00 (constant 4-byte value)
At 0x04: pointer to Animation (2 bytes)

Animation

Animations are just groups of two bytes (Frame ID, Frame Duration).
However, there are special values (duration 0xFE = Frame ID becomes looping point index for animation; duration 0xFF = end animation; duration 0 = delay of 0xFF frames).
At the first frame of an animation, the special values have no effect, and instead duration values will act as expected.
At 0x00: OAM frame index
At 0x01: Frame duration

Palette Table

At 0x00: Palette Count
At 0x01: Amount of colors by which palette should be shifted to the right
At 0x02: Last color index for palettes
At 0x03: ??? (usually 0x00?)
At 0x04: BGR15 color palette (2 bytes per color)

Palette Animation file

At 0x00: Entry Count
At 0x04: pointer to animation table
From 0x08 to 0x08 + 4*(Entry Count - 1): pointer to palette (by chunks of 2 BGR15 colors)
At 0x04 + 4*EntryCount: File size

Animation table

Animations are structured the same as in OAM files
At 0x00: Header size
From 0x00 to 4*Header size: pointers to animations

Palette

At 0x00: Frame Count
At 0x01: Color slot 0 (index of color in 4bpp palette that will be replaced during animation)
At 0x02: Color slot 1

Note

Level data

The game contains files that are named after its areas (example: a01.bin for area A-1, l01.bin for area L-1, x02.bin for area X-2. t01.bin is the "Test" area, aka the debug room).
Those files contain data that is directly related to the corresponding (sub) area (l01.bin contains data for rooms in L-1 and x02.bin contains data for rooms in X-2). Those files contain level data (tile set, collision set, screen tiles) that has been compressed with Lempel-Ziv 77 type 0x10 (A.K.A. LZ10), 8bpp graphics (uncompressed if used for graphics animation), color palettes. The room layouts and entity placements are stored in ARM9 overlays loaded at RAM address 0x02194000.

ZXA Sprites

In this game, not all tiles are 8 per 8 pixels. In fact, it looks like all graphics (for sprites, at least) have a tile width that corresponds to the width of the graphic itself. For instance, Vent/Aile Model ZX have a tile width of 0x20 for their body while the hair and some helmet parts right after that instead have a width of 0x10 and the hand tile right before is 0x8 pixels wide. Having a tile width that isn't 8 is not very practical for loading graphics to VRAM. However, the corresponding OAM entries are in a different format that allows to change the tile width that should be used for the graphics of each object, and sprites (as well as level screens on the foreground?) in this game appear to be rendered by the 3d engine, strangely enough.

Other

https://gbatemp.net/threads/gbatemp-rom-hacking-documentation-project-new-2016-edition-out.73394/
https://gbatemp.net/threads/how-can-i-see-the-code-in-a-nds-file.629210/#post-10110225
https://haroohie.club/blog/2022-10-19-chokuretsu-compression
https://www.starcubelabs.com/reverse-engineering-ds/
https://wiki.vg-resource.com/Nintendo_DS

Home
ROM Hacking Notes

ZX
USA JP
RAM map RAM map
ROM map ROM map
Value Tables
Dialogue Mugshots
Dialogue Names
Font Chars
Value Tables
(Possibly
same values,
but unconfirmed)
Font Chars
ZX Advent
USA JP
RAM map RAM map
ROM map ROM map
Value Tables
Dialogue Mugshots
Dialogue Names
Font Chars
Value Tables
(Possibly
same values,
but unconfirmed)
Font Chars

Clone this wiki locally