├── .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 |
--------------------------------------------------------------------------------