├── .gitignore ├── .gitmodules ├── DEVELOPERS.md ├── Firmware ├── MiraFW │ ├── Makefile │ ├── MiraFW.vcxproj │ └── src │ │ ├── crt0.s │ │ ├── entrypoint.c │ │ ├── link.x │ │ └── mira │ │ ├── boot │ │ ├── patches.c │ │ ├── patches.h │ │ └── patches │ │ │ ├── patches455.c │ │ │ ├── patches501.c │ │ │ └── patches505.c │ │ ├── plugins │ │ ├── debugger │ │ │ ├── debugger_plugin.c │ │ │ └── debugger_plugin.h │ │ ├── filetransfer │ │ │ ├── filetransfer_plugin.c │ │ │ └── filetransfer_plugin.h │ │ ├── logserver │ │ │ ├── logserver_plugin.c │ │ │ └── logserver_plugin.h │ │ ├── pluginloader.c │ │ └── pluginloader.h │ │ └── utils │ │ ├── hde │ │ ├── hde64.c │ │ ├── hde64.h │ │ └── table64.h │ │ ├── hook.c │ │ └── hook.h └── Plugins │ ├── MiraExamplePlugin │ ├── Makefile │ ├── MiraExamplePlugin.vcxproj │ └── src │ │ ├── crt0.s │ │ ├── example_plugin.c │ │ └── example_plugin.h │ └── MiraFileTransferPlugin │ ├── MiraFileTransferPlugin.vcxproj │ └── src │ └── crt0.s ├── Mira.sln ├── Output └── README.md ├── README.md ├── Scripts ├── clean_all.cmd ├── clean_all.sh ├── config.txt ├── init_development_environment.cmd └── init_development_environment.sh ├── Tests └── MiraLibTests │ ├── ConnectionTests.cs │ ├── MiraLibTests.csproj │ ├── Properties │ └── AssemblyInfo.cs │ └── packages.config ├── Tools └── MiraLib │ ├── MiraConnection.cs │ ├── MiraFileTransferExtension.cs │ ├── MiraLib.csproj │ └── Properties │ └── AssemblyInfo.cs └── USERS.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #Ignore thumbnails created by Windows 3 | Thumbs.db 4 | #Ignore files built by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs/ 31 | #Nuget packages folder 32 | packages/ 33 | 34 | #Ignore output files 35 | Output/** 36 | 37 | #Do not ignore the README file that is in output 38 | !Output/README.md 39 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Firmware/Dependencies/oni-framework"] 2 | path = Firmware/Dependencies/oni-framework 3 | url = https://github.com/OpenOrbis/oni-framework 4 | [submodule "Firmware/Dependencies/freebsd-headers"] 5 | path = Firmware/Dependencies/freebsd-headers 6 | url = https://github.com/OpenOrbis/freebsd-headers.git 7 | -------------------------------------------------------------------------------- /DEVELOPERS.md: -------------------------------------------------------------------------------- 1 | # Developers Guide 2 | 3 | ## Project Layout 4 | 5 | At first glance, it may seem like the Mira-Project is very complicated, but once you understand the basic layout it is very clear and simple. 6 | 7 | * `Tools/` - The tooling folder, which may contain additional libraries and tools to assist with Mira development. These tools are not required to build Mira, but will help developers. 8 | * `Scripts/` - These are general puropse scripts that may get executed automatically by the build, or there for initializing development environments. 9 | * `Output/` - When configured (by default it's not) will be the output directory for all builds 10 | * `Firmware/` - This directory contains all the components to Mira's core 11 | * `Dependencies/` - The dependencies for the Mira project, usually just freebsd-headers, and oni-framework 12 | * `MiraFW/` - The actual source code for Mira, which handles auto-escalation and execution as a background kernel process 13 | * `Plugins/` - These are all of the *external* plugins that Mira will use. These can be built and compiled independently, and where all developers should create new projects in 14 | 15 | ## Setting up the development environment 16 | 17 | In order to build Mira, you will need either a Windows machine with Visual Studio 2017, the C++ for Linux plugin and Windows Subsystem for Linux (highly reccomended), or a linux-based machine or VM with `build-essentials` (gcc, clang, etc). 18 | 19 | ### Windows Setup 20 | 21 | This is the most reccomended way to develop for Mira. Since Mira is developed using Unix Makefiles, there is a direct compatibility with the Windows and Linux development environments. 22 | 23 | 1. [Download & Install](https://www.visualstudio.com/downloads/) Visual Studio 2017 WITH the [C++ for Linux support](https://blogs.msdn.microsoft.com/vcblog/2017/04/11/linux-development-with-c-in-visual-studio/) 24 | 2. [Enable](https://docs.microsoft.com/en-us/windows/wsl/install-win10) the Windows Subsystem for Linux 25 | 1. You will need to configure the newly created WSL environment's ssh daemon. 26 | 2. This can be done by editing `/etc/ssh/sshd_config` on most platforms. 27 | * You will need to change the port number to 2222 as Windows 10 may use port 22 for other reasons 28 | 3. Configure Windows Firewall to allow port 2222 on LAN (**_LAN ONLY OR LOCALHOST ONLY_**) 29 | 4. Configure Visual Studio's remote targets to use `localhost` port 2222 as the port number and your username/password created during the WSL install screen 30 | * If there's a red box error use `127.0.0.1` as the IP address 31 | 5. Open the `Mira.sln` with Visual Studio 2017 and do a full rebuild, this should deploy the [freebsd-headers](https://github.com/OpenOrbis/freebsd-headers) and [modified oni-framework](https://github.com/OpenOrbis/oni-framework) 32 | 33 | ### Linux Setup 34 | 35 | TODO: Implement Linux setup instructions 36 | 37 | ### Cloning the project 38 | 39 | No matter if you are using Windows or Linux, these commands will be the same. 40 | 41 | * If you are on Windows, you *MUST* clone inside of WSL and not within Windows itself 42 | * You can access all Windows partitions from within WSL by navigating to `/mnt/{windows drive letter}` (ex: `/mnt/c/Users/example/Desktop`) 43 | 44 | 1. Clone the repository 45 | * `git clone --recurse-submodules https://github.com/OpenOrbis/mira-project.git` 46 | 2. (Linux Users Only) Create all needed directories 47 | * Windows users using the Mira.sln, this will automatically get done for you when you do a Rebuild all on the solution. 48 | * `cd mira-project/Firmware/Dependencies/oni-framework` 49 | * `make create` 50 | * `cd ../../MiraFW` 51 | * `make create` 52 | 53 | ### Building the project 54 | 55 | Build in this order 56 | 1. freebsd-headers 57 | 2. oni-framework 58 | 3. mira 59 | 60 | TODO: Linux build instructions 61 | -------------------------------------------------------------------------------- /Firmware/MiraFW/Makefile: -------------------------------------------------------------------------------- 1 | # If ONI_FRAMEWORK is not set, we will use a default path of same directory 2 | ifeq ($(ONI_FRAMEWORK),) 3 | ONI_FRAMEWORK := ../Dependencies/oni-framework 4 | endif 5 | 6 | # If the FREEBSD headers path is not set we will try to use the relative path 7 | ifeq ($(BSD_INC),) 8 | BSD_INC := ../Dependencies/freebsd-headers 9 | endif 10 | 11 | # Project name 12 | PROJ_NAME := MiraFW 13 | 14 | # C++ compiler 15 | CPPC := gcc++ 16 | 17 | # Linker 18 | LNK := gcc # ps4-ld, we are compiling for the kernel so this is not going to use the OpenOrbis userland linker 19 | 20 | # C compiler 21 | CC := gcc 22 | 23 | # Archiver 24 | AS := gcc 25 | 26 | # Objcopy 27 | OBJCOPY := objcopy 28 | 29 | # Output directory, by default is build 30 | ifeq ($(OUT_DIR),) 31 | OUT_DIR := build 32 | endif 33 | 34 | # Source directory 35 | SRC_DIR := src 36 | 37 | # Include directory paths 38 | I_DIRS := -I. -IInclude -I$(SRC_DIR) -I$(ONI_FRAMEWORK)/depends/include -I$(ONI_FRAMEWORK)/include -I$(BSD_INC)/include 39 | 40 | # Library directory paths 41 | L_DIRS := -L. -Llib -L$(ONI_FRAMEWORK) 42 | 43 | # Included libraries 44 | LIBS := -l:OniFramework.a 45 | 46 | # Orbis flags 47 | ORB_VER := -D_KERNEL -D_DEBUG=1 48 | 49 | # C++ Flags 50 | CFLAGS := $(I_DIRS) $(ORB_VER) -std=c11 -O2 -fno-builtin -nostartfiles -nodefaultlibs -nostdlib -nostdinc -fcheck-new -ffreestanding -fno-strict-aliasing -fno-exceptions -fno-asynchronous-unwind-tables -Wall -m64 -fPIC -Werror -Wno-unknown-pragmas 51 | 52 | # Assembly flags 53 | SFLAGS := -nostartfiles -nodefaultlibs -nostdlib -fPIC 54 | 55 | # Linker flags 56 | LFLAGS := $(L_DIRS) -nostdlib -T $(SRC_DIR)/link.x -Wl,--build-id=none 57 | 58 | # Calculate the listing of all file paths 59 | CFILES := $(wildcard $(SRC_DIR)/*.c) 60 | CPPFILES := $(wildcard $(SRC_DIR)/*.cpp) 61 | SFILES := $(wildcard $(SRC_DIR)/*.s) 62 | OBJS := $(patsubst $(SRC_DIR)/%.s, $(OUT_DIR)/$(SRC_DIR)/%.o, $(SFILES)) $(patsubst $(SRC_DIR)/%.c, $(OUT_DIR)/$(SRC_DIR)/%.o, $(CFILES)) $(patsubst $(SRC_DIR)/%.cpp, $(OUT_DIR)/$(SRC_DIR)/%.o, $(CPPFILES)) 63 | 64 | ALL_CPP := $(shell find $(SRC_DIR)/ -type f -name '*.cpp') 65 | ALL_C := $(shell find $(SRC_DIR)/ -type f -name '*.c') 66 | ALL_S := $(shell find $(SRC_DIR)/ -type f -name '*.s') 67 | 68 | ALL_SOURCES := $(ALL_S) $(ALL_C) $(ALL_CPP) 69 | TO_BUILD := $(ALL_S:$(SRC_DIR)%=$(OUT_DIR)/$(SRC_DIR)%) $(ALL_C:$(SRC_DIR)%=$(OUT_DIR)/$(SRC_DIR)%) $(ALL_CPP:$(SRC_DIR)%=$(OUT_DIR)/$(SRC_DIR)%) 70 | ALL_OBJ_CPP := $(TO_BUILD:.cpp=.o) 71 | ALL_OBJ_C := $(ALL_OBJ_CPP:.c=.o) 72 | ALL_OBJ := $(ALL_OBJ_C:.s=.o) 73 | 74 | # Target elf name 75 | TARGET = $(PROJ_NAME)_Orbis.elf 76 | 77 | # Target payload name (data + text only, no elf) 78 | PAYLOAD = $(PROJ_NAME)_Orbis.bin 79 | 80 | $(TARGET): $(ALL_OBJ) 81 | @echo Compiling $(PROJ_NAME)... 82 | @$(LNK) $(ALL_OBJ) -o $(TARGET) $(LFLAGS) $(LIBS) 83 | @echo "Creating Payload..." 84 | @$(OBJCOPY) -O binary $(TARGET) $(PAYLOAD) 85 | 86 | $(OUT_DIR)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.c 87 | @echo "Compiling $< ..." 88 | @$(CC) $(CFLAGS) $(IDIRS) -c $< -o $@ 89 | 90 | $(OUT_DIR)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp 91 | @echo "Compiling $< ..." 92 | @$(CPPC) $(CFLAGS) $(IDIRS) -c $< -o $@ 93 | 94 | $(OUT_DIR)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.s 95 | @echo "Compiling $< ..." 96 | @$(CC) -c -o $@ $< $(SFLAGS) 97 | 98 | .PHONY: clean 99 | 100 | clean: 101 | @echo "Cleaning project..." 102 | @rm -f $(TARGET) $(PAYLOAD) $(shell find $(OUT_DIR)/ -type f -name '*.o') 103 | 104 | create: 105 | @echo "Creating directories..." 106 | @mkdir -p $(shell find '$(SRC_DIR)/' -type d -printf '$(OUT_DIR)/%p\n') 107 | -------------------------------------------------------------------------------- /Firmware/MiraFW/MiraFW.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {db146b77-3c14-4680-85ac-50b83292b1a8} 15 | Linux 16 | MiraFW 17 | 15.0 18 | Linux 19 | 1.0 20 | Generic 21 | {2238F9CD-F817-4ECC-BD14-2524D2669B35} 22 | 23 | 24 | 25 | true 26 | Makefile 27 | ~/mira/Firmware 28 | 29 | 30 | false 31 | Makefile 32 | ~/mira/Firmware 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 41 | _KERNEL;_DEBUG;_KERNEL; 42 | Makefile;$(AdditionalSourcesToCopyMapping) 43 | cd $(RemoteProjectDir);make create;make 44 | cd $(RemoteProjectDir);make create;make clean;make 45 | cd $(RemoteProjectDir);make create;make clean 46 | Oni_Orbis.elf;Oni_Orbis.bin 47 | 48 | 49 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 50 | _KERNEL;_KERNEL; 51 | Makefile;$(AdditionalSourcesToCopyMapping) 52 | cd $(RemoteProjectDir);make create;make 53 | cd $(RemoteProjectDir);make create;make clean;make 54 | cd $(RemoteProjectDir);make create;make clean 55 | Oni_Orbis.elf;Oni_Orbis.bin 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/crt0.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .text 3 | 4 | .global _start 5 | 6 | _start: 7 | jmp mira_entry 8 | 9 | 10 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/entrypoint.c: -------------------------------------------------------------------------------- 1 | // 2 | // Oni-Framework core 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // 12 | // Mira Core 13 | // 14 | #include // Load plugins from file 15 | 16 | // 17 | // Console specific patches 18 | // 19 | #include 20 | 21 | // 22 | // Built-in plugins 23 | // 24 | #include 25 | #include 26 | #include 27 | 28 | // 29 | // Utilities 30 | // 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | // 41 | // Free-BSD Specifics 42 | // 43 | #include // sysent_t 44 | #include // proc 45 | 46 | // 47 | // Required framework variables 48 | // 49 | const char* gNull = "(null)"; 50 | uint8_t* gKernelBase = NULL; 51 | struct logger_t* gLogger = NULL; 52 | struct initparams_t* gInitParams = NULL; 53 | struct framework_t* gFramework = NULL; 54 | 55 | // TODO: Enable better management of plugins 56 | struct debugger_plugin_t* gDebugger = NULL; 57 | 58 | // TODO: Move this somewhere 59 | #define kdlsym_addr_self_orbis_sysvec 0x019bbcd0 60 | 61 | // Forward declarations 62 | int init_oni(); 63 | uint8_t __noinline mira_installDefaultPlugins(); 64 | 65 | void* mira_entry(void* args) 66 | /* 67 | This is the entry point for the userland payload 68 | 69 | args - pointer to struct initparams_t in userland memory 70 | */ 71 | { 72 | // Initialize the Oni Framework 73 | int result = init_oni(); 74 | if (!result) 75 | return NULL; 76 | 77 | // Prompt the user 78 | int64_t moduleId = sys_dynlib_load_prx("libSceSysUtil.sprx"); 79 | int(*sceSysUtilSendSystemNotificationWithText)(int messageType, int userID, char* message) = NULL; 80 | 81 | // TODO: Fix, this call fails and never populates sceSysUtilSendSystemNotificationWithText investigate why 82 | sys_dynlib_dlsym(moduleId, "sceSysUtilSendSystemNotificationWithText", &sceSysUtilSendSystemNotificationWithText); 83 | 84 | if (sceSysUtilSendSystemNotificationWithText) 85 | { 86 | char* initMessage = "Mira Project Loaded\nRPC Server Port: 9999\nkLog Server Port: 9998\n"; 87 | sceSysUtilSendSystemNotificationWithText(36, 0x10000000, initMessage); 88 | } 89 | 90 | sys_dynlib_unload_prx(moduleId); 91 | 92 | return NULL; 93 | } 94 | 95 | int init_oni() 96 | /* 97 | This is the OniFramework entry where platform specific 98 | configurations should be set up and the framework initialized 99 | */ 100 | { 101 | // Elevate to kernel 102 | SelfElevateAndRun((uint8_t*)0x926200000, 0x80000, oni_kernelInitialization); 103 | 104 | return true; 105 | } 106 | 107 | struct hook_t* gHook = NULL; 108 | 109 | void oni_kernelInitialization(void* args) 110 | /* 111 | This function handles the kernel (ring-0) mode initialization 112 | */ 113 | { 114 | struct vmspace* (*vmspace_alloc)(vm_offset_t min, vm_offset_t max) = kdlsym(vmspace_alloc); 115 | void(*pmap_activate)(struct thread *td) = kdlsym(pmap_activate); 116 | struct sysentvec* sv = kdlsym(self_orbis_sysvec); 117 | void(*printf)(char *format, ...) = kdlsym(printf); 118 | 119 | // Let'em know we made it 120 | printf("[+] mira has reached stage 2\n"); 121 | 122 | printf("[+] starting logging\n"); 123 | gLogger = (struct logger_t*)kmalloc(sizeof(struct logger_t)); 124 | if (!gLogger) 125 | { 126 | printf("[-] could not allocate logger\n"); 127 | kthread_exit(); 128 | return; 129 | } 130 | logger_init(gLogger); 131 | 132 | // Verify that our initialization parameters are correct 133 | struct initparams_t* loaderInitParams = (struct initparams_t*)args; 134 | if (!loaderInitParams) 135 | { 136 | WriteLog(LL_Error, "invalid loader init params"); 137 | kthread_exit(); 138 | return; 139 | } 140 | 141 | gInitParams = (struct initparams_t*)kmalloc(sizeof(struct initparams_t)); 142 | if (!gInitParams) // TODO: Do a better job 143 | { 144 | WriteLog(LL_Error, "invalid initparams"); 145 | kthread_exit(); 146 | return; 147 | } 148 | 149 | gInitParams->payloadBase = loaderInitParams->payloadBase; 150 | gInitParams->payloadSize = loaderInitParams->payloadSize; 151 | gInitParams->process = loaderInitParams->process; 152 | 153 | // Create new vm_space 154 | WriteLog(LL_Debug, "Creating new vm space"); 155 | 156 | vm_offset_t sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE); 157 | struct vmspace* vmspace = vmspace_alloc(sv_minuser, sv->sv_maxuser); 158 | if (!vmspace) 159 | { 160 | WriteLog(LL_Error, "vmspace_alloc failed\n"); 161 | kthread_exit(); 162 | return; 163 | } 164 | 165 | // Assign our new vmspace to our process 166 | gInitParams->process->p_vmspace = vmspace; 167 | if (gInitParams->process == curthread->td_proc) 168 | pmap_activate(curthread); 169 | 170 | // Because we have now forked into a new realm of fuckery 171 | // We need to reserve the first 3 file descriptors in our process 172 | int descriptor = kopen("/dev/console", 1, 0); 173 | kdup2(descriptor, 1); 174 | kdup2(1, 2); 175 | 176 | // create our own cred 177 | ksetuid(0); 178 | 179 | // set diag auth ID flags 180 | curthread->td_ucred->cr_sceAuthID = 0x3800000000000007ULL; 181 | 182 | // make system credentials 183 | curthread->td_ucred->cr_sceCaps[0] = 0xFFFFFFFFFFFFFFFFULL; 184 | curthread->td_ucred->cr_sceCaps[1] = 0xFFFFFFFFFFFFFFFFULL; 185 | 186 | // Show over UART that we are running in a new process 187 | WriteLog(LL_Info, "[!] oni_kernel_startup in new process!\n"); 188 | 189 | gFramework = (struct framework_t*)kmalloc(sizeof(struct framework_t)); 190 | if (!gFramework) 191 | { 192 | WriteLog(LL_Error, "could not allocate framework :("); 193 | kthread_exit(); 194 | return; 195 | } 196 | 197 | // Set configuration paths 198 | gFramework->homePath = "/user/mira"; 199 | gFramework->configPath = "/user/mira/config.ini"; 200 | gFramework->downloadPath = "/user/mira/download"; 201 | gFramework->pluginsPath = "/user/mira/plugins"; 202 | 203 | // Initialize the rpc dispatcher 204 | WriteLog(LL_Debug, "MessageManager initialization"); 205 | gFramework->messageManager = (struct messagemanager_t*)kmalloc(sizeof(struct messagemanager_t)); 206 | if (!gFramework->messageManager) 207 | { 208 | kthread_exit(); 209 | return; 210 | } 211 | messagemanager_init(gFramework->messageManager); 212 | 213 | // Initialize the plugin manager 214 | WriteLog(LL_Debug, "[+] Initializing plugin manager"); 215 | gFramework->pluginManager = (struct pluginmanager_t*)kmalloc(sizeof(struct pluginmanager_t)); 216 | if (!gFramework->pluginManager) 217 | { 218 | kthread_exit(); 219 | return; 220 | } 221 | pluginmanager_init(gFramework->pluginManager); 222 | 223 | // Initialize the default plugins 224 | if (!mira_installDefaultPlugins()) 225 | { 226 | WriteLog(LL_Error, "could not initialize plugins"); 227 | kthread_exit(); 228 | return; 229 | } 230 | 231 | // At this point we don't need kernel context anymore 232 | WriteLog(LL_Info, "[!] Mira initialization complete"); 233 | kthread_exit(); 234 | } 235 | 236 | uint8_t __noinline mira_installDefaultPlugins() 237 | { 238 | // Initialize default plugins 239 | 240 | // Register file transfer plugin 241 | struct filetransfer_plugin_t* filetransferPlugin = (struct filetransfer_plugin_t*)kmalloc(sizeof(struct filetransfer_plugin_t)); 242 | if (!filetransferPlugin) 243 | { 244 | WriteLog(LL_Error, "Error allocating file transfer plugin"); 245 | return false; 246 | } 247 | filetransfer_plugin_init(filetransferPlugin); 248 | pluginmanager_registerPlugin(gFramework->pluginManager, &filetransferPlugin->plugin); 249 | 250 | WriteLog(LL_Info, "Allocating logserver"); 251 | struct logserver_plugin_t* logServer = (struct logserver_plugin_t*)kmalloc(sizeof(struct logserver_plugin_t)); 252 | if (!logServer) 253 | { 254 | WriteLog(LL_Error, "Could not allocate log server."); 255 | return false; 256 | } 257 | logserver_init(logServer); 258 | pluginmanager_registerPlugin(gFramework->pluginManager, &logServer->plugin); 259 | 260 | // Initialize the plugin loader to read from file 261 | struct pluginloader_t* pluginLoader = (struct pluginloader_t*)kmalloc(sizeof(struct pluginloader_t)); 262 | if (!pluginLoader) 263 | { 264 | WriteLog(LL_Error, "Error allocating plugin loader."); 265 | return false; 266 | } 267 | pluginloader_init(pluginLoader); 268 | 269 | pluginloader_loadPlugins(pluginLoader); 270 | 271 | // Debugger 272 | WriteLog(LL_Debug, "Allocating debugger"); 273 | gDebugger = (struct debugger_plugin_t*)kmalloc(sizeof(struct debugger_plugin_t)); 274 | if (!gDebugger) 275 | { 276 | WriteLog(LL_Error, "could not allocate debugger plugin"); 277 | return false; 278 | } 279 | debugger_plugin_init(gDebugger); 280 | pluginmanager_registerPlugin(gFramework->pluginManager, &gDebugger->plugin); 281 | 282 | // Kick off the rpc server thread 283 | WriteLog(LL_Debug, "[+] Allocating rpc server"); 284 | gFramework->rpcServer = (struct rpcserver_t*)kmalloc(sizeof(struct rpcserver_t)); 285 | if (!gFramework->rpcServer) 286 | { 287 | WriteLog(LL_Error, "could not allocate rpc server."); 288 | return false; 289 | } 290 | rpcserver_init(gFramework->rpcServer, gInitParams->process); 291 | 292 | WriteLog(LL_Debug, "[+] Finished Initializing rpc server proc: %p", gInitParams->process); 293 | 294 | // Startup the server, it will kick off the thread 295 | if (!rpcserver_startup(gFramework->rpcServer, 9999)) 296 | { 297 | WriteLog(LL_Error, "[-] rpcserver_startup failed"); 298 | return false; 299 | } 300 | 301 | return true; 302 | } -------------------------------------------------------------------------------- /Firmware/MiraFW/src/link.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(_start) 5 | 6 | PHDRS 7 | { 8 | /* 9 | * PF_X = 0x1 10 | * PF_W = 0x2 11 | * PF_R = 0x4 12 | */ 13 | 14 | ph_text PT_LOAD FLAGS (0x1 | 0x4); 15 | ph_data PT_LOAD FLAGS (0x2 | 0x4); 16 | } 17 | 18 | SECTIONS 19 | { 20 | __payload_base = .; 21 | 22 | .text : 23 | { 24 | KEEP (*(.init)) 25 | KEEP (*(.fini)) 26 | 27 | *(.text .text.*) 28 | 29 | . = ALIGN(4); 30 | } : ph_text = 0x90909090 31 | 32 | .rodata : 33 | { 34 | *(.rodata .rodata.*) 35 | 36 | . = ALIGN(4); 37 | } 38 | 39 | . = ALIGN(0x4000); 40 | 41 | .data : 42 | { 43 | *(.data .data.*) 44 | 45 | . = ALIGN(0x10); 46 | 47 | __imports_start = .; 48 | KEEP(*(.imports .imports.*)) 49 | __imports_end = .; 50 | 51 | __patches_start = .; 52 | KEEP(*(.patches .patches.*)) 53 | QUAD(0); BYTE(0); BYTE(0); 54 | __patches_end = .; 55 | 56 | __bss_start = .; 57 | *(.bss .bss.*) *(COMMON) 58 | __bss_end = .; 59 | 60 | . = . + 4; 61 | . = ALIGN(4); 62 | } : ph_data 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/boot/patches.c: -------------------------------------------------------------------------------- 1 | #include "patches.h" 2 | #include 3 | #include 4 | 5 | void oni_installPrePatches() 6 | { 7 | switch (ONI_PLATFORM) 8 | { 9 | case ONI_PLATFORM_ORBIS_BSD_455: 10 | install_prerunPatches_455(); 11 | break; 12 | case ONI_PLATFORM_ORBIS_BSD_501: 13 | install_prerunPatches_501(); 14 | break; 15 | case ONI_PLATFORM_ORBIS_BSD_505: 16 | install_prerunPatches_505(); 17 | break; 18 | default: 19 | break; 20 | } 21 | } -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/boot/patches.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void install_prerunPatches_455(); 4 | void install_prerunPatches_501(); 5 | void install_prerunPatches_505(); -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/boot/patches/patches455.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Patches done by CrazyVoid 6 | // Thanks to 7 | // WildCard for helping with patches 8 | // Joonie for helping with memcpy patch 9 | // LightingMod for being a tester 10 | 11 | void install_prerunPatches_455() 12 | { 13 | 14 | if(!gKernelBase) 15 | return; 16 | 17 | void(*critical_enter)(void) = kdlsym(critical_enter); 18 | void(*critical_exit)(void) = kdlsym(critical_exit); 19 | 20 | critical_enter(); 21 | cpu_disable_wp(); 22 | 23 | // enable UART 24 | // Done by WildCard 25 | gKernelBase[0x1997BC8] = 0; 26 | 27 | // Verbose Panics patch 28 | // Done by WildCard 29 | uint8_t *kmem = (uint8_t *)&gKernelBase[0x3DBDC7]; 30 | kmem[0] = 0x90; kmem[1] = 0x90; kmem[2] = 0x90; kmem[3] = 0x90; 31 | kmem[4] = 0x90; 32 | //kmem[5] = 0x65; kmem[6] = 0x8B; kmem[7] = 0x34; 33 | 34 | // Enable rwx - By WildCard 35 | kmem = (uint8_t*)&gKernelBase[0x16ed8c]; 36 | kmem[0] = 0x07; 37 | kmem = (uint8_t*)&gKernelBase[0x16eda2]; 38 | kmem[0] = 0x07; 39 | 40 | // Map Self Patch - IDC 41 | gKernelBase[0x143BF2] = 0x90; 42 | gKernelBase[0x143BF3] = 0xE9; 43 | gKernelBase[0x143E0E] = 0x90; 44 | gKernelBase[0x143E0F] = 0x90; 45 | 46 | // Copyin Patch - Copyin Offset = (0x14A890) 47 | // Done by CrazyVoid 48 | gKernelBase[0x14A8E7] = 0x90; 49 | gKernelBase[0x14A8E7 + 1] = 0x90; 50 | 51 | // Copyout Patch - Copyout offset = (0x14A7B0) 52 | // Done by CrazyVoid 53 | gKernelBase[0x14A802] = 0x90; 54 | gKernelBase[0x14A802 + 1] = 0x90; 55 | 56 | // Patch copyinstr - CrazyVoid 57 | gKernelBase[0x14AD53] = 0x90; 58 | gKernelBase[0x14AD53 + 1] = 0x90; 59 | gKernelBase[0x14AD83] = 0x90; 60 | gKernelBase[0x14AD83 + 1] = 0x90; 61 | 62 | 63 | // Patch memcpy stack - By CrazyVoid 64 | gKernelBase[0x14A6BD] = 0xEB; 65 | 66 | // ptrace patches - By WildCard 67 | gKernelBase[0x17D2EE] = 0x90; 68 | gKernelBase[0x17D2EE + 1] = 0x90; 69 | gKernelBase[0x17D2EE + 2] = 0x90; 70 | gKernelBase[0x17D2EE + 3] = 0x90; 71 | gKernelBase[0x17D2EE + 4] = 0x90; 72 | gKernelBase[0x17D2EE + 5] = 0x90; 73 | 74 | cpu_enable_wp(); 75 | critical_exit(); 76 | 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/boot/patches/patches501.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void install_prerunPatches_501() 6 | { 7 | // You must assign the kernel base pointer before anything is done 8 | if (!gKernelBase) 9 | return; 10 | 11 | void(*critical_enter)(void) = kdlsym(critical_enter); 12 | void(*crtical_exit)(void) = kdlsym(critical_exit); 13 | 14 | // Apply patches 15 | critical_enter(); 16 | cpu_disable_wp(); 17 | 18 | // enable UART 19 | gKernelBase[0x09ECAE0] = 0; 20 | 21 | // Verbose Panics 22 | uint8_t *kmem = (uint8_t *)&gKernelBase[0x171517]; 23 | kmem[0] = 0x90; kmem[1] = 0x90; kmem[2] = 0x90; kmem[3] = 0x90; 24 | kmem[4] = 0x90; kmem[5] = 0x65; kmem[6] = 0x8B; kmem[7] = 0x34; 25 | kmem = (uint8_t *)&gKernelBase[0x11730]; 26 | kmem[0] = 0xB8; kmem[1] = 0x01; kmem[2] = 0x00; kmem[3] = 0x00; 27 | kmem[4] = 0x00; kmem[5] = 0xC3; kmem[6] = 0x90; kmem[7] = 0x90; 28 | kmem = (uint8_t *)&gKernelBase[0x11750]; 29 | kmem[0] = 0xB8; kmem[1] = 0x01; kmem[2] = 0x00; kmem[3] = 0x00; 30 | kmem[4] = 0x00; kmem[5] = 0xC3; kmem[6] = 0x90; kmem[7] = 0x90; 31 | 32 | // Enable rwx 33 | kmem = (uint8_t*)&gKernelBase[0xFCC38]; 34 | kmem[0] = 0x07; 35 | kmem = (uint8_t*)&gKernelBase[0xFCC46]; 36 | kmem[0] = 0x07; 37 | 38 | // Patch copy(in/out) ? 39 | uint16_t *copyinpatch = (uint16_t*)&gKernelBase[0x1EA657]; 40 | uint16_t *copyoutpatch = (uint16_t*)&gKernelBase[0x1EA572]; 41 | 42 | *copyinpatch = 0x9090; 43 | *copyoutpatch = 0x9090; 44 | 45 | // Enable MAP_SELF 46 | kmem = (uint8_t*)&gKernelBase[0x117b0]; 47 | kmem[0] = 0xB8; 48 | kmem[1] = 0x01; 49 | kmem[2] = 0x00; 50 | kmem[3] = 0x00; 51 | kmem[4] = 0x00; 52 | kmem[5] = 0xC3; 53 | kmem = (uint8_t*)&gKernelBase[0x117c0]; 54 | kmem[0] = 0xB8; 55 | kmem[1] = 0x01; 56 | kmem[2] = 0x00; 57 | kmem[3] = 0x00; 58 | kmem[4] = 0x00; 59 | kmem[5] = 0xC3; 60 | kmem = (uint8_t*)&gKernelBase[0x13ef2f]; 61 | kmem[0] = 0x31; 62 | kmem[1] = 0xC0; 63 | kmem[2] = 0x90; 64 | kmem[3] = 0x90; 65 | kmem[4] = 0x90; 66 | 67 | // Patch copyinstr 68 | gKernelBase[0x001EAA83] = 0x90; 69 | gKernelBase[0x001EAA84] = 0x90; 70 | 71 | gKernelBase[0x001EAAB3] = 0x90; 72 | gKernelBase[0x001EAAB4] = 0x90; 73 | 74 | // Patch memcpy stack 75 | gKernelBase[0x001EA42D] = 0xEB; 76 | 77 | // ptrace patches 78 | gKernelBase[0x0030D633] = 0x90; 79 | gKernelBase[0x0030D633 + 1] = 0x90; 80 | gKernelBase[0x0030D633 + 2] = 0x90; 81 | gKernelBase[0x0030D633 + 3] = 0x90; 82 | gKernelBase[0x0030D633 + 4] = 0x90; 83 | gKernelBase[0x0030D633 + 5] = 0x90; 84 | 85 | 86 | cpu_enable_wp(); 87 | crtical_exit(); 88 | } 89 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/boot/patches/patches505.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void install_prerunPatches_505() 6 | { 7 | // You must assign the kernel base pointer before anything is done 8 | if (!gKernelBase) 9 | return; 10 | 11 | void(*critical_enter)(void) = kdlsym(critical_enter); 12 | void(*crtical_exit)(void) = kdlsym(critical_exit); 13 | 14 | // Apply patches 15 | critical_enter(); 16 | cpu_disable_wp(); 17 | 18 | // enable UART 19 | gKernelBase[0x09ECEB0] = 0; 20 | 21 | // Verbose Panics 22 | uint8_t *kmem = (uint8_t *)&gKernelBase[0x00171580]; 23 | kmem[0] = 0x90; kmem[1] = 0x90; kmem[2] = 0x90; kmem[3] = 0x90; 24 | kmem[4] = 0x90; kmem[5] = 0x65; kmem[6] = 0x8B; kmem[7] = 0x34; 25 | 26 | // sceSblACMgrIsAllowedSystemLevelDebugging 27 | kmem = (uint8_t *)&gKernelBase[0x00010FC0]; 28 | kmem[0] = 0xB8; kmem[1] = 0x01; kmem[2] = 0x00; kmem[3] = 0x00; 29 | kmem[4] = 0x00; kmem[5] = 0xC3; kmem[6] = 0x90; kmem[7] = 0x90; 30 | 31 | kmem = (uint8_t *)&gKernelBase[0x00011756]; 32 | kmem[0] = 0xB8; kmem[1] = 0x01; kmem[2] = 0x00; kmem[3] = 0x00; 33 | kmem[4] = 0x00; kmem[5] = 0xC3; kmem[6] = 0x90; kmem[7] = 0x90; 34 | 35 | // Enable rwx 36 | kmem = (uint8_t*)&gKernelBase[0x000FCD48]; 37 | kmem[0] = 0x07; 38 | kmem = (uint8_t*)&gKernelBase[0x000FCD56]; 39 | kmem[0] = 0x07; 40 | 41 | // Patch copy(in/out) 42 | uint16_t *copyinpatch = (uint16_t*)&gKernelBase[0x001EA767]; 43 | uint16_t *copyoutpatch = (uint16_t*)&gKernelBase[0x001EA682]; 44 | 45 | *copyinpatch = 0x9090; 46 | *copyoutpatch = 0x9090; 47 | 48 | // Enable MAP_SELF 49 | kmem = (uint8_t*)&gKernelBase[0x000117b0]; 50 | kmem[0] = 0xB8; 51 | kmem[1] = 0x01; 52 | kmem[2] = 0x00; 53 | kmem[3] = 0x00; 54 | kmem[4] = 0x00; 55 | kmem[5] = 0xC3; 56 | kmem = (uint8_t*)&gKernelBase[0x117c0]; 57 | kmem[0] = 0xB8; 58 | kmem[1] = 0x01; 59 | kmem[2] = 0x00; 60 | kmem[3] = 0x00; 61 | kmem[4] = 0x00; 62 | kmem[5] = 0xC3; 63 | kmem = (uint8_t*)&gKernelBase[0x0013F03F]; 64 | kmem[0] = 0x31; 65 | kmem[1] = 0xC0; 66 | kmem[2] = 0x90; 67 | kmem[3] = 0x90; 68 | kmem[4] = 0x90; 69 | 70 | // Patch copyinstr 71 | gKernelBase[0x001EAB93] = 0x90; 72 | gKernelBase[0x001EAB93+1] = 0x90; 73 | 74 | gKernelBase[0x001EABC3] = 0x90; 75 | gKernelBase[0x001EABC3+1] = 0x90; 76 | 77 | // Patch memcpy stack 78 | gKernelBase[0x001EA53D] = 0xEB; 79 | 80 | // ptrace patches 81 | gKernelBase[0x0030D9C3] = 0x90; 82 | gKernelBase[0x0030D9C3 + 1] = 0x90; 83 | gKernelBase[0x0030D9C3 + 2] = 0x90; 84 | gKernelBase[0x0030D9C3 + 3] = 0x90; 85 | gKernelBase[0x0030D9C3 + 4] = 0x90; 86 | gKernelBase[0x0030D9C3 + 5] = 0x90; 87 | 88 | cpu_enable_wp(); 89 | crtical_exit(); 90 | } 91 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/debugger/debugger_plugin.c: -------------------------------------------------------------------------------- 1 | #include "debugger_plugin.h" 2 | #define LOCK_PROFILING 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | enum { Debugger_MaxMem = 0x1000 }; 26 | 27 | struct debugger_getprocs_t 28 | { 29 | int32_t process_id; 30 | 31 | char path[1024]; 32 | char process_name[32]; 33 | 34 | uint64_t text_address; 35 | uint64_t text_size; 36 | 37 | uint64_t data_address; 38 | uint64_t data_size; 39 | 40 | uint64_t virtual_size; 41 | }; 42 | 43 | struct debugger_readmem_t 44 | { 45 | int32_t process_id; 46 | 47 | uint64_t address; 48 | uint64_t dataLength; 49 | uint8_t data[Debugger_MaxMem]; 50 | }; 51 | 52 | struct debugger_writemem_t 53 | { 54 | int32_t process_id; 55 | 56 | uint64_t address; 57 | uint64_t dataLength; 58 | uint8_t data[Debugger_MaxMem]; 59 | }; 60 | 61 | struct debugger_setbp_t 62 | { 63 | int32_t process_id; 64 | 65 | uint64_t address; 66 | uint8_t hardware; 67 | }; 68 | 69 | struct debugger_ptrace_t 70 | { 71 | int res; 72 | int req; 73 | int pid; 74 | uint64_t addr; 75 | int data; 76 | int setAddrToBuffer; 77 | char buffer[0x800]; 78 | }; 79 | 80 | struct debugger_kill_t 81 | { 82 | int pid; 83 | int signal; 84 | }; 85 | 86 | 87 | void debugger_getprocs_callback(struct allocation_t* ref); 88 | void debugger_readmem_callback(struct allocation_t* ref); 89 | void debugger_writemem_callback(struct allocation_t* ref); 90 | void debugger_ptrace_callback(struct allocation_t* ref); 91 | void debugger_kill_callback(struct allocation_t* ref); 92 | 93 | // Credits: flatz 94 | int proc_rw_mem(struct proc* p, void* ptr, size_t size, void* data, size_t* n, int write); 95 | 96 | 97 | uint8_t debugger_load(struct debugger_plugin_t * plugin) 98 | { 99 | return true; 100 | } 101 | 102 | uint8_t debugger_unload(struct debugger_plugin_t * plugin) 103 | { 104 | return true; 105 | } 106 | 107 | void debugger_plugin_init(struct debugger_plugin_t* plugin) 108 | { 109 | if (!plugin) 110 | return; 111 | 112 | plugin->plugin.name = "Debugger"; 113 | plugin->plugin.description = "Kernel mode debugger"; 114 | 115 | plugin->plugin.plugin_load = (uint8_t(*)(void*)) debugger_load; 116 | plugin->plugin.plugin_unload = (uint8_t(*)(void*)) debugger_unload; 117 | } 118 | 119 | void debugger_readmem_callback(struct allocation_t* ref) 120 | { 121 | struct message_t* message = __get(ref); 122 | if (!message) 123 | return; 124 | 125 | if (message->header.request != 1) 126 | goto cleanup; 127 | 128 | if (message->socket < 0) 129 | goto cleanup; 130 | 131 | if (!message->payload) 132 | goto cleanup; 133 | 134 | struct debugger_readmem_t* request = (struct debugger_readmem_t*)message->payload; 135 | if (request->process_id < 0) 136 | { 137 | WriteLog(LL_Error, "invalid process id."); 138 | goto error; 139 | } 140 | 141 | if (request->address == 0) 142 | { 143 | WriteLog(LL_Error, "Invalid address"); 144 | goto error; 145 | } 146 | 147 | if (request->dataLength == 0) 148 | { 149 | WriteLog(LL_Error, "Invalid data length."); 150 | goto error; 151 | } 152 | 153 | void(*_mtx_unlock_flags)(struct mtx *m, int opts, const char *file, int line) = kdlsym(_mtx_unlock_flags); 154 | struct proc* (*pfind)(pid_t) = kdlsym(pfind); 155 | 156 | struct proc* process = pfind(request->process_id); 157 | if (process == 0) 158 | goto error; 159 | 160 | int result = proc_rw_mem(process, (void*)request->address, request->dataLength, request->data, &request->dataLength, 0); 161 | PROC_UNLOCK(process); 162 | 163 | WriteLog(LL_Debug, "proc_rw_mem returned(%d, %p, %d, %p, %d, %s) %d", process, request->address, request->dataLength, request->data, &request->dataLength, "read", result); 164 | if (result < 0) 165 | goto error; 166 | 167 | message->header.request = 0; 168 | kwrite(message->socket, request, sizeof(*request)); 169 | 170 | // Error conditions 171 | if (1 == 0) 172 | { 173 | error: 174 | kmemset(request, 0, sizeof(*request)); 175 | request->process_id = -1; 176 | kwrite(message->socket, request, sizeof(*request)); 177 | } 178 | 179 | cleanup: 180 | __dec(ref); 181 | } 182 | 183 | void debugger_writemem_callback(struct allocation_t* ref) 184 | { 185 | struct message_t* message = __get(ref); 186 | if (!message) 187 | return; 188 | 189 | if (message->header.request != 1) 190 | goto cleanup; 191 | 192 | if (message->socket < 0) 193 | goto cleanup; 194 | 195 | if (!message->payload) 196 | goto cleanup; 197 | 198 | struct debugger_writemem_t* request = (struct debugger_writemem_t*)message->payload; 199 | if (request->process_id < 0) 200 | goto cleanup; 201 | 202 | if (request->address == 0) 203 | goto cleanup; 204 | 205 | if (request->dataLength == 0) 206 | goto cleanup; 207 | 208 | struct proc* (*pfind)(pid_t) = kdlsym(pfind); 209 | 210 | struct proc* process = pfind(request->process_id); 211 | if (process == 0) 212 | goto cleanup; 213 | 214 | void(*_mtx_unlock_flags)(struct mtx *m, int opts, const char *file, int line) = kdlsym(_mtx_unlock_flags); 215 | 216 | int result = proc_rw_mem(process, (void*)request->address, request->dataLength, request->data, &request->dataLength, 1); 217 | // You need to unlock the process, or the kernel will assert and hang 218 | PROC_UNLOCK(process); 219 | 220 | WriteLog(LL_Debug, "proc_rw_mem returned %d", result); 221 | 222 | 223 | cleanup: 224 | __dec(ref); 225 | } 226 | 227 | void debugger_getprocs_callback(struct allocation_t* ref) 228 | { 229 | if (!ref) 230 | return; 231 | 232 | struct message_t* message = __get(ref); 233 | if (!message) 234 | return; 235 | 236 | // Only handle requests 237 | if (message->header.request != 1) 238 | goto cleanup; 239 | 240 | int(*_sx_slock)(struct sx *sx, int opts, const char *file, int line) = kdlsym(_sx_slock); 241 | void(*_sx_sunlock)(struct sx *sx, const char *file, int line) = kdlsym(_sx_sunlock); 242 | void(*_mtx_lock_flags)(struct mtx *m, int opts, const char *file, int line) = kdlsym(_mtx_lock_flags); 243 | void(*_mtx_unlock_flags)(struct mtx *m, int opts, const char *file, int line) = kdlsym(_mtx_unlock_flags); 244 | struct sx* allproclock = (struct sx*)kdlsym(allproc_lock); 245 | struct proclist* allproc = (struct proclist*)*(uint64_t*)kdlsym(allproc); 246 | 247 | void(*vmspace_free)(struct vmspace *) = kdlsym(vmspace_free); 248 | struct vmspace* (*vmspace_acquire_ref)(struct proc *) = kdlsym(vmspace_acquire_ref); 249 | void(*_vm_map_lock_read)(vm_map_t map, const char *file, int line) = kdlsym(_vm_map_lock_read); 250 | void(*_vm_map_unlock_read)(vm_map_t map, const char *file, int line) = kdlsym(_vm_map_unlock_read); 251 | 252 | uint64_t procCount = 0; 253 | struct proc* p = NULL; 254 | struct debugger_getprocs_t getproc = { 0 }; 255 | 256 | sx_slock(allproclock); 257 | FOREACH_PROC_IN_SYSTEM(p) 258 | { 259 | PROC_LOCK(p); 260 | // Zero out our process information 261 | kmemset(&getproc, 0, sizeof(getproc)); 262 | 263 | // Get the vm map 264 | struct vmspace* vm = vmspace_acquire_ref(p); 265 | vm_map_t map = &p->p_vmspace->vm_map; 266 | vm_map_lock_read(map); 267 | 268 | struct vm_map_entry* entry = map->header.next; 269 | 270 | // Copy over all of the address information 271 | getproc.process_id = p->p_pid; 272 | getproc.text_address = (uint64_t)entry->start; 273 | getproc.text_size = (uint64_t)entry->end - entry->start; 274 | getproc.data_address = (uint64_t)p->p_vmspace->vm_daddr; 275 | getproc.data_size = p->p_vmspace->vm_dsize; 276 | // Copy over the name and path 277 | kmemcpy(getproc.process_name, p->p_comm, sizeof(getproc.process_name)); 278 | kmemcpy(getproc.path, p->p_elfpath, sizeof(getproc.path)); 279 | // Write it back to the PC 280 | kwrite(message->socket, &getproc, sizeof(getproc)); 281 | procCount++; 282 | 283 | // Free the vmmap 284 | vm_map_unlock_read(map); 285 | vmspace_free(vm); 286 | 287 | PROC_UNLOCK(p); 288 | } 289 | sx_sunlock(allproclock); 290 | // Send finalizer, because fuck this shit 291 | kmemset(&getproc, 0xDD, sizeof(getproc)); 292 | kwrite(message->socket, &getproc, sizeof(getproc)); 293 | 294 | cleanup: 295 | __dec(ref); 296 | } 297 | 298 | void debugger_ptrace_callback(struct allocation_t* ref) 299 | { 300 | if (!ref) 301 | return; 302 | 303 | struct message_t* message = __get(ref); 304 | if (!message) 305 | return; 306 | 307 | // Only handle requests 308 | if (message->header.request != 1) 309 | goto cleanup; 310 | 311 | if (!message->payload) 312 | { 313 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 314 | goto cleanup; 315 | } 316 | 317 | // set diag auth ID flags 318 | curthread->td_ucred->cr_sceAuthID = 0x3800000000000007ULL; 319 | 320 | // make system credentials 321 | curthread->td_ucred->cr_sceCaps[0] = 0xFFFFFFFFFFFFFFFFULL; 322 | curthread->td_ucred->cr_sceCaps[1] = 0xFFFFFFFFFFFFFFFFULL; 323 | 324 | struct debugger_ptrace_t* ptraceRequest = (struct debugger_ptrace_t*)message->payload; 325 | 326 | 327 | if (ptraceRequest->setAddrToBuffer) 328 | ptraceRequest->addr = (uint64_t)&ptraceRequest->buffer[0]; 329 | 330 | WriteLog(LL_Debug, "%d %d %llx %d %s", ptraceRequest->req, ptraceRequest->pid, ptraceRequest->addr, ptraceRequest->data, ptraceRequest->setAddrToBuffer ? "true" : "false"); 331 | ptraceRequest->res = kptrace(ptraceRequest->req, ptraceRequest->pid, (caddr_t)ptraceRequest->addr, ptraceRequest->data); 332 | 333 | WriteLog(LL_Debug, "ptrace: %d", ptraceRequest->res); 334 | 335 | kwrite(message->socket, ptraceRequest, sizeof(*ptraceRequest)); 336 | 337 | cleanup: 338 | __dec(ref); 339 | } 340 | 341 | void debugger_kill_callback(struct allocation_t* ref) 342 | { 343 | if (!ref) 344 | return; 345 | 346 | struct message_t* message = __get(ref); 347 | if (!message) 348 | return; 349 | 350 | // Only handle requests 351 | if (message->header.request != 1) 352 | goto cleanup; 353 | 354 | if (!message->payload) 355 | { 356 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 357 | goto cleanup; 358 | } 359 | 360 | struct debugger_kill_t* killRequest = (struct debugger_kill_t*)message->payload; 361 | 362 | int result = kkill(killRequest->pid, killRequest->signal); 363 | if (result < 0) 364 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, result); 365 | else 366 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 367 | 368 | cleanup: 369 | __dec(ref); 370 | } -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/debugger/debugger_plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct debugger_plugin_t 5 | { 6 | struct plugin_t plugin; 7 | }; 8 | 9 | uint8_t debugger_load(struct debugger_plugin_t* plugin); 10 | uint8_t debugger_unload(struct debugger_plugin_t* plugin); 11 | 12 | void debugger_plugin_init(struct debugger_plugin_t* plugin); -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/filetransfer/filetransfer_plugin.c: -------------------------------------------------------------------------------- 1 | #include "filetransfer_plugin.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef MIN 13 | #define MIN ( x, y ) ( (x) < (y) ? : (x) : (y) ) 14 | #endif 15 | 16 | enum { FileTransfer_MaxPath = 255 }; 17 | enum FileTransferCmds 18 | { 19 | FileTransfer_Open = 0x58AFA0D4, 20 | FileTransfer_Close = 0x43F82FDB, 21 | FileTransfer_GetDents = 0x7433E67A, 22 | FileTransfer_Read = 0x64886217, 23 | FileTransfer_ReadFile = 0x13B55E44, 24 | FileTransfer_Write = 0x2D92D440, 25 | FileTransfer_WriteFile = 0x3B91E812, 26 | FileTransfer_Delete = 0xB74A88DC, 27 | FileTransfer_Move = 0x13E11408, 28 | FileTransfer_Stat = 0xDC67DC51, 29 | FileTransfer_Mkdir = 0x5EB439FE, 30 | FileTransfer_Rmdir = 0x996F6671, 31 | FileTransfer_COUNT 32 | }; 33 | 34 | // Request with an open handle, rest zeroed. Response with all info filled 35 | struct filetransfer_getdents_t 36 | { 37 | // Previously opened handle 38 | int32_t handle; 39 | 40 | // Dirent type 41 | uint8_t type; 42 | 43 | // Path of a return entry 44 | char path[FileTransfer_MaxPath]; 45 | }; 46 | 47 | struct filetransfer_mkdir_t 48 | { 49 | char path[FileTransfer_MaxPath]; 50 | int mode; 51 | }; 52 | 53 | struct filetransfer_rmdir_t 54 | { 55 | char path[FileTransfer_MaxPath]; 56 | }; 57 | 58 | struct filetransfer_open_t 59 | { 60 | // File or folder path 61 | char path[255]; 62 | 63 | // Flags to open with 64 | int32_t flags; 65 | 66 | // Mode to open with 67 | int32_t mode; 68 | 69 | // Handle handle returned 70 | int32_t handle; 71 | }; 72 | 73 | struct filetransfer_close_t 74 | { 75 | // File or folder handle 76 | int32_t handle; 77 | }; 78 | 79 | struct filetransfer_readfile_t 80 | { 81 | // File handle 82 | int32_t handle; 83 | // Size of file 84 | uint64_t size; 85 | // Payload of the file is sent afterwards 86 | //uint8_t data[size]; 87 | }; 88 | 89 | struct filetransfer_writefile_t 90 | { 91 | // File handle 92 | int32_t handle; 93 | // File data to write 94 | uint64_t size; 95 | // Payload of the file is sent 96 | //uint8_t data[size]; 97 | }; 98 | 99 | struct filetransfer_read_t 100 | { 101 | // File handle 102 | int32_t handle; 103 | 104 | // Offset to read data in file 105 | uint64_t offset; 106 | 107 | // Size to read 108 | uint64_t size; 109 | 110 | // Payload of the data is sent 111 | }; 112 | 113 | struct filetransfer_write_t 114 | { 115 | // File handle 116 | int32_t handle; 117 | 118 | // Offset in file to write 119 | uint64_t offset; 120 | // Size of the data to write 121 | uint64_t size; 122 | // Payload is sent afterwards 123 | }; 124 | 125 | struct filetransfer_delete_t 126 | { 127 | // Path to delete 128 | char path[FileTransfer_MaxPath]; 129 | }; 130 | 131 | struct filetransfer_stat_t 132 | { 133 | // Path to stat 134 | char path[FileTransfer_MaxPath]; 135 | // protection mode 136 | int32_t mode; 137 | // user id owner; 138 | int32_t uid; 139 | // group id owner 140 | int32_t gid; 141 | // size 142 | uint64_t size; 143 | }; 144 | 145 | void filetransfer_open_callback(struct allocation_t* ref); 146 | void filetransfer_close_callback(struct allocation_t* ref); 147 | void filetransfer_read_callback(struct allocation_t* ref); 148 | void filetransfer_readfile_callback(struct allocation_t* ref); 149 | void filetransfer_write_callback(struct allocation_t* ref); 150 | void filetransfer_writefile_callback(struct allocation_t* ref); 151 | void filetransfer_getdents_callback(struct allocation_t* ref); 152 | void filetransfer_delete_callback(struct allocation_t* ref); 153 | void filetransfer_stat_callback(struct allocation_t* ref); 154 | void filetransfer_mkdir_callback(struct allocation_t* ref); 155 | void filetransfer_rmdir_callback(struct allocation_t* ref); 156 | void filetransfer_unlink_callback(struct allocation_t* ref); 157 | 158 | extern struct logger_t* gLogger; 159 | 160 | void filetransfer_plugin_init(struct filetransfer_plugin_t* plugin) 161 | { 162 | if (!plugin) 163 | return; 164 | 165 | plugin->plugin.name = "FileTransfer"; 166 | plugin->plugin.description = "File transfer plugin using a custom standalone protocol"; 167 | 168 | plugin->plugin.plugin_load = (uint8_t(*)(void*)) filetransfer_load; 169 | plugin->plugin.plugin_unload = (uint8_t(*)(void*)) filetransfer_unload; 170 | } 171 | 172 | uint8_t filetransfer_load(struct filetransfer_plugin_t* plugin) 173 | { 174 | // Register all of the callbacks 175 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Open, filetransfer_open_callback); 176 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Close, filetransfer_close_callback); 177 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Read, filetransfer_read_callback); 178 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_ReadFile, filetransfer_readfile_callback); 179 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Write, filetransfer_write_callback); 180 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_WriteFile, filetransfer_writefile_callback); 181 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_GetDents, filetransfer_getdents_callback); 182 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Delete, filetransfer_delete_callback); 183 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Stat, filetransfer_stat_callback); 184 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Mkdir, filetransfer_mkdir_callback); 185 | messagemanager_registerCallback(gFramework->messageManager, RPCCAT_FILE, FileTransfer_Rmdir, filetransfer_rmdir_callback); 186 | 187 | return true; 188 | } 189 | 190 | uint8_t filetransfer_unload(struct filetransfer_plugin_t* plugin) 191 | { 192 | return true; 193 | } 194 | 195 | void filetransfer_stat_callback(struct allocation_t* ref) 196 | { 197 | if (!ref) 198 | return; 199 | 200 | struct message_t* message = __get(ref); 201 | if (!message) 202 | return; 203 | 204 | if (message->header.request != 1) 205 | goto cleanup; 206 | 207 | 208 | if (!message->payload) 209 | { 210 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 211 | goto cleanup; 212 | } 213 | 214 | struct filetransfer_stat_t* fileStat = (struct filetransfer_stat_t*)message->payload; 215 | struct stat stat = { 0 }; 216 | 217 | int result = kstat(fileStat->path, &stat); 218 | if (result < 0) 219 | { 220 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, result); 221 | WriteLog(LL_Error, "kstat %s returned %d", fileStat->path, result); 222 | goto cleanup; 223 | } 224 | 225 | // Send success message 226 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 227 | 228 | // Fill out the struct 229 | fileStat->gid = stat.st_gid; 230 | fileStat->uid = stat.st_uid; 231 | fileStat->size = stat.st_size; 232 | fileStat->mode = stat.st_mode; 233 | 234 | // Send that shit back 235 | kwrite(message->socket, fileStat, sizeof(*fileStat)); 236 | 237 | cleanup: 238 | __dec(ref); 239 | } 240 | 241 | void filetransfer_open_callback(struct allocation_t* ref) 242 | { 243 | if (!ref) 244 | return; 245 | 246 | struct message_t* message = __get(ref); 247 | if (!message) 248 | return; 249 | 250 | if (message->header.request != 1) 251 | goto cleanup; 252 | 253 | 254 | if (!message->payload) 255 | { 256 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 257 | goto cleanup; 258 | } 259 | 260 | struct filetransfer_open_t* openRequest = (struct filetransfer_open_t*)message->payload; 261 | 262 | WriteLog(LL_Debug, "[+] openRequest %p %d %d.", openRequest, openRequest->flags, openRequest->mode); 263 | 264 | openRequest->handle = kopen(openRequest->path, openRequest->flags, openRequest->mode); 265 | if (openRequest->handle < 0) 266 | { 267 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, openRequest->handle); 268 | WriteLog(LL_Error, "[-] could not open file %s %d.", openRequest->path, openRequest->handle); 269 | goto cleanup; 270 | } 271 | 272 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 273 | 274 | // Send to socket if needed 275 | if (message->socket > 0) 276 | kwrite(message->socket, openRequest, sizeof(*openRequest)); 277 | 278 | cleanup: 279 | __dec(ref); 280 | } 281 | 282 | void filetransfer_rmdir_callback(struct allocation_t* ref) 283 | { 284 | if (!ref) 285 | return; 286 | 287 | struct message_t* message = __get(ref); 288 | if (!message) 289 | return; 290 | 291 | if (message->header.request != true) 292 | goto cleanup; 293 | 294 | if (!message->payload) 295 | { 296 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 297 | goto cleanup; 298 | } 299 | 300 | struct filetransfer_rmdir_t* rmdirRequest = (struct filetransfer_rmdir_t*)message->payload; 301 | 302 | WriteLog(LL_Debug, "rmdir (%s)", rmdirRequest->path); 303 | 304 | int result = krmdir(rmdirRequest->path); 305 | if (result == -1) 306 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOENT); 307 | else 308 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 309 | 310 | cleanup: 311 | __dec(ref); 312 | } 313 | 314 | void filetransfer_mkdir_callback(struct allocation_t* ref) 315 | { 316 | if (!ref) 317 | return; 318 | 319 | struct message_t* message = __get(ref); 320 | if (!message) 321 | return; 322 | 323 | if (message->header.request != true) 324 | goto cleanup; 325 | 326 | if (!message->payload) 327 | { 328 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 329 | goto cleanup; 330 | } 331 | 332 | struct filetransfer_mkdir_t* mkdirRequest = (struct filetransfer_mkdir_t*)message->payload; 333 | 334 | WriteLog(LL_Debug, "mk (%s) (%d)", mkdirRequest->path, mkdirRequest->mode); 335 | 336 | int result = kmkdir(mkdirRequest->path, mkdirRequest->mode); 337 | if (result == -1) 338 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, EACCES); 339 | else 340 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 341 | 342 | cleanup: 343 | __dec(ref); 344 | } 345 | 346 | void filetransfer_close_callback(struct allocation_t* ref) 347 | { 348 | struct message_t* message = __get(ref); 349 | if (!message) 350 | return; 351 | 352 | if (message->header.request != 1) 353 | goto cleanup; 354 | 355 | if (!message->payload) 356 | goto cleanup; 357 | 358 | struct filetransfer_close_t* closeRequest = (struct filetransfer_close_t*)message->payload; 359 | 360 | WriteLog(LL_Debug, "[+] closeRequest %p %d", closeRequest, closeRequest->handle); 361 | 362 | kclose(closeRequest->handle); 363 | 364 | cleanup: 365 | __dec(ref); 366 | } 367 | 368 | void filetransfer_read_callback(struct allocation_t* ref) 369 | { 370 | // TODO: implement 371 | if (!ref) 372 | return; 373 | 374 | struct message_t* message = __get(ref); 375 | if (!message) 376 | return; 377 | 378 | if (message->header.request != 1) 379 | goto cleanup; 380 | 381 | if (!message->payload) 382 | { 383 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 384 | goto cleanup; 385 | } 386 | 387 | struct filetransfer_read_t* readRequest = (struct filetransfer_read_t*)message->payload; 388 | 389 | // Verify that the handle is valid 390 | if (readRequest->handle < 0) 391 | { 392 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOENT); 393 | goto cleanup; 394 | } 395 | 396 | WriteLog(LL_Debug, "[+] creating struct"); 397 | struct stat statbuf; 398 | kmemset(&statbuf, 0, sizeof(statbuf)); 399 | 400 | // Get the file size 401 | WriteLog(LL_Debug, "[+] calling stat(%d, %p);", readRequest->handle, &statbuf); 402 | int res = kfstat(readRequest->handle, &statbuf); 403 | if (res < 0) 404 | { 405 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, res); 406 | WriteLog(LL_Error, "[-] could not get %d handle stat: %d", readRequest->handle, res); 407 | goto cleanup; 408 | } 409 | 410 | // Verify that the offset is within bounds 411 | if (readRequest->offset > statbuf.st_size) 412 | { 413 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, EIO); 414 | WriteLog(LL_Error, "offset > fileSize"); 415 | goto cleanup; 416 | } 417 | 418 | // Check to see if the offset + size is greater than the length 419 | if (readRequest->offset + readRequest->size > statbuf.st_size) 420 | { 421 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, EIO); 422 | WriteLog(LL_Error, "offset + size > fileSize"); 423 | goto cleanup; 424 | 425 | } 426 | 427 | const int bufferSize = 0x4000; 428 | uint8_t* buffer = (uint8_t*)kmalloc(bufferSize); 429 | if (!buffer) 430 | { 431 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 432 | goto cleanup; 433 | } 434 | 435 | // Send success message sayuing we got all of our information 436 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 437 | 438 | // Seek to the position in file 439 | klseek(readRequest->handle, readRequest->offset, 0); 440 | 441 | // Zero the buffer 442 | kmemset(buffer, 0, bufferSize); 443 | 444 | // Write the header 445 | message->header.request = 0; 446 | kwrite(message->socket, readRequest, sizeof(*readRequest)); 447 | 448 | // Calculate the blocks and leftover data 449 | uint64_t blocks = readRequest->size / bufferSize; 450 | uint64_t leftover = readRequest->size % bufferSize; 451 | 452 | // Write all blocks 453 | for (uint64_t i = 0; i < blocks; ++i) 454 | { 455 | kread(readRequest->handle, buffer, bufferSize); 456 | kwrite(message->socket, buffer, bufferSize); 457 | kmemset(buffer, 0, bufferSize); 458 | } 459 | 460 | // Write leftover data 461 | kread(readRequest->handle, buffer, leftover); 462 | kwrite(message->socket, buffer, leftover); 463 | 464 | kfree(buffer, bufferSize); 465 | cleanup: 466 | __dec(ref); 467 | } 468 | 469 | void filetransfer_readfile_callback(struct allocation_t* ref) 470 | { 471 | struct message_t* message = __get(ref); 472 | if (!message) 473 | return; 474 | 475 | if (message->header.request != 1) 476 | goto cleanup; 477 | 478 | // Validate that the socket is valid before we continue 479 | if (message->socket < 0) 480 | { 481 | WriteLog(LL_Error, "[-] socket not set"); 482 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 483 | goto cleanup; 484 | } 485 | 486 | struct filetransfer_readfile_t* readRequest = (struct filetransfer_readfile_t*)message->payload; 487 | if (!readRequest) 488 | { 489 | WriteLog(LL_Error, "[-] invalid payload"); 490 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 491 | goto cleanup; 492 | } 493 | 494 | WriteLog(LL_Debug, "[+] creating struct"); 495 | struct stat statbuf; 496 | kmemset(&statbuf, 0, sizeof(statbuf)); 497 | 498 | // Get the file size 499 | WriteLog(LL_Debug, "[+] calling stat(%d, %p);", readRequest->handle, &statbuf); 500 | int res = kfstat(readRequest->handle, &statbuf); 501 | if (res < 0) 502 | { 503 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, res); 504 | WriteLog(LL_Error, "[-] could not get %d handle stat: %d", readRequest->handle, res); 505 | goto cleanup; 506 | } 507 | 508 | const int bufferSize = 0x4000; 509 | uint8_t* buffer = (uint8_t*)kmalloc(bufferSize); 510 | if (!buffer) 511 | { 512 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 513 | goto cleanup; 514 | } 515 | 516 | // Send success 517 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 518 | 519 | // Set the size 520 | readRequest->size = statbuf.st_size; 521 | WriteLog(LL_Debug, "[+] file size: %llx", readRequest->size); 522 | 523 | // Zero the buffer 524 | kmemset(buffer, 0, bufferSize); 525 | 526 | // Write the header 527 | message->header.request = 0; 528 | kwrite(message->socket, readRequest, sizeof(*readRequest)); 529 | 530 | // Calculate the blocks and leftover data 531 | uint64_t blocks = statbuf.st_size / bufferSize; 532 | uint64_t leftover = statbuf.st_size % bufferSize; 533 | 534 | // Write all blocks 535 | for (uint64_t i = 0; i < blocks; ++i) 536 | { 537 | kread(readRequest->handle, buffer, bufferSize); 538 | kwrite(message->socket, buffer, bufferSize); 539 | kmemset(buffer, 0, bufferSize); 540 | } 541 | 542 | // Write leftover data 543 | kread(readRequest->handle, buffer, leftover); 544 | kwrite(message->socket, buffer, leftover); 545 | 546 | kfree(buffer, bufferSize); 547 | 548 | cleanup: 549 | __dec(ref); 550 | } 551 | 552 | void filetransfer_write_callback(struct allocation_t* ref) 553 | { 554 | if (!ref) 555 | return; 556 | 557 | struct message_t* message = __get(ref); 558 | if (!message) 559 | return; 560 | 561 | if (message->header.request != 1) 562 | goto cleanup; 563 | 564 | if (!message->payload) 565 | { 566 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 567 | goto cleanup; 568 | } 569 | 570 | struct filetransfer_write_t* writeRequest = (struct filetransfer_write_t*)message->payload; 571 | 572 | // Verify that the handle is valid 573 | if (writeRequest->handle < 0) 574 | { 575 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOENT); 576 | goto cleanup; 577 | } 578 | 579 | const int bufferSize = 0x4000; 580 | uint8_t* buffer = (uint8_t*)kmalloc(bufferSize); 581 | if (!buffer) 582 | { 583 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 584 | goto cleanup; 585 | } 586 | 587 | // Send success message sayuing we got all of our information 588 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 589 | 590 | // Seek to the position in file 591 | klseek(writeRequest->handle, writeRequest->offset, 0); 592 | 593 | // Zero the buffer 594 | kmemset(buffer, 0, bufferSize); 595 | 596 | // Write the header 597 | message->header.request = 0; 598 | 599 | // Calculate the blocks and leftover data 600 | uint64_t blocks = writeRequest->size / bufferSize; 601 | uint64_t leftover = writeRequest->size % bufferSize; 602 | 603 | // Write all blocks 604 | for (uint64_t i = 0; i < blocks; ++i) 605 | { 606 | kread(message->socket, buffer, bufferSize); 607 | kwrite(writeRequest->handle, buffer, bufferSize); 608 | kmemset(buffer, 0, bufferSize); 609 | } 610 | 611 | // Write leftover data 612 | kread(message->socket, buffer, leftover); 613 | kwrite(writeRequest->handle, buffer, leftover); 614 | 615 | kfree(buffer, bufferSize); 616 | cleanup: 617 | __dec(ref); 618 | } 619 | 620 | void filetransfer_writefile_callback(struct allocation_t* ref) 621 | { 622 | if (!ref) 623 | return; 624 | 625 | struct message_t* message = __get(ref); 626 | if (!message) 627 | return; 628 | 629 | if (message->header.request != 1) 630 | goto cleanup; 631 | 632 | if (!message->payload) 633 | { 634 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 635 | goto cleanup; 636 | } 637 | 638 | struct filetransfer_writefile_t* writeRequest = (struct filetransfer_writefile_t*)message->payload; 639 | 640 | // Verify that the handle is valid 641 | if (writeRequest->handle < 0) 642 | { 643 | WriteLog(LL_Error, "invalid handle"); 644 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOENT); 645 | goto cleanup; 646 | } 647 | 648 | const int bufferSize = 0x4000; 649 | uint8_t* buffer = (uint8_t*)kmalloc(bufferSize); 650 | if (!buffer) 651 | { 652 | WriteLog(LL_Error, "could not allocate temporary buffer"); 653 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 654 | goto cleanup; 655 | } 656 | 657 | // Seek to the position in file 658 | klseek(writeRequest->handle, 0, 0); 659 | 660 | uint64_t totalSize = writeRequest->size; 661 | uint64_t dataReceived = 0; 662 | 663 | while (dataReceived < totalSize) 664 | { 665 | // seek to the right position 666 | klseek(writeRequest->handle, dataReceived, 0); 667 | 668 | int32_t currentSize = MIN(0x4000, writeRequest->size - dataReceived); 669 | kmemset(buffer, 0, bufferSize); 670 | 671 | int recvSize = krecv(message->socket, buffer, currentSize, 0); 672 | if (recvSize < 0) 673 | { 674 | WriteLog(LL_Error, "could not recv %d", recvSize); 675 | goto cleanup; 676 | } 677 | 678 | dataReceived += recvSize; 679 | 680 | kwrite(writeRequest->handle, buffer, currentSize); 681 | } 682 | 683 | kfree(buffer, bufferSize); 684 | buffer = NULL; 685 | 686 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 687 | 688 | cleanup: 689 | __dec(ref); 690 | } 691 | 692 | void filetransfer_getdents_callback(struct allocation_t* ref) 693 | { 694 | if (!ref) 695 | return; 696 | 697 | struct message_t* message = __get(ref); 698 | if (!message) 699 | return; 700 | 701 | if (message->header.request != 1) 702 | goto cleanup; 703 | 704 | if (!message->payload) 705 | { 706 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 707 | WriteLog(LL_Error, "[-] invalid payload"); 708 | goto cleanup; 709 | } 710 | 711 | struct filetransfer_getdents_t* payload = (struct filetransfer_getdents_t*)message->payload; 712 | 713 | WriteLog(LL_Debug, "[+] getdents %s", payload->path); 714 | 715 | int handle = kopen(payload->path, 0x0000 | 0x00020000, 0); 716 | if (handle < 0) 717 | { 718 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, handle); 719 | WriteLog(LL_Error, "[-] could not open path %s", payload->path); 720 | goto cleanup; 721 | } 722 | 723 | // Run through once to get the count 724 | uint64_t dentCount = 0; 725 | struct dirent* dent = 0; 726 | const uint32_t bufferSize = 0x8000; 727 | char* buffer = kmalloc(bufferSize); 728 | if (!buffer) 729 | { 730 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 731 | WriteLog(LL_Error, "could not allocate memory"); 732 | goto cleanup; 733 | } 734 | 735 | // Zero out the buffer size 736 | kmemset(buffer, 0, bufferSize); 737 | 738 | // Get all of the directory entries the first time to get the count 739 | while (kgetdents(handle, buffer, bufferSize) > 0) 740 | { 741 | dent = (struct dirent*)buffer; 742 | 743 | while (dent->d_fileno) 744 | { 745 | if (dent->d_type == 0) 746 | break; 747 | 748 | dentCount++; 749 | dent = (struct dirent*)((uint8_t*)dent + dent->d_reclen); 750 | } 751 | } 752 | 753 | WriteLog(LL_Debug, "[+] closing handle"); 754 | kclose(handle); 755 | 756 | // Re-open the handle 757 | handle = kopen(payload->path, 0x0000 | 0x00020000, 0); 758 | if (handle < 0) 759 | { 760 | kfree(buffer, bufferSize); 761 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, handle); 762 | WriteLog(LL_Error, "[-] could not open path %s", payload->path); 763 | goto cleanup; 764 | } 765 | 766 | // Return success code 767 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 768 | 769 | // Send the dent count 770 | kwrite(message->socket, &dentCount, sizeof(dentCount)); 771 | 772 | struct filetransfer_getdents_t writeDent; 773 | kmemset(&writeDent, 0, sizeof(writeDent)); 774 | kmemset(buffer, 0, bufferSize); 775 | 776 | dent = 0; 777 | while (kgetdents(handle, buffer, bufferSize) > 0) 778 | { 779 | dent = (struct dirent*)buffer; 780 | while (dent->d_fileno) 781 | { 782 | //printf("[+] fileno %d\n", dent->d_fileno); 783 | 784 | if (dent->d_type == 0) 785 | break; 786 | 787 | // Zero out the dent 788 | kmemset(&writeDent, 0, sizeof(writeDent)); 789 | 790 | // Copy over the name, truncating it if need be 791 | int nameLength = dent->d_namlen > 255 ? 255 : dent->d_namlen; 792 | 793 | kmemcpy(writeDent.path, dent->d_name, nameLength); 794 | 795 | writeDent.type = dent->d_type; 796 | writeDent.handle = dent->d_fileno; 797 | 798 | kwrite(message->socket, &writeDent, sizeof(writeDent)); 799 | 800 | //printf("[+] writing dent %p\n", dent); 801 | dent = (struct dirent*)((uint8_t*)dent + dent->d_reclen); 802 | } 803 | } 804 | 805 | kfree(buffer, bufferSize); 806 | kclose(handle); 807 | 808 | cleanup: 809 | __dec(ref); 810 | } 811 | 812 | void filetransfer_delete_callback(struct allocation_t* ref) 813 | { 814 | if (!ref) 815 | return; 816 | 817 | struct message_t* message = __get(ref); 818 | if (!message) 819 | return; 820 | 821 | if (message->header.request != 1) 822 | goto cleanup; 823 | 824 | if (!message->payload) 825 | { 826 | messagemanager_sendErrorMessage(gFramework->messageManager, ref, ENOMEM); 827 | goto cleanup; 828 | } 829 | 830 | struct filetransfer_delete_t* deleteRequest = (struct filetransfer_delete_t*)message->payload; 831 | 832 | message->header.request = 0; 833 | message->header.error_type = kunlink(deleteRequest->path); 834 | 835 | messagemanager_sendSuccessMessage(gFramework->messageManager, ref); 836 | 837 | cleanup: 838 | __dec(ref); 839 | } 840 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/filetransfer/filetransfer_plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct filetransfer_plugin_t 5 | { 6 | struct plugin_t plugin; 7 | }; 8 | 9 | struct filetransfer_transfer_t 10 | { 11 | uint64_t position; 12 | uint64_t length; 13 | }; 14 | 15 | uint8_t filetransfer_load(struct filetransfer_plugin_t* plugin); 16 | uint8_t filetransfer_unload(struct filetransfer_plugin_t* plugin); 17 | 18 | void filetransfer_plugin_init(struct filetransfer_plugin_t* plugin); -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/logserver/logserver_plugin.c: -------------------------------------------------------------------------------- 1 | #include "logserver_plugin.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | uint8_t logserver_load(struct logserver_plugin_t* plugin); 12 | uint8_t logserver_unload(struct logserver_plugin_t* plugin); 13 | 14 | void logserver_init(struct logserver_plugin_t* plugin) 15 | { 16 | plugin->plugin.name = "LogServer"; 17 | plugin->plugin.description = "(empty)"; 18 | plugin->plugin.plugin_load = (uint8_t(*)(void*)) logserver_load; 19 | plugin->plugin.plugin_unload = (uint8_t(*)(void*)) logserver_unload; 20 | 21 | plugin->socket = -1; 22 | plugin->port = 9998; 23 | plugin->thread = NULL; 24 | } 25 | 26 | uint8_t logserver_load(struct logserver_plugin_t* plugin) 27 | { 28 | if (!plugin) 29 | return false; 30 | 31 | // Create a new socket 32 | plugin->socket = ksocket(AF_INET, SOCK_STREAM, 0); 33 | if (plugin->socket == -1) 34 | { 35 | WriteLog(LL_Error, "could not create listen socket"); 36 | return false; 37 | } 38 | 39 | // Set up address 40 | kmemset(&plugin->address, 0, sizeof(plugin->address)); 41 | plugin->address.sin_family = AF_INET; 42 | plugin->address.sin_addr.s_addr = INADDR_ANY; 43 | plugin->address.sin_port = __bswap16(plugin->port); 44 | plugin->address.sin_len = sizeof(plugin->address); 45 | 46 | // Bind to port 47 | int ret = kbind(plugin->socket, (struct sockaddr*)&plugin->address, sizeof(plugin->address)); 48 | if (ret < 0) 49 | { 50 | kshutdown(plugin->socket, 2); 51 | kclose(plugin->socket); 52 | plugin->socket = -1; 53 | 54 | WriteLog(LL_Error, "could not bind to socket %d", ret); 55 | return false; 56 | } 57 | 58 | // Listen for clients 59 | if (klisten(plugin->socket, 3) == -1) 60 | { 61 | kshutdown(plugin->socket, 2); 62 | kclose(plugin->socket); 63 | plugin->socket = -1; 64 | 65 | WriteLog(LL_Error, "could not listen to the socket."); 66 | return false; 67 | } 68 | 69 | utilUSleep(100, ""); 70 | 71 | int creationResult = kthread_add(logserver_serverThread, plugin, curthread->td_proc, (struct thread**)&plugin->thread, 0, 0, "logserver"); 72 | if (creationResult != 0) 73 | return 0; 74 | 75 | WriteLog(LL_Debug, "logserver thread started."); 76 | 77 | return true; 78 | } 79 | 80 | uint8_t logserver_unload(struct logserver_plugin_t* plugin) 81 | { 82 | if (!plugin) 83 | return false; 84 | 85 | 86 | plugin->isRunning = false; 87 | return true; 88 | } 89 | 90 | void logserver_serverThread(void* data) 91 | { 92 | if (!data) 93 | { 94 | kthread_exit(); 95 | return; 96 | } 97 | 98 | WriteLog(LL_Info, "Entered Log Thread"); 99 | 100 | struct logserver_plugin_t* plugin = (struct logserver_plugin_t*)data; 101 | plugin->isRunning = true; 102 | 103 | struct sockaddr_in address; 104 | size_t clientAddressSize = sizeof(address); 105 | kmemset(&address, 0, sizeof(address)); 106 | 107 | int32_t socket = -1; 108 | 109 | char buffer[2]; 110 | 111 | WriteLog(LL_Info, "Accepting klog clients"); 112 | while ((socket = kaccept(plugin->socket, (struct sockaddr*)&address, &clientAddressSize)) >= 0) 113 | { 114 | if (!plugin->isRunning) 115 | break; 116 | 117 | WriteLog(LL_Info, "New logclient connected"); 118 | 119 | if (socket == -1) 120 | continue; 121 | 122 | WriteLog(LL_Info, "Opening klog"); 123 | int32_t klog = kopen("/dev/klog", O_RDONLY, 0); 124 | if (klog < 0) 125 | { 126 | WriteLog(LL_Error, "could not open klog for reading (%d).", klog); 127 | break; 128 | } 129 | 130 | int32_t bytesRead = 0; 131 | 132 | while ((bytesRead = kread(klog, buffer, 1)) > 0) 133 | { 134 | if (!plugin->isRunning) 135 | break; 136 | 137 | if (kwrite(socket, buffer, 1) < 0) 138 | break; 139 | 140 | kmemset(buffer, 0, sizeof(buffer)); 141 | } 142 | 143 | kclose(klog); 144 | 145 | kshutdown(socket, 2); 146 | kclose(socket); 147 | socket = -1; 148 | } 149 | 150 | WriteLog(LL_Info, "shutting down thread"); 151 | plugin->isRunning = false; 152 | 153 | kshutdown(plugin->socket, 2); 154 | kclose(plugin->socket); 155 | plugin->socket = -1; 156 | 157 | kthread_exit(); 158 | } -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/logserver/logserver_plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define LOGSERVER_MAXCLIENTS 8 6 | #define LOGSERVER_BUFFERSIZE 0x1000 7 | 8 | struct logserver_plugin_t; 9 | 10 | struct logserver_client_t 11 | { 12 | int32_t socket; 13 | 14 | struct thread* thread; 15 | 16 | // Buffer 17 | uint8_t buffer[LOGSERVER_BUFFERSIZE]; 18 | 19 | // Address of the client 20 | struct sockaddr_in address; 21 | 22 | struct loginserver_plugin_t* server; 23 | }; 24 | 25 | struct logserver_plugin_t 26 | { 27 | struct plugin_t plugin; 28 | 29 | struct sockaddr_in address; 30 | int32_t socket; 31 | uint16_t port; 32 | 33 | int isRunning; 34 | struct thread* thread; 35 | 36 | }; 37 | 38 | void logserver_init(struct logserver_plugin_t* plugin); 39 | 40 | void logserver_serverThread(void* data); -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/pluginloader.c: -------------------------------------------------------------------------------- 1 | #include "pluginloader.h" 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define PLUGIN_MAXSIZE 0x200000 // 2MB hard cap 16 | 17 | static struct plugininit_t gLoaderPluginInit; 18 | 19 | static uint8_t pluginloader_addPluginToList(struct pluginloader_t* loader, struct loaderplugin_t* pluginEntry); 20 | 21 | struct loaderplugin_t* pluginloader_loadPluginFromFile(struct pluginloader_t* loader, char* path); 22 | 23 | size_t strlen(const char * str) 24 | { 25 | const char *s; 26 | for (s = str; *s; ++s) {} 27 | return(s - str); 28 | } 29 | 30 | int strcmp(const char * s1, const char * s2) 31 | { 32 | for (; *s1 == *s2; ++s1, ++s2) 33 | if (*s1 == 0) 34 | return 0; 35 | return *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1; 36 | } 37 | 38 | void pluginloader_init(struct pluginloader_t* loader) 39 | { 40 | if (!loader) 41 | return; 42 | 43 | // Initialize all fields 44 | loader->pluginList = NULL; 45 | loader->pluginCount = 0; 46 | loader->pluginDirectory = NULL; 47 | 48 | // Get the currently configured framework plugin path 49 | char* frameworkPluginPath = gFramework->pluginsPath; 50 | if (!frameworkPluginPath) 51 | { 52 | WriteLog(LL_Error, "could not initialize pluginloader, plugin path not set"); 53 | return; 54 | } 55 | 56 | // Calculate the path length 57 | // TODO: Unhack this 58 | size_t pluginPathLength = strlen(frameworkPluginPath); 59 | if (pluginPathLength == 0 || pluginPathLength > 260) 60 | { 61 | WriteLog(LL_Error, "path length is either zero, or > 260"); 62 | return; 63 | } 64 | 65 | // Update the length 66 | loader->pluginDirectoryLength = pluginPathLength; 67 | 68 | // Allocate space for the plugin path 69 | char* pluginPath = (char*)kmalloc(pluginPathLength + 1); 70 | if (!pluginPath) 71 | { 72 | WriteLog(LL_Error, "could not allocate space for plugin path."); 73 | return; 74 | } 75 | kmemset(pluginPath, 0, pluginPathLength + 1); 76 | 77 | // Copy over our string 78 | kmemcpy(pluginPath, frameworkPluginPath, pluginPathLength); 79 | 80 | loader->pluginDirectory = pluginPath; 81 | 82 | // Assign our plugin loader params 83 | gLoaderPluginInit.framework = gFramework; 84 | gLoaderPluginInit.kernelBase = gKernelBase; 85 | gLoaderPluginInit.logger = gLogger; 86 | } 87 | 88 | uint8_t pluginloader_addPluginToList(struct pluginloader_t* loader, struct loaderplugin_t* pluginEntry) 89 | { 90 | if (!loader || !pluginEntry) 91 | return false; 92 | 93 | // CHeck if we have a plugin list at all 94 | if (!loader->pluginList || !loader->pluginCount) 95 | { 96 | // Calculate the new size (sizeof(pointer) * however many in list) 97 | size_t newListSize = sizeof(pluginEntry) * 1; 98 | struct loaderplugin_t** newList = (struct loaderplugin_t**)kmalloc(newListSize); 99 | if (!newList) 100 | { 101 | WriteLog(LL_Error, "could not allocate new list"); 102 | return false; 103 | } 104 | 105 | // Assign our new entry 106 | newList[0] = pluginEntry; 107 | 108 | // Assign our new plugin list 109 | loader->pluginList = newList; 110 | loader->pluginCount = 1; 111 | 112 | return true; 113 | } 114 | 115 | // Am I bat-shit insane for this?... probably 116 | // This screams, I need locks 117 | 118 | // If there exist a list already add a new entry 119 | struct loaderplugin_t** oldList = loader->pluginList; 120 | size_t oldPluginCount = loader->pluginCount; 121 | size_t oldListSize = sizeof(struct loaderplugin_t*) * oldPluginCount; 122 | 123 | size_t newPluginCount = oldPluginCount + 1; 124 | size_t newListSize = sizeof(struct loaderplugin_t*) * (newPluginCount); 125 | struct loaderplugin_t** newList = (struct loaderplugin_t**)kmalloc(newListSize); 126 | if (!newList) 127 | { 128 | WriteLog(LL_Error, "could not allocate new list"); 129 | return false; 130 | } 131 | kmemset(newList, 0, newListSize); 132 | 133 | // Copy over the old list 134 | kmemcpy(newList, oldList, oldListSize); 135 | 136 | // Add our final entry 137 | newList[oldPluginCount] = pluginEntry; 138 | 139 | // Assign everything 140 | loader->pluginList = newList; 141 | loader->pluginCount = newPluginCount; 142 | 143 | return true; 144 | } 145 | 146 | uint32_t pluginloader_getAvailablePluginCount(struct pluginloader_t* loader) 147 | { 148 | if (!loader) 149 | return 0; 150 | 151 | if (!loader->pluginDirectory || loader->pluginDirectoryLength == 0) 152 | return 0; 153 | 154 | int handle = kopen(loader->pluginDirectory, 0x0000 | 0x00020000, 0); 155 | if (handle < 0) 156 | { 157 | WriteLog(LL_Error, "could not open plugin directory %s", loader->pluginDirectory); 158 | return 0; 159 | } 160 | 161 | // Run through once to get the count 162 | uint64_t dentCount = 0; 163 | struct dirent* dent = 0; 164 | const uint32_t bufferSize = 0x8000; 165 | char* buffer = kmalloc(bufferSize); 166 | if (!buffer) 167 | { 168 | WriteLog(LL_Error, "could not allocate memory"); 169 | kclose(handle); 170 | return 0; 171 | } 172 | 173 | // Zero out the buffer size 174 | kmemset(buffer, 0, bufferSize); 175 | 176 | // Get all of the directory entries the first time to get the count 177 | while (kgetdents(handle, buffer, bufferSize) > 0) 178 | { 179 | dent = (struct dirent*)buffer; 180 | 181 | while (dent->d_fileno) 182 | { 183 | if (dent->d_type == 0) 184 | break; 185 | 186 | // Create a new plugin entry 187 | 188 | dent = (struct dirent*)((uint8_t*)dent + dent->d_reclen); 189 | } 190 | } 191 | 192 | kclose(handle); 193 | 194 | return dentCount; 195 | } 196 | 197 | struct loaderplugin_t* pluginloader_loadPluginFromFile(struct pluginloader_t* loader, char* pluginPath) 198 | { 199 | if (!loader || !pluginPath) 200 | return NULL; 201 | 202 | int fd = kopen(pluginPath, O_RDONLY, 0); 203 | if (fd < 0) 204 | { 205 | WriteLog(LL_Error, "could not load plugin (%s).", pluginPath); 206 | return NULL; 207 | } 208 | 209 | struct stat statbuf; 210 | kmemset(&statbuf, 0, sizeof(statbuf)); 211 | 212 | // Get the file size 213 | int res = kfstat(fd, &statbuf); 214 | if (res < 0) 215 | { 216 | WriteLog(LL_Error, "could not get %d handle stat: %d", fd, res); 217 | kclose(fd); 218 | return NULL; 219 | } 220 | 221 | // Verify that our plugin is under the size limit 222 | size_t pluginSize = statbuf.st_size; 223 | if (pluginSize > PLUGIN_MAXSIZE) 224 | { 225 | WriteLog(LL_Warn, "plugin (%s) is too large, skipping.", pluginPath); 226 | kclose(fd); 227 | return NULL; 228 | } 229 | 230 | uint8_t* pluginData = (uint8_t*)kmalloc(pluginSize); 231 | if (!pluginData) 232 | { 233 | WriteLog(LL_Error, "could not allocate space for plugin (%s) (size: %lld)", pluginPath, pluginSize); 234 | kclose(fd); 235 | return NULL; 236 | } 237 | kmemset(pluginData, 0, pluginSize); 238 | 239 | // Read out our plugin data 240 | klseek(fd, 0, SEEK_SET); 241 | kread(fd, pluginData, pluginSize); 242 | kclose(fd); 243 | 244 | // Allocate a new entry for our list 245 | struct loaderplugin_t* entry = (struct loaderplugin_t*)kmalloc(sizeof(struct loaderplugin_t)); 246 | if (!entry) 247 | { 248 | WriteLog(LL_Error, "could not allocate new entry"); 249 | kfree(pluginData, pluginSize); 250 | return NULL; 251 | } 252 | 253 | entry->data = pluginData; 254 | entry->dataLength = pluginSize; 255 | entry->plugin = NULL; // do not create the plugin here 256 | 257 | size_t pathLength = strlen(pluginPath); 258 | if (pathLength > sizeof(entry->path)) 259 | WriteLog(LL_Warn, "path is too long, not setting"); 260 | else 261 | kmemcpy(entry->path, pluginPath, pathLength); 262 | 263 | return entry; 264 | } 265 | 266 | void pluginloader_loadPlugins(struct pluginloader_t* loader) 267 | { 268 | // Verify that the loader is valid 269 | if (!loader) 270 | return; 271 | 272 | // Verify that the plugin directory is set 273 | char* pluginDirectory = loader->pluginDirectory; 274 | if (!pluginDirectory) 275 | { 276 | WriteLog(LL_Error, "Plugin directory not set."); 277 | return; 278 | } 279 | 280 | // Get the total available plugin count 281 | uint32_t pluginCount = pluginloader_getAvailablePluginCount(loader); 282 | if (pluginCount == 0) 283 | { 284 | WriteLog(LL_Info, "No plugins available to load from %s.", pluginDirectory); 285 | return; 286 | } 287 | 288 | int handle = kopen(pluginDirectory, 0x0000 | 0x00020000, 0); 289 | if (handle < 0) 290 | { 291 | WriteLog(LL_Error, "[-] could not open path %s", pluginDirectory); 292 | return; 293 | } 294 | 295 | struct dirent* dent = 0; 296 | const uint32_t bufferSize = 0x8000; 297 | char* buffer = kmalloc(bufferSize); 298 | if (!buffer) 299 | { 300 | kclose(handle); 301 | WriteLog(LL_Error, "could not allocate memory"); 302 | return; 303 | } 304 | 305 | // Zero out the buffer size 306 | kmemset(buffer, 0, bufferSize); 307 | 308 | while (kgetdents(handle, buffer, bufferSize) > 0) 309 | { 310 | dent = (struct dirent*)buffer; 311 | 312 | while (dent->d_fileno) 313 | { 314 | if (dent->d_type == 0) 315 | break; 316 | 317 | // Skip over the . and .. entries 318 | if (!strcmp(".", dent->d_name) || !strcmp("..", dent->d_name)) 319 | { 320 | dent = (struct dirent*)((uint8_t*)dent + dent->d_reclen); 321 | continue; 322 | } 323 | 324 | // Load the plugin from file 325 | struct loaderplugin_t* entry = pluginloader_loadPluginFromFile(loader, dent->d_name); 326 | if (!pluginloader_addPluginToList(loader, entry)) 327 | { 328 | WriteLog(LL_Error, "could not add plugin to list."); 329 | kfree(entry, sizeof(*entry)); 330 | } 331 | 332 | // Continue 333 | dent = (struct dirent*)((uint8_t*)dent + dent->d_reclen); 334 | } 335 | } 336 | 337 | WriteLog(LL_Debug, "closing handle"); 338 | kclose(handle); 339 | 340 | pluginCount = pluginloader_getAvailablePluginCount(loader); 341 | for (uint32_t i = 0; i < pluginCount; ++i) 342 | { 343 | struct loaderplugin_t* availablePlugin = loader->pluginList[i]; 344 | if (!availablePlugin) 345 | continue; 346 | 347 | struct pluginheader_t* header = (struct pluginheader_t*)availablePlugin->data; 348 | if (!header) 349 | { 350 | WriteLog(LL_Warn, "there is a loaderplugin_t with no data???"); 351 | continue; 352 | } 353 | 354 | // TODO: Cast this properly 355 | void(* pluginInitialize)(void*, void*) = (void(*)(void*, void*))(availablePlugin->data + header->initializeOffset); 356 | uint64_t pluginSize = *(uint64_t*)(availablePlugin->data + header->pluginSizeOffset); 357 | 358 | WriteLog(LL_Info, "PluginSize: %lld, PluginInitialize: %p", pluginSize, pluginInitialize); 359 | 360 | if (pluginSize < sizeof(struct plugin_t)) 361 | continue; 362 | 363 | // Allocate the new plugin structure 364 | struct plugin_t* newPlugin = (struct plugin_t*)kmalloc(pluginSize); // We allocate the plugin size which should be >= plugin_t 365 | if (!newPlugin) 366 | { 367 | WriteLog(LL_Error, "could not allocate new plugin space"); 368 | continue; 369 | } 370 | kmemset(newPlugin, 0, pluginSize); 371 | 372 | // Initialize the plugin 373 | pluginInitialize(newPlugin, &gLoaderPluginInit); 374 | 375 | // This should work fine if everything went according to plan 376 | WriteLog(LL_Info, "Initialized (%s) plugin from file woot woot!", newPlugin->name); 377 | 378 | // Register the plugin with everything else 379 | pluginmanager_registerPlugin(gFramework->pluginManager, newPlugin); 380 | } 381 | } -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/plugins/pluginloader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | 6 | struct pluginheader_t 7 | { 8 | uint64_t initializeOffset; 9 | uint64_t pluginSizeOffset; 10 | }; 11 | 12 | struct loaderplugin_t 13 | { 14 | char path[260]; 15 | 16 | uint8_t* data; 17 | uint32_t dataLength; 18 | 19 | void* plugin; 20 | }; 21 | 22 | /* 23 | pluginloader_t 24 | 25 | This will eventually be merged into the pluginmanager_t class 26 | */ 27 | struct pluginloader_t 28 | { 29 | // Plugin directory path 30 | char* pluginDirectory; 31 | uint32_t pluginDirectoryLength; 32 | 33 | struct loaderplugin_t** pluginList; 34 | uint32_t pluginCount; 35 | }; 36 | 37 | void pluginloader_init(struct pluginloader_t* loader); 38 | 39 | uint32_t pluginloader_getAvailablePluginCount(struct pluginloader_t* loader); 40 | struct loaderplugin_t* pluginloader_loadPluginFromFile(struct pluginloader_t* loader, char* pluginPath); 41 | void pluginloader_loadPlugins(struct pluginloader_t* loader); 42 | 43 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/utils/hde/hde64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | //#include 9 | //#include 10 | 11 | #include "hde64.h" 12 | #include "table64.h" 13 | 14 | #include 15 | 16 | unsigned int hde64_disasm(const void *code, hde64s *hs) 17 | { 18 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 19 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 20 | uint8_t op64 = 0; 21 | 22 | kmemset(hs, 0, sizeof(hde64s)); 23 | 24 | for (x = 16; x; x--) 25 | switch (c = *p++) { 26 | case 0xf3: 27 | hs->p_rep = c; 28 | pref |= PRE_F3; 29 | break; 30 | case 0xf2: 31 | hs->p_rep = c; 32 | pref |= PRE_F2; 33 | break; 34 | case 0xf0: 35 | hs->p_lock = c; 36 | pref |= PRE_LOCK; 37 | break; 38 | case 0x26: case 0x2e: case 0x36: 39 | case 0x3e: case 0x64: case 0x65: 40 | hs->p_seg = c; 41 | pref |= PRE_SEG; 42 | break; 43 | case 0x66: 44 | hs->p_66 = c; 45 | pref |= PRE_66; 46 | break; 47 | case 0x67: 48 | hs->p_67 = c; 49 | pref |= PRE_67; 50 | break; 51 | default: 52 | goto pref_done; 53 | } 54 | pref_done: 55 | 56 | hs->flags = (uint32_t)pref << 23; 57 | 58 | if (!pref) 59 | pref |= PRE_NONE; 60 | 61 | if ((c & 0xf0) == 0x40) { 62 | hs->flags |= F_PREFIX_REX; 63 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) 64 | op64++; 65 | hs->rex_r = (c & 7) >> 2; 66 | hs->rex_x = (c & 3) >> 1; 67 | hs->rex_b = c & 1; 68 | if (((c = *p++) & 0xf0) == 0x40) { 69 | opcode = c; 70 | goto error_opcode; 71 | } 72 | } 73 | 74 | if ((hs->opcode = c) == 0x0f) { 75 | hs->opcode2 = c = *p++; 76 | ht += DELTA_OPCODES; 77 | } 78 | else if (c >= 0xa0 && c <= 0xa3) { 79 | op64++; 80 | if (pref & PRE_67) 81 | pref |= PRE_66; 82 | else 83 | pref &= ~PRE_66; 84 | } 85 | 86 | opcode = c; 87 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 88 | 89 | if (cflags == C_ERROR) { 90 | error_opcode: 91 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 92 | cflags = 0; 93 | if ((opcode & -3) == 0x24) 94 | cflags++; 95 | } 96 | 97 | x = 0; 98 | if (cflags & C_GROUP) { 99 | uint16_t t; 100 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 101 | cflags = (uint8_t)t; 102 | x = (uint8_t)(t >> 8); 103 | } 104 | 105 | if (hs->opcode2) { 106 | ht = hde64_table + DELTA_PREFIXES; 107 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 108 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 109 | } 110 | 111 | if (cflags & C_MODRM) { 112 | hs->flags |= F_MODRM; 113 | hs->modrm = c = *p++; 114 | hs->modrm_mod = m_mod = c >> 6; 115 | hs->modrm_rm = m_rm = c & 7; 116 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 117 | 118 | if (x && ((x << m_reg) & 0x80)) 119 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 120 | 121 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 122 | uint8_t t = opcode - 0xd9; 123 | if (m_mod == 3) { 124 | ht = hde64_table + DELTA_FPU_MODRM + t * 8; 125 | t = ht[m_reg] << m_rm; 126 | } 127 | else { 128 | ht = hde64_table + DELTA_FPU_REG; 129 | t = ht[t] << m_reg; 130 | } 131 | if (t & 0x80) 132 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 133 | } 134 | 135 | if (pref & PRE_LOCK) { 136 | if (m_mod == 3) { 137 | hs->flags |= F_ERROR | F_ERROR_LOCK; 138 | } 139 | else { 140 | uint8_t *table_end, op = opcode; 141 | if (hs->opcode2) { 142 | ht = hde64_table + DELTA_OP2_LOCK_OK; 143 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 144 | } 145 | else { 146 | ht = hde64_table + DELTA_OP_LOCK_OK; 147 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 148 | op &= -2; 149 | } 150 | for (; ht != table_end; ht++) 151 | if (*ht++ == op) { 152 | if (!((*ht << m_reg) & 0x80)) 153 | goto no_lock_error; 154 | else 155 | break; 156 | } 157 | hs->flags |= F_ERROR | F_ERROR_LOCK; 158 | no_lock_error: 159 | ; 160 | } 161 | } 162 | 163 | if (hs->opcode2) { 164 | switch (opcode) { 165 | case 0x20: case 0x22: 166 | m_mod = 3; 167 | if (m_reg > 4 || m_reg == 1) 168 | goto error_operand; 169 | else 170 | goto no_error_operand; 171 | case 0x21: case 0x23: 172 | m_mod = 3; 173 | if (m_reg == 4 || m_reg == 5) 174 | goto error_operand; 175 | else 176 | goto no_error_operand; 177 | } 178 | } 179 | else { 180 | switch (opcode) { 181 | case 0x8c: 182 | if (m_reg > 5) 183 | goto error_operand; 184 | else 185 | goto no_error_operand; 186 | case 0x8e: 187 | if (m_reg == 1 || m_reg > 5) 188 | goto error_operand; 189 | else 190 | goto no_error_operand; 191 | } 192 | } 193 | 194 | if (m_mod == 3) { 195 | uint8_t *table_end; 196 | if (hs->opcode2) { 197 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 198 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 199 | } 200 | else { 201 | ht = hde64_table + DELTA_OP_ONLY_MEM; 202 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 203 | } 204 | for (; ht != table_end; ht += 2) 205 | if (*ht++ == opcode) { 206 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 207 | goto error_operand; 208 | else 209 | break; 210 | } 211 | goto no_error_operand; 212 | } 213 | else if (hs->opcode2) { 214 | switch (opcode) { 215 | case 0x50: case 0xd7: case 0xf7: 216 | if (pref & (PRE_NONE | PRE_66)) 217 | goto error_operand; 218 | break; 219 | case 0xd6: 220 | if (pref & (PRE_F2 | PRE_F3)) 221 | goto error_operand; 222 | break; 223 | case 0xc5: 224 | goto error_operand; 225 | } 226 | goto no_error_operand; 227 | } 228 | else 229 | goto no_error_operand; 230 | 231 | error_operand: 232 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 233 | no_error_operand: 234 | 235 | c = *p++; 236 | if (m_reg <= 1) { 237 | if (opcode == 0xf6) 238 | cflags |= C_IMM8; 239 | else if (opcode == 0xf7) 240 | cflags |= C_IMM_P66; 241 | } 242 | 243 | switch (m_mod) { 244 | case 0: 245 | if (pref & PRE_67) { 246 | if (m_rm == 6) 247 | disp_size = 2; 248 | } 249 | else 250 | if (m_rm == 5) 251 | disp_size = 4; 252 | break; 253 | case 1: 254 | disp_size = 1; 255 | break; 256 | case 2: 257 | disp_size = 2; 258 | if (!(pref & PRE_67)) 259 | disp_size <<= 1; 260 | } 261 | 262 | if (m_mod != 3 && m_rm == 4) { 263 | hs->flags |= F_SIB; 264 | p++; 265 | hs->sib = c; 266 | hs->sib_scale = c >> 6; 267 | hs->sib_index = (c & 0x3f) >> 3; 268 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 269 | disp_size = 4; 270 | } 271 | 272 | p--; 273 | switch (disp_size) { 274 | case 1: 275 | hs->flags |= F_DISP8; 276 | hs->disp.disp8 = *p; 277 | break; 278 | case 2: 279 | hs->flags |= F_DISP16; 280 | hs->disp.disp16 = *(uint16_t *)p; 281 | break; 282 | case 4: 283 | hs->flags |= F_DISP32; 284 | hs->disp.disp32 = *(uint32_t *)p; 285 | } 286 | p += disp_size; 287 | } 288 | else if (pref & PRE_LOCK) 289 | hs->flags |= F_ERROR | F_ERROR_LOCK; 290 | 291 | if (cflags & C_IMM_P66) { 292 | if (cflags & C_REL32) { 293 | if (pref & PRE_66) { 294 | hs->flags |= F_IMM16 | F_RELATIVE; 295 | hs->imm.imm16 = *(uint16_t *)p; 296 | p += 2; 297 | goto disasm_done; 298 | } 299 | goto rel32_ok; 300 | } 301 | if (op64) { 302 | hs->flags |= F_IMM64; 303 | hs->imm.imm64 = *(uint64_t *)p; 304 | p += 8; 305 | } 306 | else if (!(pref & PRE_66)) { 307 | hs->flags |= F_IMM32; 308 | hs->imm.imm32 = *(uint32_t *)p; 309 | p += 4; 310 | } 311 | else 312 | goto imm16_ok; 313 | } 314 | 315 | 316 | if (cflags & C_IMM16) { 317 | imm16_ok: 318 | hs->flags |= F_IMM16; 319 | hs->imm.imm16 = *(uint16_t *)p; 320 | p += 2; 321 | } 322 | if (cflags & C_IMM8) { 323 | hs->flags |= F_IMM8; 324 | hs->imm.imm8 = *p++; 325 | } 326 | 327 | if (cflags & C_REL32) { 328 | rel32_ok: 329 | hs->flags |= F_IMM32 | F_RELATIVE; 330 | hs->imm.imm32 = *(uint32_t *)p; 331 | p += 4; 332 | } 333 | else if (cflags & C_REL8) { 334 | hs->flags |= F_IMM8 | F_RELATIVE; 335 | hs->imm.imm8 = *p++; 336 | } 337 | 338 | disasm_done: 339 | 340 | if ((hs->len = (uint8_t)(p - (uint8_t *)code)) > 15) { 341 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 342 | hs->len = 15; 343 | } 344 | 345 | return (unsigned int)hs->len; 346 | } 347 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/utils/hde/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | //#include 23 | #include 24 | 25 | #define F_MODRM 0x00000001 26 | #define F_SIB 0x00000002 27 | #define F_IMM8 0x00000004 28 | #define F_IMM16 0x00000008 29 | #define F_IMM32 0x00000010 30 | #define F_IMM64 0x00000020 31 | #define F_DISP8 0x00000040 32 | #define F_DISP16 0x00000080 33 | #define F_DISP32 0x00000100 34 | #define F_RELATIVE 0x00000200 35 | #define F_ERROR 0x00001000 36 | #define F_ERROR_OPCODE 0x00002000 37 | #define F_ERROR_LENGTH 0x00004000 38 | #define F_ERROR_LOCK 0x00008000 39 | #define F_ERROR_OPERAND 0x00010000 40 | #define F_PREFIX_REPNZ 0x01000000 41 | #define F_PREFIX_REPX 0x02000000 42 | #define F_PREFIX_REP 0x03000000 43 | #define F_PREFIX_66 0x04000000 44 | #define F_PREFIX_67 0x08000000 45 | #define F_PREFIX_LOCK 0x10000000 46 | #define F_PREFIX_SEG 0x20000000 47 | #define F_PREFIX_REX 0x40000000 48 | #define F_PREFIX_ANY 0x7f000000 49 | 50 | #define PREFIX_SEGMENT_CS 0x2e 51 | #define PREFIX_SEGMENT_SS 0x36 52 | #define PREFIX_SEGMENT_DS 0x3e 53 | #define PREFIX_SEGMENT_ES 0x26 54 | #define PREFIX_SEGMENT_FS 0x64 55 | #define PREFIX_SEGMENT_GS 0x65 56 | #define PREFIX_LOCK 0xf0 57 | #define PREFIX_REPNZ 0xf2 58 | #define PREFIX_REPX 0xf3 59 | #define PREFIX_OPERAND_SIZE 0x66 60 | #define PREFIX_ADDRESS_SIZE 0x67 61 | 62 | #pragma pack(push,1) 63 | 64 | typedef struct { 65 | uint8_t len; 66 | uint8_t p_rep; 67 | uint8_t p_lock; 68 | uint8_t p_seg; 69 | uint8_t p_66; 70 | uint8_t p_67; 71 | uint8_t rex; 72 | uint8_t rex_w; 73 | uint8_t rex_r; 74 | uint8_t rex_x; 75 | uint8_t rex_b; 76 | uint8_t opcode; 77 | uint8_t opcode2; 78 | uint8_t modrm; 79 | uint8_t modrm_mod; 80 | uint8_t modrm_reg; 81 | uint8_t modrm_rm; 82 | uint8_t sib; 83 | uint8_t sib_scale; 84 | uint8_t sib_index; 85 | uint8_t sib_base; 86 | union { 87 | uint8_t imm8; 88 | uint16_t imm16; 89 | uint32_t imm32; 90 | uint64_t imm64; 91 | } imm; 92 | union { 93 | uint8_t disp8; 94 | uint16_t disp16; 95 | uint32_t disp32; 96 | } disp; 97 | uint32_t flags; 98 | } hde64s; 99 | 100 | #pragma pack(pop) 101 | 102 | #ifdef __cplusplus 103 | extern "C" { 104 | #endif 105 | 106 | /* __cdecl */ 107 | unsigned int hde64_disasm(const void *code, hde64s *hs); 108 | 109 | #ifdef __cplusplus 110 | } 111 | #endif 112 | 113 | #endif /* _HDE64_H_ */ 114 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/utils/hde/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/utils/hook.c: -------------------------------------------------------------------------------- 1 | #include "hook.h" 2 | #include "hde/hde64.h" 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #define HOOK_LENGTH 14 10 | 11 | static int32_t hook_getMinHookSize(void* targetFunction) 12 | { 13 | hde64s hs; 14 | 15 | uint32_t hookSize = HOOK_LENGTH; 16 | uint32_t totalLength = 0; 17 | 18 | 19 | while (totalLength < hookSize) 20 | { 21 | uint32_t length = hde64_disasm(targetFunction, &hs); 22 | if (hs.flags & F_ERROR) 23 | return -1; 24 | 25 | totalLength += length; 26 | } 27 | 28 | return totalLength; 29 | } 30 | 31 | struct hook_t* hook_create(void* targetFunction, void* functionHook) 32 | { 33 | if (!targetFunction || !functionHook) 34 | return NULL; 35 | 36 | // Allocate a new hook structure to be returned 37 | struct hook_t* hook = (struct hook_t*)kmalloc(sizeof(struct hook_t)); 38 | if (!hook) 39 | return NULL; 40 | 41 | // Zero out the buffer 42 | kmemset(hook, 0, sizeof(*hook)); 43 | 44 | int32_t backupDataLength = hook_getMinHookSize(targetFunction); 45 | if (backupDataLength == -1) 46 | { 47 | kfree(hook, sizeof(*hook)); 48 | return NULL; 49 | } 50 | 51 | // Allocate our backup bytes data 52 | uint8_t* backupData = (uint8_t*)kmalloc(backupDataLength); 53 | if (!backupData) 54 | { 55 | kfree(hook, sizeof(*hook)); 56 | return NULL; 57 | } 58 | 59 | // Zero out and copy the beginning of the function 60 | kmemset(backupData, 0, backupDataLength); 61 | kmemcpy(backupData, targetFunction, backupDataLength); 62 | 63 | hook->targetAddress = targetFunction; 64 | hook->hookAddress = functionHook; 65 | hook->backupData = backupData; 66 | hook->backupLength = backupDataLength; 67 | hook->enabled = false; 68 | 69 | return hook; 70 | } 71 | 72 | void hook_enable(struct hook_t* hook) 73 | { 74 | if (!hook) 75 | return; 76 | 77 | if (!hook->hookAddress) 78 | return; 79 | 80 | if (!hook->targetAddress) 81 | return; 82 | 83 | void(*critical_enter)(void) = kdlsym(critical_enter); 84 | void(*critical_exit)(void) = kdlsym(critical_exit); 85 | 86 | int8_t jumpBuffer[] = { 87 | 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // # jmp QWORD PTR [rip+0x0] 88 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, // # DQ: AbsoluteAddress 89 | }; // Shit takes 14 bytes 90 | 91 | uint64_t* jumpBufferAddress = (uint64_t*)(jumpBuffer + 6); 92 | 93 | // Assign the address 94 | *jumpBufferAddress = (uint64_t)hook->hookAddress; 95 | 96 | // Change permissions and apply the hook 97 | critical_enter(); 98 | cpu_disable_wp(); 99 | kmemcpy(hook->targetAddress, jumpBuffer, sizeof(jumpBuffer)); 100 | cpu_enable_wp(); 101 | critical_exit(); 102 | 103 | hook->enabled = true; 104 | } 105 | 106 | void hook_disable(struct hook_t* hook) 107 | { 108 | if (!hook) 109 | return; 110 | 111 | if (!hook->hookAddress) 112 | return; 113 | 114 | if (!hook->targetAddress) 115 | return; 116 | 117 | if (!hook->backupData || hook->backupLength == 0) 118 | return; 119 | 120 | void(*critical_enter)(void) = kdlsym(critical_enter); 121 | void(*critical_exit)(void) = kdlsym(critical_exit); 122 | 123 | // Change permissions and apply the hook 124 | critical_enter(); 125 | cpu_disable_wp(); 126 | kmemcpy(hook->targetAddress, hook->backupData, hook->backupLength); 127 | cpu_enable_wp(); 128 | critical_exit(); 129 | 130 | hook->enabled = false; 131 | } 132 | 133 | void* hook_getFunctionAddress(struct hook_t* hook) 134 | { 135 | if (!hook) 136 | return NULL; 137 | 138 | return hook->targetAddress; 139 | } -------------------------------------------------------------------------------- /Firmware/MiraFW/src/mira/utils/hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct hook_t 5 | { 6 | // Address of the target function 7 | void* targetAddress; 8 | 9 | // Address of the hook 10 | void* hookAddress; 11 | 12 | // If this hook is enabled 13 | uint8_t enabled; 14 | 15 | // The backup data length for the jmp overwrite 16 | uint32_t backupLength; 17 | uint8_t* backupData; 18 | }; 19 | 20 | struct hook_t* hook_create(void* targetFunction, void* functionHook); 21 | 22 | void hook_enable(struct hook_t* hook); 23 | void hook_disable(struct hook_t* hook); 24 | 25 | void* hook_getFunctionAddress(struct hook_t* hook); -------------------------------------------------------------------------------- /Firmware/Plugins/MiraExamplePlugin/Makefile: -------------------------------------------------------------------------------- 1 | # If ONI_FRAMEWORK is not set, we will use a default path of same directory 2 | ifeq ($(ONI_FRAMEWORK),) 3 | ONI_FRAMEWORK := ../Dependencies/oni-framework 4 | endif 5 | 6 | # If the FREEBSD headers path is not set we will try to use the relative path 7 | ifeq ($(BSD_INC),) 8 | BSD_INC := ../Dependencies/freebsd-headers 9 | endif 10 | 11 | # Project name 12 | PROJ_NAME := ExamplePlugin 13 | 14 | # C++ compiler 15 | CPPC := g++ 16 | 17 | # Linker 18 | LNK := gcc # ps4-ld, we are compiling for the kernel so this is not going to use the OpenOrbis userland linker 19 | 20 | # C compiler 21 | CC := gcc 22 | 23 | # Archiver 24 | AS := gcc 25 | 26 | # Objcopy 27 | OBJCOPY := objcopy 28 | 29 | # Output directory, by default is build 30 | ifeq ($(OUT_DIR),) 31 | OUT_DIR := build 32 | endif 33 | 34 | # Source directory 35 | SRC_DIR := src 36 | 37 | # Include directory paths 38 | I_DIRS := -I. -IInclude -I$(SRC_DIR) -I$(ONI_FRAMEWORK)/depends/include -I$(ONI_FRAMEWORK)/include -I$(BSD_INC) 39 | 40 | # Library directory paths 41 | L_DIRS := -L. -Llib -L$(ONI_FRAMEWORK) 42 | 43 | # Included libraries 44 | LIBS := -l:OniFramework.a 45 | 46 | # Orbis flags 47 | ORB_VER := -D_KERNEL -D_DEBUG=1 48 | 49 | # C++ Flags 50 | CFLAGS := $(I_DIRS) $(ORB_VER) -std=c11 -O2 -fno-builtin -nostartfiles -nodefaultlibs -nostdlib -nostdinc -fcheck-new -ffreestanding -fno-strict-aliasing -fno-exceptions -fno-asynchronous-unwind-tables -Wall -m64 -fPIC -Werror=implicit-function-declaration -Wno-unknown-pragmas 51 | 52 | # Assembly flags 53 | SFLAGS := -nostartfiles -nodefaultlibs -nostdlib -fPIC 54 | 55 | # Linker flags 56 | LFLAGS := $(L_DIRS) -nostdlib -T $(ONI_FRAMEWORK)/link.x -Wl,--build-id=none 57 | 58 | # Calculate the listing of all file paths 59 | CFILES := $(wildcard $(SRC_DIR)/*.c) 60 | CPPFILES := $(wildcard $(SRC_DIR)/*.cpp) 61 | SFILES := $(wildcard $(SRC_DIR)/*.s) 62 | OBJS := $(patsubst $(SRC_DIR)/%.s, $(OUT_DIR)/$(SRC_DIR)/%.o, $(SFILES)) $(patsubst $(SRC_DIR)/%.c, $(OUT_DIR)/$(SRC_DIR)/%.o, $(CFILES)) $(patsubst $(SRC_DIR)/%.cpp, $(OUT_DIR)/$(SRC_DIR)/%.o, $(CPPFILES)) 63 | 64 | ALL_CPP := $(shell find $(SRC_DIR)/ -type f -name '*.cpp') 65 | ALL_C := $(shell find $(SRC_DIR)/ -type f -name '*.c') 66 | ALL_S := $(shell find $(SRC_DIR)/ -type f -name '*.s') 67 | 68 | ALL_SOURCES := $(ALL_S) $(ALL_C) $(ALL_CPP) 69 | TO_BUILD := $(ALL_S:$(SRC_DIR)%=$(OUT_DIR)/$(SRC_DIR)%) $(ALL_C:$(SRC_DIR)%=$(OUT_DIR)/$(SRC_DIR)%) $(ALL_CPP:$(SRC_DIR)%=$(OUT_DIR)/$(SRC_DIR)%) 70 | ALL_OBJ_CPP := $(TO_BUILD:.cpp=.o) 71 | ALL_OBJ_C := $(ALL_OBJ_CPP:.c=.o) 72 | ALL_OBJ := $(ALL_OBJ_C:.s=.o) 73 | 74 | # Target elf name 75 | TARGET = $(PROJ_NAME)_Orbis.elf 76 | 77 | # Target payload name (data + text only, no elf) 78 | PAYLOAD = $(PROJ_NAME)_Orbis.bin 79 | 80 | $(TARGET): $(ALL_OBJ) 81 | @echo Compiling $(PROJ_NAME)... 82 | @$(LNK) $(ALL_OBJ) -o $(TARGET) $(LFLAGS) $(LIBS) 83 | @echo "Creating Payload..." 84 | @$(OBJCOPY) -O binary $(TARGET) $(PAYLOAD) 85 | 86 | $(OUT_DIR)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.c 87 | @echo "Compiling $< ..." 88 | @$(CC) $(CFLAGS) $(IDIRS) -c $< -o $@ 89 | 90 | $(OUT_DIR)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp 91 | @echo "Compiling $< ..." 92 | @$(CPPC) $(CFLAGS) $(IDIRS) -c $< -o $@ 93 | 94 | $(OUT_DIR)/$(SRC_DIR)/%.o: $(SRC_DIR)/%.s 95 | @echo "Compiling $< ..." 96 | @$(CC) -c -o $@ $< $(SFLAGS) 97 | 98 | .PHONY: clean 99 | 100 | clean: 101 | @echo "Cleaning project..." 102 | @rm -f $(TARGET) $(PAYLOAD) $(shell find $(OUT_DIR)/ -type f -name '*.o') 103 | 104 | create: 105 | @echo "Creating directories..." 106 | @mkdir -p $(shell find '$(SRC_DIR)/' -type d -printf '$(OUT_DIR)/%p\n') 107 | -------------------------------------------------------------------------------- /Firmware/Plugins/MiraExamplePlugin/MiraExamplePlugin.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Release 10 | ARM 11 | 12 | 13 | Debug 14 | x86 15 | 16 | 17 | Release 18 | x86 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {c62ea872-92c1-42b8-9bf3-c14d3fc05a64} 31 | Linux 32 | MiraExamplePlugin 33 | 15.0 34 | Linux 35 | 1.0 36 | Generic 37 | {FC1A4D80-50E9-41DA-9192-61C0DBAA00D2} 38 | 39 | 40 | 41 | true 42 | Makefile 43 | ~/mira/Firmware/Plugins 44 | 45 | 46 | false 47 | Makefile 48 | ~/mira/Firmware/Plugins 49 | 50 | 51 | true 52 | Makefile 53 | ~/mira/Firmware/Plugins 54 | 55 | 56 | false 57 | Makefile 58 | ~/mira/Firmware/Plugins 59 | 60 | 61 | true 62 | Makefile 63 | ~/mira/Firmware/Plugins 64 | 65 | 66 | false 67 | Makefile 68 | ~/mira/Firmware/Plugins 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 77 | _KERNEL 78 | cd $(RemoteProjectDir);make create;make 79 | cd $(RemoteProjectDir);make create;make clean;make 80 | cd $(RemoteProjectDir);make create;make clean 81 | 82 | 83 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 84 | _KERNEL 85 | cd $(RemoteProjectDir);make create;make 86 | cd $(RemoteProjectDir);make create;make clean;make 87 | cd $(RemoteProjectDir);make create;make clean 88 | 89 | 90 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 91 | _KERNEL 92 | cd $(RemoteProjectDir);make create;make 93 | cd $(RemoteProjectDir);make create;make clean;make 94 | cd $(RemoteProjectDir);make create;make clean 95 | 96 | 97 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 98 | _KERNEL 99 | cd $(RemoteProjectDir);make create;make 100 | cd $(RemoteProjectDir);make create;make clean;make 101 | cd $(RemoteProjectDir);make create;make clean 102 | 103 | 104 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 105 | _KERNEL 106 | cd $(RemoteProjectDir);make create;make 107 | cd $(RemoteProjectDir);make create;make clean;make 108 | cd $(RemoteProjectDir);make create;make clean 109 | 110 | 111 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 112 | _KERNEL 113 | cd $(RemoteProjectDir);make create;make 114 | cd $(RemoteProjectDir);make create;make clean;make 115 | cd $(RemoteProjectDir);make create;make clean 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Firmware/Plugins/MiraExamplePlugin/src/crt0.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .text 3 | 4 | .quad plugin_size 5 | .quad plugin_initialize 6 | 7 | .global _start 8 | 9 | # Plugins should always spinloop 10 | _start: 11 | jmp _start 12 | -------------------------------------------------------------------------------- /Firmware/Plugins/MiraExamplePlugin/src/example_plugin.c: -------------------------------------------------------------------------------- 1 | #include "example_plugin.h" 2 | #include 3 | #include 4 | 5 | uint64_t plugin_size = sizeof(struct example_plugin_t); 6 | struct framework_t* gFramework = NULL; 7 | struct logger_t* gLogger = NULL; 8 | uint8_t* gKernelBase = NULL; 9 | 10 | void plugin_initialize(void* plugin, struct plugininit_t* arg) 11 | { 12 | if (!plugin || !arg) 13 | return; 14 | 15 | struct example_plugin_t* examplePlugin = (struct example_plugin_t*)plugin; 16 | examplePlugin->plugin.name = "ExamplePlugin"; 17 | examplePlugin->plugin.description = "This is the example plugin description"; 18 | examplePlugin->plugin.plugin_load = plugin_load; 19 | examplePlugin->plugin.plugin_unload = plugin_unload; 20 | 21 | gKernelBase = arg->kernelBase; 22 | gFramework = arg->framework; 23 | gLogger = arg->logger; 24 | } 25 | 26 | uint8_t plugin_load(void* plugin) 27 | { 28 | if (!plugin) 29 | return false; 30 | 31 | WriteLog(LL_Info, "Hello World from dynamically loaded plugin"); 32 | 33 | return true; 34 | } 35 | 36 | uint8_t plugin_unload(void* plugin) 37 | { 38 | if (!plugin) 39 | return false; 40 | 41 | return true; 42 | } 43 | -------------------------------------------------------------------------------- /Firmware/Plugins/MiraExamplePlugin/src/example_plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | struct example_plugin_t 6 | { 7 | struct plugin_t plugin; 8 | }; 9 | 10 | extern uint64_t plugin_size; 11 | 12 | void plugin_initialize(void* plugin, struct plugininit_t* arg); 13 | 14 | // Plugin initialization prototype 15 | uint8_t plugin_load(void* plugin); 16 | 17 | // Plugin close prototype 18 | uint8_t plugin_unload(void* plugin); 19 | -------------------------------------------------------------------------------- /Firmware/Plugins/MiraFileTransferPlugin/MiraFileTransferPlugin.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {c58f0ecb-1b49-42f4-b05e-4e5c6211d8ef} 15 | Linux 16 | MiraFileTransferPlugin 17 | 15.0 18 | Linux 19 | 1.0 20 | Generic 21 | {2238F9CD-F817-4ECC-BD14-2524D2669B35} 22 | 23 | 24 | 25 | true 26 | Makefile 27 | ~/mira/Firmware/Plugins 28 | 29 | 30 | false 31 | Makefile 32 | ~/mira/Firmware/Plugins 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 41 | _KERNEL; 42 | cd $(RemoteProjectDir);make create;make 43 | cd $(RemoteProjectDir);make create;make clean;make 44 | cd $(RemoteProjectDir);make create;make clean 45 | MiraFileTransferPlugin.a 46 | 47 | 48 | $(SolutionDir)Firmware\Dependencies\oni-framework\include;$(ProjectDir)src;$(SolutionDir)Firmware\Dependencies\freebsd-headers\include 49 | _KERNEL; 50 | cd $(RemoteProjectDir);make create;make 51 | cd $(RemoteProjectDir);make create;make clean;make 52 | cd $(RemoteProjectDir);make create;make clean 53 | MiraFileTransferPlugin.a 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Firmware/Plugins/MiraFileTransferPlugin/src/crt0.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .text 3 | 4 | .global _pluginInitialize 5 | .global _pluginSize 6 | .global _plugin 7 | 8 | _pluginInitialize: 9 | .quad plugin_initialize 10 | 11 | _pluginSize: 12 | .quad 0 13 | 14 | .global _start 15 | 16 | # Plugins should always spinloop 17 | _start: 18 | jmp _start -------------------------------------------------------------------------------- /Mira.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2015 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiraFW", "Firmware\MiraFW\MiraFW.vcxproj", "{DB146B77-3C14-4680-85AC-50B83292B1A8}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {73D88A70-8F6F-49A7-B921-9DB254527F92} = {73D88A70-8F6F-49A7-B921-9DB254527F92} 9 | EndProjectSection 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{1F457151-6069-41BD-B8A0-80E71C81B9E1}" 12 | ProjectSection(SolutionItems) = preProject 13 | Scripts\clean_all.cmd = Scripts\clean_all.cmd 14 | Scripts\clean_all.sh = Scripts\clean_all.sh 15 | Scripts\config.txt = Scripts\config.txt 16 | Scripts\init_development_environment.cmd = Scripts\init_development_environment.cmd 17 | Scripts\init_development_environment.sh = Scripts\init_development_environment.sh 18 | EndProjectSection 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Firmware", "Firmware", "{108E0975-87E1-4DA3-9D1A-8FC900B15521}" 21 | EndProject 22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Output", "Output", "{FE93FC17-67D9-491B-98BF-D905BC085FBF}" 23 | ProjectSection(SolutionItems) = preProject 24 | Output\README.md = Output\README.md 25 | EndProjectSection 26 | EndProject 27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{ACBBEE03-2C7A-4CEF-897C-B36730F4B32E}" 28 | EndProject 29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraLib", "Tools\MiraLib\MiraLib.csproj", "{7F17F9F8-0220-4814-824A-30BC4E919341}" 30 | EndProject 31 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B51D4C03-AC1C-483F-8280-B864DDDA8F56}" 32 | EndProject 33 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraLibTests", "Tests\MiraLibTests\MiraLibTests.csproj", "{EC822E41-97A2-448C-958F-88F8D55C3100}" 34 | EndProject 35 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{EBF5AE95-E479-4541-AF8B-CE7F1DCA420D}" 36 | EndProject 37 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiraFileTransferPlugin", "Firmware\Plugins\MiraFileTransferPlugin\MiraFileTransferPlugin.vcxproj", "{C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}" 38 | ProjectSection(ProjectDependencies) = postProject 39 | {73D88A70-8F6F-49A7-B921-9DB254527F92} = {73D88A70-8F6F-49A7-B921-9DB254527F92} 40 | EndProjectSection 41 | EndProject 42 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependencies", "Dependencies", "{FFABB202-681E-492F-B3CC-A1E862EC5E13}" 43 | EndProject 44 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oni-framework", "Firmware\Dependencies\oni-framework\oni-framework.vcxproj", "{73D88A70-8F6F-49A7-B921-9DB254527F92}" 45 | EndProject 46 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freebsd-headers", "Firmware\Dependencies\freebsd-headers\freebsd-headers.vcxproj", "{72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}" 47 | EndProject 48 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiraExamplePlugin", "Firmware\Plugins\MiraExamplePlugin\MiraExamplePlugin.vcxproj", "{C62EA872-92C1-42B8-9BF3-C14D3FC05A64}" 49 | EndProject 50 | Global 51 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 52 | Debug|ARM = Debug|ARM 53 | Debug|x64 = Debug|x64 54 | Debug|x86 = Debug|x86 55 | Release|ARM = Release|ARM 56 | Release|x64 = Release|x64 57 | Release|x86 = Release|x86 58 | EndGlobalSection 59 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 60 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Debug|ARM.ActiveCfg = Debug|x64 61 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Debug|x64.ActiveCfg = Debug|x64 62 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Debug|x64.Build.0 = Debug|x64 63 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Debug|x86.ActiveCfg = Debug|x64 64 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Release|ARM.ActiveCfg = Release|x64 65 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Release|x64.ActiveCfg = Release|x64 66 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Release|x64.Build.0 = Release|x64 67 | {DB146B77-3C14-4680-85AC-50B83292B1A8}.Release|x86.ActiveCfg = Release|x64 68 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Debug|ARM.ActiveCfg = Debug|x64 69 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Debug|x64.ActiveCfg = Debug|x64 70 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Debug|x64.Build.0 = Debug|x64 71 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Debug|x86.ActiveCfg = Debug|x64 72 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Release|ARM.ActiveCfg = Release|x64 73 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Release|x64.ActiveCfg = Release|x64 74 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Release|x64.Build.0 = Release|x64 75 | {7F17F9F8-0220-4814-824A-30BC4E919341}.Release|x86.ActiveCfg = Release|x64 76 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Debug|ARM.ActiveCfg = Debug|x64 77 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Debug|x64.ActiveCfg = Debug|x64 78 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Debug|x64.Build.0 = Debug|x64 79 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Debug|x86.ActiveCfg = Debug|x64 80 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Release|ARM.ActiveCfg = Release|x64 81 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Release|x64.ActiveCfg = Release|x64 82 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Release|x64.Build.0 = Release|x64 83 | {EC822E41-97A2-448C-958F-88F8D55C3100}.Release|x86.ActiveCfg = Release|x64 84 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Debug|ARM.ActiveCfg = Debug|x64 85 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Debug|x64.ActiveCfg = Debug|x64 86 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Debug|x64.Build.0 = Debug|x64 87 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Debug|x86.ActiveCfg = Debug|x64 88 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Release|ARM.ActiveCfg = Release|x64 89 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Release|x64.ActiveCfg = Release|x64 90 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Release|x64.Build.0 = Release|x64 91 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF}.Release|x86.ActiveCfg = Release|x64 92 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Debug|ARM.ActiveCfg = Debug|x64 93 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Debug|x64.ActiveCfg = Debug|x64 94 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Debug|x64.Build.0 = Debug|x64 95 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Debug|x86.ActiveCfg = Debug|x64 96 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Release|ARM.ActiveCfg = Release|x64 97 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Release|x64.ActiveCfg = Release|x64 98 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Release|x64.Build.0 = Release|x64 99 | {73D88A70-8F6F-49A7-B921-9DB254527F92}.Release|x86.ActiveCfg = Release|x64 100 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Debug|ARM.ActiveCfg = Debug|ARM 101 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Debug|ARM.Build.0 = Debug|ARM 102 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Debug|x64.ActiveCfg = Debug|x64 103 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Debug|x64.Build.0 = Debug|x64 104 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Debug|x86.ActiveCfg = Debug|x86 105 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Debug|x86.Build.0 = Debug|x86 106 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Release|ARM.ActiveCfg = Release|ARM 107 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Release|ARM.Build.0 = Release|ARM 108 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Release|x64.ActiveCfg = Release|x64 109 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Release|x64.Build.0 = Release|x64 110 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Release|x86.ActiveCfg = Release|x86 111 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A}.Release|x86.Build.0 = Release|x86 112 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Debug|ARM.ActiveCfg = Debug|ARM 113 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Debug|ARM.Build.0 = Debug|ARM 114 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Debug|x64.ActiveCfg = Debug|x64 115 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Debug|x64.Build.0 = Debug|x64 116 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Debug|x86.ActiveCfg = Debug|x86 117 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Debug|x86.Build.0 = Debug|x86 118 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Release|ARM.ActiveCfg = Release|ARM 119 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Release|ARM.Build.0 = Release|ARM 120 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Release|x64.ActiveCfg = Release|x64 121 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Release|x64.Build.0 = Release|x64 122 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Release|x86.ActiveCfg = Release|x86 123 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64}.Release|x86.Build.0 = Release|x86 124 | EndGlobalSection 125 | GlobalSection(SolutionProperties) = preSolution 126 | HideSolutionNode = FALSE 127 | EndGlobalSection 128 | GlobalSection(NestedProjects) = preSolution 129 | {DB146B77-3C14-4680-85AC-50B83292B1A8} = {108E0975-87E1-4DA3-9D1A-8FC900B15521} 130 | {7F17F9F8-0220-4814-824A-30BC4E919341} = {ACBBEE03-2C7A-4CEF-897C-B36730F4B32E} 131 | {EC822E41-97A2-448C-958F-88F8D55C3100} = {B51D4C03-AC1C-483F-8280-B864DDDA8F56} 132 | {EBF5AE95-E479-4541-AF8B-CE7F1DCA420D} = {108E0975-87E1-4DA3-9D1A-8FC900B15521} 133 | {C58F0ECB-1B49-42F4-B05E-4E5C6211D8EF} = {EBF5AE95-E479-4541-AF8B-CE7F1DCA420D} 134 | {FFABB202-681E-492F-B3CC-A1E862EC5E13} = {108E0975-87E1-4DA3-9D1A-8FC900B15521} 135 | {73D88A70-8F6F-49A7-B921-9DB254527F92} = {FFABB202-681E-492F-B3CC-A1E862EC5E13} 136 | {72FCDDFB-59B4-4D4C-B1FE-1C3E9404900A} = {FFABB202-681E-492F-B3CC-A1E862EC5E13} 137 | {C62EA872-92C1-42B8-9BF3-C14D3FC05A64} = {EBF5AE95-E479-4541-AF8B-CE7F1DCA420D} 138 | EndGlobalSection 139 | GlobalSection(ExtensibilityGlobals) = postSolution 140 | SolutionGuid = {A6AF288B-CD5B-480E-A2E9-FF6B003EFBCC} 141 | EndGlobalSection 142 | EndGlobal 143 | -------------------------------------------------------------------------------- /Output/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyVoidProgrammer/mira-project/99b9572d111ab28bb6202dbe392eb17e42b32755/Output/README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Mira Project 2 | The Mira Project is a set of tools that grants you more power and control over your jailbroken Playstation 4. It is the result of all the hard work by the OpenOrbis team. 3 | 4 | It works differently to the custom firmware experience on Playstation 3, where CFW would be installed on the system via modified PUP files (e.g. Rebug), however once the framework is installed and ran it gives users the same functionality they were previously used to. 5 | 6 | ## Firmware 7 | 8 | Formerly known as MiraHEN, this has now been developed into a full custom firmware. Thanks to everyone who helped Mira reach a 1.0 beta goal (May 20, 2018). There will be updated goals placed within the [GitHub issue tracker](https://github.com/OpenOrbis/mira-project/milestones) so the community can follow the internal progress, contribute and help provide the best platform possible for users. 9 | 10 | ## Tools 11 | 12 | ### [newlib-ps4](https://github.com/OpenOrbis/newlib) 13 | 14 | This is the libc implementation ported for PS4. Check the repository for updates and more information. Currently is in development, and may not be ready to use. 15 | 16 | ### [lld-ps4](https://github.com/OpenOrbis/lld) 17 | 18 | This is the linker to be used with newlib-ps4 to create Orbis compatible ELF files. Alternatively, you can use CrazyVoid's elfFixupTool. Currently in development, and may not ready to use. 19 | 20 | ### MiraLib 21 | 22 | This is the communications library that will be specialized for operation with the Mira firmware. 23 | 24 | ### OpenOrbis Store 25 | 26 | Community driven store and application that will allow you to download new plugins, payloads, tweaks, trainers from a trusted centralized source without ever leaving the comfort of your console. 27 | 28 | Inspired by vitaDB <3 Rin 29 | 30 | ### PS4 Payload Sender 31 | 32 | A simple Android application to send payloads to your PS4. 33 | 34 | ## Plugins 35 | 36 | The Mira Project offers two types of plugins: built-in plugins and external plugins. Default plugins are embedded inside Mira firmware and include file transfer, a log server and a debugger. External plugins can be loaded from internal/external HDD, for example PS4 Linux Loader. 37 | 38 | ### PS4 Linux Loader 39 | 40 | A simple plugin that lets you run the Linux kernel from a remote device without webkit. 41 | 42 | ## User Guide 43 | 44 | The users guide can be found at [USERS.md](https://github.com/OpenOrbis/mira-project/blob/master/USERS.md). This guide should be followed if you require instructions on how to build, install and use the firmware once it is installed on the console. 45 | 46 | ## Developer Guide 47 | 48 | You will need VS2017, with Linux plugin and WSL (Ubuntu on Windows) or a physical Linux machine or Linux VM to be able to build the project. You may find the documentation for developers at [DEVELOPERS.md](https://github.com/OpenOrbis/mira-project/blob/master/DEVELOPERS.md) 49 | 50 | ## Special Thanks and Friends 51 | 52 | We want to give a special shout out to these people in no particular order. 53 | 54 | * flatz 55 | * SpecterDev 56 | * EvilSperm 57 | * Rogero 58 | * Joonie 59 | * AlexAltea 60 | * Mistawes 61 | * Abkarino 62 | * qwertyoruiop 63 | * CTurT 64 | * Mathieulh 65 | * Senaxx 66 | * m0rph3us1987 67 | * CrazyVoid 68 | * xvortex 69 | * bigboss 70 | * ZeraTron 71 | * xorloser 72 | * AlAzif 73 | * masterzorag 74 | * fail0verflow 75 | * idc 76 | * valentinbreiz 77 | * Anonymous Contributors (you know who you are) 78 | -------------------------------------------------------------------------------- /Scripts/clean_all.cmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyVoidProgrammer/mira-project/99b9572d111ab28bb6202dbe392eb17e42b32755/Scripts/clean_all.cmd -------------------------------------------------------------------------------- /Scripts/clean_all.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyVoidProgrammer/mira-project/99b9572d111ab28bb6202dbe392eb17e42b32755/Scripts/clean_all.sh -------------------------------------------------------------------------------- /Scripts/config.txt: -------------------------------------------------------------------------------- 1 | MIRA_DIR=!cd! 2 | MIRA_REMOTE_DIR=~/mira 3 | MIRA_OUTPUT_DIR=!MIRA_DIR!/Output 4 | MIRA_REMOTE_OUTPUT_DIR=!MIRA_REMOTE_DIR!/Output 5 | ONI_FRAMEWORK=!MIRA_DIR!/Firmware/Dependencies/oni-framework -------------------------------------------------------------------------------- /Scripts/init_development_environment.cmd: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | REM We will start by parsing the configuration 4 | 5 | REM The path of the configuration file, it should be within this directory 6 | @SET MIRA_CONFIG_PATH=Scripts/config.txt 7 | @SET MIRA_ERR=ERR: 8 | @SET MIRA_WARN=WARN: 9 | @SET MIRA_INFO=INFO: 10 | @SETLOCAL ENABLEDELAYEDEXPANSION 11 | 12 | REM Checks to see if the configuration file exists 13 | if EXIST %MIRA_CONFIG_PATH% ( 14 | for /f "delims=" %%i in (%MIRA_CONFIG_PATH%) do SET "%%i" 15 | ) else ( 16 | REM Let the user know why the configuration script errored 17 | @echo "%MIRA_ERR% Configuration file not found (%MIRA_CONFIG_PATH%)." 18 | 19 | REM Return with an error, file not found 20 | goto :eof 21 | ) 22 | 23 | REM Output all of the settings that we have imported from the configuration file 24 | @echo "Environment variables configured:" 25 | @echo "Mira Remote Directory: (%MIRA_REMOTE_DIR%)" 26 | @echo "Mira Remote Output Directory: (%MIRA_REMOTE_OUTPUT_DIR%)" 27 | 28 | REM Verify that the MIRA_DIR directory actually exists 29 | if NOT EXIST "%MIRA_DIR%" ( 30 | @echo "%MIRA_ERR% 'MIRA_DIR' environment variable not set in Scripts/config.txt" 31 | @echo "Directory not found" 32 | 33 | goto :eof 34 | ) else ( 35 | @echo "Mira Directory: (%MIRA_DIR%)" 36 | ) 37 | 38 | if NOT EXIST "%ONI_FRAMEWORK%" ( 39 | @echo "%MIRA_ERR% 'ONI_FRAMEWORK' environment variable not set in the Scripts/config.txt" 40 | @echo "Directory not found" 41 | 42 | goto :eof 43 | ) else ( 44 | @echo "OniFramework directory: %ONI_FRAMEWORK%" 45 | ) 46 | 47 | REM Handle the launching of visual studio with our environment variables pre-set 48 | if "%1"=="-launchvs" ( 49 | call "%VS140COMNTOOLS%/vsvars32.bat" 50 | dev "%MIRA_DIR%/Mira.sln" 51 | ) -------------------------------------------------------------------------------- /Scripts/init_development_environment.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrazyVoidProgrammer/mira-project/99b9572d111ab28bb6202dbe392eb17e42b32755/Scripts/init_development_environment.sh -------------------------------------------------------------------------------- /Tests/MiraLibTests/ConnectionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using MiraLib; 4 | using MiraLib.Extensions; 5 | 6 | namespace MiraLibTests 7 | { 8 | [TestClass] 9 | public class ConnectionTests 10 | { 11 | // Change this to the target IP address 12 | private const string c_Address = "192.168.1.2"; 13 | 14 | // CHange this to the target port (default: 9999) 15 | private const ushort c_Port = 9999; 16 | 17 | private MiraConnection m_Connection; 18 | 19 | [TestInitialize] 20 | public void TestInitialization() 21 | { 22 | m_Connection = new MiraConnection(c_Address, c_Port); 23 | } 24 | 25 | [TestMethod] 26 | public void TestIsConnected() 27 | { 28 | // Verify the connection is valid 29 | Assert.IsNotNull(m_Connection); 30 | 31 | // Verify that the connection is actually connected 32 | Assert.IsTrue(m_Connection.Connected); 33 | } 34 | 35 | [TestMethod] 36 | public void TestFileTransfer() 37 | { 38 | // Verify the connection is valid 39 | Assert.IsNotNull(m_Connection); 40 | 41 | // Verify that the connection is actually connected 42 | Assert.IsTrue(m_Connection.Connected); 43 | 44 | var s_Flags = (int)MiraFileTransferExtensions.FileTransferFlags.O_RDONLY; 45 | 46 | var s_FileHandle = m_Connection.Open("/user", s_Flags, 0); 47 | Assert.AreNotEqual(-1, s_FileHandle); 48 | 49 | m_Connection.Close(s_FileHandle); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Tests/MiraLibTests/MiraLibTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EC822E41-97A2-448C-958F-88F8D55C3100} 8 | Library 9 | Properties 10 | MiraLibTests 11 | MiraLibTests 12 | v4.7.1 13 | 512 14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 15.0 16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 18 | False 19 | UnitTest 20 | 21 | 22 | 23 | 24 | true 25 | bin\x64\Debug\ 26 | DEBUG;TRACE 27 | full 28 | x64 29 | prompt 30 | MinimumRecommendedRules.ruleset 31 | 32 | 33 | bin\x64\Release\ 34 | TRACE 35 | true 36 | pdbonly 37 | x64 38 | prompt 39 | MinimumRecommendedRules.ruleset 40 | 41 | 42 | 43 | ..\..\packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 44 | 45 | 46 | ..\..\packages\MSTest.TestFramework.1.2.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {7f17f9f8-0220-4814-824a-30bc4e919341} 61 | MiraLib 62 | 63 | 64 | 65 | 66 | 67 | 68 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Tests/MiraLibTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("MiraLibTests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("MiraLibTests")] 10 | [assembly: AssemblyCopyright("Copyright © 2018")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("ec822e41-97a2-448c-958f-88f8d55c3100")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /Tests/MiraLibTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Tools/MiraLib/MiraConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Sockets; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace MiraLib 8 | { 9 | /// 10 | /// Categories, these MUST MATCH THE C IMPLEMENTATION 11 | /// 12 | public enum RPC_CATEGORY 13 | { 14 | /// 15 | /// Nothing 16 | /// 17 | RPCCAT_NONE = 0, 18 | 19 | /// 20 | /// System category 21 | /// 22 | RPCCAT_SYSTEM, 23 | 24 | /// 25 | /// Logger category 26 | /// 27 | RPCCAT_LOG, 28 | 29 | /// 30 | /// Debugger category 31 | /// 32 | RPCCAT_DBG, 33 | 34 | /// 35 | /// File category 36 | /// 37 | RPCCAT_FILE, 38 | 39 | /// 40 | /// Command category 41 | /// 42 | RPCCAT_CMD, 43 | 44 | /// 45 | /// Category count 46 | /// 47 | RPCCAT_COUNT 48 | }; 49 | 50 | public class RpcMessageHeader 51 | { 52 | private ulong m_Bits; 53 | 54 | public byte Magic 55 | { 56 | get 57 | { 58 | return (byte)(m_Bits & 0x7); 59 | } 60 | set 61 | { 62 | var s_Bits = (m_Bits & ~(ulong)0x7); 63 | m_Bits = s_Bits | (value & (ulong)0x7); 64 | } 65 | } 66 | 67 | public byte Category 68 | { 69 | get 70 | { 71 | return (byte)(m_Bits & (0xF << 3)); 72 | } 73 | set 74 | { 75 | const ulong V = 0xF; 76 | var s_Bits = (m_Bits & (~(V << 3))); 77 | m_Bits = s_Bits | (((ulong)value & V) << 3); 78 | } 79 | } 80 | 81 | public int ErrorType 82 | { 83 | get 84 | { 85 | return (int)(m_Bits & (0xFFFFFFFF << 0x7)); 86 | } 87 | set 88 | { 89 | const ulong V = 0xFFFFFFFF; 90 | var s_Bits = (m_Bits & (~(V << 0x7))); 91 | m_Bits = s_Bits | (((ulong)value & V) << 0x7); 92 | } 93 | } 94 | 95 | public ushort PayloadSize 96 | { 97 | get 98 | { 99 | return (ushort)(m_Bits & (0xFFFF << 0x27)); 100 | } 101 | set 102 | { 103 | const ulong V = 0xFFFF; 104 | var s_Bits = (m_Bits & (~(V << 0x27))); 105 | m_Bits = s_Bits | (((ulong)value & V) << 0x27); 106 | } 107 | } 108 | 109 | public bool Request 110 | { 111 | get 112 | { 113 | return ((m_Bits & (0x1 << 0x37)) != 0); 114 | } 115 | set 116 | { 117 | const ulong V = 0x1; 118 | var s_Bits = (m_Bits & (~(V << 0x37))); 119 | m_Bits = s_Bits | (((ulong)(value ? 1 : 0) & V) << 0x37); 120 | } 121 | } 122 | 123 | public byte[] Serialize() 124 | { 125 | return BitConverter.GetBytes(m_Bits); 126 | } 127 | 128 | public ulong ToUInt64() 129 | { 130 | return m_Bits; 131 | } 132 | 133 | public RpcMessageHeader() 134 | { 135 | Magic = MiraConnection.c_Magic; 136 | } 137 | 138 | public RpcMessageHeader(ulong p_Bits) 139 | { 140 | m_Bits = p_Bits; 141 | } 142 | } 143 | 144 | /// 145 | /// The bread and butter 146 | /// 147 | public class MiraConnection 148 | { 149 | // Header magic, THIS MUST MATCH C IMPLEMENTATION 150 | public const byte c_Magic = 0x5; 151 | 152 | // Buffer size, THIS MUST MATCH C IMPLEMENTATION 153 | public const int c_BufferSize = 0x4000; 154 | 155 | // IP address 156 | protected readonly string m_Address; 157 | 158 | // Server port 159 | protected readonly ushort m_Port; 160 | 161 | // Client 162 | internal TcpClient m_Client; 163 | 164 | /// 165 | /// Returns if the client is connected 166 | /// 167 | public bool Connected => m_Client?.Connected ?? false; 168 | 169 | /// 170 | /// IP Address 171 | /// 172 | public string Address => m_Address; 173 | 174 | /// 175 | /// Creates a new connection instance 176 | /// 177 | /// Ip address of the server 178 | /// Port to connect to 179 | public MiraConnection(string p_IpAddress, ushort p_Port) 180 | { 181 | m_Address = p_IpAddress; 182 | m_Port = p_Port; 183 | } 184 | 185 | /// 186 | /// Connect to a remote client 187 | /// 188 | /// True on success, false otherwise 189 | public bool Connect() 190 | { 191 | try 192 | { 193 | m_Client = new TcpClient(m_Address, m_Port) 194 | { 195 | // Large file transfers will stall if this is set to low 196 | SendTimeout = 1000 * 10, 197 | ReceiveTimeout = 1000 * 10, 198 | 199 | // These must match the c implementation 200 | SendBufferSize = c_BufferSize, 201 | ReceiveBufferSize = c_BufferSize 202 | }; 203 | } 204 | catch (Exception p_Exception) 205 | { 206 | Console.WriteLine(p_Exception); 207 | return false; 208 | } 209 | 210 | return m_Client.Connected; 211 | } 212 | 213 | /// 214 | /// Disconnects the client 215 | /// 216 | public void Disconnect() 217 | { 218 | try 219 | { 220 | m_Client.Close(); 221 | } 222 | catch (Exception p_Exception) 223 | { 224 | Console.WriteLine(p_Exception); 225 | } 226 | } 227 | 228 | /// 229 | /// Serializes an object into a byte array 230 | /// 231 | /// Structure to serialize 232 | /// Byte array of object 233 | public byte[] SerializeObject(object p_Object) 234 | { 235 | var s_Size = Marshal.SizeOf(p_Object); 236 | 237 | var s_Data = new byte[s_Size]; 238 | 239 | var s_Ptr = Marshal.AllocHGlobal(s_Size); 240 | 241 | Marshal.StructureToPtr(p_Object, s_Ptr, true); 242 | 243 | Marshal.Copy(s_Ptr, s_Data, 0, s_Size); 244 | 245 | Marshal.FreeHGlobal(s_Ptr); 246 | 247 | return s_Data; 248 | } 249 | 250 | /// 251 | /// Deserializes a object to the specified structure 252 | /// 253 | /// Structure to deserialize 254 | /// Incoming data to deserialize from 255 | /// Object or null 256 | public T DeserializeObject(byte[] p_Data) 257 | { 258 | var s_Size = Marshal.SizeOf(); 259 | if (p_Data.Length < s_Size) 260 | throw new InvalidDataException($"Data size is too small to deserialize {typeof(T).FullName}"); 261 | 262 | var s_Ptr = Marshal.AllocHGlobal(s_Size); 263 | Marshal.Copy(p_Data, 0, s_Ptr, s_Size); 264 | var s_Object = (T)Marshal.PtrToStructure(s_Ptr, typeof(T)); 265 | Marshal.FreeHGlobal(s_Ptr); 266 | 267 | return s_Object; 268 | } 269 | 270 | /// 271 | /// Receive's an object from over the network, will not accept data afterwards 272 | /// 273 | /// Structure type to download 274 | /// Object created 275 | public T ReceiveObject() 276 | { 277 | var s_Size = Marshal.SizeOf(); 278 | 279 | byte[] s_Data; 280 | using (var s_Reader = new BinaryReader(m_Client.GetStream(), Encoding.ASCII, true)) 281 | s_Data = s_Reader.ReadBytes(s_Size); 282 | 283 | if (s_Data.Length < s_Size) 284 | throw new InvalidDataException("incoming data length < required size"); 285 | 286 | var s_Object = DeserializeObject(s_Data); 287 | 288 | return s_Object; 289 | } 290 | 291 | /// 292 | /// Sends a structure to the server 293 | /// 294 | /// Type of structure 295 | /// Structure to send 296 | public void SendMessage(T p_Object) 297 | { 298 | var s_Data = SerializeObject(p_Object); 299 | 300 | using (var s_Writer = new BinaryWriter(m_Client.GetStream(), Encoding.ASCII, true)) 301 | s_Writer.Write(s_Data); 302 | } 303 | 304 | /// 305 | /// Sends a message with the supplied header, and payload 306 | /// 307 | /// Header 308 | /// Payload data 309 | public void SendMessage(RpcMessageHeader p_Object, byte[] p_Payload) 310 | { 311 | var s_Bits = p_Object.ToUInt64(); 312 | var s_HeaderData = SerializeObject(s_Bits); 313 | 314 | using (var s_Writer = new BinaryWriter(m_Client.GetStream(), Encoding.ASCII, true)) 315 | { 316 | s_Writer.Write(s_HeaderData); 317 | s_Writer.Write(p_Payload); 318 | } 319 | } 320 | 321 | /// 322 | /// Sends a message with a structure payload 323 | /// 324 | /// Type of payload 325 | /// Header 326 | /// Structure to send 327 | public void SendMessage(RpcMessageHeader p_Header, T p_Payload) 328 | { 329 | var s_Bits = p_Header.ToUInt64(); 330 | var s_HeaderData = SerializeObject(s_Bits); 331 | var s_PayloadData = SerializeObject(p_Payload); 332 | 333 | using (var s_Writer = new BinaryWriter(m_Client.GetStream(), Encoding.ASCII, true)) 334 | { 335 | s_Writer.Write(s_HeaderData); 336 | s_Writer.Write(s_PayloadData); 337 | } 338 | } 339 | 340 | public (RpcMessageHeader, byte[]) ReceiveObjectAndPayload() 341 | { 342 | using (var s_Reader = new BinaryReader(m_Client.GetStream(), Encoding.ASCII, true)) 343 | { 344 | 345 | var s_Header = new RpcMessageHeader(s_Reader.ReadUInt64()); 346 | 347 | var s_PayloadSize = (ushort)(s_Header.PayloadSize > c_BufferSize ? c_BufferSize : s_Header.PayloadSize); 348 | 349 | var s_Payload = s_Reader.ReadBytes(s_PayloadSize); 350 | 351 | return (s_Header, s_Payload); 352 | } 353 | } 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /Tools/MiraLib/MiraFileTransferExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | 8 | namespace MiraLib.Extensions 9 | { 10 | public static class MiraFileTransferExtensions 11 | { 12 | /* 13 | * 73 #define O_RDONLY 0x0000 /* open for reading only 14 | 74 #define O_WRONLY 0x0001 /* open for writing only 15 | 75 #define O_RDWR 0x0002 /* open for reading and writing 16 | */ 17 | 18 | public enum FileTransferFlags 19 | { 20 | O_RDONLY = 0x0000, 21 | O_WRONLY = 0x0001, 22 | O_RDWR = 0x0002, 23 | 24 | O_TRUNC = 0x0400, 25 | O_CREAT = 0x0200, 26 | O_APPEND = 0x0008, 27 | } 28 | 29 | enum FileTransferCmds : uint 30 | { 31 | FileTransfer_Open = 0x58AFA0D4, 32 | FileTransfer_Close = 0x43F82FDB, 33 | FileTransfer_GetDents = 0x7433E67A, 34 | FileTransfer_Read = 0x64886217, 35 | FileTransfer_ReadFile = 0x13B55E44, 36 | FileTransfer_Write = 0x2D92D440, 37 | FileTransfer_WriteFile = 0x3B91E812, 38 | FileTransfer_Delete = 0xB74A88DC, 39 | FileTransfer_Move = 0x13E11408, 40 | FileTransfer_Stat = 0xDC67DC51, 41 | FileTransfer_COUNT 42 | }; 43 | 44 | public enum FileTransferDirentType : int 45 | { 46 | Unknown = 0, 47 | NamedPipe = 1, 48 | CharacterDevice = 2, 49 | Directory = 4, 50 | BlockDevice = 8, 51 | Symlink = 10, 52 | Socket = 12, 53 | Wht = 14 54 | }; 55 | 56 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 57 | public struct FileTransferOpen 58 | { 59 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 60 | public string Path; 61 | 62 | public int Flags; 63 | 64 | public int Mode; 65 | 66 | public int Handle; 67 | } 68 | 69 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 70 | public struct FileTransferReadFile 71 | { 72 | public int Handle; 73 | public ulong Size; 74 | // Payload 75 | } 76 | 77 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 78 | public struct FileTransferWriteFile 79 | { 80 | public int Handle; 81 | public ulong Size; 82 | // Payload 83 | } 84 | 85 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 86 | public struct FileTransferClose 87 | { 88 | public int Handle; 89 | } 90 | 91 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 92 | public struct FileTransferGetdents 93 | { 94 | public int Handle; 95 | public byte Type; 96 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 97 | public string Path; 98 | } 99 | 100 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 101 | public struct FileTransferDelete 102 | { 103 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 104 | public string Path; 105 | } 106 | 107 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 108 | public struct FileTransferRead 109 | { 110 | public int Handle; 111 | public ulong Offset; 112 | public ulong Size; 113 | // Payload data gets sent afterwards 114 | } 115 | 116 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 0)] 117 | public struct FileTransferStat 118 | { 119 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 120 | public string Path; 121 | public int Mode; 122 | public int Uid; 123 | public int Gid; 124 | public ulong Size; 125 | } 126 | 127 | public static int Open(this MiraConnection p_Connection, string p_Path, int p_Flags, int p_Mode) 128 | { 129 | if (!p_Connection.Connected) 130 | return -1; 131 | 132 | if (p_Path.Length > 255) 133 | return -1; 134 | 135 | p_Connection.SendMessage(new RpcMessageHeader 136 | { 137 | Magic = MiraConnection.c_Magic, 138 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 139 | Request = true, 140 | ErrorType = (int)FileTransferCmds.FileTransfer_Open, 141 | PayloadSize = (ushort)Marshal.SizeOf() 142 | }, p_Connection.SerializeObject(new FileTransferOpen 143 | { 144 | Flags = p_Flags, 145 | Handle = -1, 146 | Mode = p_Mode, 147 | Path = p_Path 148 | })); 149 | 150 | var s_Result = new RpcMessageHeader(p_Connection.ReceiveObject()); 151 | if (s_Result.ErrorType != 0) 152 | return -1; 153 | 154 | var s_Response = p_Connection.ReceiveObject(); 155 | return s_Response.Handle; 156 | } 157 | 158 | public static void Close(this MiraConnection p_Connection, int p_Descriptor) 159 | { 160 | if (!p_Connection.Connected) 161 | return; 162 | 163 | if (p_Descriptor < 0) 164 | return; 165 | 166 | p_Connection.SendMessage(new RpcMessageHeader 167 | { 168 | Magic = MiraConnection.c_Magic, 169 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 170 | Request = true, 171 | ErrorType = (int)FileTransferCmds.FileTransfer_Close, 172 | PayloadSize = (ushort)Marshal.SizeOf() 173 | }, p_Connection.SerializeObject(new FileTransferClose 174 | { 175 | Handle = p_Descriptor 176 | })); 177 | } 178 | 179 | public static byte[] ReadFile(this MiraConnection p_Connection, string p_Path) 180 | { 181 | if (!p_Connection.Connected) 182 | return null; 183 | 184 | int s_Descriptor = p_Connection.Open(p_Path, 0, 0); 185 | if (s_Descriptor < 0) 186 | return null; 187 | 188 | var s_HeaderData = p_Connection.SerializeObject(new RpcMessageHeader 189 | { 190 | Magic = MiraConnection.c_Magic, 191 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 192 | Request = true, 193 | ErrorType = (int)FileTransferCmds.FileTransfer_ReadFile, 194 | PayloadSize = (ushort)Marshal.SizeOf() 195 | }); 196 | 197 | var s_RequestData = p_Connection.SerializeObject(new FileTransferReadFile 198 | { 199 | Handle = s_Descriptor, 200 | Size = 0 201 | }); 202 | 203 | using (var s_Writer = new BinaryWriter(p_Connection.m_Client.GetStream(), Encoding.ASCII, true)) 204 | { 205 | s_Writer.Write(s_HeaderData); 206 | s_Writer.Write(s_RequestData); 207 | } 208 | 209 | var s_Response = p_Connection.ReceiveObject(); 210 | 211 | var s_BlockCount = s_Response.Size / 0x4000; 212 | var s_Leftover = s_Response.Size % 0x4000; 213 | var s_CurrentSize = 0; 214 | 215 | byte[] s_Data; 216 | using (var s_Reader = new BinaryReader(p_Connection.m_Client.GetStream(), Encoding.ASCII, true)) 217 | { 218 | using (var s_Writer = new BinaryWriter(new MemoryStream())) 219 | { 220 | for (ulong i = 0; i < s_BlockCount; ++i) 221 | { 222 | s_CurrentSize += 0x4000; 223 | s_Writer.Write(s_Reader.ReadBytes(0x4000)); 224 | } 225 | 226 | 227 | s_Writer.Write(s_Reader.ReadBytes((int)s_Leftover)); 228 | 229 | s_Data = ((MemoryStream)s_Writer.BaseStream).ToArray(); 230 | } 231 | } 232 | 233 | // Close the handle 234 | p_Connection.Close(s_Descriptor); 235 | 236 | return s_Data; 237 | } 238 | 239 | public static void ReadFile(this MiraConnection p_Connection, string p_SourcePath, string p_LocalPath) 240 | { 241 | if (!p_Connection.Connected) 242 | return; 243 | 244 | int s_Descriptor = p_Connection.Open(p_SourcePath, 0, 0); 245 | if (s_Descriptor < 0) 246 | return; 247 | 248 | p_Connection.SendMessage(new RpcMessageHeader 249 | { 250 | Magic = MiraConnection.c_Magic, 251 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 252 | Request = true, 253 | ErrorType = (int)FileTransferCmds.FileTransfer_ReadFile, 254 | PayloadSize = (ushort)Marshal.SizeOf() 255 | }, p_Connection.SerializeObject(new FileTransferReadFile 256 | { 257 | Handle = s_Descriptor, 258 | Size = 0 259 | })); 260 | 261 | var s_Result = new RpcMessageHeader(p_Connection.ReceiveObject()); 262 | if (s_Result.ErrorType != 0) 263 | return; 264 | 265 | var s_Response = p_Connection.ReceiveObject(); 266 | 267 | var s_BlockCount = s_Response.Size / 0x4000; 268 | var s_Leftover = s_Response.Size % 0x4000; 269 | 270 | using (var s_Reader = new BinaryReader(p_Connection.m_Client.GetStream(), Encoding.ASCII, true)) 271 | { 272 | using (var s_Writer = new BinaryWriter(new FileStream(p_LocalPath, FileMode.Create, FileAccess.ReadWrite))) 273 | { 274 | for (ulong i = 0; i < s_BlockCount; ++i) 275 | s_Writer.Write(s_Reader.ReadBytes(0x4000)); 276 | 277 | s_Writer.Write(s_Reader.ReadBytes((int)s_Leftover)); 278 | } 279 | } 280 | 281 | // Close the handle 282 | p_Connection.Close(s_Descriptor); 283 | } 284 | 285 | public static bool WriteFile(this MiraConnection p_Connection, string p_Path, byte[] p_Data) 286 | { 287 | if (!p_Connection.Connected) 288 | return false; 289 | 290 | var s_Descriptor = p_Connection.Open(p_Path, 0x0002 | 0x0200 /* O_RDWR | O_CREAT*/, 0777); 291 | if (s_Descriptor < 0) 292 | return false; 293 | 294 | p_Connection.SendMessage(new RpcMessageHeader 295 | { 296 | Magic = MiraConnection.c_Magic, 297 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 298 | Request = true, 299 | ErrorType = (int)FileTransferCmds.FileTransfer_WriteFile, 300 | PayloadSize = (ushort)Marshal.SizeOf() 301 | }, p_Connection.SerializeObject(new FileTransferWriteFile 302 | { 303 | Handle = s_Descriptor, 304 | Size = (ulong)p_Data.Length 305 | })); 306 | 307 | var s_BlockCount = p_Data.Length / 0x4000; 308 | var s_Leftover = p_Data.Length % 0x4000; 309 | 310 | using (var s_Reader = new BinaryReader(new MemoryStream(p_Data))) 311 | { 312 | using (var s_Writer = new BinaryWriter(p_Connection.m_Client.GetStream(), Encoding.ASCII, true)) 313 | { 314 | for (int i = 0; i < s_BlockCount; ++i) 315 | s_Writer.Write(s_Reader.ReadBytes(0x4000)); 316 | 317 | s_Writer.Write(s_Reader.ReadBytes((int)s_Leftover)); 318 | } 319 | } 320 | 321 | var s_Result = new RpcMessageHeader(p_Connection.ReceiveObject()); 322 | 323 | p_Connection.Close(s_Descriptor); 324 | 325 | return s_Result.ErrorType == 0; 326 | } 327 | 328 | public static byte[] Read(this MiraConnection p_Connection, int p_Descriptor, uint p_Offset, ulong p_Size) 329 | { 330 | if (!p_Connection.Connected) 331 | return null; 332 | 333 | if (p_Descriptor < 0) 334 | return null; 335 | 336 | p_Connection.SendMessage(new RpcMessageHeader 337 | { 338 | Magic = MiraConnection.c_Magic, 339 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 340 | Request = true, 341 | ErrorType = (int)FileTransferCmds.FileTransfer_Read, 342 | PayloadSize = (ushort)Marshal.SizeOf(), 343 | }, p_Connection.SerializeObject(new FileTransferRead 344 | { 345 | Handle = p_Descriptor, 346 | Offset = p_Offset, 347 | Size = p_Size 348 | })); 349 | 350 | var s_Response = new RpcMessageHeader(p_Connection.ReceiveObject()); 351 | if (s_Response.ErrorType != 0) 352 | return null; 353 | 354 | var s_Payload = p_Connection.ReceiveObject(); 355 | 356 | var s_BlockCount = s_Payload.Size / 0x4000; 357 | var s_Leftover = s_Payload.Size % 0x4000; 358 | 359 | byte[] s_Data; 360 | using (var s_Reader = new BinaryReader(p_Connection.m_Client.GetStream(), Encoding.ASCII, true)) 361 | { 362 | using (var s_Writer = new BinaryWriter(new MemoryStream())) 363 | { 364 | for (ulong i = 0; i < s_BlockCount; ++i) 365 | s_Writer.Write(s_Reader.ReadBytes(0x4000)); 366 | 367 | s_Writer.Write(s_Reader.ReadBytes((int)s_Leftover)); 368 | s_Data = ((MemoryStream)s_Writer.BaseStream).ToArray(); 369 | } 370 | } 371 | 372 | return s_Data; 373 | } 374 | 375 | public static bool Delete(this MiraConnection p_Connection, string p_Path) 376 | { 377 | if (!p_Connection.Connected) 378 | return false; 379 | 380 | if (string.IsNullOrWhiteSpace(p_Path)) 381 | return false; 382 | 383 | if (p_Path.Length > 255) 384 | return false; 385 | 386 | p_Connection.SendMessage(new RpcMessageHeader 387 | { 388 | Magic = MiraConnection.c_Magic, 389 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 390 | Request = true, 391 | ErrorType = unchecked((int)FileTransferCmds.FileTransfer_Delete), 392 | PayloadSize = (ushort)Marshal.SizeOf(), 393 | }, p_Connection.SerializeObject(new FileTransferDelete 394 | { 395 | Path = p_Path 396 | })); 397 | 398 | var s_Result = new RpcMessageHeader(p_Connection.ReceiveObject()); 399 | if (s_Result.ErrorType != 0) 400 | return false; 401 | 402 | return true; 403 | } 404 | 405 | public static IEnumerable GetDents(this MiraConnection p_Connection, string p_Path) 406 | { 407 | if (!p_Connection.Connected) 408 | return null; 409 | 410 | // Send the request 411 | p_Connection.SendMessage(new RpcMessageHeader 412 | { 413 | Magic = MiraConnection.c_Magic, 414 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 415 | Request = true, 416 | ErrorType = (int)FileTransferCmds.FileTransfer_GetDents, 417 | PayloadSize = (ushort)Marshal.SizeOf(), 418 | }, p_Connection.SerializeObject(new FileTransferGetdents 419 | { 420 | Path = p_Path, 421 | Handle = -1, 422 | Type = 0 423 | })); 424 | 425 | // Check the result 426 | var s_Result = new RpcMessageHeader(p_Connection.ReceiveObject()); 427 | if (s_Result.ErrorType != 0) 428 | return Enumerable.Empty(); 429 | 430 | // Read the amount of directory entries 431 | var s_List = new List(); 432 | ulong s_DentCount = 0; 433 | using (var s_Reader = new BinaryReader(p_Connection.m_Client.GetStream(), Encoding.ASCII, true)) 434 | s_DentCount = s_Reader.ReadUInt64(); 435 | 436 | Debug.WriteLine($"Dent Count: {s_DentCount}"); 437 | 438 | for (ulong i = 0; i < s_DentCount; ++i) 439 | s_List.Add(p_Connection.ReceiveObject()); 440 | 441 | return s_List; 442 | } 443 | 444 | public static bool Stat(this MiraConnection p_Connection, string p_Path, out FileTransferStat p_Stat) 445 | { 446 | p_Stat = new FileTransferStat(); 447 | 448 | if (!p_Connection.Connected) 449 | return false; 450 | 451 | if (p_Path.Length > 255) 452 | return false; 453 | 454 | p_Connection.SendMessage(new RpcMessageHeader 455 | { 456 | Magic = MiraConnection.c_Magic, 457 | Category = (int)RPC_CATEGORY.RPCCAT_FILE, 458 | Request = true, 459 | ErrorType = unchecked((int)FileTransferCmds.FileTransfer_Stat), 460 | PayloadSize = (ushort)Marshal.SizeOf() 461 | }, p_Connection.SerializeObject(new FileTransferStat 462 | { 463 | Path = p_Path 464 | })); 465 | 466 | var s_Response = new RpcMessageHeader(p_Connection.ReceiveObject()); 467 | if (s_Response.ErrorType != 0) 468 | return false; 469 | 470 | p_Stat = p_Connection.ReceiveObject(); 471 | 472 | return true; 473 | } 474 | } 475 | } 476 | -------------------------------------------------------------------------------- /Tools/MiraLib/MiraLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7F17F9F8-0220-4814-824A-30BC4E919341} 8 | Library 9 | Properties 10 | MiraLib 11 | MiraLib 12 | v4.7.1 13 | 512 14 | 15 | 16 | true 17 | bin\x64\Debug\ 18 | DEBUG;TRACE 19 | full 20 | x64 21 | prompt 22 | MinimumRecommendedRules.ruleset 23 | 24 | 25 | bin\x64\Release\ 26 | TRACE 27 | true 28 | pdbonly 29 | x64 30 | prompt 31 | MinimumRecommendedRules.ruleset 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Tools/MiraLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MiraLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MiraLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7f17f9f8-0220-4814-824a-30bc4e919341")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /USERS.md: -------------------------------------------------------------------------------- 1 | # Mira Users Guide 2 | 3 | This user guide will help you build, install and use the Mira Framework on your Playstation 4 console. 4 | 5 | ## How to install 6 | 7 | You can install Mira firmware via several methods. You should choose the method that works best for you. Typically, this will be via a webkit exploit in the web browser. 8 | 9 | ### Webkit exploit (non-permanent installation) 10 | 11 | This involves using a webkit userland exploit to elevate the kernel to install MiraCFW. The changes will be lost upon reboot, but should survive sleep mode. 12 | 13 | ### Permanent installation 14 | 15 | There is no permanent install option at this time, nor will one be offered in the near future. 16 | 17 | #### Preparing 18 | 19 | TODO: Instructions on how to prepare 20 | 21 | #### Installing 22 | 23 | In order to install Mira you will need a few things... 24 | 25 | 1. An exploitable PlayStation 26 | 2. Support within Mira 27 | 3. Way to send payloads 28 | 1. Windows 29 | 2. Linux 30 | 3. Android 31 | 32 | Start by downloading the latest release of Mira from the github Releases page. If there are no current releases for your current firmware, then you will need to compile the payloads from source code. If this is the case, refer to the developers documentation. 33 | 34 | * We are also working towards preparing full stack webpage loaders in the near future for those who don't want to send payloads themselves. 35 | 36 | ##### WSL / Linux 37 | 38 | After the payload has either been downloaded from the Releases page on github, or compiled from source. You can send the payload to a console at "waiting for payloads" by using the following command. 39 | 40 | `nc {IP ADDRESS OF DEVICE} 9020 < ~/mira/Firmware/MiraFW/MiraFW_Orbis.bin` 41 | 42 | Provided you are using the default build paths of Mira. 43 | 44 | ##### Windows 45 | 46 | Currently there are no tools provided by the Mira-Project that will send payloads to the console. You may use your favorite tool for sending TCP payloads and it should work the same. 47 | 48 | #### Using MiraCFW 49 | 50 | Once Mira has been installed, it will automatically self-elevate, and check by default in the `/user/mira` folder for `config.ini` which contains the rest of the configuration for Mira. It will load plugins from the `/user/mira/plugins` directory and initialize them. 51 | 52 | Once Mira has been installed, there will be a notification prompting you to which ports have been opened on the device. You can now read the kernel log by connecting to the IP address if your PS4 on port `9998`, and access the RPC interface on the console via `9999`. 53 | 54 | #### Using MiraLib 55 | 56 | Currently there is no application or tools that support using MiraLib, there will be tools avaiable in the future. 57 | 58 | #### PS4 Payload Sender 59 | 60 | To send payloads from your Android device without webkit, you can follow [these instructions](https://github.com/valentinbreiz/PS4-Payload-Sender-Android/blob/master/DOCUMENTATION.md). 61 | 62 | ### Plugins 63 | 64 | Mira supports 2 types of plugins which both use the same framework. 65 | 66 | * Internal / integrated plugins 67 | * External plugins 68 | 69 | All external plugins must be copied over via FTP to the `/user/mira/plugins` directory in order for the plugin to be loaded on startup. External plugins have a specific linker format that they must follow, meanwhile internal or integrated plugins can just call the initialization routine directly. 70 | --------------------------------------------------------------------------------