ro: start implementing 23.0.0 changes

This commit is contained in:
hexkyz
2026-09-20 23:23:56 +01:00
parent f62bc71ea4
commit 0411dbfdda
7 changed files with 280 additions and 78 deletions

View File

@@ -19,12 +19,12 @@
#include <stratosphere/ro/ro_types.hpp>
#include <stratosphere/sf.hpp>
#define AMS_RO_I_RO_INTERFACE_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, MapManualLoadModuleMemory, (sf::Out<u64> out_load_address, const sf::ClientProcessId &client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size), (out_load_address, client_pid, nro_address, nro_size, bss_address, bss_size)) \
AMS_SF_METHOD_INFO(C, H, 1, Result, UnmapManualLoadModuleMemory, (const sf::ClientProcessId &client_pid, u64 nro_address), (client_pid, nro_address)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, RegisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size), (client_pid, nrr_address, nrr_size)) \
AMS_SF_METHOD_INFO(C, H, 3, Result, UnregisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address), (client_pid, nrr_address)) \
AMS_SF_METHOD_INFO(C, H, 4, Result, RegisterProcessHandle, (const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h), (client_pid, std::move(process_h))) \
AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterProcessModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h), (client_pid, nrr_address, nrr_size, std::move(process_h)), hos::Version_7_0_0)
#define AMS_RO_I_RO_INTERFACE_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, MapManualLoadModuleMemory, (sf::Out<u64> out_load_address, const sf::ClientProcessId &client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size), (out_load_address, client_pid, nro_address, nro_size, bss_address, bss_size)) \
AMS_SF_METHOD_INFO(C, H, 1, Result, UnmapManualLoadModuleMemory, (const sf::ClientProcessId &client_pid, u64 nro_address), (client_pid, nro_address)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, RegisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size), (client_pid, nrr_address, nrr_size)) \
AMS_SF_METHOD_INFO(C, H, 3, Result, UnregisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address), (client_pid, nrr_address)) \
AMS_SF_METHOD_INFO(C, H, 4, Result, RegisterProcessHandle, (const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h), (client_pid, std::move(process_h))) \
AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterModuleInfoWithUserProcessHandle, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h), (client_pid, nrr_address, nrr_size, std::move(process_h)), hos::Version_7_0_0)
AMS_SF_DEFINE_INTERFACE(ams::ro::impl, IRoInterface, AMS_RO_I_RO_INTERFACE_INTERFACE_INFO, 0xA52C55A9)

View File

@@ -17,6 +17,7 @@
#pragma once
#include <vapours.hpp>
#include <stratosphere/ncm/ncm_ids.hpp>
#include <stratosphere/rocrt/rocrt.hpp>
namespace ams::ro {
@@ -40,30 +41,30 @@ namespace ams::ro {
u64 program_id_mask;
u64 program_id_pattern;
u8 reserved_10[0x10];
u8 modulus[RsaKeySize];
u8 signature[RsaKeySize];
u8 public_key[RsaKeySize];
u8 sign[RsaKeySize];
};
static_assert(sizeof(NrrCertification) == NrrCertification::RsaKeySize + NrrCertification::SignedSize);
class NrrHeader {
public:
static constexpr u32 Magic = util::FourCC<'N','R','R','0'>::Code;
static constexpr u32 Signature = util::FourCC<'N','R','R','0'>::Code;
private:
u32 m_magic;
u32 m_signature;
u32 m_key_generation;
u8 m_reserved_08[0x08];
NrrCertification m_certification;
u8 m_signature[0x100];
u8 m_sign[0x100];
ncm::ProgramId m_program_id;
u32 m_size;
u8 m_nrr_kind; /* 7.0.0+ */
u8 m_reserved_33D[3];
u32 m_hashes_offset;
u32 m_num_hashes;
u32 m_hash_list_offset_address;
u32 m_num_hash;
u8 m_reserved_348[8];
public:
bool IsMagicValid() const {
return m_magic == Magic;
return m_signature == Signature;
}
bool IsProgramIdValid() const {
@@ -85,11 +86,11 @@ namespace ams::ro {
}
u32 GetNumHashes() const {
return m_num_hashes;
return m_num_hash;
}
size_t GetHashesOffset() const {
return m_hashes_offset;
return m_hash_list_offset_address;
}
uintptr_t GetHashes() const {
@@ -101,7 +102,7 @@ namespace ams::ro {
}
const u8 *GetCertificationSignature() const {
return m_certification.signature;
return m_certification.sign;
}
const u8 *GetCertificationSignedArea() const {
@@ -109,11 +110,11 @@ namespace ams::ro {
}
const u8 *GetCertificationModulus() const {
return m_certification.modulus;
return m_certification.public_key;
}
const u8 *GetSignature() const {
return m_signature;
return m_sign;
}
const u8 *GetSignedArea() const {
@@ -131,32 +132,45 @@ namespace ams::ro {
constexpr size_t NrrHeader::GetSignedAreaOffset() {
return AMS_OFFSETOF(NrrHeader, m_program_id);
}
static constexpr size_t RocrtHeaderSize = 0x10;
struct RocrtHeader {
rocrt::ModuleHeaderLocation module_header_location;
u32 reserved;
};
static_assert(sizeof(RocrtHeader) == RocrtHeaderSize);
class NroHeader {
public:
static constexpr u32 Magic = util::FourCC<'N','R','O','0'>::Code;
static constexpr u32 Signature = util::FourCC<'N','R','O','0'>::Code;
static constexpr u32 FlagAlignedHeader = 1;
static constexpr u32 FlagCompress = 2;
private:
u32 m_entrypoint_insn;
u32 m_mod_offset;
u8 m_reserved_08[0x8];
u32 m_magic;
u8 m_version;
RocrtHeader m_rocrt;
u32 m_signature;
u32 m_version;
u32 m_size;
u32 m_flags;
u32 m_text_offset;
u32 m_text_memory_offset;
u32 m_text_size;
u32 m_ro_offset;
u32 m_ro_memory_offset;
u32 m_ro_size;
u32 m_rw_offset;
u32 m_rw_size;
u32 m_data_memory_offset;
u32 m_data_size;
u32 m_bss_size;
u8 m_reserved_3C[0x4];
u32 m_additional_header_offset; /* 23.0.0+ */
ModuleId m_module_id;
u8 m_reserved_60[0x20];
u32 m_dso_handle_offset;
u32 m_reserved_64;
u32 m_embedded_offset;
u32 m_embedded_size;
u32 m_dyn_str_offset;
u32 m_dyn_str_size;
u32 m_dyn_sym_offset;
u32 m_dyn_sym_size;
public:
bool IsMagicValid() const {
return m_magic == Magic;
return m_signature == Signature;
}
u32 GetVersion() const {
@@ -174,9 +188,13 @@ namespace ams::ro {
bool IsAlignedHeader() const {
return m_flags & FlagAlignedHeader;
}
bool IsCompress() const {
return m_flags & FlagCompress;
}
u32 GetTextOffset() const {
return m_text_offset;
return m_text_memory_offset;
}
u32 GetTextSize() const {
@@ -184,7 +202,7 @@ namespace ams::ro {
}
u32 GetRoOffset() const {
return m_ro_offset;
return m_ro_memory_offset;
}
u32 GetRoSize() const {
@@ -192,21 +210,60 @@ namespace ams::ro {
}
u32 GetRwOffset() const {
return m_rw_offset;
return m_data_memory_offset;
}
u32 GetRwSize() const {
return m_rw_size;
return m_data_size;
}
u32 GetBssSize() const {
return m_bss_size;
}
u32 GetAdditionalHeaderOffset() const {
return m_additional_header_offset;
}
const ModuleId *GetModuleId() const {
return std::addressof(m_module_id);
}
};
static_assert(sizeof(NroHeader) == 0x80, "NroHeader definition!");
class AdditionalNroHeader {
public:
static constexpr u32 Signature = util::FourCC<'N','R','A','0'>::Code;
private:
u32 m_signature;
u8 m_reserved_04[0xC];
u32 m_compressed_size;
u32 m_reserved_14;
u32 m_hash_size;
u32 m_hash_offset;
u8 m_reserved_20[0x40];
u8 m_hash[0x20];
public:
bool IsMagicValid() const {
return m_signature == Signature;
}
u32 GetCompressedSize() const {
return m_compressed_size;
}
u32 GetHashSize() const {
return m_hash_size;
}
u32 GetHashOffset() const {
return m_hash_offset;
}
const u8 *GetHash() const {
return m_hash;
}
};
static_assert(sizeof(AdditionalNroHeader) == 0x80, "AdditionalNroHeader definition!");
}

View File

@@ -29,11 +29,18 @@ namespace ams::rocrt {
u32 exception_info_start_offset;
u32 exception_info_end_offset;
u32 module_offset;
u32 relro_start_offset; /* 19.0.0+ */
u32 full_relro_end_offset; /* 19.0.0+ */
u32 nx_debug_link_start_offset; /* 19.0.0+ */
u32 nx_debug_link_end_offset; /* 19.0.0+ */
u32 note_gnu_build_id_start_offset; /* 19.0.0+ */
u32 note_gnu_build_id_end_offset; /* 19.0.0+ */
};
struct ModuleHeaderLocation {
u32 pad;
u32 version;
u32 header_offset;
u32 version_offset;
};
constexpr inline u32 CheckModuleHeaderSignature(const ModuleHeader *header) {

View File

@@ -25,18 +25,20 @@ namespace ams::ro {
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 2);
R_DEFINE_ERROR_RESULT(AlreadyLoaded, 3);
R_DEFINE_ERROR_RESULT(InvalidNro, 4);
R_DEFINE_ERROR_RESULT(NotFound, 5);
R_DEFINE_ERROR_RESULT(InvalidNrr, 6);
R_DEFINE_ERROR_RESULT(TooManyNro, 7);
R_DEFINE_ERROR_RESULT(TooManyNrr, 8);
R_DEFINE_ERROR_RESULT(NotAuthorized, 9);
R_DEFINE_ERROR_RESULT(InvalidNrrKind, 10);
R_DEFINE_ERROR_RESULT(InvalidBssSize, 11);
R_DEFINE_ERROR_RESULT(NotImplemented, 1022);
R_DEFINE_ERROR_RESULT(InternalError, 1023);
R_DEFINE_ERROR_RESULT(InvalidAddress, 1025);
R_DEFINE_ERROR_RESULT(InvalidSize, 1026);
R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 1027);
R_DEFINE_ERROR_RESULT(NotLoaded, 1028);
R_DEFINE_ERROR_RESULT(NotRegistered, 1029);
R_DEFINE_ERROR_RESULT(InvalidSession, 1030);

View File

@@ -47,7 +47,7 @@ namespace ams::ro::impl {
}
};
static_assert(sizeof(Sha256Hash) == sizeof(Sha256Hash::hash));
struct NroInfo {
u64 base_address;
u64 nro_heap_address;
@@ -55,8 +55,10 @@ namespace ams::ro::impl {
u64 bss_heap_address;
u64 bss_heap_size;
u64 code_size;
u64 ro_size; /* 23.0.0+ */
u64 rw_size;
ModuleId module_id;
bool is_compress; /* 23.0.0+ */
};
struct NrrInfo {
@@ -72,7 +74,17 @@ namespace ams::ro::impl {
u8 cached_signed_area[sizeof(NrrHeader) - NrrHeader::GetSignedAreaOffset()];
Sha256Hash signed_area_hash;
};
struct AdditionalNroHeaderInfo {
u32 signature;
u8 reserved_04[0xC];
u32 compressed_size;
u32 reserved_14;
u32 hash_size;
u32 hash_offset;
u8 reserved_20[0x40];
};
struct ProcessContext {
private:
bool m_nro_in_use[MaxNroInfos]{};
@@ -246,21 +258,12 @@ namespace ams::ro::impl {
R_THROW(ro::ResultNotAuthorized());
}
Result ValidateNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, bool *out_aligned_header, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
/* Map the NRO. */
void *mapped_memory = nullptr;
R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size, ro::impl::GenerateSecureRandom)) {
R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH;
/* When we're done, unmap the memory. */
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, m_process_handle, base_address, expected_nro_size); };
Result ValidateNro(NroHeader **out_header, AdditionalNroHeaderInfo **out_additional_header_info, void *out_additional_header_hash, u8 *mapped_memory, u64 expected_nro_size, u64 expected_bss_size) {
/* Validate header. */
const NroHeader *header = static_cast<const NroHeader *>(mapped_memory);
NroHeader *header = reinterpret_cast<NroHeader *>(mapped_memory);
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNro());
/* Read sizes from header. */
const u64 nro_size = header->GetSize();
const u64 text_ofs = header->GetTextOffset();
@@ -270,17 +273,28 @@ namespace ams::ro::impl {
const u64 rw_ofs = header->GetRwOffset();
const u64 rw_size = header->GetRwSize();
const u64 bss_size = header->GetBssSize();
/* Validate sizes meet expected. */
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
/* Validate all sizes are aligned. */
R_UNLESS(util::IsAligned(text_size, os::MemoryPageSize), ro::ResultInvalidNro());
R_UNLESS(util::IsAligned(ro_size, os::MemoryPageSize), ro::ResultInvalidNro());
R_UNLESS(util::IsAligned(rw_size, os::MemoryPageSize), ro::ResultInvalidNro());
R_UNLESS(util::IsAligned(bss_size, os::MemoryPageSize), ro::ResultInvalidNro());
/* Validate sizes meet expected. */
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
/* Account for compression when checking bss size. */
if (header->IsCompress()) {
R_UNLESS((bss_size - expected_nro_size + (rw_ofs + rw_size)) == expected_bss_size, ro::ResultInvalidBssSize());
} else {
/* 23.0.0+ uses the new error code here too. */
if (hos::GetVersion() >= hos::Version_23_0_0) {
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidBssSize());
} else {
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
}
}
/* Validate sections are in order. */
R_UNLESS(text_ofs <= ro_ofs, ro::ResultInvalidNro());
R_UNLESS(ro_ofs <= rw_ofs, ro::ResultInvalidNro());
@@ -289,24 +303,119 @@ namespace ams::ro::impl {
R_UNLESS(text_ofs == 0, ro::ResultInvalidNro());
R_UNLESS(text_ofs + text_size == ro_ofs, ro::ResultInvalidNro());
R_UNLESS(ro_ofs + ro_size == rw_ofs, ro::ResultInvalidNro());
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
/* Only check data section if not using compression. */
if (!header->IsCompress()) {
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
}
/* Verify NRO hash. */
R_TRY(this->ValidateHasNroHash(header));
/* Check if NRO has already been loaded. */
const ModuleId *module_id = header->GetModuleId();
R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), ro::ResultAlreadyLoaded());
/* Validate compression related fields. */
if (header->IsCompress()) {
const u64 additional_header_offset = header->GetAdditionalHeaderOffset();
/* Compression must have aligned header as well. */
R_UNLESS(header->IsAlignedHeader(), ro::ResultInvalidNro());
/* Validate additional header offset. */
R_UNLESS(additional_header_offset == 0x80, ro::ResultInvalidNro());
/* Validate additional header. */
AdditionalNroHeader *additional_header = reinterpret_cast<AdditionalNroHeader *>(mapped_memory + additional_header_offset);
R_UNLESS(additional_header->IsMagicValid(), ro::ResultInvalidNro());
/* Read sizes from header. */
const u64 hash_size = additional_header->GetHashSize();
const u64 hash_offset = additional_header->GetHashOffset();
const u64 compressed_size = additional_header->GetCompressedSize();
/* Validate additional header hash size and offset. */
R_UNLESS(hash_size == 0x20, ro::ResultInvalidNro());
R_UNLESS(hash_offset == 0xE0, ro::ResultInvalidNro());
/* Copy the additional header hash to output. */
std::memcpy(out_additional_header_hash, additional_header->GetHash(), hash_size);
/* Validate compressed size. */
R_UNLESS(rw_ofs + rw_size > nro_size, ro::ResultInvalidNro());
R_UNLESS(compressed_size >= 0x1000, ro::ResultInvalidNro());
R_UNLESS(util::AlignUp(compressed_size, os::MemoryPageSize) == expected_nro_size, ro::ResultInvalidNro());
/* Copy the additional header info to output. This is AdditionalNroHeader minus the hash. */
std::memcpy(out_additional_header_info, additional_header, sizeof(*additional_header) - hash_size);
} else {
/* Explicitly clear additional header hash and info. */
std::memset(out_additional_header_hash, 0, crypto::Sha256Generator::HashSize);
std::memset(out_additional_header_info, 0, sizeof(AdditionalNroHeaderInfo));
}
/* Copy the header to output. */
*out_header = header;
R_SUCCEED();
}
Result DecompressNro(u8 *mapped_nro, u64 expected_nro_size, const NroHeader *nro_header, u32 compressed_size) {
/* TODO */
AMS_UNUSED(mapped_nro, expected_nro_size, nro_header, compressed_size);
R_SUCCEED();
}
Result CheckAdditionalHeaderHash(const u8 *mapped_nro, const void *additional_nro_header_hash, size_t additional_nro_header_hash_size, u64 rw_ofs, u64 rw_size) {
/* Calculate hash. */
Sha256Hash nro_rw_hash;
crypto::GenerateSha256(std::addressof(nro_rw_hash), additional_nro_header_hash_size, mapped_nro + 0x1000, (rw_ofs + rw_size) - 0x1000);
/* Compare the hashes. */
const Sha256Hash *expected_hash = reinterpret_cast<const Sha256Hash *>(additional_nro_header_hash);
if (*expected_hash != nro_rw_hash) {
R_THROW(ro::ResultInvalidNro());
}
R_SUCCEED();
}
Result ParseNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, bool *out_aligned_header, bool *out_is_compress, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
/* Map the NRO. */
void *mapped_memory = nullptr;
R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size, ro::impl::GenerateSecureRandom)) {
R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH;
/* When we're done, unmap the memory. */
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, m_process_handle, base_address, expected_nro_size); };
/* ValidateNro */
NroHeader *nro_header = nullptr;
AdditionalNroHeaderInfo *additional_nro_header_info = nullptr;
u8 additional_nro_header_hash[crypto::Sha256Generator::HashSize];
R_TRY(this->ValidateNro(std::addressof(nro_header), std::addressof(additional_nro_header_info), std::addressof(additional_nro_header_hash), static_cast<u8 *>(mapped_memory), expected_nro_size, expected_bss_size));
/* DecompressNro */
if (nro_header->IsCompress()) {
R_TRY(this->DecompressNro(static_cast<u8 *>(mapped_memory), expected_nro_size, nro_header, additional_nro_header_info->compressed_size));
/* CheckAdditionalHeaderHash */
if (nro_header->GetAdditionalHeaderOffset() != 0) {
R_TRY(this->CheckAdditionalHeaderHash(static_cast<u8 *>(mapped_memory), std::addressof(additional_nro_header_hash), sizeof(additional_nro_header_hash), nro_header->GetRwOffset(), nro_header->GetRwSize()));
}
}
/* Apply patches to NRO. */
LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8 *>(mapped_memory), nro_size);
const ModuleId *module_id = nro_header->GetModuleId();
LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8 *>(mapped_memory), nro_header->GetSize());
/* Copy to output. */
*out_module_id = *module_id;
*out_rx_size = text_size;
*out_ro_size = ro_size;
*out_rw_size = rw_size;
*out_aligned_header = header->IsAlignedHeader();
*out_rx_size = nro_header->GetTextSize();
*out_ro_size = nro_header->GetRoSize();
*out_rw_size = nro_header->GetRwSize();
*out_aligned_header = nro_header->IsAlignedHeader();
*out_is_compress = nro_header->IsCompress();
R_SUCCEED();
}
@@ -547,26 +656,34 @@ namespace ams::ro::impl {
/* Check we have space for a new NRO. */
NroInfo *nro_info = nullptr;
R_TRY(context->GetFreeNroInfo(std::addressof(nro_info)));
nro_info->nro_heap_address = nro_address;
nro_info->nro_heap_size = nro_size;
nro_info->bss_heap_address = bss_address;
nro_info->bss_heap_size = bss_size;
/* Map the NRO. */
R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcessHandle(), nro_address, nro_size, bss_address, bss_size));
ON_RESULT_FAILURE { UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size); };
/* Validate the NRO (parsing region extents). */
/* Parse the NRO. */
u64 rx_size = 0, ro_size = 0, rw_size = 0;
bool aligned_header = false;
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), std::addressof(aligned_header), nro_info->base_address, nro_size, bss_size));
bool is_compress = false;
R_TRY(context->ParseNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), std::addressof(aligned_header), std::addressof(is_compress), nro_info->base_address, nro_size, bss_size));
/* Set NRO perms. */
R_TRY(SetNroPerms(context->GetProcessHandle(), nro_info->base_address, rx_size, ro_size, rw_size + bss_size, aligned_header));
context->SetNroInfoInUse(nro_info, true);
nro_info->code_size = rx_size + ro_size;
nro_info->nro_heap_address = nro_address;
nro_info->nro_heap_size = nro_size;
nro_info->bss_heap_address = bss_address;
nro_info->bss_heap_size = bss_size;
if (hos::GetVersion() >= hos::Version_23_0_0) {
nro_info->code_size = rx_size;
nro_info->ro_size = ro_size;
} else {
nro_info->code_size = rx_size + ro_size;
nro_info->ro_size = 0;
}
nro_info->rw_size = rw_size;
nro_info->is_compress = is_compress;
*out_address = nro_info->base_address;
R_SUCCEED();
}
@@ -582,6 +699,25 @@ namespace ams::ro::impl {
/* Check the NRO is loaded. */
NroInfo *nro_info = nullptr;
R_TRY(context->GetNroInfoByAddress(std::addressof(nro_info), nro_address));
/* Handle compression related mappings. */
if (nro_info->is_compress) {
const u64 code_address = nro_info->base_address + 0x1000;
const u64 code_size = nro_info->code_size - 0x1000;
/* Remove code region permissions. */
R_TRY(os::SetProcessMemoryPermission(context->GetProcessHandle(), code_address, code_size, os::MemoryPermission_None));
/* Map the code region. */
void *mapped_memory = nullptr;
R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), context->GetProcessHandle(), code_address, code_size, ro::impl::GenerateSecureRandom));
/* Clear the memory. */
std::memset(mapped_memory, 0, code_size);
/* Unmap the code region. */
os::UnmapProcessMemory(mapped_memory, context->GetProcessHandle(), code_address, code_size);
}
/* Unmap. */
const NroInfo nro_backup = *nro_info;

View File

@@ -60,7 +60,7 @@ namespace ams::ro {
R_RETURN(impl::RegisterProcess(std::addressof(m_context_id), std::move(process_h), client_pid.GetValue()));
}
Result RoService::RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h) {
Result RoService::RegisterModuleInfoWithUserProcessHandle(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h) {
/* Validate the process. */
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));

View File

@@ -38,7 +38,7 @@ namespace ams::ro {
Result RegisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size);
Result UnregisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address);
Result RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h);
Result RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h);
Result RegisterModuleInfoWithUserProcessHandle(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h);
};
static_assert(ro::impl::IsIRoInterface<RoService>);