mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-25 03:36:02 +00:00
loader: remove ldr:ro (moved into ro sysmodule)
This commit is contained in:
parent
13ded6bd1c
commit
253afc90a4
8 changed files with 7 additions and 610 deletions
|
@ -26,7 +26,6 @@
|
||||||
#include "ldr_process_manager.hpp"
|
#include "ldr_process_manager.hpp"
|
||||||
#include "ldr_debug_monitor.hpp"
|
#include "ldr_debug_monitor.hpp"
|
||||||
#include "ldr_shell.hpp"
|
#include "ldr_shell.hpp"
|
||||||
#include "ldr_ro_service.hpp"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern u32 __start__;
|
extern u32 __start__;
|
||||||
|
@ -114,21 +113,15 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
consoleDebugInit(debugDevice_SVC);
|
consoleDebugInit(debugDevice_SVC);
|
||||||
|
|
||||||
auto server_manager = new WaitableManager<LoaderServerOptions>(1);
|
static auto s_server_manager = WaitableManager<LoaderServerOptions>(1);
|
||||||
|
|
||||||
/* Add services to manager. */
|
/* Add services to manager. */
|
||||||
server_manager->AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1));
|
s_server_manager.AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1));
|
||||||
server_manager->AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3));
|
s_server_manager.AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3));
|
||||||
server_manager->AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2));
|
s_server_manager.AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2));
|
||||||
if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
|
|
||||||
/* On 1.0.0-2.3.0, Loader services ldr:ro instead of ro. */
|
|
||||||
server_manager->AddWaitable(new ServiceServer<RelocatableObjectsService>("ldr:ro", 0x20));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
server_manager->Process();
|
s_server_manager.Process();
|
||||||
|
|
||||||
delete server_manager;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <functional>
|
|
||||||
#include <cstring>
|
|
||||||
#include "ldr_nro.hpp"
|
|
||||||
#include "ldr_registration.hpp"
|
|
||||||
#include "ldr_map.hpp"
|
|
||||||
|
|
||||||
Result NroUtils::ValidateNrrHeader(NrrHeader *header, u64 size, u64 title_id_min) {
|
|
||||||
if (header->magic != MAGIC_NRR0) {
|
|
||||||
return ResultLoaderInvalidNrr;
|
|
||||||
}
|
|
||||||
if (header->nrr_size != size) {
|
|
||||||
return ResultLoaderInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Check NRR signature. */
|
|
||||||
if (false) {
|
|
||||||
return ResultLoaderInvalidSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header->title_id_min != title_id_min) {
|
|
||||||
return ResultLoaderInvalidNrr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result NroUtils::LoadNro(Registration::Process *target_proc, Handle process_h, u64 nro_heap_address, u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size, u64 *out_address) {
|
|
||||||
NroHeader nro_hdr = {};
|
|
||||||
MappedCodeMemory mcm_nro = {};
|
|
||||||
MappedCodeMemory mcm_bss = {};
|
|
||||||
unsigned int i;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
u8 nro_hash[0x20];
|
|
||||||
|
|
||||||
/* Perform cleanup on failure. */
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
mcm_nro.Close();
|
|
||||||
mcm_bss.Close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Ensure there is an available NRO slot. */
|
|
||||||
if (std::all_of(target_proc->nro_infos.begin(), target_proc->nro_infos.end(), std::mem_fn(&Registration::NroInfo::in_use))) {
|
|
||||||
rc = ResultLoaderInsufficientNroRegistrations;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
for (i = 0; i < 0x200; i++) {
|
|
||||||
if (R_SUCCEEDED(mcm_nro.Open(process_h, target_proc->is_64_bit_addspace, nro_heap_address, nro_heap_size))) {
|
|
||||||
if (R_SUCCEEDED(mcm_bss.OpenAtAddress(process_h, bss_heap_address, bss_heap_size, mcm_nro.code_memory_address + nro_heap_size))) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
mcm_nro.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i >= 0x200) {
|
|
||||||
rc = ResultLoaderInsufficientAddressSpace;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map the NRO. */
|
|
||||||
if (R_FAILED((rc = mcm_nro.Map()))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read data from NRO while it's mapped. */
|
|
||||||
{
|
|
||||||
nro_hdr = *((NroHeader *)mcm_nro.mapped_address);
|
|
||||||
|
|
||||||
if (nro_hdr.magic != MAGIC_NRO0) {
|
|
||||||
rc = ResultLoaderInvalidNro;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (nro_hdr.nro_size != nro_heap_size || nro_hdr.bss_size != bss_heap_size) {
|
|
||||||
rc = ResultLoaderInvalidNro;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if ((nro_hdr.text_size & 0xFFF) || (nro_hdr.ro_size & 0xFFF) || (nro_hdr.rw_size & 0xFFF) || (nro_hdr.bss_size & 0xFFF)) {
|
|
||||||
rc = ResultLoaderInvalidNro;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (nro_hdr.text_offset != 0 || nro_hdr.text_offset + nro_hdr.text_size != nro_hdr.ro_offset || nro_hdr.ro_offset + nro_hdr.ro_size != nro_hdr.rw_offset || nro_hdr.rw_offset + nro_hdr.rw_size != nro_hdr.nro_size) {
|
|
||||||
rc = ResultLoaderInvalidNro;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
sha256CalculateHash(nro_hash, mcm_nro.mapped_address, nro_hdr.nro_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unmap the NRO. */
|
|
||||||
if (R_FAILED((rc = mcm_nro.Unmap()))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Registration::IsNroHashPresent(target_proc->index, nro_hash)) {
|
|
||||||
rc = ResultLoaderInvalidSignature;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Registration::IsNroAlreadyLoaded(target_proc->index, nro_hash)) {
|
|
||||||
rc = ResultLoaderNroAlreadyLoaded;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address, nro_hdr.text_size, 5)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address + nro_hdr.ro_offset, nro_hdr.ro_size, 1)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, mcm_nro.code_memory_address + nro_hdr.rw_offset, nro_hdr.rw_size + nro_hdr.bss_size, 3)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Registration::AddNroToProcess(target_proc->index, &mcm_nro, &mcm_bss, nro_hdr.text_size, nro_hdr.ro_size, nro_hdr.rw_size, nro_hdr.build_id);
|
|
||||||
*out_address = mcm_nro.code_memory_address;
|
|
||||||
rc = ResultSuccess;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <switch.h>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include "ldr_registration.hpp"
|
|
||||||
#define MAGIC_NRO0 0x304F524E
|
|
||||||
#define MAGIC_NRR0 0x3052524E
|
|
||||||
|
|
||||||
class NroUtils {
|
|
||||||
public:
|
|
||||||
struct NrrHeader {
|
|
||||||
u32 magic;
|
|
||||||
u32 _0x4;
|
|
||||||
u32 _0x8;
|
|
||||||
u32 _0xC;
|
|
||||||
u64 title_id_mask;
|
|
||||||
u64 title_id_pattern;
|
|
||||||
u64 _0x20;
|
|
||||||
u64 _0x28;
|
|
||||||
u8 modulus[0x100];
|
|
||||||
u8 fixed_key_signature[0x100];
|
|
||||||
u8 nrr_signature[0x100];
|
|
||||||
u64 title_id_min;
|
|
||||||
u32 nrr_size;
|
|
||||||
u32 _0x33C;
|
|
||||||
u32 hash_offset;
|
|
||||||
u32 num_hashes;
|
|
||||||
u64 _0x348;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NroHeader {
|
|
||||||
u32 entrypoint_insn;
|
|
||||||
u32 mod_offset;
|
|
||||||
u64 padding;
|
|
||||||
u32 magic;
|
|
||||||
u32 _0x14;
|
|
||||||
u32 nro_size;
|
|
||||||
u32 _0x1C;
|
|
||||||
u32 text_offset;
|
|
||||||
u32 text_size;
|
|
||||||
u32 ro_offset;
|
|
||||||
u32 ro_size;
|
|
||||||
u32 rw_offset;
|
|
||||||
u32 rw_size;
|
|
||||||
u32 bss_size;
|
|
||||||
u32 _0x3C;
|
|
||||||
unsigned char build_id[0x20];
|
|
||||||
u8 _0x60[0x20];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static_assert(sizeof(NrrHeader) == 0x350, "Incorrectly defined NrrHeader!");
|
|
||||||
static_assert(sizeof(NroHeader) == 0x80, "Incorrectly defined NroHeader!");
|
|
||||||
static Result ValidateNrrHeader(NrrHeader *header, u64 size, u64 title_id_min);
|
|
||||||
static Result LoadNro(Registration::Process *target_proc, Handle process_h, u64 nro_heap_address, u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size, u64 *out_address);
|
|
||||||
};
|
|
|
@ -28,8 +28,6 @@ Result ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 index,
|
||||||
LaunchQueue::LaunchItem *launch_item;
|
LaunchQueue::LaunchItem *launch_item;
|
||||||
char nca_path[FS_MAX_PATH] = {0};
|
char nca_path[FS_MAX_PATH] = {0};
|
||||||
|
|
||||||
fprintf(stderr, "CreateProcess(%016lx, %08x, %08x);\n", index, flags, reslimit_h.handle);
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
/* Loader doesn't persist the copied resource limit handle. */
|
/* Loader doesn't persist the copied resource limit handle. */
|
||||||
svcCloseHandle(reslimit_h.handle);
|
svcCloseHandle(reslimit_h.handle);
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "ldr_registration.hpp"
|
#include "ldr_registration.hpp"
|
||||||
#include "ldr_nro.hpp"
|
|
||||||
|
|
||||||
static Registration::List g_registration_list = {};
|
static Registration::List g_registration_list = {};
|
||||||
static u64 g_num_registered = 1;
|
static u64 g_num_registered = 1;
|
||||||
|
@ -51,15 +50,6 @@ Registration::Process *Registration::GetProcessByProcessId(u64 pid) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Registration::Process *Registration::GetProcessByRoService(void *service) {
|
|
||||||
for (unsigned int i = 0; i < Registration::MaxProcesses; i++) {
|
|
||||||
if (g_registration_list.processes[i].in_use && g_registration_list.processes[i].owner_ro_service == service) {
|
|
||||||
return &g_registration_list.processes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Registration::RegisterTidSid(const TidSid *tid_sid, u64 *out_index) {
|
bool Registration::RegisterTidSid(const TidSid *tid_sid, u64 *out_index) {
|
||||||
Registration::Process *free_process = GetFreeProcess();
|
Registration::Process *free_process = GetFreeProcess();
|
||||||
if (free_process == NULL) {
|
if (free_process == NULL) {
|
||||||
|
@ -124,140 +114,6 @@ void Registration::AddModuleInfo(u64 index, u64 base_address, u64 size, const un
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Registration::CloseRoService(void *service, Handle process_h) {
|
|
||||||
Registration::Process *target_process = GetProcessByRoService(service);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < Registration::MaxNrrInfos; i++) {
|
|
||||||
if (target_process->nrr_infos[i].IsActive() && target_process->nrr_infos[i].process_handle == process_h) {
|
|
||||||
target_process->nrr_infos[i].Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target_process->owner_ro_service = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Registration::AddNrrInfo(u64 index, MappedCodeMemory *nrr_info) {
|
|
||||||
Registration::Process *target_process = GetProcess(index);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
/* TODO: std::abort(); */
|
|
||||||
return ResultLoaderProcessNotRegistered;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nrr_info_it = std::find_if_not(target_process->nrr_infos.begin(), target_process->nrr_infos.end(), std::mem_fn(&MappedCodeMemory::IsActive));
|
|
||||||
if (nrr_info_it == target_process->nrr_infos.end()) {
|
|
||||||
return ResultLoaderInsufficientNrrRegistrations;
|
|
||||||
}
|
|
||||||
*nrr_info_it = *nrr_info;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Registration::RemoveNrrInfo(u64 index, u64 base_address) {
|
|
||||||
Registration::Process *target_process = GetProcess(index);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
/* Despite the fact that this should really be a panic condition, Nintendo returns 0x1009 in this case. */
|
|
||||||
return ResultLoaderProcessNotRegistered;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Registration::MaxNrrInfos; i++) {
|
|
||||||
if (target_process->nrr_infos[i].IsActive() && target_process->nrr_infos[i].base_address == base_address) {
|
|
||||||
target_process->nrr_infos[i].Close();
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ResultLoaderNotRegistered;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Registration::IsNroHashPresent(u64 index, u8 *nro_hash) {
|
|
||||||
Registration::Process *target_process = GetProcess(index);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
/* TODO: panic */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Registration::MaxNrrInfos; i++) {
|
|
||||||
if (target_process->nrr_infos[i].IsActive()) {
|
|
||||||
NroUtils::NrrHeader *nrr = (NroUtils::NrrHeader *)target_process->nrr_infos[i].mapped_address;
|
|
||||||
/* Binary search. */
|
|
||||||
int low = 0, high = (int)(nrr->num_hashes - 1);
|
|
||||||
while (low <= high) {
|
|
||||||
int mid = (low + high) / 2;
|
|
||||||
u8 *hash_in_nrr = (u8 *)nrr + nrr->hash_offset + 0x20 * mid;
|
|
||||||
int ret = std::memcmp(hash_in_nrr, nro_hash, 0x20);
|
|
||||||
if (ret == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (ret > 0) {
|
|
||||||
high = mid - 1;
|
|
||||||
} else {
|
|
||||||
low = mid + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Registration::IsNroAlreadyLoaded(u64 index, u8 *build_id) {
|
|
||||||
Registration::Process *target_process = GetProcess(index);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
/* TODO: panic */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Registration::MaxNroInfos; i++) {
|
|
||||||
if (target_process->nro_infos[i].in_use && std::equal(build_id, build_id + 0x20, target_process->nro_infos[i].build_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Registration::AddNroToProcess(u64 index, MappedCodeMemory *nro, MappedCodeMemory *bss, u32 text_size, u32 ro_size, u32 rw_size, u8 *build_id) {
|
|
||||||
Registration::Process *target_process = GetProcess(index);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
/* TODO: panic */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nro_info_it = std::find_if_not(target_process->nro_infos.begin(), target_process->nro_infos.end(), std::mem_fn(&Registration::NroInfo::in_use));
|
|
||||||
if (nro_info_it != target_process->nro_infos.end()) {
|
|
||||||
nro_info_it->base_address = nro->code_memory_address;
|
|
||||||
nro_info_it->nro_heap_address = nro->base_address;
|
|
||||||
nro_info_it->nro_heap_size = nro->size;
|
|
||||||
nro_info_it->bss_heap_address = bss->base_address;
|
|
||||||
nro_info_it->bss_heap_size = bss->size;
|
|
||||||
nro_info_it->text_size = text_size;
|
|
||||||
nro_info_it->ro_size = ro_size;
|
|
||||||
nro_info_it->rw_size = rw_size;
|
|
||||||
std::copy(build_id, build_id + sizeof(nro_info_it->build_id), nro_info_it->build_id);
|
|
||||||
nro_info_it->in_use = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Registration::RemoveNroInfo(u64 index, Handle process_h, u64 nro_heap_address) {
|
|
||||||
Registration::Process *target_process = GetProcess(index);
|
|
||||||
if (target_process == NULL) {
|
|
||||||
return ResultLoaderProcessNotRegistered;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Registration::MaxNroInfos; i++) {
|
|
||||||
if (target_process->nro_infos[i].in_use && target_process->nro_infos[i].nro_heap_address == nro_heap_address) {
|
|
||||||
NroInfo *info = &target_process->nro_infos[i];
|
|
||||||
Result rc = svcUnmapProcessCodeMemory(process_h, info->base_address + info->text_size + info->ro_size + info->rw_size, info->bss_heap_address, info->bss_heap_size);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
rc = svcUnmapProcessCodeMemory(process_h, info->base_address + info->text_size + info->ro_size, nro_heap_address + info->text_size + info->ro_size, info->rw_size);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
rc = svcUnmapProcessCodeMemory(process_h, info->base_address, nro_heap_address, info->text_size + info->ro_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target_process->nro_infos[i] = {};
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ResultLoaderNotLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Registration::GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u64 process_id, u32 *num_written) {
|
Result Registration::GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u64 process_id, u32 *num_written) {
|
||||||
Registration::Process *target_process = GetProcessByProcessId(process_id);
|
Registration::Process *target_process = GetProcessByProcessId(process_id);
|
||||||
if (target_process == NULL) {
|
if (target_process == NULL) {
|
||||||
|
|
|
@ -24,28 +24,12 @@ class Registration {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t MaxProcesses = 0x40;
|
static constexpr size_t MaxProcesses = 0x40;
|
||||||
static constexpr size_t MaxModuleInfos = 0x20;
|
static constexpr size_t MaxModuleInfos = 0x20;
|
||||||
static constexpr size_t MaxNrrInfos = 0x40;
|
|
||||||
static constexpr size_t MaxNroInfos = 0x40;
|
|
||||||
public:
|
public:
|
||||||
struct ModuleInfoHolder {
|
struct ModuleInfoHolder {
|
||||||
bool in_use;
|
bool in_use;
|
||||||
LoaderModuleInfo info;
|
LoaderModuleInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NroInfo {
|
|
||||||
bool in_use;
|
|
||||||
u64 base_address;
|
|
||||||
u64 total_mapped_size;
|
|
||||||
u64 nro_heap_address;
|
|
||||||
u64 nro_heap_size;
|
|
||||||
u64 bss_heap_address;
|
|
||||||
u64 bss_heap_size;
|
|
||||||
u64 text_size;
|
|
||||||
u64 ro_size;
|
|
||||||
u64 rw_size;
|
|
||||||
unsigned char build_id[0x20];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TidSid {
|
struct TidSid {
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
FsStorageId storage_id;
|
FsStorageId storage_id;
|
||||||
|
@ -59,9 +43,6 @@ class Registration {
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
Registration::TidSid tid_sid;
|
Registration::TidSid tid_sid;
|
||||||
std::array<Registration::ModuleInfoHolder, MaxModuleInfos> module_infos;
|
std::array<Registration::ModuleInfoHolder, MaxModuleInfos> module_infos;
|
||||||
std::array<Registration::NroInfo, MaxNroInfos> nro_infos;
|
|
||||||
std::array<MappedCodeMemory, MaxNrrInfos> nrr_infos;
|
|
||||||
void *owner_ro_service;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct List {
|
struct List {
|
||||||
|
@ -72,19 +53,11 @@ class Registration {
|
||||||
static Registration::Process *GetFreeProcess();
|
static Registration::Process *GetFreeProcess();
|
||||||
static Registration::Process *GetProcess(u64 index);
|
static Registration::Process *GetProcess(u64 index);
|
||||||
static Registration::Process *GetProcessByProcessId(u64 pid);
|
static Registration::Process *GetProcessByProcessId(u64 pid);
|
||||||
static Registration::Process *GetProcessByRoService(void *service);
|
|
||||||
static Result GetRegisteredTidSid(u64 index, Registration::TidSid *out);
|
static Result GetRegisteredTidSid(u64 index, Registration::TidSid *out);
|
||||||
static bool RegisterTidSid(const TidSid *tid_sid, u64 *out_index);
|
static bool RegisterTidSid(const TidSid *tid_sid, u64 *out_index);
|
||||||
static bool UnregisterIndex(u64 index);
|
static bool UnregisterIndex(u64 index);
|
||||||
static void SetProcessIdTidAndIs64BitAddressSpace(u64 index, u64 process_id, u64 tid, bool is_64_bit_addspace);
|
static void SetProcessIdTidAndIs64BitAddressSpace(u64 index, u64 process_id, u64 tid, bool is_64_bit_addspace);
|
||||||
static void AddModuleInfo(u64 index, u64 base_address, u64 size, const unsigned char *build_id);
|
static void AddModuleInfo(u64 index, u64 base_address, u64 size, const unsigned char *build_id);
|
||||||
static void CloseRoService(void *service, Handle process_h);
|
|
||||||
static Result AddNrrInfo(u64 index, MappedCodeMemory *nrr_info);
|
|
||||||
static Result RemoveNrrInfo(u64 index, u64 base_address);
|
|
||||||
static bool IsNroHashPresent(u64 index, u8 *nro_hash);
|
|
||||||
static bool IsNroAlreadyLoaded(u64 index, u8 *build_id);
|
|
||||||
static void AddNroToProcess(u64 index, MappedCodeMemory *nro, MappedCodeMemory *bss, u32 text_size, u32 ro_size, u32 rw_size, u8 *build_id);
|
|
||||||
static Result RemoveNroInfo(u64 index, Handle process_h, u64 base_address);
|
|
||||||
static Result GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u64 process_id, u32 *num_written);
|
static Result GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u64 process_id, u32 *num_written);
|
||||||
|
|
||||||
/* Atmosphere MitM Extension. */
|
/* Atmosphere MitM Extension. */
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
#include "ldr_ro_service.hpp"
|
|
||||||
#include "ldr_registration.hpp"
|
|
||||||
#include "ldr_map.hpp"
|
|
||||||
#include "ldr_nro.hpp"
|
|
||||||
|
|
||||||
Result RelocatableObjectsService::LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
|
|
||||||
Registration::Process *target_proc = NULL;
|
|
||||||
if (!this->has_initialized || this->process_id != pid_desc.pid) {
|
|
||||||
return ResultLoaderInvalidProcess;
|
|
||||||
}
|
|
||||||
if (nro_address & 0xFFF) {
|
|
||||||
return ResultLoaderInvalidAddress;
|
|
||||||
}
|
|
||||||
if (nro_address + nro_size <= nro_address || !nro_size || (nro_size & 0xFFF)) {
|
|
||||||
return ResultLoaderInvalidSize;
|
|
||||||
}
|
|
||||||
if (bss_size && bss_address + bss_size <= bss_address) {
|
|
||||||
return ResultLoaderInvalidSize;
|
|
||||||
}
|
|
||||||
/* Ensure no overflow for combined sizes. */
|
|
||||||
if (U64_MAX - nro_size < bss_size) {
|
|
||||||
return ResultLoaderInvalidSize;
|
|
||||||
}
|
|
||||||
target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
|
|
||||||
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
|
|
||||||
return ResultLoaderInvalidSession;
|
|
||||||
}
|
|
||||||
target_proc->owner_ro_service = this;
|
|
||||||
|
|
||||||
return NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, load_address.GetPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result RelocatableObjectsService::UnloadNro(PidDescriptor pid_desc, u64 nro_address) {
|
|
||||||
Registration::Process *target_proc = NULL;
|
|
||||||
if (!this->has_initialized || this->process_id != pid_desc.pid) {
|
|
||||||
return ResultLoaderInvalidProcess;
|
|
||||||
}
|
|
||||||
if (nro_address & 0xFFF) {
|
|
||||||
return ResultLoaderInvalidAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
|
|
||||||
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
|
|
||||||
return ResultLoaderInvalidSession;
|
|
||||||
}
|
|
||||||
target_proc->owner_ro_service = this;
|
|
||||||
|
|
||||||
return Registration::RemoveNroInfo(target_proc->index, this->process_handle, nro_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result RelocatableObjectsService::LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) {
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
Registration::Process *target_proc = NULL;
|
|
||||||
MappedCodeMemory nrr_info = {};
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
if (R_FAILED(rc) && nrr_info.IsActive()) {
|
|
||||||
nrr_info.Close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!this->has_initialized || this->process_id != pid_desc.pid) {
|
|
||||||
rc = ResultLoaderInvalidProcess;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (nrr_address & 0xFFF) {
|
|
||||||
rc = ResultLoaderInvalidAddress;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (nrr_address + nrr_size <= nrr_address || !nrr_size || (nrr_size & 0xFFF)) {
|
|
||||||
rc = ResultLoaderInvalidSize;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
|
|
||||||
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
|
|
||||||
rc = ResultLoaderInvalidSession;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
target_proc->owner_ro_service = this;
|
|
||||||
|
|
||||||
if (R_FAILED((rc = nrr_info.Open(this->process_handle, target_proc->is_64_bit_addspace, nrr_address, nrr_size)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = nrr_info.Map()))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = NroUtils::ValidateNrrHeader((NroUtils::NrrHeader *)nrr_info.mapped_address, nrr_size, target_proc->title_id);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
Registration::AddNrrInfo(target_proc->index, &nrr_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result RelocatableObjectsService::UnloadNrr(PidDescriptor pid_desc, u64 nrr_address) {
|
|
||||||
Registration::Process *target_proc = NULL;
|
|
||||||
if (!this->has_initialized || this->process_id != pid_desc.pid) {
|
|
||||||
return ResultLoaderInvalidProcess;
|
|
||||||
}
|
|
||||||
if (nrr_address & 0xFFF) {
|
|
||||||
return ResultLoaderInvalidAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_proc = Registration::GetProcessByProcessId(pid_desc.pid);
|
|
||||||
if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) {
|
|
||||||
return ResultLoaderInvalidSession;
|
|
||||||
}
|
|
||||||
target_proc->owner_ro_service = this;
|
|
||||||
|
|
||||||
return Registration::RemoveNrrInfo(target_proc->index, nrr_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result RelocatableObjectsService::Initialize(PidDescriptor pid_desc, CopiedHandle process_h) {
|
|
||||||
u64 handle_pid;
|
|
||||||
if (R_SUCCEEDED(svcGetProcessId(&handle_pid, process_h.handle)) && handle_pid == pid_desc.pid) {
|
|
||||||
if (this->has_initialized) {
|
|
||||||
svcCloseHandle(this->process_handle);
|
|
||||||
}
|
|
||||||
this->process_handle = process_h.handle;
|
|
||||||
this->process_id = handle_pid;
|
|
||||||
this->has_initialized = true;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
return ResultLoaderInvalidProcess;
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <switch.h>
|
|
||||||
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#include "ldr_registration.hpp"
|
|
||||||
|
|
||||||
enum RoServiceCmd {
|
|
||||||
Ro_Cmd_LoadNro = 0,
|
|
||||||
Ro_Cmd_UnloadNro = 1,
|
|
||||||
Ro_Cmd_LoadNrr = 2,
|
|
||||||
Ro_Cmd_UnloadNrr = 3,
|
|
||||||
Ro_Cmd_Initialize = 4,
|
|
||||||
Ro_Cmd_LoadNrrEx = 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
class RelocatableObjectsService final : public IServiceObject {
|
|
||||||
Handle process_handle = 0;
|
|
||||||
u64 process_id = U64_MAX;
|
|
||||||
bool has_initialized = false;
|
|
||||||
public:
|
|
||||||
virtual ~RelocatableObjectsService() override {
|
|
||||||
Registration::CloseRoService(this, this->process_handle);
|
|
||||||
if (this->has_initialized) {
|
|
||||||
svcCloseHandle(this->process_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/* Actual commands. */
|
|
||||||
Result LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
|
|
||||||
Result UnloadNro(PidDescriptor pid_desc, u64 nro_address);
|
|
||||||
Result LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size);
|
|
||||||
Result UnloadNrr(PidDescriptor pid_desc, u64 nrr_address);
|
|
||||||
Result Initialize(PidDescriptor pid_desc, CopiedHandle process_h);
|
|
||||||
Result LoadNrrEx(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size, CopiedHandle process_h);
|
|
||||||
public:
|
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
|
||||||
MakeServiceCommandMeta<Ro_Cmd_LoadNro, &RelocatableObjectsService::LoadNro>(),
|
|
||||||
MakeServiceCommandMeta<Ro_Cmd_UnloadNro, &RelocatableObjectsService::UnloadNro>(),
|
|
||||||
MakeServiceCommandMeta<Ro_Cmd_LoadNrr, &RelocatableObjectsService::LoadNrr>(),
|
|
||||||
MakeServiceCommandMeta<Ro_Cmd_UnloadNrr, &RelocatableObjectsService::UnloadNrr>(),
|
|
||||||
MakeServiceCommandMeta<Ro_Cmd_Initialize, &RelocatableObjectsService::Initialize>(),
|
|
||||||
};
|
|
||||||
};
|
|
Loading…
Reference in a new issue