ROM Hack Injecting ASM code to homebrew

xonn

Well-Known Member
OP
Member
Joined
Jan 11, 2020
Messages
145
Trophies
0
Age
32
XP
824
Country
Spain
I want to share with us some thoughs in order to guess if I'm in a good direction or not :)
I don't have experience in hacking NDS roms, but after some searches, I have following info:
As indicated in libnds, function lcdSwap() has following implementation:
Code:
#define    REG_POWERCNT       *(vu16*)0x4000304
#define    PM_ARM9_DIRECT     BIT(16)
[...]
POWER_SWAP_LCDS    = PM_ARM9_DIRECT | BIT(15);
[...]
static inline void lcdSwap(void) { REG_POWERCNT ^= POWER_SWAP_LCDS; }
So, as far as I know, if a program changes 15th bit of half word located in address 0x4000304, screens will be swapped
This, coded using ASM, should be like:
Code:
mov r0, #4
lsl r0, r0, #0x18
add r0, r0, #0x304
ldrh r1, [r0]
lsl r1, r1, #18
lsr r1, r1, #18
strh r1, [r0]
And in ARM is:
Code:
0400A0E3
000CA0E1
C10F80E2
B010D0E1
0119A0E1
2119A0E1
B010C0E1
Assuming up to this point, I haven't said anything stupid... would be a way to inject this code in any homebrew app (compiled using libnds) to force a swap screen?
I suppose that there are a lot of things that I have missed, but I want to know if this is a good start or not.
Thanks!
 
Last edited by xonn,

xonn

Well-Known Member
OP
Member
Joined
Jan 11, 2020
Messages
145
Trophies
0
Age
32
XP
824
Country
Spain
I'm going to answer to myself. YES, it works!
I have tried with jEnesisDS emulator and a random line (I have chosen 0x1610) and just after pressing select button, the emulator swap screen, but just after that, it crashes :( Maybe near here is the function that is called everytime this button is pressed.
The next goal is find a place where the code will be executed, but not replacing original code.
 
  • Like
Reactions: banjo2

xonn

Well-Known Member
OP
Member
Joined
Jan 11, 2020
Messages
145
Trophies
0
Age
32
XP
824
Country
Spain
Good news!
I have found a place where new code seems to be executed just after selecting the rom (paste from line 1140). Now Sonic1 is playable at bottom screen :grog:
However, any function is useless, and deleted lines are freezing some games (as far as I have checked, Gunstar Heroes). The solution could be jumping to another place, do screen swap, and return to original line, but I need help :(
Attached NDS file, check it and give me your feedback, please.
 

Attachments

  • jEnesisDS_bottomscreen.zip
    128.4 KB · Views: 153

DavidRO99

Average Ryzen user.
Member
Joined
Jun 11, 2016
Messages
1,018
Trophies
0
Age
24
Location
your back-door
XP
920
Country
Korea, North
"The solution could be jumping to another place, do screen swap, and return to original line, but I need help :("

What you are describing is a hook. Basically just write a jmp instruction at your hook address that jumps into a function that executes your code, then the original code and jumps back to the instruction after the one you overwrote. If you do everything right it should work without issues, although some more instructions may need to be executed in order to preserve the stack and thus prevent crashes.
 

xonn

Well-Known Member
OP
Member
Joined
Jan 11, 2020
Messages
145
Trophies
0
Age
32
XP
824
Country
Spain
"The solution could be jumping to another place, do screen swap, and return to original line, but I need help :("

What you are describing is a hook. Basically just write a jmp instruction at your hook address that jumps into a function that executes your code, then the original code and jumps back to the instruction after the one you overwrote. If you do everything right it should work without issues, although some more instructions may need to be executed in order to preserve the stack and thus prevent crashes.
In rom header there is enough room to write code, however jump is too big (0x1140 to 0x0160) and I don't know how could this be done.
 

xonn

Well-Known Member
OP
Member
Joined
Jan 11, 2020
Messages
145
Trophies
0
Age
32
XP
824
Country
Spain
Anybody knows why this solution doesn't work?

Starting from line 0x111C we found originally:

0x111C mov r2, #0x4000000
0x1120 ldrh r3, [r2, #6]
0x1124 lsl r3, r3, #0x17
0x1128 lsr r3, r3, #0x17
0x112C cmp r3, #0xbf
0x1130 mov r0, r3

0x1134 bxhi lr

I replace orange lines with a branch to line 0x160. I use r2 and r3 as scratch registers because them are written in original code, and I save lr into stack to recover it at the end, so we have now:

0x111C push {lr}
0x1120 mov r2, #0x1000
0x1124 sub r2, r2, #0x2C
0x1128 mov lr, pc
0x112C sub pc, pc, r2
0x1130 pop {lr}

0x1134 bxhi lr

Starting from line 0x160, I put the both fragments of code: green ones are for lcd swap code and blue ones are lines previously deleted (the last line is just to recover PC and return to line 0x1130):

0x160 mov r2, #0x4000000
0x164 add r2, r2, #0x304
0x168 ldrh r3, [r2]
0x16C lsl r3, r3, #18
0x170 lsr r3, r3, #18
0x174 strh r3, [r2]

0x178 mov r2, #0x4000000
0x17C ldrh r3, [r2, #6]
0x180 lsl r3, r3, #0x17
0x184 lsr r3, r3, #0x17
0x188 cmp r3, #0xbf
0x18C mov r0, r3

0x190 mov pc, lr

I have debugged this code using NO$GBA and it works well, but in a real hardware, the program freezes... Is there any problem at using header free space to execute code?
 
Last edited by xonn,
  • Like
Reactions: cearp

xonn

Well-Known Member
OP
Member
Joined
Jan 11, 2020
Messages
145
Trophies
0
Age
32
XP
824
Country
Spain
Finally I decided to place screen swap from line 0x1690. Here, the branch works and only "destroy" functionality related to savestate button 1. I know that is not the best place to put, but for now I'm satisfied with the result. Finally, GBMacro users have a great emulator with sound for Genesis games :)

Edit: Final version can be downloaded from here https://gbatemp.net/threads/jenesisds-for-gbmacro-users.573933/
 
Last edited by xonn,
General chit-chat
Help Users
    AncientBoi @ AncientBoi: I had a controller that just couldn't handle it