diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp index 65c98d7cd..0c849f49d 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp @@ -16,10 +16,15 @@ #include #include "dmnt_cheat_manager.hpp" +#include "pm_shim.h" static HosMutex g_cheat_lock; static HosThread g_detect_thread, g_vm_thread; +static bool g_has_cheat_process; +static CheatProcessMetadata g_cheat_process_metadata = {0}; +static Handle g_cheat_process_debug_hnd = 0; + Handle DmntCheatManager::PrepareDebugNextApplication() { Result rc; Handle event_h; @@ -30,10 +35,82 @@ Handle DmntCheatManager::PrepareDebugNextApplication() { return event_h; } +static void PopulateMemoryExtents(MemoryRegionExtents *extents, Handle p_h, u64 id_base, u64 id_size) { + Result rc; + /* Get base extent. */ + if (R_FAILED((rc = svcGetInfo(&extents->base, id_base, p_h, 0)))) { + fatalSimple(rc); + } + + /* Get size extent. */ + if (R_FAILED((rc = svcGetInfo(&extents->size, id_size, p_h, 0)))) { + fatalSimple(rc); + } +} + void DmntCheatManager::OnNewApplicationLaunch() { std::scoped_lock lk(g_cheat_lock); + Result rc; - /* TODO: load information about the new process. */ + /* Close the current application, if it's open. */ + if (g_cheat_process_debug_hnd != 0) { + svcCloseHandle(g_cheat_process_debug_hnd); + g_cheat_process_debug_hnd = 0; + g_cheat_process_metadata = (CheatProcessMetadata){0}; + } + + /* Get the new application's process ID. */ + if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) { + fatalSimple(rc); + } + + /* Get process handle, use it to learn memory extents. */ + { + Handle proc_h = 0; + ON_SCOPE_EXIT { if (proc_h != 0) { svcCloseHandle(proc_h); } }; + + if (R_FAILED((rc = pmdmntAtmosphereGetProcessHandle(&proc_h, g_cheat_process_metadata.process_id)))) { + fatalSimple(rc); + } + + /* Get memory extents. */ + PopulateMemoryExtents(&g_cheat_process_metadata.heap_extents, proc_h, 4, 5); + PopulateMemoryExtents(&g_cheat_process_metadata.alias_extents, proc_h, 2, 3); + if (kernelAbove200()) { + PopulateMemoryExtents(&g_cheat_process_metadata.address_space_extents, proc_h, 12, 13); + } else { + g_cheat_process_metadata.address_space_extents.base = 0x08000000UL; + g_cheat_process_metadata.address_space_extents.size = 0x78000000UL; + } + } + + /* Get module information from Loader. */ + { + LoaderModuleInfo proc_modules[2]; + u32 num_modules; + if (R_FAILED((rc = ldrDmntGetModuleInfos(g_cheat_process_metadata.process_id, &proc_modules, 2, &num_modules)))) { + fatalSimple(rc); + } + + /* All applications must have two modules. */ + /* If we only have one, we must be e.g. mitming HBL. */ + /* We don't want to fuck with HBL. */ + if (num_modules != 2) { + g_cheat_process_metadata.process_id = 0; + return; + } + + g_cheat_process_metadata.main_nso_extents.base = proc_modules[1].base_address; + g_cheat_process_metadata.main_nso_extents.size = proc_modules[1].size; + g_cheat_process_metadata.main_nso_build_id = proc_modules[1].build_id; + } + + /* Open a debug handle. */ + if (R_FAILED((rc = svcDebugActiveProcess(&g_cheat_process_debug_hnd, g_cheat_process_metadata.process_id)))) { + fatalSimple(rc); + } + + /* TODO: Continue debug events, etc. */ } void DmntCheatManager::DetectThread(void *arg) { diff --git a/stratosphere/dmnt/source/dmnt_cheat_types.hpp b/stratosphere/dmnt/source/dmnt_cheat_types.hpp index b077d1e09..7b2069dd2 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_types.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_types.hpp @@ -24,11 +24,12 @@ struct MemoryRegionExtents { }; struct CheatProcessMetadata { + u64 process_id; MemoryRegionExtents main_nso_extents; MemoryRegionExtents heap_extents; MemoryRegionExtents alias_extents; MemoryRegionExtents address_space_extents; - u64 main_nso_build_id[4]; + u8 main_nso_build_id[0x20]; }; struct CheatEntry { diff --git a/stratosphere/dmnt/source/pm_shim.c b/stratosphere/dmnt/source/pm_shim.c new file mode 100644 index 000000000..027265817 --- /dev/null +++ b/stratosphere/dmnt/source/pm_shim.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 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 "pm_shim.h" + +/* Atmosphere extension commands. */ +Result pmdmntAtmosphereGetProcessHandle(Handle* out, u64 pid) { + IpcCommand c; + ipcInitialize(&c); + Service *s = pmdmntGetServiceSession(); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + } *raw; + + raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65000; + raw->pid = pid; + + Result rc = serviceIpcDispatch(s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = r.Handles[0]; + } + } + + return rc; +} diff --git a/stratosphere/dmnt/source/pm_shim.h b/stratosphere/dmnt/source/pm_shim.h new file mode 100644 index 000000000..ae2ca9403 --- /dev/null +++ b/stratosphere/dmnt/source/pm_shim.h @@ -0,0 +1,19 @@ +/** + * @file pm_shim.h + * @brief Process Management (pm) IPC wrapper. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Atmosphere extension commands. */ +Result pmdmntAtmosphereGetProcessHandle(Handle* out, u64 pid); + +#ifdef __cplusplus +} +#endif \ No newline at end of file