From 269765a3bc6374663a7af8ea84ffe7e392aa6cca Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 24 Jun 2019 11:20:27 -0700 Subject: [PATCH] StratosphereRandomUtils --> sts::rnd --- Makefile | 2 +- include/stratosphere.hpp | 2 +- include/stratosphere/rnd.hpp | 20 +++ .../{random.hpp => rnd/rnd_api.hpp} | 15 +- source/map/map_api.cpp | 4 +- source/random.cpp | 86 ------------ source/rnd/rnd_api.cpp | 132 ++++++++++++++++++ 7 files changed, 163 insertions(+), 98 deletions(-) create mode 100644 include/stratosphere/rnd.hpp rename include/stratosphere/{random.hpp => rnd/rnd_api.hpp} (72%) delete mode 100644 source/random.cpp create mode 100644 source/rnd/rnd_api.cpp diff --git a/Makefile b/Makefile index 6bf7befb..d5eacb64 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules # INCLUDES is a list of directories containing header files #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) -SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map +SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map source/rnd DATA := data INCLUDES := include diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp index 688d452d..fd478c37 100644 --- a/include/stratosphere.hpp +++ b/include/stratosphere.hpp @@ -45,4 +45,4 @@ #include "stratosphere/on_crash.hpp" -#include "stratosphere/random.hpp" \ No newline at end of file +#include "stratosphere/rnd.hpp" \ No newline at end of file diff --git a/include/stratosphere/rnd.hpp b/include/stratosphere/rnd.hpp new file mode 100644 index 00000000..7315f6b9 --- /dev/null +++ b/include/stratosphere/rnd.hpp @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +#pragma once +#include + +#include "rnd/rnd_api.hpp" diff --git a/include/stratosphere/random.hpp b/include/stratosphere/rnd/rnd_api.hpp similarity index 72% rename from include/stratosphere/random.hpp rename to include/stratosphere/rnd/rnd_api.hpp index 877f97c4..d7d22789 100644 --- a/include/stratosphere/random.hpp +++ b/include/stratosphere/rnd/rnd_api.hpp @@ -17,12 +17,11 @@ #pragma once #include -class StratosphereRandomUtils { - public: - static u32 GetRandomU32(u32 max); - static u64 GetRandomU64(u64 max); - static void GetRandomBytes(void* out, size_t size); +namespace sts::rnd { - template - static T GetRandom(T max); -}; \ No newline at end of file + /* Random utilities. */ + void GenerateRandomBytes(void* out, size_t size); + u32 GenerateRandomU32(u32 max = std::numeric_limits::max()); + u64 GenerateRandomU64(u64 max = std::numeric_limits::max()); + +} diff --git a/source/map/map_api.cpp b/source/map/map_api.cpp index 0281f940..60fdccd0 100644 --- a/source/map/map_api.cpp +++ b/source/map/map_api.cpp @@ -116,7 +116,7 @@ namespace sts::map { uintptr_t try_address; for (unsigned int i = 0; i < LocateRetryCount; i++) { - try_address = address_space.aslr_base + (StratosphereRandomUtils::GetRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12); + try_address = address_space.aslr_base + (rnd::GenerateRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12); MappedCodeMemory tmp_mcm(process_handle, try_address, base_address, size); R_TRY_CATCH(tmp_mcm.GetResult()) { @@ -148,7 +148,7 @@ namespace sts::map { uintptr_t try_address; for (unsigned int i = 0; i < LocateRetryCount; i++) { while (true) { - try_address = address_space.aslr_base + (StratosphereRandomUtils::GetRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12); + try_address = address_space.aslr_base + (rnd::GenerateRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12); if (address_space.heap_size && (address_space.heap_base <= try_address + size - 1 && try_address <= address_space.heap_end - 1)) { continue; } diff --git a/source/random.cpp b/source/random.cpp deleted file mode 100644 index 0d442c15..00000000 --- a/source/random.cpp +++ /dev/null @@ -1,86 +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 . - */ - -#include -#include -#include - -/* Official HOS uses TinyMT. This is high effort. Let's just use XorShift. */ -/* https://en.wikipedia.org/wiki/Xorshift */ -class XorShiftGenerator { - public: - using result_type = uint32_t; - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return UINT32_MAX; } - static constexpr size_t num_seed_dwords = 4; - private: - result_type random_state[num_seed_dwords]; - public: - - explicit XorShiftGenerator() { - /* Seed using process entropy. */ - u64 val = 0; - for (size_t i = 0; i < num_seed_dwords; i++) { - R_ASSERT(svcGetInfo(&val, 0xB, 0, i)); - this->random_state[i] = result_type(val); - } - } - - explicit XorShiftGenerator(std::random_device &rd) { - for (size_t i = 0; i < num_seed_dwords; i++) { - this->random_state[i] = result_type(rd()); - } - } - - result_type operator()() { - result_type s, t = this->random_state[3]; - t ^= t << 11; - t ^= t >> 8; - this->random_state[3] = this->random_state[2]; this->random_state[2] = this->random_state[1]; this->random_state[1] = (s = this->random_state[0]); - t ^= s; - t ^= s >> 19; - this->random_state[0] = t; - return t; - } - - void discard(size_t n) { - for (size_t i = 0; i < n; i++) { - operator()(); - } - } -}; - -static XorShiftGenerator g_rnd_generator; - -template -T StratosphereRandomUtils::GetRandom(T max) { - std::uniform_int_distribution rnd(0, max); - return rnd(g_rnd_generator); -} - -/* These are slightly biased, but I think that's totally okay. */ -u32 StratosphereRandomUtils::GetRandomU32(u32 max) { - return GetRandom(max); -} - -u64 StratosphereRandomUtils::GetRandomU64(u64 max) { - return GetRandom(max); -} - -void StratosphereRandomUtils::GetRandomBytes(void* out, size_t size) { - std::generate(reinterpret_cast(out), reinterpret_cast(out) + size, std::bind(GetRandom, 0xFF)); -} - diff --git a/source/rnd/rnd_api.cpp b/source/rnd/rnd_api.cpp new file mode 100644 index 00000000..c9c83bb8 --- /dev/null +++ b/source/rnd/rnd_api.cpp @@ -0,0 +1,132 @@ +/* + * 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 . + */ + +#include +#include +#include +#include + +namespace sts::rnd { + + namespace { + + /* Generator type. */ + /* Official HOS uses TinyMT. This is high effort. Let's just use XorShift. */ + /* https://en.wikipedia.org/wiki/Xorshift */ + class XorShiftGenerator { + public: + using ResultType = uint32_t; + using result_type = ResultType; + static constexpr ResultType (min)() { return std::numeric_limits::min(); } + static constexpr ResultType (max)() { return std::numeric_limits::max(); } + static constexpr size_t SeedSize = 4; + private: + ResultType random_state[SeedSize]; + public: + + explicit XorShiftGenerator() { + /* Seed using process entropy. */ + u64 val = 0; + for (size_t i = 0; i < SeedSize; i++) { + R_ASSERT(svcGetInfo(&val, InfoType_RandomEntropy, INVALID_HANDLE, i)); + this->random_state[i] = ResultType(val); + } + } + + explicit XorShiftGenerator(std::random_device &rd) { + for (size_t i = 0; i < SeedSize; i++) { + this->random_state[i] = ResultType(rd()); + } + } + + ResultType operator()() { + ResultType s, t = this->random_state[3]; + t ^= t << 11; + t ^= t >> 8; + this->random_state[3] = this->random_state[2]; this->random_state[2] = this->random_state[1]; this->random_state[1] = (s = this->random_state[0]); + t ^= s; + t ^= s >> 19; + this->random_state[0] = t; + return t; + } + + void discard(size_t n) { + for (size_t i = 0; i < n; i++) { + operator()(); + } + } + }; + + /* Generator global. */ + XorShiftGenerator g_rnd_generator; + + /* Templated helpers. */ + template + T GenerateRandom(T max = std::numeric_limits::max()) { + std::uniform_int_distribution rnd(std::numeric_limits::min(), max); + return rnd(g_rnd_generator); + } + + } + + void GenerateRandomBytes(void* _out, size_t size) { + uintptr_t out = reinterpret_cast(_out); + uintptr_t end = out + size; + + /* Force alignment. */ + if (out % sizeof(u16) && out < end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u8); + } + if (out % sizeof(u32) && out < end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u16); + } + if (out % sizeof(u64) && out < end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u32); + } + + /* Perform as many aligned writes as possible. */ + while (out + sizeof(u64) <= end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u64); + } + + /* Do remainder writes. */ + if (out + sizeof(u32) <= end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u32); + } + if (out + sizeof(u16) <= end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u16); + } + if (out + sizeof(u8) <= end) { + *reinterpret_cast(out) = GenerateRandom(); + out += sizeof(u8); + } + } + + u32 GenerateRandomU32(u32 max) { + return GenerateRandom(max); + } + + u64 GenerateRandomU64(u64 max) { + return GenerateRandom(max); + } + +}