diff --git a/include/stratosphere/services.hpp b/include/stratosphere/services.hpp index 7db23469..fdb8d18e 100644 --- a/include/stratosphere/services.hpp +++ b/include/stratosphere/services.hpp @@ -18,4 +18,5 @@ #include "ipc.hpp" -#include "services/smm_ams.h" \ No newline at end of file +#include "services/smm_ams.h" +#include "services/dmntcht.h" \ No newline at end of file diff --git a/include/stratosphere/services/dmntcht.h b/include/stratosphere/services/dmntcht.h new file mode 100644 index 00000000..fadadcf2 --- /dev/null +++ b/include/stratosphere/services/dmntcht.h @@ -0,0 +1,92 @@ +/* + * 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 . + */ + +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + u64 base; + u64 size; +} DmntMemoryRegionExtents; + +typedef struct { + u64 process_id; + u64 title_id; + DmntMemoryRegionExtents main_nso_extents; + DmntMemoryRegionExtents heap_extents; + DmntMemoryRegionExtents alias_extents; + DmntMemoryRegionExtents address_space_extents; + u8 main_nso_build_id[0x20]; +} DmntCheatProcessMetadata; + +typedef struct { + char readable_name[0x40]; + uint32_t num_opcodes; + uint32_t opcodes[0x100]; +} DmntCheatDefinition; + +typedef struct { + bool enabled; + uint32_t cheat_id; + DmntCheatDefinition definition; +} DmntCheatEntry; + +typedef struct { + u64 value; + u8 width; +} DmntFrozenAddressValue; + +typedef struct { + u64 address; + DmntFrozenAddressValue value; +} DmntFrozenAddressEntry; + +Result dmntchtInitialize(void); +void dmntchtExit(void); +Service* dmntchtGetServiceSession(void); + +Result dmntchtHasCheatProcess(bool *out); +Result dmntchtGetCheatProcessEvent(Event *event); +Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata); +Result dmntchtForceOpenCheatProcess(void); + +Result dmntchtGetCheatProcessMappingCount(u64 *out_count); +Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count); +Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size); +Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size); +Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address); + +Result dmntchtGetCheatCount(u64 *out_count); +Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count); +Result dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id); +Result dmntchtToggleCheat(u32 cheat_id); +Result dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id); +Result dmntchtRemoveCheat(u32 cheat_id); + +Result dmntchtGetFrozenAddressCount(u64 *out_count); +Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count); +Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address); +Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value); +Result dmntchtDisableFrozenAddress(u64 address); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/dmntcht.c b/source/dmntcht.c new file mode 100644 index 00000000..64795793 --- /dev/null +++ b/source/dmntcht.c @@ -0,0 +1,650 @@ +/* + * 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 +#include + +static Service g_dmntchtService; +static u64 g_refCnt; + +static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count); +static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count); + +Result dmntchtInitialize(void) { + atomicIncrement64(&g_refCnt); + + if (serviceIsActive(&g_dmntchtService)) { + return 0; + } + + return smGetService(&g_dmntchtService, "dmnt:cht"); +} + +void dmntchtExit(void) { + if (atomicIncrement64(&g_refCnt) == 0) { + serviceClose(&g_dmntchtService); + } +} + +Service* dmntchtGetServiceSession(void) { + return &g_dmntchtService; +} + +Result dmntchtHasCheatProcess(bool *out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65000; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + bool out; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out) *out = resp->out; + } + } + + return rc; +} + +Result dmntchtGetCheatProcessEvent(Event *event) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65001; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + eventLoadRemote(event, r.Handles[0], true); + } + } + + return rc; +} + +Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65002; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + DmntCheatProcessMetadata metadata; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_metadata) *out_metadata = resp->metadata; + } + } + + return rc; +} + +Result dmntchtForceOpenCheatProcess(void) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65003; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 count; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + *out_count = resp->count; + } + + return rc; +} + +static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, buffer_size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 offset; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->offset = offset; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 count; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_count) *out_count = resp->count; + } + } + + return rc; +} + +Result dmntchtGetCheatProcessMappingCount(u64 *out_count) { + return _dmntchtGetCount(65100, out_count); +} + +Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) { + return _dmntchtGetEntries(65101, buffer, sizeof(*buffer) * max_count, offset, out_count); +} + +Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + u64 size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65102; + raw->address = address; + raw->size = size; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + u64 size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65103; + raw->address = address; + raw->size = size; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){ + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65104; + raw->address = address; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + MemoryInfo mem_info; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (mem_info) *mem_info = resp->mem_info; + } + } + + return rc; +} + +Result dmntchtGetCheatCount(u64 *out_count) { + return _dmntchtGetCount(65200, out_count); +} + +Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { + return _dmntchtGetEntries(65201, buffer, sizeof(*buffer) * max_count, offset, out_count); +} + +Result dmntchtGetCheatById(DmntCheatEntry *buffer, u32 cheat_id) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, sizeof(*buffer), 0); + + struct { + u64 magic; + u64 cmd_id; + u32 cheat_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65202; + raw->cheat_id = cheat_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtToggleCheat(u32 cheat_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 cheat_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65203; + raw->cheat_id = cheat_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtAddCheat(DmntCheatDefinition *buffer, bool enabled, u32 *out_cheat_id) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buffer, sizeof(*buffer), 0); + + struct { + u64 magic; + u64 cmd_id; + u8 enabled; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65204; + raw->enabled = enabled; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u32 cheat_id; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_cheat_id) *out_cheat_id = resp->cheat_id; + } + } + + return rc; +} + +Result dmntchtRemoveCheat(u32 cheat_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 cheat_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65205; + raw->cheat_id = cheat_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + + +Result dmntchtGetFrozenAddressCount(u64 *out_count) { + return _dmntchtGetCount(65300, out_count); +} + +Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { + return _dmntchtGetEntries(65301, buffer, sizeof(*buffer) * max_count, offset, out_count); +} + +Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65302; + raw->address = address; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + DmntFrozenAddressEntry entry; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out) *out = resp->entry; + } + } + + return rc; +} + +Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + u64 width; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65303; + raw->address = address; + raw->address = width; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 value; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_value) *out_value = resp->value; + } + } + + return rc; +} + +Result dmntchtDisableFrozenAddress(u64 address) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65304; + raw->address = address; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 value; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +}