dmnt-cheat: Implement remaining VM opcodes

This commit is contained in:
Michael Scire 2019-03-03 06:29:48 -08:00
parent a3fc2c95b8
commit bc6ad53018
4 changed files with 135 additions and 8 deletions

View file

@ -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<HosMutex> 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<HosMutex> lk(g_cheat_lock);
return WriteCheatProcessMemoryForVm(proc_addr, data, size);
}
Handle DmntCheatManager::PrepareDebugNextApplication() { Handle DmntCheatManager::PrepareDebugNextApplication() {
Result rc; Result rc;
Handle event_h; Handle event_h;

View file

@ -30,10 +30,15 @@ class DmntCheatManager {
static bool HasActiveCheatProcess(); static bool HasActiveCheatProcess();
static void CloseActiveCheatProcess(); static void CloseActiveCheatProcess();
static void ContinueCheatProcess(); static void ContinueCheatProcess();
public:; public:
static bool GetHasActiveCheatProcess(); static bool GetHasActiveCheatProcess();
static Handle GetCheatProcessEventHandle(); static Handle GetCheatProcessEventHandle();
static Result GetCheatProcessMetadata(CheatProcessMetadata *out); 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(); static void InitializeCheatManager();
}; };

View file

@ -17,6 +17,7 @@
#include <switch.h> #include <switch.h>
#include "dmnt_cheat_types.hpp" #include "dmnt_cheat_types.hpp"
#include "dmnt_cheat_vm.hpp" #include "dmnt_cheat_vm.hpp"
#include "dmnt_cheat_manager.hpp"
bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) { bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) {
/* TODO: Parse opcodes */ /* 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) { void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) {
CheatVmOpcode cur_opcode; CheatVmOpcode cur_opcode;
u64 kDown = 0; u64 kDown = 0;
@ -70,12 +81,59 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) {
switch (cur_opcode.opcode) { switch (cur_opcode.opcode) {
case CheatVmOpcodeType_StoreStatic: 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; break;
case CheatVmOpcodeType_BeginConditionalBlock: 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; break;
case CheatVmOpcodeType_EndConditionalBlock: case CheatVmOpcodeType_EndConditionalBlock:
@ -100,12 +158,45 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) {
break; break;
case CheatVmOpcodeType_LoadRegisterMemory: 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; break;
case CheatVmOpcodeType_StoreToRegisterAddress: 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; break;
case CheatVmOpcodeType_PerformArithmeticStatic: case CheatVmOpcodeType_PerformArithmeticStatic:

View file

@ -76,7 +76,7 @@ struct StoreStaticOpcode {
u32 bit_width; u32 bit_width;
MemoryAccessType mem_type; MemoryAccessType mem_type;
u32 offset_register; u32 offset_register;
u64 relative_address; u64 rel_address;
VmInt value; VmInt value;
}; };
@ -84,7 +84,7 @@ struct BeginConditionalOpcode {
u32 bit_width; u32 bit_width;
MemoryAccessType mem_type; MemoryAccessType mem_type;
ConditionalComparisonType cond_type; ConditionalComparisonType cond_type;
u64 relative_address; u64 rel_address;
VmInt value; VmInt value;
}; };
@ -106,7 +106,7 @@ struct LoadRegisterMemoryOpcode {
MemoryAccessType mem_type; MemoryAccessType mem_type;
u32 reg_index; u32 reg_index;
bool load_from_reg; bool load_from_reg;
u64 relative_address; u64 rel_address;
}; };
struct StoreToRegisterAddressOpcode { struct StoreToRegisterAddressOpcode {
@ -170,6 +170,7 @@ class DmntCheatVm {
void SkipConditionalBlock(); void SkipConditionalBlock();
static u64 GetVmInt(VmInt value, u32 bit_width); static u64 GetVmInt(VmInt value, u32 bit_width);
static u64 GetCheatProcessAddress(const CheatProcessMetadata* metadata, MemoryAccessType mem_type, u64 rel_address);
public: public:
DmntCheatVm() { } DmntCheatVm() { }