Nimbus 1.6.0

- Add HTTP and Socket patches (redirects Nintendo URLs to Pretendo)
- Add Citra check
- Fix ACT crash when using the patches with no accounts on the system
This commit is contained in:
Daniel López Guimaraes 2024-04-07 19:25:44 +01:00
parent a1853c23cd
commit 78230638fc
No known key found for this signature in database
GPG key ID: 6AC74DE3DEF050E0
14 changed files with 453 additions and 8 deletions

View file

@ -15,6 +15,8 @@ This is a tutorial on how to get, extract, and decompress code.bin files for pat
### Modules to dump
- Account (act): 0004013000003802
- Friends (friends): 0004013000003202
- HTTP (http): 0004013000002902
- Socket (socket): 0004013000002E02
- SSL (ssl): 0004013000002F02
- Miiverse (miiverse):
- JPN: 000400300000BC02

View file

@ -15,13 +15,17 @@ LUMA_SYSMODULE_OUT := luma/sysmodules
FRIENDS_TITLE_ID := 0004013000003202
ACT_TITLE_ID := 0004013000003802
HTTP_TITLE_ID := 0004013000002902
SOCKET_TITLE_ID := 0004013000002E02
SSL_TITLE_ID := 0004013000002F02
MIIVERSE_ID_JPN := 000400300000BC02
MIIVERSE_ID_USA := 000400300000BD02
MIIVERSE_ID_EUR := 000400300000BE02
FRIENDS_OUT := $(LUMA_SYSMODULE_OUT)/$(FRIENDS_TITLE_ID).ips
ACT_OUT := $(LUMA_SYSMODULE_OUT)/$(ACT_TITLE_ID).ips
FRIENDS_OUT := $(LUMA_SYSMODULE_OUT)/$(FRIENDS_TITLE_ID).ips
HTTP_OUT := $(LUMA_SYSMODULE_OUT)/$(HTTP_TITLE_ID).ips
SOCKET_OUT := $(LUMA_SYSMODULE_OUT)/$(SOCKET_TITLE_ID).ips
SSL_OUT := $(LUMA_SYSMODULE_OUT)/$(SSL_TITLE_ID).ips
MIIVERSE_OUT_JPN := $(LUMA_OUT)/$(MIIVERSE_ID_JPN)
MIIVERSE_OUT_USA := $(LUMA_OUT)/$(MIIVERSE_ID_USA)
@ -39,8 +43,10 @@ all:
@$(MAKE) -C patches
# copy patches to patches folders
@cp -r patches/friends/out/* $(PATCHES_OUT_FOLDER)/$(FRIENDS_OUT)
@cp -r patches/act/out/* $(PATCHES_OUT_FOLDER)/$(ACT_OUT)
@cp -r patches/friends/out/* $(PATCHES_OUT_FOLDER)/$(FRIENDS_OUT)
@cp -r patches/http/out/* $(PATCHES_OUT_FOLDER)/$(HTTP_OUT)
@cp -r patches/socket/out/* $(PATCHES_OUT_FOLDER)/$(SOCKET_OUT)
@cp -r patches/ssl/out/* $(PATCHES_OUT_FOLDER)/$(SSL_OUT)
@cp -r patches/miiverse/out/* $(PATCHES_OUT_FOLDER)/$(MIIVERSE_OUT_JPN)
@cp -r patches/miiverse/out/* $(PATCHES_OUT_FOLDER)/$(MIIVERSE_OUT_USA)

View file

@ -24,6 +24,7 @@ Thanks to:
- [pinklimes](https://github.com/gitlimes) for the CIA version banner
- [TraceEntertains](https://github.com/TraceEntertains) for making a CIA version of Nimbus and maintaining the project
- [DaniElectra](https://github.com/DaniElectra) for making the 3DS HTTP and Socket patches
- [SciresM](https://github.com/SciresM) for making the 3DS SSL patches
- [zaksabeast](https://github.com/zaksabeast) for the original 3ds-Friend-Account-Manager and all the research into the friends and act system titles
- [shutterbug2000](https://github.com/shutterbug2000) for the GUI

View file

@ -52,7 +52,7 @@ BNR_AUDIO := meta/audio.wav
VERSION_HEADER = version.hpp
VERSION_MAJOR := 1
VERSION_MINOR := 5
VERSION_MINOR := 6
VERSION_MICRO := 0
#GFXBUILD := $(ROMFS)/gfx

View file

@ -291,7 +291,12 @@ int main()
if (lastState != state) firstStateRun = true;
if (state == 0) {
exit = checkIfLumaOptionsEnabled(top_screen, bottom_screen, kDown, kHeld, touch);
// Don't check for Luma options if running under Citra
s64 output = 0;
svcGetSystemInfo(&output, 0x20000, 0);
if (!output) {
exit = checkIfLumaOptionsEnabled(top_screen, bottom_screen, kDown, kHeld, touch);
}
}
else {
exit = drawUI(top_screen, bottom_screen, kDown, kHeld, touch);

View file

@ -1,21 +1,29 @@
.PHONY: all clean act friends miiverse ssl
.PHONY: all clean act friends http miiverse ssl socket
all: act friends miiverse ssl
all: act friends http miiverse ssl socket
act:
@make -C act
friends:
@make -C friends
http:
@make -C http
miiverse:
@make -C miiverse
ssl:
@make -C ssl
socket:
@make -C socket
clean:
@make -C act clean
@make -C friends clean
@make -C http clean
@make -C miiverse clean
@make -C ssl clean
@make -C socket clean

4
patches/http/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# build stuff and code.bin
code.bin
build
out

9
patches/http/Makefile Normal file
View file

@ -0,0 +1,9 @@
.PHONY: all clean
all:
@mkdir -p build out
@armips src/main.s
@flips -c code.bin build/patched_code.bin out/code.ips
clean:
@rm -rf build out

63
patches/http/src/frdu.s Normal file
View file

@ -0,0 +1,63 @@
; according to ghidra these .data addresses are not used, lets hope that its right
frd_handle equ 0x11C340
nasc_environment equ 0x11C344
get_nasc_environment: ; 0x1accc
push {r4, r11, lr}
; we have to cache the nasc environment on memory
; or the frd sysmodule will hang when trying to perform
; a request due to call recursion
ldr r0, =nasc_environment ; load nasc environment address to r0
ldr r0, [r0] ; load nasc environment
cmn r0, #0 ; check if r0 has a value
bne get_nasc_environment_end ; if it does, return it
bl get_frd_u_handle ; get the frd_handle
; first we use the SetClientSdkVersion command, or this wont work
mrc p15, 0x0, r4, c13, c0, 0x3 ; get our thread local storage and store it in r4
ldr r0, =0x00320042 ; load frd:u SetClientSdkVersion header into r0
str r0, [r4, #0x80]! ; set cmdbuf[0] to our cmdhdr from r0
ldr r0, =0x70000C8 ; set sdk version, same as nimbus
str r0, [r4, #0x4] ; set cmdbuf[1] to the sdk version
mov r0, 32 ; set placeholder kernel process id
str r0, [r4, #0x8] ; set cmdbuf[2] to the placeholder process id
ldr r0, =frd_handle ; load frd_handle address to r0
ldr r0, [r0] ; load frd_handle
swi 0x32 ; send the request
; now, we can make the request for the nasc environment
mrc p15, 0x0, r4, c13, c0, 0x3 ; get our thread local storage and store it in r4
ldr r0, =0x00300000 ; load frd:u GetServerTypes header into r0
str r0, [r4, #0x80]! ; set cmdbuf[0] to our cmdhdr from r0
ldr r0, =frd_handle ; load frd_handle address to r0
ldr r0, [r0] ; load frd_handle
swi 0x32 ; send the request
cmn r0, #0 ; check if r0 is negative
bmi get_nasc_environment_clear ; if it is, go to the clear label to return 0
ldr r2, [r4, #0x4] ; load result into r2
cmn r2, #0 ; check if r2 is negative
bmi get_nasc_environment_clear ; if it is, go to the clear label to return 0
ldr r0, [r4, #0x8] ; get our nasc environment from cmdbuf[2] to return and store it in r0
add r0, r0, #1 ; add 1 to distinguish uninitialized value 0
ldr r1, =nasc_environment ; load nasc environment address to r1
str r0, [r1] ; store the local nasc environment to memory
b get_nasc_environment_end ; jump to the end
get_nasc_environment_clear: ; 0x1ad4c
mov r0, #0
get_nasc_environment_end: ; 0x1ad50
pop {r4, r11, lr}
bx lr
get_frd_u_handle: ; 0x1ad58
push {r11, lr}
ldr r0, =frd_handle ; load frd_handle address to r0
ldr r1, =frdu_name ; load frdu name into r1
bl get_service_handle ; get frd_handle
pop {r11, lr}
bx lr

146
patches/http/src/main.s Normal file
View file

@ -0,0 +1,146 @@
.3ds
.open "code.bin", "build/patched_code.bin", 0x100000
; (r0) (r1)
; Result get_service_handle(Handle* handle_out, char* service_name)
get_service_handle equ 0x10DB40
; (r0) (r1) (r2)
; void* memcpy(void* dst, void* src, size_t size)
memcpy equ 0x10D2DC
; (r0)
; size_t strlen(char* string)
strlen equ 0x10F8B0
replace_hook_addr equ 0x113868
replace_function_addr equ 0x11AA70
.org replace_hook_addr
replace_hook:
bl replace_func_jump ; Load our custom code instead of the normal address (0xE04C)
.org replace_function_addr
; moves the char* from r5 into r0, then jumps to the code that replaces stuff in it
replace_func_jump: ; 0x1aa70
mov r0, r5
b handle_replacements
.include "src/strfunctions.s"
; (r0) (r1) (r2)
; returns modified char* in r0, func variables are (char* stringToReplaceOn, char* target, char* replacement)
find_and_replace: ; 0x1ac38 0x1ab90
push {r11, lr}
add r11, sp, #4
sub sp, sp, #0x20
str r0, [r11, #-0x18]
str r1, [r11, #-0x1c]
str r2, [r11, #-0x20]
ldr r1, [r11, #-0x1c]
ldr r0, [r11, #-0x18]
bl strstr
str r0, [r11, #-8]
ldr r3, [r11, #-8]
cmp r3, #0
beq find_and_replace_lab_1
ldr r0, [r11, #-0x1c]
bl strlen
mov r3, r0
str r3, [r11, #-0xc]
ldr r0, [r11, #-0x20]
bl strlen
mov r3, r0
str r3, [r11, #-0x10]
ldr r3, [r11, #-0xc]
ldr r2, [r11, #-8]
add r3, r2, r3
mov r0, r3
bl strlen
mov r3, r0
str r3, [r11, #-0x14]
ldr r3, [r11, #-0x10]
ldr r2, [r11, #-8]
add r0, r2, r3
ldr r3, [r11, #-0xc]
ldr r2, [r11, #-8]
add r1, r2, r3
ldr r3, [r11, #-0x14]
add r3, r3, #1
mov r2, r3
bl memcpy
ldr r2, [r11, #-0x10]
ldr r1, [r11, #-0x20]
ldr r0, [r11, #-8]
bl memcpy
b find_and_replace_lab_2
find_and_replace_lab_1: ; 0x1ac3c
mov r0, r0
find_and_replace_lab_2: ; 0x1ac40
sub sp, r11, #4
pop {r11, lr}
bx lr
handle_replacements: ; 0x1ac4c
push {r11, lr}
add r11, sp, #4
sub sp, sp, #0x28
str r0, [r11, #-0x28] ; store r0 (our char* we are replacing string stuff on) into stack -0x28
bl get_nasc_environment ; get the nasc environment
cmp r0, #2 ; check if r0 is 2
bne handle_replacements_end ; if it isnt, skip the replacements
; else, run the replacements
ldr r3, =target1
str r3, [r11, #-0x8] ; store the just loaded target1 into stack -0x8
ldr r3, =target2
str r3, [r11, #-0xc] ; store the just loaded target2 into stack -0xc
ldr r3, =target3
str r3, [r11, #-0x10] ; store the just loaded target3 into stack -0x10
ldr r3, =replacementPretendo
str r3, [r11, #-0x14] ; store the just loaded replacementPretendo into stack -0x14
ldr r2, [r11, #-0x14] ; load replacementPretendo into r2
ldr r1, [r11, #-0x8] ; load target1 into r1
ldr r0, [r11, #-0x28] ; load our char* back into r0
bl find_and_replace
ldr r2, [r11, #-0x14] ; load replacementPretendo into r2
ldr r1, [r11, #-0xc] ; load target2 into r1
ldr r0, [r11, #-0x28] ; load our char* back into r0
bl find_and_replace
ldr r2, [r11, #-0x14] ; load replacementPretendo into r2
ldr r1, [r11, #-0x10] ; load target3 into r1
ldr r0, [r11, #-0x28] ; load our char* back into r0
bl find_and_replace
handle_replacements_end: ; 0x1acb8
mov r0, r0
mov r0, r3
sub sp, r11, #4
pop {r11, lr}
bx lr
.include "src/frdu.s"
; strings
.pool
frdu_name:
.asciiz "frd:u"
target1:
.asciiz "nintendowifi.net"
target2:
.asciiz "nintendo.net"
target3:
.asciiz "pokemon-gl.com"
replacementPretendo:
.asciiz "pretendo.cc"
.close

View file

@ -0,0 +1,91 @@
strcmp: ; 0x1aa78
str r11, [sp, #-4]!
add r11, sp, #0
sub sp, sp, #0xc
str r0, [r11, #-8]
str r1, [r11, #-0xc]
b strcmp_lab_3
strcmp_lab_1: ; 0x1aa90
ldr r3, [r11, #-8]
ldrb r2, [r3]
ldr r3, [r11, #-0xc]
ldrb r3, [r3]
cmp r2, r3
beq strcmp_lab_2
mov r3, #0
b strcmp_lab_5
strcmp_lab_2: ; 0x1aab0
ldr r3, [r11, #-8]
add r3, r3, #1
str r3, [r11, #-8]
ldr r3, [r11, #-0xc]
add r3, r3, #1
str r3, [r11, #-0xc]
strcmp_lab_3: ; 0x1aac8
ldr r3, [r11, #-8]
ldrb r3, [r3]
cmp r3, #0
beq strcmp_lab_4
ldr r3, [r11, #-0xc]
ldrb r3, [r3]
cmp r3, #0
bne strcmp_lab_1
strcmp_lab_4: ; 0x1aae8
ldr r3, [r11, #-0xc]
ldrb r3, [r3]
cmp r3, #0
moveq r3, #1
movne r3, #0
and r3, r3, #0xff
strcmp_lab_5: ; 0x1ab00
mov r0, r3
sub sp, r11, #0
ldr r11, [sp], #0x4
bx lr
strstr: ; 0x1ab10
push {r11, lr}
add r11, sp, #4
sub sp, sp, #8
str r0, [r11, #-8]
str r1, [r11, #-0xc]
b strstr_lab_3
strstr_lab_1: ; 0x1ab28
ldr r3, [r11, #-8]
ldrb r2, [r3]
ldr r3, [r11, #-0xc]
ldrb r3, [r3]
cmp r2, r3
bne strstr_lab_2
ldr r1, [r11, #-0xc]
ldr r0, [r11, #-8]
bl strcmp
mov r3, r0
cmp r3, #0
beq strstr_lab_2
ldr r3, [r11, #-8]
b strstr_lab_4
strstr_lab_2: ; 0x1ab60
ldr r3, [r11, #-8]
add r3, r3, #1
str r3, [r11, #-8]
strstr_lab_3: ; 0x1ab6c
ldr r3, [r11, #-8]
ldrb r3, [r3]
cmp r3, #0
bne strstr_lab_1
mov r3, #0
strstr_lab_4: ; 0x1ab80
mov r0, r3
sub sp, r11, #4
pop {r11, lr}
bx lr

4
patches/socket/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# build stuff and code.bin
code.bin
build
out

9
patches/socket/Makefile Normal file
View file

@ -0,0 +1,9 @@
.PHONY: all clean
all:
@mkdir -p build out
@armips src/main.s
@flips -c code.bin build/patched_code.bin out/code.ips
clean:
@rm -rf build out

97
patches/socket/src/main.s Normal file
View file

@ -0,0 +1,97 @@
.3ds
.open "code.bin", "build/patched_code.bin", 0x100000
; (r0) (r1)
; int strcmp(char* str1, char* str2)
strcmp equ 0x1011E8
; Relevant registers:
; - r1: input_hostname (we are hooking the copy from r9 to r1)
; - r2: host_size (we are hooking before a memcpy)
; - r5: host_size
; - r9: input_hostname
gethostbyname_hook_addr equ 0x12C660
gethostbyname_hook_end equ 0x12C664
; Relevant registers:
; - r2: node (we are hooking the copy from r2 to r0 with gt condition)
; - r3: node_size
getaddrinfo_hook_addr equ 0x12C3E8
getaddrinfo_hook_end equ 0x12C3EC
; This is where the code cave starts, we have space up to 0x132000
start_replacements_addr equ 0x131088
.org gethostbyname_hook_addr
b gethostbyname_hook
.org getaddrinfo_hook_addr
bgt getaddrinfo_hook ; we replicate the original condition in this instruction
.org start_replacements_addr
gethostbyname_hook: ; 0x131088
bl handle_gethostbyname_replacements
b gethostbyname_hook_end ; go back to the original function
getaddrinfo_hook: ; 0x131090
bl handle_getaddrinfo_replacements
b getaddrinfo_hook_end ; go back to the original function
handle_gethostbyname_replacements:
stmdb sp!, {r0, r3, r4, r6, r7, r8, r9, r10, r11, r12, lr} ; save the current state just in case
mov r0, r9 ; move original hostname to r0 for replacements
bl handle_replacements
cmp r1, #0 ; check if the pointer has been modified (a size is returned)
movgt r2, r1 ; if we did, modify the hostname size on r2 (the memcpy used later)
movgt r5, r1 ; and on the original register r5
mov r1, r0 ; move the returned hostname to r1 (original behavior)
ldmia sp!, {r0, r3, r4, r6, r7, r8, r9, r10, r11, r12, pc} ; load the original state back and return
; Note: We do not need to modify the size here because getaddrinfo handles it using strlen
handle_getaddrinfo_replacements:
stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, lr} ; save the current state just in case
mov r0, r2 ; move original hostname to r0 (original behavior)
bl handle_replacements
ldmia sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, pc} ; load the original state back and return
; Checks if the domain is an NNCS domain. Returns the pointer to a Pretendo domain if it matches, or the original domain
; (r0) (r0)
; char* handle_replacements(char* original)
handle_replacements:
stmdb sp!, {r10, r12, lr} ; save the current state
mov r10, r0 ; move original hostname to r10 to save it for later
ldr r1, =nncs1_orig_name
bl strcmp ; compare hostname with nncs1
cmp r0, #0
ldreq r0, =nncs1_pretendo_name ; if it matches, return the pretendo domain and its size
moveq r1, #21 ; size of pretendo domain
beq handle_replacements_end
mov r0, r10 ; move original hostname to r0
ldr r1, =nncs2_orig_name
bl strcmp ; compare hostname with nncs2
cmp r0, #0
ldreq r0, =nncs2_pretendo_name ; if it matches, return the pretendo domain and its size
moveq r1, #21 ; size of pretendo domain
movne r0, r10 ; if none of the nncs domains match, use the original hostname
movne r1, #0 ; size of 0 to represent the domain hasn't been modified
handle_replacements_end:
ldmia sp!, {r10, r12, pc} ; load the original state back and return
; strings
.pool
nncs1_orig_name:
.asciiz "nncs1.app.nintendowifi.net"
nncs2_orig_name:
.asciiz "nncs2.app.nintendowifi.net"
nncs1_pretendo_name:
.asciiz "nncs1.app.pretendo.cc"
nncs2_pretendo_name:
.asciiz "nncs2.app.pretendo.cc"
.close