diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp index bb24343f6..cdd2e15ff 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp @@ -77,6 +77,36 @@ void DmntCheatManager::ContinueCheatProcess() { } } +Result DmntCheatManager::ReadCheatProcessMemoryForVm(u64 proc_addr, void *out_data, size_t size) { + if (HasActiveCheatProcess()) { + return svcReadDebugProcessMemory(out_data, g_cheat_process_debug_hnd, proc_addr, size); + } + + /* TODO: Return value... */ + return 0x20F; +} + +Result DmntCheatManager::WriteCheatProcessMemoryForVm(u64 proc_addr, const void *data, size_t size) { + if (HasActiveCheatProcess()) { + return svcWriteDebugProcessMemory(g_cheat_process_debug_hnd, data, proc_addr, size); + } + + /* TODO: Return value... */ + return 0x20F; +} + +Result DmntCheatManager::ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size) { + std::scoped_lock lk(g_cheat_lock); + + return ReadCheatProcessMemoryForVm(proc_addr, out_data, size); +} + +Result DmntCheatManager::WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size) { + std::scoped_lock lk(g_cheat_lock); + + return WriteCheatProcessMemoryForVm(proc_addr, data, size); +} + Handle DmntCheatManager::PrepareDebugNextApplication() { Result rc; Handle event_h; diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.hpp b/stratosphere/dmnt/source/dmnt_cheat_manager.hpp index e454c30a0..5d7518ae6 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.hpp @@ -30,10 +30,15 @@ class DmntCheatManager { static bool HasActiveCheatProcess(); static void CloseActiveCheatProcess(); static void ContinueCheatProcess(); - public:; + public: static bool GetHasActiveCheatProcess(); static Handle GetCheatProcessEventHandle(); static Result GetCheatProcessMetadata(CheatProcessMetadata *out); + static Result ReadCheatProcessMemoryForVm(u64 proc_addr, void *out_data, size_t size); + static Result WriteCheatProcessMemoryForVm(u64 proc_addr, const void *data, size_t size); + static Result ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size); + static Result WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size); + static void InitializeCheatManager(); }; diff --git a/stratosphere/dmnt/source/dmnt_cheat_vm.cpp b/stratosphere/dmnt/source/dmnt_cheat_vm.cpp index 627c94d06..c3766de8d 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_vm.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_vm.cpp @@ -17,6 +17,7 @@ #include #include "dmnt_cheat_types.hpp" #include "dmnt_cheat_vm.hpp" +#include "dmnt_cheat_manager.hpp" bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) { /* TODO: Parse opcodes */ @@ -53,6 +54,16 @@ u64 DmntCheatVm::GetVmInt(VmInt value, u32 bit_width) { } } +u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata* metadata, MemoryAccessType mem_type, u64 rel_address) { + switch (mem_type) { + case MemoryAccessType_MainNso: + default: + return metadata->main_nso_extents.base + rel_address; + case MemoryAccessType_Heap: + return metadata->heap_extents.base + rel_address; + } +} + void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) { CheatVmOpcode cur_opcode; u64 kDown = 0; @@ -70,12 +81,59 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) { switch (cur_opcode.opcode) { case CheatVmOpcodeType_StoreStatic: { - /* TODO */ + /* Calculate address, write value to memory. */ + u64 dst_address = GetCheatProcessAddress(metadata, cur_opcode.store_static.mem_type, cur_opcode.store_static.rel_address + this->registers[cur_opcode.store_static.offset_register]); + u64 dst_value = GetVmInt(cur_opcode.store_static.value, cur_opcode.store_static.bit_width); + switch (cur_opcode.store_static.bit_width) { + case 1: + case 2: + case 4: + case 8: + DmntCheatManager::WriteCheatProcessMemoryForVm(dst_address, &dst_value, cur_opcode.store_static.bit_width); + break; + } } break; case CheatVmOpcodeType_BeginConditionalBlock: { - /* TODO */ + /* Read value from memory. */ + u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type, cur_opcode.begin_cond.rel_address); + u64 src_value = 0; + switch (cur_opcode.store_static.bit_width) { + case 1: + case 2: + case 4: + case 8: + DmntCheatManager::ReadCheatProcessMemoryForVm(src_address, &src_value, cur_opcode.begin_cond.bit_width); + break; + } + /* Check against condition. */ + u64 cond_value = GetVmInt(cur_opcode.begin_cond.value, cur_opcode.begin_cond.bit_width); + bool cond_met = false; + switch (cur_opcode.begin_cond.cond_type) { + case ConditionalComparisonType_GT: + cond_met = src_value > cond_value; + break; + case ConditionalComparisonType_GE: + cond_met = src_value >= cond_value; + break; + case ConditionalComparisonType_LT: + cond_met = src_value < cond_value; + break; + case ConditionalComparisonType_LE: + cond_met = src_value <= cond_value; + break; + case ConditionalComparisonType_EQ: + cond_met = src_value == cond_value; + break; + case ConditionalComparisonType_NE: + cond_met = src_value != cond_value; + break; + } + /* Skip conditional block if condition not met. */ + if (!cond_met) { + this->SkipConditionalBlock(); + } } break; case CheatVmOpcodeType_EndConditionalBlock: @@ -100,12 +158,45 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) { break; case CheatVmOpcodeType_LoadRegisterMemory: { - /* TODO */ + /* Choose source address. */ + u64 src_address; + if (cur_opcode.ldr_memory.load_from_reg) { + src_address = this->registers[cur_opcode.ldr_memory.reg_index] + cur_opcode.ldr_memory.rel_address; + } else { + src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, cur_opcode.ldr_memory.rel_address); + } + /* Read into register. Gateway only reads on valid bitwidth. */ + switch (cur_opcode.ldr_memory.bit_width) { + case 1: + case 2: + case 4: + case 8: + DmntCheatManager::ReadCheatProcessMemoryForVm(src_address, &this->registers[cur_opcode.ldr_memory.reg_index], cur_opcode.ldr_memory.bit_width); + break; + } } break; case CheatVmOpcodeType_StoreToRegisterAddress: { - /* TODO */ + /* Calculate address. */ + u64 dst_address = this->registers[cur_opcode.str_regaddr.reg_index]; + u64 dst_value = cur_opcode.str_regaddr.value; + if (cur_opcode.str_regaddr.add_offset_reg) { + dst_address += this->registers[cur_opcode.str_regaddr.offset_reg_index]; + } + /* Write value to memory. Gateway only writes on valid bitwidth. */ + switch (cur_opcode.str_regaddr.bit_width) { + case 1: + case 2: + case 4: + case 8: + DmntCheatManager::WriteCheatProcessMemoryForVm(dst_address, &dst_value, cur_opcode.str_regaddr.bit_width); + break; + } + /* Increment register if relevant. */ + if (cur_opcode.str_regaddr.increment_reg) { + this->registers[cur_opcode.str_regaddr.reg_index] += cur_opcode.str_regaddr.bit_width; + } } break; case CheatVmOpcodeType_PerformArithmeticStatic: diff --git a/stratosphere/dmnt/source/dmnt_cheat_vm.hpp b/stratosphere/dmnt/source/dmnt_cheat_vm.hpp index 51499690a..705f26a4a 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_vm.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_vm.hpp @@ -76,7 +76,7 @@ struct StoreStaticOpcode { u32 bit_width; MemoryAccessType mem_type; u32 offset_register; - u64 relative_address; + u64 rel_address; VmInt value; }; @@ -84,7 +84,7 @@ struct BeginConditionalOpcode { u32 bit_width; MemoryAccessType mem_type; ConditionalComparisonType cond_type; - u64 relative_address; + u64 rel_address; VmInt value; }; @@ -106,7 +106,7 @@ struct LoadRegisterMemoryOpcode { MemoryAccessType mem_type; u32 reg_index; bool load_from_reg; - u64 relative_address; + u64 rel_address; }; struct StoreToRegisterAddressOpcode { @@ -170,6 +170,7 @@ class DmntCheatVm { void SkipConditionalBlock(); static u64 GetVmInt(VmInt value, u32 bit_width); + static u64 GetCheatProcessAddress(const CheatProcessMetadata* metadata, MemoryAccessType mem_type, u64 rel_address); public: DmntCheatVm() { }