From e443b625ec8a569e30b2d045812128a6386c951d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 24 Apr 2018 06:52:13 -0600 Subject: [PATCH] Loader: Finish Loader::CreateProcess(). --- stratosphere/loader/source/ldr_nso.cpp | 41 +++++++++++++++++++++++--- stratosphere/loader/source/ldr_nso.hpp | 2 +- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/stratosphere/loader/source/ldr_nso.cpp b/stratosphere/loader/source/ldr_nso.cpp index 9472f3835..7e9ab7bef 100644 --- a/stratosphere/loader/source/ldr_nso.cpp +++ b/stratosphere/loader/source/ldr_nso.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include "lz4.h" #include "ldr_nso.hpp" #include "ldr_map.hpp" #include "ldr_random.hpp" @@ -180,9 +183,39 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo } -Result NsoUtils::LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base) { - /* TODO */ - return 0xA09; +Result NsoUtils::LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end) { + bool is_compressed = ((g_nso_headers[index].flags >> segment) & 1) != 0; + bool check_hash = ((g_nso_headers[index].flags >> (segment + 3)) & 1) != 0; + size_t out_size = g_nso_headers[index].segments[segment].decomp_size; + size_t size = is_compressed ? g_nso_headers[index].compressed_sizes[segment] : out_size; + if (size > out_size) { + return 0xA09; + } + if ((u32)(size | out_size) >> 31) { + return 0xA09; + } + + u8 *dst_addr = map_base + g_nso_headers[index].segments[segment].dst_offset; + u8 *load_addr = is_compressed ? map_end - size : dst_addr; + if (fread(load_addr, 1, size, f_nso) != size) { + return 0xA09; + } + + if (is_compressed) { + if (LZ4_decompress_safe((char *)load_addr, (char *)dst_addr, size, out_size) != (int)out_size) { + return 0xA09; + } + } + + if (check_hash) { + u8 hash[0x20] = {0}; + picosha2::hash256(dst_addr, dst_addr + out_size, hash, hash + sizeof(hash)); + if (std::memcmp(g_nso_headers[index].section_hashes[segment], hash, sizeof(hash))) { + return 0xA09; + } + } + + return 0x0; } Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size) { @@ -206,7 +239,7 @@ Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLo return 0xA09; } for (unsigned int seg = 0; seg < 3; seg++) { - if (R_FAILED((rc = LoadNsoSegment(i, seg, f_nso, map_base)))) { + if (R_FAILED((rc = LoadNsoSegment(i, seg, f_nso, map_base, map_base + extents->nso_sizes[i])))) { fclose(f_nso); svcUnmapProcessMemory(map_base, process_h, extents->nso_addresses[i], extents->nso_sizes[i]); return rc; diff --git a/stratosphere/loader/source/ldr_nso.hpp b/stratosphere/loader/source/ldr_nso.hpp index 2a2d8caf8..79fd7a1a3 100644 --- a/stratosphere/loader/source/ldr_nso.hpp +++ b/stratosphere/loader/source/ldr_nso.hpp @@ -91,6 +91,6 @@ class NsoUtils { static Result ValidateNsoLoadSet(); static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents); - static Result LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base); + static Result LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end); static Result LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size); }; \ No newline at end of file