TUTORIAL: Creating your own trainer for NDS Rom.

by: toenailed

I - Tools

II - Obvious Requirements

NOTE: If you didn't made the code, it is still a good idea to give credit to code searcher/hacker sometimes finding a one line code is more difficult than making a trainer.

III - Preparation

  1. First thing is to gather all tools and information
  2. Then converting a usual AR/CB DS Code  to ASM Routine, look below for example

Here's an Example, for this tutorial I Use the Following

 

Now here's how it looks like when it was translated as ASM

;Max Nook Points
ldr r0, =0x21D8FE4
ldr r1, =0x4E20
strh r1, [r0]

;Tom Nook is Never SOLD OUT
ldr r0, =0x21ECBE0
mov r1, #0x0
str r1, [r0]
str r1, [r0,#0x4]

;Catalog Items Only Cost 1 Bell
ldr r0, =0x22A925C
mov r1, #0x1
strh r1, [r0]

;Never Get Resetti
ldr r0, =0x21cd774
mov r1, #0x0
strb r1, [r0]

;Max/Infinite Bells
ldr r0, =0x021d891c
ldr r1, =0x1869F
str r1, [r0]

;Savings Account Full
ldr r0, =0x21d8fc0
ldr r1, =0x05f5e0ff
str r1, [r0]

PS. Don't Compile the ASM yet

III - Locating where to Hook and store ASM Routine

        Here's where all the Fun Start's, Finding where to Hook and store the ASM Routine can be relatively easy to annoyingly difficult. Different Hacker (or even in different game)  uses different approach/method. For this tutorial we will use the easiest method.

In this Tutorial with our example we will look for where the button routine occur, that's where we hook our ASM Routine

And we will store our ASM Routine on 0x2000010 in RAM, in most ROM it is located in @0x0004010.

NOTE:  This definitely is not the greatest idea since it might cause a culprit if you use dipstar along with this trainer and some flashcart stores some important data on those location, if you able to find  a better address/offset you should use that instead.

A.  Locating the Button Routine

    A-1. First Makes a RAM Dump

  1. First Run the ROM in Emulator, make sure that the game is fully loaded.
  2. Run Emuhaste or hasteDS
  3. Press [Snap DeSmuME/iDeaS/NeeDS/no$gba] for hasteDS or [Snap Process for Emuhaste], make sure it doesn't give an error
  4. Press [DUMP]/[File DUMP] then save the dump, name it with your own choice

    A-2. Locating the Button Routine here is 3 different method, you can use any of the following

            A-2a. METHOD 1: Using ndsdis2.exe

  1. Open the command prompt (Start => Run= > cmd)
  2. Goto directory where the ndsdis2.exe is located
  3. Type "ndsdis2 -NH9 0 [filename of dump] > dump.txt" (without quotes and close/open bracket)
  4. Open dump.txt in a text editor.
  5. Search for 0x04000130
  6. It might give more than one result but look for where there are occurance of "E12FFF1E bx r14".
  7. The offset location of "E12FFF1E bx r14" will be hooking address
  8. Since it stored in RAM we should add 0x2000000 so our final hooking address will be 0x020E7EB8

:000E7E44 E59F1074 ldr r1,[r15, #+0x74] ;r15+0x74=*(000e7ec0)=#67109168(0x04000130)
:000E7E48 E59F0074 ldr r0,[r15, #+0x74] ;r15+0x74=*(000e7ec4)=#12287(0x00002fff)
:000E7E4C E1D120B0 ldrh r2,[r1, #+0x0] ;r1+0x0=*(04000130)=#0(0x00000000)
:000E7E50 E1D310B0 ldrh r1,[r3, #+0x0] ;r3+0x0=*(027fffa8)=#0(0x00000000)
:000E7E54 E1821001 orr r1,r2,r1
:000E7E58 E0211000 eor r1,r1,r0
:000E7E5C E0010000 and r0,r1,r0
:000E7E60 E1A00800 mov r0,r0,lsl #0x10 ;r0=805240832(0x2fff0000)
:000E7E64 E1A04820 mov r4,r0,lsr #0x10 ;r4=12287(0x2fff)
:000E7E68 E59F1058 ldr r1,[r15, #+0x58] ;r15+0x58=*(000e7ec8)=#35603028(0x021f4254)
:000E7E6C E20400F0 and r0,r4,#0xF0
:000E7E70 E1A00220 mov r0,r0,lsr #0x4 ;r0=50327552(0x2fff000)
:000E7E74 E1D1C0B0 ldrh r12,[r1, #+0x0] ;r1+0x0=*(021f4254)=#0(0x00000000)
:000E7E78 E59F204C ldr r2,[r15, #+0x4c] ;r15+0x4c=*(000e7ecc)=#34821012(0x02135394)
:000E7E7C E1A03080 mov r3,r0,lsl #0x1 ;r3=100655104(0x5ffe000)
:000E7E80 E024E00C eor r14,r4,r12
:000E7E84 E1A00804 mov r0,r4,lsl #0x10 ;r0=805240832(0x2fff0000)
:000E7E88 E1A0C820 mov r12,r0,lsr #0x10 ;r12=12287(0x2fff)
:000E7E8C E59F003C ldr r0,[r15, #+0x3c] ;r15+0x3c=*(000e7ed0)=#35603032(0x021f4258)
:000E7E90 E19230F3 ldrsh r3,[r2, +r3]
:000E7E94 E004E00E and r14,r4,r14
:000E7E98 E59F2034 ldr r2,[r15, #+0x34] ;r15+0x34=*(000e7ed4)=#35603024(0x021f4250)
:000E7E9C E3A04000 mov r4,#0x0 ;r4=0(0x0)
:000E7EA0 E5C24000 strb r4,[r2, #+0x0] ;r2+0x0=*(021f4250)=#0(0x00000000)
:000E7EA4 E1C0E0B2 strh r14,[r0, #+0x2] ;r0+0x2=*(021f425a)=#0(0x00000000)
:000E7EA8 E1C1C0B0 strh r12,[r1, #+0x0] ;r1+0x0=*(021f4254)=#0(0x00000000)
:000E7EAC E1C0C0B0 strh r12,[r0, #+0x0] ;r0+0x0=*(021f4258)=#0(0x00000000)
:000E7EB0 E1C030B4 strh r3,[r0, #+0x4] ;r0+0x4=*(021f425c)=#0(0x00000000)
:000E7EB4 E8BD4010 ldmia r13!,{r4,r14}
:000E7EB8 E12FFF1E bx r14 (Jump to addr_00000000?)

            A-2b. METHOD 2: Using iDeaS freeware version and Hex Editor

  • Open the dump in Hex Editor
  • The Search for 30 01 00 04  (0x04000130 little endian), list out all possible offset result (add 0x02000000 to all offset result)

 

 

  • Open the ROM in iDeaS, make the game load enough till you see the "Press Touch/Start" or something
  • Then Open the Debugger or press Alt+F2
  • On Debugger window set the following EXTERN WRAM, Mode: Arm 9 and CPU: ARM (in this tutorial we will use ARM but some game store the button routine in THUMB)
  • Then on the Text Box, input each offset then Press GO
  •  Locate which contains "bx lr".

 

  • Scroll farther upward till you find something like "ldr r1, 0x04000130" followed by something like "ldr r0,0x2FFF" , if not look for other offset. (r1 and r0 can be any register but 0x04000130 and should be 0x2FFF load in register)

 

 

If confirmed that it was the button routine we will use the offset of bx lr which is in this example 0x020E7EB8

 

            A-2c. METHOD 3: Using a Commercial Emulator with breakpoint debugger, like No$GBA Debbuger Edition and iDeaS Professional Edition

  1. Open the ROM in emulator, nope you don't need a dump here
  2. Set a bpr  to 0x04000130
  3. it might break after a ldr r1, 0x04000130, in the example game it breaks in "ldr r0,0x2FFF"
  4. Scroll farther downward till you find the first "bx lr" or "bx r14", its location will be our Hooking address which in this game located in 0x020E7EB8

B.  Check if the hooking address/offset is compressed

         After locating the hooking address/offset we have to make sure that the offset is not compressed in ROM. Anyway the Method is simple just locate if the routine and the value in 0x020E7EB8 can be found in ROM. You have to make sure that it really occurs, If it is then you can skip the next steps and go directly in Preparing the ASM Custom Routine , If not then it requires an additional debugging.

C.  Make an ASM Routine that will Patch  the Hooking Address

This can be very difficult and requires a big patience, in this tutorial we will use iDeaS freeware version (obviously commercial version of the emulator is still powerful)

  1. First Open  an Emulator with debugger,
  2. Make sure that the debugger window is opened
  3. Then load the ROM in emulator and press Play in Emulator Window but not in debugger window
  4. Then locate our hooking address, see if it has still the same value which in our example it should be 0xE12FFF1E.
  5. Then sad to realize that it doesn't contain the same value.

    Using the Steps above we can go on debugging,

METHOD 1: Normally in Commercial Debugger the method is very simple

  1. Reset the game but make sure it was paused after resetting
  2. Set a bpw/breakpoint write in 0x020E7EB8
  3. Then Debugger will break somewhere in  "0x02000A14",
  4. Now Study the bx lr or bx r14 below and you can choose anything, I choose 0x02000B44 (Choose which is not far where the debugger break)

METHOD 2: if you are using a Freeware version, the method is very complicated.

  1. First Open  an Emulator with debugger,
  2. Make sure that the debugger window is opened
  3. Then load the ROM in emulator and press Play in Emulator Window but not in debugger window
  4. Open Emuhaste or hasteDS then press Snap Process
  5. Goto 0x020E7EA0, or any address as long as its a head in our hooking address
  6. Make sure that Auto Refresh function in emuhaste/hasteds
  7. Then use the [Trace Into] [F8] function in debugger window and trace 
  8. During tracing, Watch on emuhaste/hasteds till you find the value of  0x020E7EB8 becomes 1E FF 2F E1
  9. In this game it will write in 0x02000A10.
  10. Now tracing downward you will see lots of "bx lr" you can choose one but I prefer 0x02000B44 since decompressing ends there
  11. Now to make sure that it is safe to use it, reset the game again
  12. Then press the play button in Emulator window but not in debugger window
  13. Press [F8] once
  14. Go to 0x02000B44 then click the said address in assembly window then use the [Run to Cursor] [F6] function on debugger window
  15. The Debugger will break there, then look again in emuhaste/hasteds and go to 0x020E7EB8  see if the value is 1E FF 2F E1

 

 

16.  The last step would be is to check  if 0x02000B44 is not compressed in ROM, you can use it with simple search and find in hex editor and in ACWW 1.0 it is uncompressed and can be found in offset 0x00004B44

 

 
 

            METHOD 3: If you don't have a debugger with breakpoint and Method 2 is very complicated then, GUESSING is your additional Option

        This one is very inaccurate and very few times that it works. The Idea is in some ROM, executable that decompressed the some executables files in ROM are found between 0x4000 to 0x4C00 or 0x02000000 to 0x02000C00 in RAM before the word "[SDK+NINTENDO:BACKUP]" searching those portion found in RAM and ROM can be use to trace the last bx lr that was hardcoded in ROM, anyway for better understanding here's the step by step Details.

 

D.  Preparing the ASM Custom Routine

        After locating where we can hook our code, we can now prepare our ASM Custom Routine. But first we have to make sure that the register we use is safe to use. We can confirm this by debugging, although it is not always smart to do this, we can skip debugging by simply adding push and pop on our routine. And since we hook that branches in lr, we should add bx lr also in the end.

Our ASM Custom Routine  will be like this

push {r0-r1}

MaxNookPoints:
ldr r0, =0x21D8FE4
ldr r1, =0x4E20
strh r1, [r0]

TomNookNeverSOLDOUT:
ldr r0, =0x21ECBE0
mov r1, #0x0
str r1, [r0]
str r1, [r0,#0x4]

CatalogItemsOnlyCost1Bell:                        
ldr r0, =0x22A925C
mov r1, #0x1
strh r1, [r0]

NeverGetResetti:
ldr r0, =0x21cd774
mov r1, #0x0
strb r1, [r0]

InfiniteBells:
ldr r0, =0x021d891c
ldr r1, =0x1869F
str r1, [r0]

SavingsAccountFull:
ldr r0, =0x21d8fc0
ldr r1, =0x05f5e0ff
str r1, [r0]

pop {r0-r1}

bx lr

 

E.  Calculating the Branch/Jump for Hook Address

        Basically the ASM to ARDS by kenobi was design only for ARDS and branching/Jump code especially backwards requires to compile separately. I came up with a simple formula and it might not be the best formulation anyway here it is.

[Compiled Branch] = 0xEA000000 +  (([TargetAddress] - [LocationOfHook])/4 - 2) AND 0x00FFFFFF)

or use this tool CBcalc.exe created by: Virus

in Our Example Game we will store it in 0x02000010 so it will be the Target Address computation will be like This

[Compiled Branch] = 0xEA000000 + ((0x02000010 - 0x020E7EB8)/4 - 2) AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + ((0xFFF18158)/4 - 2) AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + (0x3FFC6056- 2) AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + (0x3FFC6054 AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + 0xFC6054
[Compiled Branch] = 0xEAFC6054

using CBcalc.exe by Virus it should looks like this

        To test if it has the correct branch/jump, input this code in emuhaste 020E7EB8 EAFC6054 or in hasteDS 220E7EB8 EAFC6054 then open the debugger make sure it is paused then go to  0x020E7EB8 the value should be b 0x02000010

F.  Preparing the ASM Patch Routine for Hook Address

        NOTE: If Hook address is uncompressed in ROM you can skip this Steps, but on our Example game this is very Important

        Creating a ASM Patch Routine is the same as 020E7EB8 EAFC6054 so making it as ASM will be like this

ldr r0, =0x020E7EB8
ldr r1, =0xEAFC6054
str r1,[r0]

Now since we will hook it in 0x02000B44 we need to add push and pop and of course bx lr so the code will be like this

push {r0-r1}

ldr r0, =0x020E7EB8
ldr r1, =0xEAFC6054
str r1,[r0]

pop {r0-r1}

bx lr

Now we need to find a location to store it, I choose 0x02000200 but you can use around 0x02000200 to 0x02000400, but if you find a better offset choose that instead, Compiling with ASM to ARDS by kenobi code should look like this

E0000000 00000020
E92D0003 E59F000C
E59F100C E5801000
E8BD0003 E12FFF1E
020E7EB8 EAFC6054

when stored in RAM it should look like this

02000200 E92D0003
02000204 E59F000C
02000208 E59F100C
0200020C E5801000
02000210 E8BD0003
02000214 E12FFF1E
02000218 020E7EB8
0200021C EAFC6054

Last Part will be the Branching/Jump, using the Formula in Step E we came up with  following result

[Compiled Branch] = 0xEA000000 + ((0x02000200 - 0x02000B44)/4 - 2) AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + ((0xFFFFF6BC)/4 - 2) AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + (0x3FFFFDAF - 2) AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + (0x3FFFFDAD AND 0x00FFFFFF)
[Compiled Branch] = 0xEA000000 + 0xFFFDAD
[Compiled Branch] = 0xEAFFFDAD

or simply use this tool CBcalc.exe created by: virus


 

Now we have to check it using debugger using this code 02000B44 EAFFFDAD for Emuhaste /22000B44 EAFFFDAD for hasteDS

IV - Patching in ROM

        Before we Patch everything in ROM we have to make sure that it should work. First we need is to collect all data and test it in No$GBA what we just need is to use E Code type

The ASM Patch Routine and since it should store in 0x02000200 we just need to edit the E0000000 00000020 to E2000200 00000020

E2000200 00000020
E92D0003 E59F000C
E59F100C E5801000
E8BD0003 E12FFF1E
020E7EB8 EAFC6054

The ASM Custom Routine should store in 0x02000010 so we need to edit E0000000 0000007C to E2000010 0000007C

E2000010 0000007C
E92D0003 E59F004C
E59F104C E1C010B0
E59F0048 E3A01000
E5801000 E5801004
E59F003C E3A01001
E1C010B0 E59F0034
E3A01000 E5C01000
E59F002C E59F102C
E5801000 E59F0028
E59F1028 E5801000
E8BD0003 E12FFF1E
021D8FE4 00004E20
021ECBE0 022A925C
021CD774 021D891C
0001869F 021D8FC0
05F5E0FF 00000000

and since we 02000B44 is already decompressed we just need this on the start of the code 02000B44 EAFFFDAD, and in order to write everything once we will add this one more line 52000B44 E12FFF1E and of course the termination code so the Whole code will be,

52000B44 E12FFF1E
02000B44 EAFFFDAD
E2000200 00000020
E92D0003 E59F000C
E59F100C E5801000
E8BD0003 E12FFF1E
020E7EB8 EAFC6054
E2000010 00000080
E92D0003 E59F004C
E59F104C E1C010B0
E59F0048 E3A01000
E5801000 E5801004
E59F003C E3A01001
E1C010B0 E59F0034
E3A01000 E5C01000
E59F002C E59F102C
E5801000 E59F0028
E59F1028 E5801000
E8BD0003 E12FFF1E
021D8FE4 00004E20
021ECBE0 022A925C
021CD774 021D891C
0001869F 021D8FC0
05F5E0FF 00000000
D2000000 00000000

NOTE: No$gba up to 2.5b has one minor bug in E code type to avoid this i change E2000010 0000007C to E2000010 00000080

Input the code in Cheat list then reset the Game.

        Now there is one more  reason why we test and use No$gba and it is because No$gba support ARDS E type Code.

What we just need is to run the code  in No$GBA, reset the game and now DUMP the Memory. why? so we can easily patch the rom. how?

here's how,

 

  1. First for the Record, Use the code above in No$gba
  2. Reset the Game
  3. open Emuhaste and hasteDS
  4. Play the game a little bit just to confirm that it works well
  5. DUMP the Memory
  6. Backup the ROM
  7. Then Open the newly dumped file in Hex Editor then also open the ROM in Hex Editor
  8. First edit the 0x00004B44 that we found earlier from 1E FF 2F E1 to AD FD FF EA

    9.    Then copy the 0x00000010-0x0000008C of DUMP File to 0x00004010-0x0000408C of ROM

 


    10.    Then copy the 0x00000200-0x00000220 of DUMP File to 0x00004200-0x00004220 of ROM

 


   11..  The Save the ROM, now we need to comfirm if it correctly patch, the best way is to make a file compare. you can use a typical FC/B in command prompt or use the File Compare in most hex editor

    12.  That's it we already have the Patch ROM, now to test/debug it we will need iDeaS or in No$GBA Debug version
 

NOTE: For the Record most game the Initial RAM location can be found in 0x4000 in ROM, but you have to remember that it is not always that way, in most cases you have to make a search in Hex Editor

V - Debug the ROM

        Now since we already made almost everything we need now to debug the patch we made. To do this we can use the iDeaS freeware version or No$gba Debug version.

  1. First Open  an Emulator with debugger,
  2. Make sure that the debugger window is opened
  3. Then load the ROM in emulator and press Play in Emulator Window but not in debugger window
  4. Press [F8] once
  5. Then Go to 0x02000B44 click the address then click [Run to Cursor] or Press [F6]
  6. The emulator will run, then wait till it breaks on 0x02000B44.
  7. Then Click [Trace Into] or Press [F8]
  8. Then it should jump in 0x02000200, Trace it down a bit by pressing [F8]
  9. On the lower edit box enter 0x020E7EB8, and it will be the memory on the said offset
  10. Trace it more until you already in 0x02000210 and look in Memory if it changed

    10. Now after confirming that it patch, go to 0x020E7EB8, click the address in Disassembly window then click [Run In Cursor] or press F6

    11. As the emulator Break, trace it more by clicking the [Trace Into] or press [F8]

    12.  It should jump to 0x02000010, see if the whole ASM Custom routine can be found there, then debug it

VI - Distributing The Patch

    A. Making a Final Patcher   

        This is the Final Step in Making a Trainer, depending on to hacker, he can distribute his code thru IPS, an EXE or anything. I will not make a full detail on this since the program to make an IPS or patcher depends on the application of choice. Anyway here is a little picture that show how its done anyway its already given in the program.

    B. Creating an undo ips/patcher

        After we done with almost everything, it is normal that we will encounter people that will says that they don't want a portion in cheat found in one of the trainer. So it is always wise  to make an UNDOer. But sometimes they just want one portion but not everything , for example, they want everything in the trainer except the "savings account is full", recreating without that cheat would be a very tough choice. The solution is to create an ips/patcher that will remove only one portion in the trainer for one cheat. Anyway it is relatively simple what we only need to do is to replace it with Noop (No operation) code. In ARM writing a register with the same register will act as noop so it would be like this

mov r0, r0    ;when compiled it is 0xE1A00000

so here's what we need to do,

VII - Acknowledgements and Credits

 

[email protected]

toenailed © 2007