News:

11 March 2016 - Forum Rules

Main Menu

Guide for NDS hacking?

Started by a_friendly_irin, March 11, 2023, 04:05:38 PM

Previous topic - Next topic

a_friendly_irin

I have experience hacking SNES games, but I'm finding myself a bit lost when it comes to more complex NDS files, and the NDS documents on this site aren't very detailed. Is there some sort of primer on how best to hack NDS games? I know how to extract the assets, but I'm interested in manipulating code.

The particular game I'm looking at is SMT: Devil Survivor, and I'd like to change some of the text as well as a few gameplay mechanics. I've found the text I'm looking for (it's in the ARM9 file), but I'm not sure how to find the pointer table, or if pointer tables even work remotely like they do in SNES ROMs.

For SNES hacking I used DiztinGUIsh and bsnes+ for debugging; are there analogous programs for disassembling and debugging NDS games?

FAST6191

Ah that is unfortunate for a first hack, though could be overlays I guess. The arm9.bin file is the main piece of code that runs commercial games (the arm7 is largely a library, so generic you can copy-paste it between games of similar vintage with no ill effect).

Most DS stuff is file level based for the pointers but as the ARM9 is copied there on boot to stay there throughout then most things within it (many data things have been fished out the binary) tend to reference its location during runtime.
The location of such things is known
http://web.archive.org/web/20210706214637/https://no-intro.org/gbadat/tools/ndsts-b2-en.zip from http://web.archive.org/web/20220324051254/https://no-intro.org/tools.htm for the sake of something you can readily grab it from but there are plenty of other things that will tell you.

If it is just menu entries many have tried to match lengths of things here. Otherwise yeah the pointers will likely reference the 02?????? range https://problemkaputt.de/gbatek.htm#dsmemorymaps where the arm9 ends up landing.


Debugging wise. You have a few choices.
no$gba is https://problemkaputt.de/gba.htm one such thing, some don't get on well with it though as its UI takes a bit of getting used to. There are ways to have it speak to crystaltile2 (wonder DS hacking tool -- does graphics better than most dedicated tile editors, some audio, files, hex, assembly, some text, compression, is aware of a variety of files...) https://www.romhacking.net/utilities/818/ as well, especially using the NEF format.
desmume more recently came back and had some nice debugging bridges added to it to use with other tools. https://wrongbaud.github.io/posts/ghidra-debugger/ is for the GBA but it is the GNU compilers GDB format that is aimed for so the general principles apply whatever debugger you care to throw at it (granted that mostly comes down to ghidra, radare2 and IDA for non PC stuff).
melonds seems to be favoured by the kids. https://melonds.kuribo64.net/

You can do static as well, though that will be informed more by running code than anything you want to go in cold on.

I tend to use an old script for my assembly purposes but these days you would be better pointed at ARMIPS
https://github.com/Kingcom/armips

If the ARM9 binary is compressed (naturally it won't be at runtime) then the DS binary compression is different to standard ones. https://www.romhacking.net/utilities/826/ should have a BLZ one for the task.

If you need free space in the binary then if this is a wifi game the wifi error messages tend to be included within the arm9 as well and it is not like a) anybody ever probably got some of the weird and wonderful ones and b) it is much of an issue today (while third party replacement servers exist then yeah).

sharksnack

Took a quick look at one of the text sections in arm9.bin just now.

Not sure if this is actually correct since I A) went ahead and assumed it's Shift-JIS instead of a custom encoding, and B) didn't check very many entries, but it seems to line up at first glance?


FAST6191

Most shiftJIS is not strict shiftJIS (certainly a rare occasion for it support the 8 bit/u8 unicode that it officially supports) but reasonable enough assumption if you are using the Japanese aspect ( http://rikai.com/library/kanjitables/kanji_codes.sjis.shtml ). Other than compression only thing likely to trouble you there is if the game uses some kind of 8 bit formatting value somewhere (end of line, end of section, placeholder or such) which will then mean you lose presumably alternating sections as the formatting brings it in and out of line with the 16 bit multiples that a crude decoder will expect.

Anyway that looks like something, guess they went with calculated values for this one which is nice of them I guess (probably smaller as well). Though as the section goes on it probably goes up from 1 byte to 2 bytes (or was 2 bytes all along and for your example you dropped the 00/left it in the boxed highlights) and maybe in need of a flip because endianness.
Only thing I might look to see if I can spot beyond that is a length of section indicator/number of pointers (or files in archive if this was an archive format), be it for the pointers (kind of pointless here as you are likely not adding anything, still a common enough occurrence in pointer sections in DS games and quite useful when you are pulling something apart) or inclusive of the text section (which may have a further pointer/size value elsewhere -- I don't know if the shiftJIS text above it saying Positions is a part of the format or another section. We have then seen pointers-text section-pointers-section-pointers-section before in some games and shuffling those forward as it were would be troublesome).

a_friendly_irin

Oh, yes, the text is in ShiftJIS. What surprised me was that the English text appears to be in special Japanese characters instead of regular ASCII ones, which further complicates things. I assume it wouldn't work if I replaced them with regular characters?

Thanks for the links, I will look into them when time permits.

Jorpho

Quote from: a_friendly_irin on March 12, 2023, 09:23:17 PMOh, yes, the text is in ShiftJIS. What surprised me was that the English text appears to be in special Japanese characters instead of regular ASCII ones, which further complicates things.
Why would that be surprising..?

QuoteI assume it wouldn't work if I replaced them with regular characters?
No, replacing Shift-JIS characters with ASCII will probably not work.
This signature is an illusion and is a trap devisut by Satan. Go ahead dauntlessly! Make rapid progres!

a_friendly_irin

Quote from: Jorpho on March 13, 2023, 01:33:41 AMWhy would that be surprising..?
Shift-JIS also supports the ASCII Roman characters, does it not?

FAST6191

Quote from: a_friendly_irin on March 13, 2023, 12:25:18 PMShift-JIS also supports the ASCII Roman characters, does it not?

On your PC. Yes.

On the DS (and probably most other consoles that are not glorified PC recompiles)... I am going to struggle to get to 5 examples* out of the at this point thousands of things using the rikai link listing of shiftJIS. It is far easier to have a 16 bit decode plus whatever markup and placeholders than it is to do true unicode style approaches.

*and one of those might have to be a one line 8 bit, next line 16 bit effort rather than PC/strict compliance with the standard.

Depending upon the game and the font the particular part uses you might be able to add something more easily (NFTR fonts can have new symbols added reasonably enough compared to most things, nftredit being a good start for a tool on that one) but depending upon the game then most hackers just make do with the region the Japanese set provides.
If you need to type in it then the various Japanese text editors (JWPCE, njstar and some others) do have it as an option -- on the buttons in the menu bar will be A,J and a kanji symbol, J and save as shiftJIS should be it.

The main reason for hackers to go for the effort of changing things though is the ones usually included in the font are pig ugly, probably fixed width, if space is going to be a premium (not in the ROM but RAM and maybe the text format itself could pose some limits) and that is less fun if you are going for a big RPG as opposed to a nice menu and a bit more for a puzzle game.

a_friendly_irin

#8
Okay, I finally had time to work on this again. I'm using No$GBA for debugging, however I can't tell how its data panel corresponds to the ARM9. What it considers address 0 corresponds to address 175060 in the ARM9, and after 5B0 bytes it changes to something else (presumably a different file, but I can't find it). This makes it hard to find relevant memory addresses. I'm not sure if there's something obvious I'm missing here.

Additionally, is there a program to convert ASCII Roman characters into the special SJIS Roman characters? Having to cross-reference with a SJIS table and input the hex values manually is quite tedious.

The text I'm currently trying to edit are the demon race names, which start at 0155380 in the ARM9. By changing the length of some of the strings I can tell that the pointers point to the beginning of each string, however I cannot find anything that looks like the corresponding pointer table.


The only place it seems like a pointer table could be is the section I highlighted, but it doesn't look like a pointer table. Is it possible for the pointer table to be located after the text data?

If this were an SNES ROM I would make a read breakpoint in bsnes+ at the text location, but I can't figure out how to make read breakpoints in No$GBA or DesMuMe.

FAST6191

For the shiftJIS Roman stuff then most use something like njstar, jwpce or one of the similar Japanese word processors
https://www.at-it-translator.com/jwpce/ looks like a reasonable link for a current ish version.

I forget the exact procedure but it is along the lines of on the top row there is a button saying A, one saying J and some kind of Kanji.
A is presumably ASCII, J is what you want I think and the other is what it is.
Typing normally on the keyboard and saving as shiftJIS should then give you something to copy-paste if you want to go that way.

Alternatively without checking there should be a fairly simple relationship between ASCII/U16 and the shiftJIS eventuality along the lines of add a given value (or expand to 16 bit and add a value) which is not the hardest thing to code.

You may also like to add https://www.romhacking.net/utilities/504/ to the arsenal if I did not note it already.

I am not sure where you confusion is coming in for the ARM stuff.

The ARM9 gets possibly decompressed (using BLZ/binary compression rather than conventional BIOS style LZ, https://www.romhacking.net/utilities/826/ , beware of false positives with crystaltile2's DS file system viewer) which might account for the change in data (any encryption should long since have been sorted by the time you are playing with ROMs, though there are some that annoy things. Overlays tend to be their own section of memory rather than intermingled, don't know if text would be left as incbin where pointers were shuffled off to an overlay but stranger things have happened).
After that it gets shoved into memory but not always at the start.
ndsts from
http://web.archive.org/web/20220727151757/https://no-intro.org/tools.htm
should tell you where things are, among many other things (crystaltile2 has some, ndstool probably has something), if you did have some encryption bothering things there is also the main tool there to handle it.

All its pointers and whatnot then play to that rather than file level stuff. Also as the DS ROM is not memory mapped it can make things there a bit trickier if coming from older systems where things are more mapped. In those cases you are more likely to be watching the B7 command detailed in http://www.problemkaputt.de/gbatek.htm#dscartridgeprotocol , though here if it is theoretically in memory then all good.

Desmume has very limited onboard debugging, though it does support gdb link/bridge
https://wrongbaud.github.io/posts/ghidra-debugger/ for using the same thing with ghidra on a GBA emulator (which probably was the basis for this), others use IDA there (there should be a plugin/definitions file/whatever they call their list of known hardware locations to boost it from being straight ARM and nothing else around somewhere, though was for an older version when I last saw), I guess you could also use the GNU debuggers as well if you are a masochist. Not sure if radare2 (the third of the big non x86 debugging tools/other major open source effort) does much here but also an option.

no$gba is frequently a source of annoyance, has always worked for me though. For the sake of others reading you do need to get the debug version which these days is free.
It does also support/make NEF files which crystaltile2 can also read, and pull things from. https://problemkaputt.de/gbatek-debugging.htm for more in general, NEF stuff should be in there somewhere as well.

There are a few older emulators with even more limited things here, and people tell me melonds has stuff going on these days but I am not sure.

Re pointer tables after text data. Sure nothing wrong or even all that odd about that. I don't have the most examples of footer driven file formats on the DS compared to conventional header or alternating pointer-data section-pointer-data section approaches but given most things get shoved in memory and it is a 32 bit system then does not even really trouble pointer maths if you are coming to us from something with more limited relative jumps or something.

a_friendly_irin

#10
Alright, I finally succeeded. The untranslated "Touki" race in Devil Survivor is now in English!


(yes I know Touki and Brutes are different races in SMT lore, I'm following DeSu's lead on condensing races for simplicity)

For future generations, here's what I did:

  • Identified the location of the text data with Hexecute, the only hex editor I found that supports SJIS encoding.
  • Created a breakpoint in No$GBA's debug mode to trigger whenever this location was referenced in memory.
  • Breakpoint found an opcode using r0 as a text pointer.
  • Set a new breakpoint to trigger when r0 = the pointer value.
  • Followed a daisy-chain of registers and memory addresses playing hot potato with the pointer value until I finally found the source location.

In this case, the pointer table was indeed immediately after the text data, rather than before as I was used to in previous ROMs I hacked. Another thing that tripped me up was that the pointers were long rather than short -- they were 4-byte doublewords pointing to the text's location in absolute memory, and thus added the 02000000 value for the ARM9's starting location in absolute memory. Knowing this, I may be able to locate pointers through simple search in the future.

Next up: Nudging the position of demons' names in the status screens right to make room for longer race names. How is BG data handled by the DS? The debugger says the BG I want has a base address of 0x06207000, but I don't know what file or area I should be searching. (That section in the ARM9 memory is just a sequentially increasing list of bytes.)

FAST6191

The DS has three elements to its graphics
1) OAM/sprites
2) BG/backgrounds
3) 3d.

3d is kind of its own thing and gets blended back in the end. Seen it for "2d" games (New Super Mario Brothers being a good example) but not seen it for text like is seen in the PS1.

2d stuff is mostly an enhanced version of the GBA but with 2 virtual screens/engines (technically different in their capabilities) which in turn was an enhanced version of most of what came before (sounds like you are familiar with the SNES, should be right at home with this).
The OAM handles the sprites aspect where it is usually a map that handles the BG tile layouts. I have seen map files and I have seen them generated from code.
Text tends to be handled by the BG which would also include the backgrounds surrounding text if editing those. Where any logic might sit regarding lengths might also be considered.

If you want to build it up from the GBA then http://coranac.com/tonc/text/ is good stuff and gbatek does it for GBA and DS. https://problemkaputt.de/gbatek.htm#dsvideobgmodescontrol

Also crystaltile2 has shiftJIS decoding, bonus has a note which file it corresponds to in the bottom status bar. In hex viewer click the bar above the text decode aspect and it should give the option (assuming you don't just feed it a table file https://www.romhacking.net/?page=documents&category=&platform=&game=&author=&perpage=20&level=&title=table&desc=&docsearch=Go ).

a_friendly_irin

To be clear: Does No$GBA break on the line that triggers the breakpoint condition, or the line immediately after? Because when I try to set a breakpoint for writing to the map/tile memory addresses, it keeps triggering on a line that doesn't seem to reference those addresses:
ldr r1,[r2] when r2 = 040000B0 and [040000B0]=00000000. The only explanation I can think of is that the write to video memory happened immediately before, followed by a subroutine jump to this line.