diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 66fe54fd..0001316e 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -6,5 +6,10 @@ set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp) include_directories(${source_DIR}/include) -add_library(lightswitch SHARED ${source_DIR}/lightswitch.cpp ${source_DIR}/core/arm/cpu.cpp) +add_library(lightswitch SHARED + ${source_DIR}/lightswitch.cpp + ${source_DIR}/core/arm/cpu.cpp + + ${source_DIR}/core/hos/loaders/nro.cpp +) target_link_libraries(lightswitch ${source_DIR}/lib/${ANDROID_ABI}/libunicorn.a) \ No newline at end of file diff --git a/app/src/main/cpp/core/hos/loaders/nro.cpp b/app/src/main/cpp/core/hos/loaders/nro.cpp new file mode 100644 index 00000000..7fd0fdc6 --- /dev/null +++ b/app/src/main/cpp/core/hos/loaders/nro.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include "nro.h" + +// TODO: Move memory to it's own file +#define MEM_BASE 0x80000000 + +void ReadDataFromFile(std::string file, char* output, uint32_t offset, size_t size) +{ + std::ifstream f(file, std::ios::binary | std::ios::beg); + + f.seekg(offset); + f.read(output, size); + + f.close(); +} + +namespace loader { + bool LoadNro(std::string file) { + syslog(LOG_INFO, "Loading NRO file %s\n", file.c_str()); + + NroHeader h; + ReadDataFromFile(file, reinterpret_cast(&h), 0x0, sizeof(NroHeader)); + if (h.magic != 0x304F524E) { + syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", h.magic); + return false; + } + + std::vector text, ro, data; + text.resize(h.segments[0].size); + ro.resize(h.segments[1].size); + data.resize(h.segments[2].size); + + ReadDataFromFile(file, reinterpret_cast(text.data()), + h.segments[0].fileOffset, h.segments[0].size); + ReadDataFromFile(file, reinterpret_cast(ro.data()), + h.segments[1].fileOffset, h.segments[1].size); + ReadDataFromFile(file, reinterpret_cast(data.data()), + h.segments[2].fileOffset, h.segments[2].size); + + + if(!mmap((void*)(MEM_BASE), + h.segments[0].size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) || + !mmap((void*)(MEM_BASE + h.segments[0].size), + h.segments[1].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) || + !mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size), + h.segments[2].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) || + !mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size), + h.bssSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0)) { + + syslog(LOG_ERR, "Failed mapping regions for executable"); + return false; + } + + std::memcpy((void*)(MEM_BASE), text.data(), text.size()); + std::memcpy((void*)(MEM_BASE + h.segments[0].size), ro.data(), ro.size()); + std::memcpy((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size), data.data(), data.size()); + + return true; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/core/hos/loaders/nro.h b/app/src/main/cpp/core/hos/loaders/nro.h new file mode 100644 index 00000000..8e016da6 --- /dev/null +++ b/app/src/main/cpp/core/hos/loaders/nro.h @@ -0,0 +1,31 @@ +#pragma once +#include + +namespace loader { + struct NroSegmentHeader { + uint32_t fileOffset; + uint32_t size; + }; + + struct NroHeader { + uint32_t unused; + uint32_t modOffset; + uint64_t padding; + + uint32_t magic; + uint32_t version; + uint32_t size; + uint32_t flags; + + NroSegmentHeader segments[3]; + + uint32_t bssSize; + uint32_t reserved0; + uint64_t buildId[4]; + uint64_t reserved1; + + NroSegmentHeader extraSegments[3]; + }; + + bool LoadNro(std::string file); +} \ No newline at end of file