From b6d6cc97509a3d967128e0ec5e2dbe65749637e4 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Thu, 21 Dec 2017 20:14:04 +0300 Subject: [PATCH 01/17] Cheat implementations --- .gitignore | 6 +- sysmodules/rosalina/include/menus.h | 1 + sysmodules/rosalina/include/menus/cheats.h | 35 + sysmodules/rosalina/source/menu.c | 7 + sysmodules/rosalina/source/menus.c | 3 +- sysmodules/rosalina/source/menus/cheats.c | 920 +++++++++++++++++++++ 6 files changed, 970 insertions(+), 2 deletions(-) create mode 100644 sysmodules/rosalina/include/menus/cheats.h create mode 100644 sysmodules/rosalina/source/menus/cheats.c diff --git a/.gitignore b/.gitignore index be0840d..48ed2a0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,8 @@ exceptions/arm11/build *.d *.elf *.cxi -.DS_Store \ No newline at end of file +.DS_Store +.project +.cproject +.settings + diff --git a/sysmodules/rosalina/include/menus.h b/sysmodules/rosalina/include/menus.h index 354c93c..b1da981 100644 --- a/sysmodules/rosalina/include/menus.h +++ b/sysmodules/rosalina/include/menus.h @@ -37,3 +37,4 @@ void RosalinaMenu_ShowCredits(void); void RosalinaMenu_ProcessList(void); void RosalinaMenu_PowerOff(void); void RosalinaMenu_Reboot(void); +void RosalinaMenu_Cheats(void); diff --git a/sysmodules/rosalina/include/menus/cheats.h b/sysmodules/rosalina/include/menus/cheats.h new file mode 100644 index 0000000..d082339 --- /dev/null +++ b/sysmodules/rosalina/include/menus/cheats.h @@ -0,0 +1,35 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016-2017 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that 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 . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#pragma once + +#include <3ds/types.h> + +#define CHEATS_PER_MENU_PAGE 18 + +void RosalinaMenu_Cheats(void); +u32 Cheats_GetCurrentPID(u64* titleId); +void Cheats_applyKeyCheats(); diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index ab010a4..7d46c6a 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -33,6 +33,7 @@ #include "menus.h" #include "utils.h" #include "menus/n3ds.h" +#include "menus/cheats.h" #include "minisoc.h" u32 waitInputWithTimeout(u32 msec) @@ -157,6 +158,12 @@ void menuThreadMain(void) menuShow(&rosalinaMenu); menuLeave(); } + else + { + if (HID_PAD & 0xFFF) { + Cheats_applyKeyCheats(); + } + } svcSleepThread(50 * 1000 * 1000LL); } } diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c index b45aeb0..af76b55 100644 --- a/sysmodules/rosalina/source/menus.c +++ b/sysmodules/rosalina/source/menus.c @@ -41,8 +41,9 @@ Menu rosalinaMenu = { "Rosalina menu", - .nbItems = 9, + .nbItems = 10, { + { "Cheats...", METHOD, .method = &RosalinaMenu_Cheats }, { "Process list", METHOD, .method = &RosalinaMenu_ProcessList }, { "Take screenshot (slow!)", METHOD, .method = &RosalinaMenu_TakeScreenshot }, { "New 3DS menu...", MENU, .menu = &N3DSMenu }, diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c new file mode 100644 index 0000000..6d147bf --- /dev/null +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -0,0 +1,920 @@ +#include <3ds.h> +#include "menus/cheats.h" +#include "memory.h" +#include "draw.h" +#include "menu.h" +#include "utils.h" +#include "fmt.h" +#include "ifile.h" + +#define MAKE_QWORD(hi,low) \ + ((u64) ((((u64)(hi)) << 32) | (low))) + +typedef struct CheatProcessInfo { + u32 pid; + u64 titleId; +} CheatProcessInfo; + +typedef struct CheatDescription { + u64 titleId; + u32 active; + u32 keyActivated; + u32 keyCombo; + char name[40]; + u32 codesCount; + u64 codes[64]; +} CheatDescription; + +static CheatProcessInfo cheatinfo[0x40] = { 0 }; + +s32 Cheats_FetchProcessInfo(void) { + u32 pidList[0x40]; + s32 processAmount; + + s64 sa, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + + svcGetProcessList(&processAmount, pidList, 0x40); + + for (s32 i = 0; i < processAmount; i++) { + Handle processHandle; + Result res = svcOpenProcess(&processHandle, pidList[i]); + if (R_FAILED(res)) + continue; + + cheatinfo[i].pid = pidList[i]; + svcGetProcessInfo((s64 *) &cheatinfo[i].titleId, processHandle, + 0x10001); + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + svcGetProcessInfo(&sa, processHandle, 0x10005); + + svcCloseHandle(processHandle); + } + + return processAmount; +} + +typedef struct CheatState { + u8 id; + u32 index; + u32 offset; + u32 data; + u8 typeELine; + u8 typeEIdx; + + s8 loopLine; + u32 loopCount; + + u32 ifStack; + u32 storedStack; + u8 ifCount; + u8 storedIfCount; + +} CheatState; + +CheatState cheat_state = { 0 }; +u8 cheatCount = 0; +u8 hasKeyActivated = 0; +u64 cheatTitleInfo = -1ULL; +CheatDescription cheatDescriptions[0x20] = { 0 }; + +char failureReason[64]; + +void Cheat_write8(u32 offset, u8 value) { + *((u8*) (cheat_state.offset + offset)) = value; +} +void Cheat_write16(u32 offset, u16 value) { + *((u16*) (cheat_state.offset + offset)) = value; +} +void Cheat_write32(u32 offset, u32 value) { + *((u32*) (cheat_state.offset + offset)) = value; +} + +u8 Cheat_read8(u32 offset) { + return *((u8*) (cheat_state.offset + offset)); +} +u16 Cheat_read16(u32 offset) { + return *((u16*) (cheat_state.offset + offset)); +} +u32 Cheat_read32(u32 offset) { + return *((u32*) (cheat_state.offset + offset)); +} + +u8 typeEMapping[] = { 4 << 3, 5 << 3, 6 << 3, 7 << 3, 0 << 3, 1 << 3, 2 << 3, 3 + << 3 }; +u8 Cheat_getNextTypeE() { + + if (cheat_state.typeEIdx == 7) { + cheat_state.typeEIdx = 0; + cheat_state.typeELine++; + } else { + cheat_state.typeEIdx++; + } + return (u8) ((cheatDescriptions[cheat_state.id].codes[cheat_state.typeELine] + >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); +} + +void Cheat_applyCheat(u8 cheatId) { + cheat_state.id = cheatId; + cheat_state.index = 0; + cheat_state.offset = 0; + cheat_state.data = 0; + cheat_state.index = 0; + cheat_state.loopCount = 0; + cheat_state.loopLine = -1; + cheat_state.ifStack = 0; + cheat_state.storedStack = 0; + cheat_state.ifCount = 0; + cheat_state.storedIfCount = 0; + + cheatDescriptions[cheat_state.id].keyCombo = 0; + + while (cheat_state.index < cheatDescriptions[cheat_state.id].codesCount) { + u32 skipExecution = cheat_state.ifStack & 0x00000001; + u32 arg0 = + (u32) ((cheatDescriptions[cheat_state.id].codes[cheat_state.index] + >> 32) & 0x00000000FFFFFFFFULL); + u32 arg1 = + (u32) ((cheatDescriptions[cheat_state.id].codes[cheat_state.index]) + & 0x00000000FFFFFFFFULL); + if (arg0 == 0 && arg1 == 0) { + goto end_main_loop; + } + u32 code = ((arg0 >> 28) & 0x0F); + u32 subcode = ((arg0 >> 24) & 0x0F); + + switch (code) { + case 0x0: + // 0 Type + // Format: 0XXXXXXX YYYYYYYY + // Description: 32bit write of YYYYYYYY to 0XXXXXXX. + if (!skipExecution) { + Cheat_write32((arg0 & 0x0FFFFFFF), arg1); + } + break; + case 0x1: + // 1 Type + // Format: 1XXXXXXX 0000YYYY + // Description: 16bit write of YYYY to 0XXXXXXX. + if (!skipExecution) { + Cheat_write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF)); + } + break; + case 0x2: + // 2 Type + // Format: 2XXXXXXX 000000YY + // Description: 8bit write of YY to 0XXXXXXX. + if (!skipExecution) { + Cheat_write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF)); + } + break; + case 0x3: + // 3 Type + // Format: 3XXXXXXXX YYYYYYYY + // Description: 32bit if less than. + // Simple: If the value at address 0XXXXXXX is less than the value YYYYYYYY. + // Example: 323D6B28 10000000 + { + u32 newSkip; + if (Cheat_read32(arg0 & 0x0FFFFFFF) < arg1) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x4: + // 4 Type + // Format: 4XXXXXXXX YYYYYYYY + // Description: 32bit if greater than. + // Simple: If the value at address 0XXXXXXX is greater than the value YYYYYYYY. + // Example: 423D6B28 10000000 + { + u32 newSkip; + if (Cheat_read32(arg0 & 0x0FFFFFFF) > arg1) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x5: + // 5 Type + // Format: 5XXXXXXXX YYYYYYYY + // Description: 32bit if equal to. + // Simple: If the value at address 0XXXXXXX is equal to the value YYYYYYYY. + // Example: 523D6B28 10000000 + { + u32 newSkip; + if (Cheat_read32(arg0 & 0x0FFFFFFF) == arg1) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x6: + // 6 Type + // Format: 3XXXXXXXX YYYYYYYY + // Description: 32bit if not equal to. + // Simple: If the value at address 0XXXXXXX is not equal to the value YYYYYYYY. + // Example: 623D6B28 10000000 + { + u32 newSkip; + if (Cheat_read32(arg0 & 0x0FFFFFFF) != arg1) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x7: + // 7 Type + // Format: 7XXXXXXXX 0000YYYY + // Description: 16bit if less than. + // Simple: If the value at address 0XXXXXXX is less than the value YYYY. + // Example: 723D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + if (mask == 0) { + mask = 0xFFFF; + } + if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) < (arg1 & 0xFFFF)) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x8: + // 8 Type + // Format: 8XXXXXXXX 0000YYYY + // Description: 16bit if greater than. + // Simple: If the value at address 0XXXXXXX is greater than the value YYYY. + // Example: 823D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + if (mask == 0) { + mask = 0xFFFF; + } + if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) > (arg1 & 0xFFFF)) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x9: + // 9 Type + // Format: 9XXXXXXXX 0000YYYY + // Description: 16bit if equal to. + // Simple: If the value at address 0XXXXXXX is equal to the value YYYY. + // Example: 923D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + if (mask == 0) { + mask = 0xFFFF; + } + if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) == (arg1 & 0xFFFF)) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0xA: + // A Type + // Format: AXXXXXXXX 0000YYYY + // Description: 16bit if not equal to. + // Simple: If the value at address 0XXXXXXX is not equal to the value YYYY. + // Example: A23D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + if (mask == 0) { + mask = 0xFFFF; + } + if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) != (arg1 & 0xFFFF)) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + + case 0xB: + // B Type + // Format: BXXXXXXX 00000000 + // Description: Loads offset register. + if (!skipExecution) { + cheat_state.offset = (arg0 & 0x0FFFFFFF); + } + break; + case 0xC: + // C Type + // Format: C0000000 ZZZZZZZZ + // Description: Repeat following lines at specified offset. + // Simple: used to write a value to an address, and then continues to write that value Z number of times to all addresses at an offset determined by the (D6, D7, D8, or DC) type following it. + // Note: used with the D6, D7, D8, and DC types. C types can not be nested. + // Example: + + // C0000000 00000005 + // 023D6B28 0009896C + // DC000000 00000010 + // D2000000 00000000 + + cheat_state.loopLine = cheat_state.index; + cheat_state.loopCount = arg1; + cheat_state.storedStack = cheat_state.ifStack; + cheat_state.storedIfCount = cheat_state.ifCount; + break; + case 0xD: + switch (subcode) { + case 0x00: + // D0 Type + // Format: D0000000 00000000 + // Description: ends most recent conditional. + // Simple: type 3 through A are all "conditionals," the conditional most recently executed before this line will be terminated by it. + // Example: + + // 94000130 FFFB0000 + // 74000100 FF00000C + // 023D6B28 0009896C + // D0000000 00000000 + + // The 7 type line would be terminated. + if (cheat_state.loopLine != -1) { + if (cheat_state.ifCount > 0 + && cheat_state.ifCount + > cheat_state.storedIfCount) { + cheat_state.ifStack >>= 1; + cheat_state.ifCount--; + } else { + + if (cheat_state.loopCount > 0) { + cheat_state.loopCount--; + if (cheat_state.loopCount == 0) { + cheat_state.loopLine = -1; + } else { + if (cheat_state.loopLine != -1) { + cheat_state.index = cheat_state.loopLine; + } + } + } + } + } else { + if (cheat_state.ifCount > 0) { + cheat_state.ifStack >>= 1; + cheat_state.ifCount--; + } + } + break; + case 0x01: + // D1 Type + // Format: D1000000 00000000 + // Description: ends repeat block. + // Simple: will end all conditionals within a C type code, along with the C type itself. + // Example: + + // 94000130 FFFB0000 + // C0000000 00000010 + // 8453DA0C 00000200 + // 023D6B28 0009896C + // D6000000 00000005 + // D1000000 00000000 + + // The C line, 8 line, 0 line, and D6 line would be terminated. + if (cheat_state.loopCount > 0) { + cheat_state.ifStack = cheat_state.storedStack; + cheat_state.ifCount = cheat_state.storedIfCount; + cheat_state.loopCount--; + if (cheat_state.loopCount == 0) { + cheat_state.loopLine = -1; + } else { + if (cheat_state.loopLine != -1) { + cheat_state.index = cheat_state.loopLine; + } + } + } + break; + case 0x02: + // D2 Type + // Format: D2000000 00000000 + // Description: ends all conditionals/repeats before it and sets offset and stored to zero. + // Simple: ends all lines. + // Example: + + // 94000130 FEEF0000 + // C0000000 00000010 + // 8453DA0C 00000200 + // 023D6B28 0009896C + // D6000000 00000005 + // D2000000 00000000 + + // All lines would terminate. + if (cheat_state.loopCount > 0) { + cheat_state.loopCount--; + if (cheat_state.loopCount == 0) { + cheat_state.data = 0; + cheat_state.offset = 0; + cheat_state.loopLine = -1; + + cheat_state.ifStack = 0; + cheat_state.ifCount = 0; + } else { + if (cheat_state.loopLine != -1) { + cheat_state.index = cheat_state.loopLine; + } + } + } else { + cheat_state.data = 0; + cheat_state.offset = 0; + cheat_state.ifStack = 0; + cheat_state.ifCount = 0; + } + break; + case 0x03: + // D3 Type + // Format: D3000000 XXXXXXXX + // Description: sets offset. + // Simple: loads the address X so that lines after can modify the value at address X. + // Note: used with the D4, D5, D6, D7, D8, and DC types. + // Example: D3000000 023D6B28 + if (!skipExecution) { + cheat_state.offset = arg1; + } + break; + case 0x04: + // D4 Type + // Format: D4000000 YYYYYYYY + // Description: adds to the stored address' value. + // Simple: adds to the value at the address defined by lines D3, D9, DA, and DB. + // Note: used with the D3, D9, DA, DB, DC types. + // Example: D4000000 00000025 + if (!skipExecution) { + cheat_state.data += arg1; + } + break; + case 0x05: + // D5 Type + // Format: D5000000 YYYYYYYY + // Description: sets the stored address' value. + // Simple: makes the value at the address defined by lines D3, D9, DA, and DB to YYYYYYYY. + // Note: used with the D3, D9, DA, DB, and DC types. + // Example: D5000000 34540099 + if (!skipExecution) { + cheat_state.data = arg1; + } + break; + case 0x06: + // D6 Type + // Format: D6000000 XXXXXXXX + // Description: 32bit store and increment by 4. + // Simple: stores the value at address XXXXXXXX and to addresses in increments of 4. + // Note: used with the C, D3, and D9 types. + // Example: D3000000 023D6B28 + if (!skipExecution) { + Cheat_write32(arg1, cheat_state.data); + cheat_state.offset += 4; + } + break; + case 0x07: + // D7 Type + // Format: D7000000 XXXXXXXX + // Description: 16bit store and increment by 2. + // Simple: stores 2 bytes of the value at address XXXXXXXX and to addresses in increments of 2. + // Note: used with the C, D3, and DA types. + // Example: D7000000 023D6B28 + if (!skipExecution) { + Cheat_write16(arg1, (u16) (cheat_state.data & 0xFFFF)); + cheat_state.offset += 2; + } + break; + case 0x08: + // D8 Type + // Format: D8000000 XXXXXXXX + // Description: 8bit store and increment by 1. + // Simple: stores 1 byte of the value at address XXXXXXXX and to addresses in increments of 1. + // Note: used with the C, D3, and DB types. + // Example: D8000000 023D6B28 + if (!skipExecution) { + Cheat_write8(arg1, (u8) (cheat_state.data & 0xFF)); + cheat_state.offset += 1; + } + break; + case 0x09: + // D9 Type + // Format: D9000000 XXXXXXXX + // Description: 32bit load. + // Simple: loads the value from address X. + // Note: used with the D5 and D6 types. + // Example: D9000000 023D6B28 + if (!skipExecution) { + cheat_state.data = Cheat_read32(arg1); + } + break; + case 0x0A: + // DA Type + // Format: DA000000 XXXXXXXX + // Description: 16bit load. + // Simple: loads 2 bytes from address X. + // Note: used with the D5 and D7 types. + // Example: DA000000 023D6B28 + if (!skipExecution) { + cheat_state.data = Cheat_read16(arg1); + } + break; + case 0x0B: + // DB Type + // Format: DB000000 XXXXXXXX + // Description: 8bit load. + // Simple: loads 1 byte from address X. + // Note: used with the D5 and D8 types. + // Example: DB000000 023D6B28 + if (!skipExecution) { + cheat_state.data = Cheat_read8(arg1); + } + break; + case 0x0C: + // DC Type + // Format: DC000000 VVVVVVVV + // Description: 32bit store and increment by V. + // Simple: stores the value at address(es) before it and to addresses in increments of V. + // Note: used with the C, D3, D5, D9, D8, DB types. + // Example: DC000000 00000100 + if (!skipExecution) { + cheat_state.offset += arg1; + } + break; + case 0x0D: + // DD Type + { + cheatDescriptions[cheat_state.id].keyCombo |= (arg1 & 0xFFF); + u32 newSkip; + if ((HID_PAD & arg1) == arg1) { + newSkip = 0; + } else { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + default: + goto end_main_loop; + } + break; + case 0xE: + // E Type + // Format: + // EXXXXXXX UUUUUUUU + // YYYYYYYY YYYYYYYY + + // Description: writes Y to X for U bytes. + + { + u32 beginOffset = (arg0 & 0x0FFFFFFF); + u32 count = arg1; + cheat_state.typeELine = cheat_state.index; + cheat_state.typeEIdx = 7; + for (u32 i = 0; i < count; i++) { + u8 byte = Cheat_getNextTypeE(); + if (!skipExecution) { + Cheat_write8(beginOffset + i, byte); + } + } + cheat_state.index = cheat_state.typeELine; + } + break; + default: + goto end_main_loop; + } + cheat_state.index++; + } + end_main_loop: ; +} + +Result Cheat_mapMemoryAndApplyCheat(u32 pid, u32 cheatIdx) { + Handle processHandle; + Result res; + res = svcOpenProcess(&processHandle, pid); + if (R_SUCCEEDED(res)) { + + u32 codeStartAddress, heapStartAddress; + u32 codeDestAddress, heapDestAddress; + u32 codeTotalSize, heapTotalSize; + + s64 textStartAddress, textTotalRoundedSize, rodataTotalRoundedSize, + dataTotalRoundedSize; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + svcGetProcessInfo(&textStartAddress, processHandle, 0x10005); + + codeTotalSize = (u32) (textTotalRoundedSize + rodataTotalRoundedSize + + dataTotalRoundedSize); + codeDestAddress = codeStartAddress = (u32) textStartAddress; //should be 0x00100000 + + MemInfo info; + PageInfo out; + + heapDestAddress = heapStartAddress = 0x08000000; + svcQueryProcessMemory(&info, &out, processHandle, heapStartAddress); + heapTotalSize = info.size; + + Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, + codeStartAddress, codeTotalSize); + Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, + heapStartAddress, heapTotalSize); + + if (R_SUCCEEDED(codeRes | heapRes)) { + Cheat_applyCheat(cheatIdx); + + if (R_SUCCEEDED(codeRes)) + svcUnmapProcessMemoryEx(processHandle, codeDestAddress, + codeTotalSize); + if (R_SUCCEEDED(heapRes)) + svcUnmapProcessMemoryEx(processHandle, heapDestAddress, + heapTotalSize); + + svcCloseHandle(processHandle); + cheatDescriptions[cheatIdx].active = 1; + } else { + svcCloseHandle(processHandle); + } + } + return res; +} + +void Cheat_progIdToStr(char *strEnd, u64 progId) { + while (progId > 0) { + static const char hexDigits[] = "0123456789ABCDEF"; + *strEnd-- = hexDigits[(u32) (progId & 0xF)]; + progId >>= 4; + } +} + +Result Cheat_fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, + int flags) { + FS_Path filePath = { PATH_ASCII, strnlen(path, 255) + 1, path }, + archivePath = { PATH_EMPTY, 1, (u8 *) "" }; + + return IFile_Open(file, archiveId, archivePath, filePath, flags); +} + +static bool Cheat_openLumaFile(IFile *file, const char *path) { + return R_SUCCEEDED(Cheat_fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ)); +} + +void loadCheatsIntoMemory(u64 titleId) { + cheatCount = 0; + cheatTitleInfo = titleId; + hasKeyActivated = 0; + + char path[] = "/luma/titles/0000000000000000/cheats.bin"; + Cheat_progIdToStr(path + 28, titleId); + + IFile file; + + if (!Cheat_openLumaFile(&file, path)) + return; + + u8 buffer[8]; + u64 total; + + IFile_Read(&file, &total, buffer, 1); + cheatCount = buffer[0]; + for (u8 i = 0; i < cheatCount; i++) { + cheatDescriptions[i].active = 0; + IFile_Read(&file, &total, buffer, 1); + u8 nameLen = buffer[0]; + IFile_Read(&file, &total, cheatDescriptions[i].name, nameLen); + cheatDescriptions[i].name[nameLen] = '\0'; + IFile_Read(&file, &total, buffer, 1); + cheatDescriptions[i].codesCount = buffer[0]; + cheatDescriptions[i].keyActivated = 0; + cheatDescriptions[i].keyCombo = 0; + for (u8 j = 0; j < cheatDescriptions[i].codesCount; j++) { + IFile_Read(&file, &total, buffer, 8); + u64 tmp = buffer[0]; + for (u8 k = 1; k < 8; k++) { + tmp = (tmp << 8) + buffer[k]; + } + cheatDescriptions[i].codes[j] = tmp; + if (((tmp >> 56) & 0xFF) == 0xDD) { + cheatDescriptions[i].keyActivated = 1; + } + } + } + + IFile_Close(&file); +} + +u32 Cheats_GetCurrentPID(u64* titleId) { + s32 processAmount = Cheats_FetchProcessInfo(); + + s32 index = -1; + + for (s32 i = 0; i < processAmount; i++) { + + if (((u32) (cheatinfo[i].titleId >> 32)) == 0x00040010 + || ((u32) (cheatinfo[i].titleId >> 32) == 0x00040000)) { + index = i; + + break; + } + } + + if (index != -1) { + *titleId = cheatinfo[index].titleId; + return cheatinfo[index].pid; + } else { + *titleId = 0; + return 0xFFFFFFFF; + } +} + +void Cheats_applyKeyCheats(void) { + if (!cheatCount) { + return; + } + if (!hasKeyActivated) { + return; + } + + u64 titleId = 0; + u32 pid = Cheats_GetCurrentPID(&titleId); + + if (!titleId) { + cheatCount = 0; + hasKeyActivated = 0; + return; + } + + if (titleId != cheatTitleInfo) { + cheatCount = 0; + hasKeyActivated = 0; + return; + } + + u32 keys = HID_PAD & 0xFFF; + for (int i = 0; i < cheatCount; i++) { + if (cheatDescriptions[i].active && cheatDescriptions[i].keyActivated + && (cheatDescriptions[i].keyCombo & keys) == keys) { + Cheat_mapMemoryAndApplyCheat(pid, i); + } + } +} + +void RosalinaMenu_Cheats(void) { + u64 titleId = 0; + u32 pid = Cheats_GetCurrentPID(&titleId); + + if (titleId != 0) { + if (cheatTitleInfo != titleId) { + loadCheatsIntoMemory(titleId); + } + } + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + if (titleId == 0 || cheatCount == 0) { + do { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Cheats"); + if (titleId == 0) { + Draw_DrawString(10, 30, COLOR_WHITE, "No suitable title found"); + } else { + Draw_DrawFormattedString(10, 30, COLOR_WHITE, + "No cheats found for title %016llx", titleId); + } + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } while (!(waitInput() & BUTTON_B) && !terminationRequest); + } else { + s32 selected = 0, page = 0, pagePrev = 0; + + do { + Draw_Lock(); + if (page != pagePrev) { + Draw_ClearFramebuffer(); + } + Draw_DrawFormattedString(10, 10, COLOR_TITLE, "Cheat list"); + + for (s32 i = 0; + i < CHEATS_PER_MENU_PAGE + && page * CHEATS_PER_MENU_PAGE + i < cheatCount; + i++) { + char buf[65] = { 0 }; + const char * checkbox = ( + cheatDescriptions[i].active ? "(x) " : "( ) "); + const char * keyAct = ( + cheatDescriptions[i].keyActivated ? "*" : " "); + sprintf(buf, "%s%s%s", checkbox, keyAct, + cheatDescriptions[i].name); + + Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, buf); + Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, + page * CHEATS_PER_MENU_PAGE + i == selected ? + '>' : ' '); + } + + Draw_FlushFramebuffer(); + Draw_Unlock(); + + if (terminationRequest) + break; + + u32 pressed; + do { + pressed = waitInputWithTimeout(50); + if (pressed != 0) + break; + } while (pressed == 0 && !terminationRequest); + + if (pressed & BUTTON_B) + break; + else if (pressed & BUTTON_A) { + if (cheatDescriptions[selected].active) { + cheatDescriptions[selected].active = 0; + } else { + Cheat_mapMemoryAndApplyCheat(pid, selected); + } + hasKeyActivated = 0; + for (int i = 0; i < cheatCount; i++) { + if (cheatDescriptions[i].active + && cheatDescriptions[i].keyActivated) { + hasKeyActivated = 1; + break; + } + } + } else if (pressed & BUTTON_DOWN) + selected++; + else if (pressed & BUTTON_UP) + selected--; + else if (pressed & BUTTON_LEFT) + selected -= CHEATS_PER_MENU_PAGE; + else if (pressed & BUTTON_RIGHT) { + if (selected + CHEATS_PER_MENU_PAGE < cheatCount) + selected += CHEATS_PER_MENU_PAGE; + else if ((cheatCount - 1) / CHEATS_PER_MENU_PAGE == page) + selected %= CHEATS_PER_MENU_PAGE; + else + selected = cheatCount - 1; + } + + if (selected < 0) + selected = cheatCount - 1; + else if (selected >= cheatCount) + selected = 0; + + pagePrev = page; + page = selected / CHEATS_PER_MENU_PAGE; + } while (!terminationRequest); + } + +} From 8052946517101e26b89a0a2d10d450376adf3171 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Fri, 22 Dec 2017 12:17:45 +0300 Subject: [PATCH 02/17] Cheats array repleced by continous buffer --- sysmodules/rosalina/source/menus/cheats.c | 108 +++++++++++++--------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 6d147bf..018f772 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -22,9 +22,12 @@ typedef struct CheatDescription { u32 keyCombo; char name[40]; u32 codesCount; - u64 codes[64]; + u64 codes[0]; } CheatDescription; +CheatDescription* cheats[1024] = { 0 }; +u8 cheatBuffer[65536] = { 0 }; + static CheatProcessInfo cheatinfo[0x40] = { 0 }; s32 Cheats_FetchProcessInfo(void) { @@ -56,7 +59,6 @@ s32 Cheats_FetchProcessInfo(void) { } typedef struct CheatState { - u8 id; u32 index; u32 offset; u32 data; @@ -77,7 +79,7 @@ CheatState cheat_state = { 0 }; u8 cheatCount = 0; u8 hasKeyActivated = 0; u64 cheatTitleInfo = -1ULL; -CheatDescription cheatDescriptions[0x20] = { 0 }; +//CheatDescription cheatDescriptions[0x20] = { 0 }; char failureReason[64]; @@ -103,7 +105,8 @@ u32 Cheat_read32(u32 offset) { u8 typeEMapping[] = { 4 << 3, 5 << 3, 6 << 3, 7 << 3, 0 << 3, 1 << 3, 2 << 3, 3 << 3 }; -u8 Cheat_getNextTypeE() { + +u8 Cheat_getNextTypeE(const CheatDescription* cheat) { if (cheat_state.typeEIdx == 7) { cheat_state.typeEIdx = 0; @@ -111,12 +114,11 @@ u8 Cheat_getNextTypeE() { } else { cheat_state.typeEIdx++; } - return (u8) ((cheatDescriptions[cheat_state.id].codes[cheat_state.typeELine] + return (u8) ((cheat->codes[cheat_state.typeELine] >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); } -void Cheat_applyCheat(u8 cheatId) { - cheat_state.id = cheatId; +void Cheat_applyCheat(CheatDescription* const cheat) { cheat_state.index = 0; cheat_state.offset = 0; cheat_state.data = 0; @@ -128,16 +130,14 @@ void Cheat_applyCheat(u8 cheatId) { cheat_state.ifCount = 0; cheat_state.storedIfCount = 0; - cheatDescriptions[cheat_state.id].keyCombo = 0; + cheat->keyCombo = 0; - while (cheat_state.index < cheatDescriptions[cheat_state.id].codesCount) { + while (cheat_state.index < cheat->codesCount) { u32 skipExecution = cheat_state.ifStack & 0x00000001; - u32 arg0 = - (u32) ((cheatDescriptions[cheat_state.id].codes[cheat_state.index] - >> 32) & 0x00000000FFFFFFFFULL); - u32 arg1 = - (u32) ((cheatDescriptions[cheat_state.id].codes[cheat_state.index]) - & 0x00000000FFFFFFFFULL); + u32 arg0 = (u32) ((cheat->codes[cheat_state.index] >> 32) + & 0x00000000FFFFFFFFULL); + u32 arg1 = (u32) ((cheat->codes[cheat_state.index]) + & 0x00000000FFFFFFFFULL); if (arg0 == 0 && arg1 == 0) { goto end_main_loop; } @@ -585,7 +585,7 @@ void Cheat_applyCheat(u8 cheatId) { case 0x0D: // DD Type { - cheatDescriptions[cheat_state.id].keyCombo |= (arg1 & 0xFFF); + cheat->keyCombo |= (arg1 & 0xFFF); u32 newSkip; if ((HID_PAD & arg1) == arg1) { newSkip = 0; @@ -616,7 +616,7 @@ void Cheat_applyCheat(u8 cheatId) { cheat_state.typeELine = cheat_state.index; cheat_state.typeEIdx = 7; for (u32 i = 0; i < count; i++) { - u8 byte = Cheat_getNextTypeE(); + u8 byte = Cheat_getNextTypeE(cheat); if (!skipExecution) { Cheat_write8(beginOffset + i, byte); } @@ -632,7 +632,7 @@ void Cheat_applyCheat(u8 cheatId) { end_main_loop: ; } -Result Cheat_mapMemoryAndApplyCheat(u32 pid, u32 cheatIdx) { +Result Cheat_mapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { Handle processHandle; Result res; res = svcOpenProcess(&processHandle, pid); @@ -668,7 +668,7 @@ Result Cheat_mapMemoryAndApplyCheat(u32 pid, u32 cheatIdx) { heapStartAddress, heapTotalSize); if (R_SUCCEEDED(codeRes | heapRes)) { - Cheat_applyCheat(cheatIdx); + Cheat_applyCheat(cheat); if (R_SUCCEEDED(codeRes)) svcUnmapProcessMemoryEx(processHandle, codeDestAddress, @@ -678,7 +678,7 @@ Result Cheat_mapMemoryAndApplyCheat(u32 pid, u32 cheatIdx) { heapTotalSize); svcCloseHandle(processHandle); - cheatDescriptions[cheatIdx].active = 1; + cheat->active = 1; } else { svcCloseHandle(processHandle); } @@ -706,6 +706,26 @@ static bool Cheat_openLumaFile(IFile *file, const char *path) { return R_SUCCEEDED(Cheat_fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ)); } +CheatDescription* Cheats_allocCheat() { + CheatDescription* cheat; + if (cheatCount == 0) { + cheat = (CheatDescription*) cheatBuffer; + } else { + CheatDescription* prev = cheats[cheatCount - 1]; + cheat = (CheatDescription *) ((u8*) (prev) + sizeof(CheatDescription) + + sizeof(u64) * (prev->codesCount)); + } + + cheats[cheatCount] = cheat; + cheatCount++; + return cheat; +} + +void Cheats_addCode(CheatDescription* cheat, u64 code) { + cheat->codes[cheat->codesCount] = code; + (cheat->codesCount)++; +} + void loadCheatsIntoMemory(u64 titleId) { cheatCount = 0; cheatTitleInfo = titleId; @@ -723,26 +743,28 @@ void loadCheatsIntoMemory(u64 titleId) { u64 total; IFile_Read(&file, &total, buffer, 1); - cheatCount = buffer[0]; - for (u8 i = 0; i < cheatCount; i++) { - cheatDescriptions[i].active = 0; + u8 cc = buffer[0]; + for (u8 i = 0; i < cc; i++) { + CheatDescription* cheat = Cheats_allocCheat(); + cheat->active = 0; IFile_Read(&file, &total, buffer, 1); u8 nameLen = buffer[0]; - IFile_Read(&file, &total, cheatDescriptions[i].name, nameLen); - cheatDescriptions[i].name[nameLen] = '\0'; + IFile_Read(&file, &total, cheat->name, nameLen); + cheat->name[nameLen] = '\0'; IFile_Read(&file, &total, buffer, 1); - cheatDescriptions[i].codesCount = buffer[0]; - cheatDescriptions[i].keyActivated = 0; - cheatDescriptions[i].keyCombo = 0; - for (u8 j = 0; j < cheatDescriptions[i].codesCount; j++) { + u8 codeCount = buffer[0]; + cheat->codesCount = 0; + cheat->keyActivated = 0; + cheat->keyCombo = 0; + for (u8 j = 0; j < codeCount; j++) { IFile_Read(&file, &total, buffer, 8); u64 tmp = buffer[0]; for (u8 k = 1; k < 8; k++) { tmp = (tmp << 8) + buffer[k]; } - cheatDescriptions[i].codes[j] = tmp; + Cheats_addCode(cheat, tmp); if (((tmp >> 56) & 0xFF) == 0xDD) { - cheatDescriptions[i].keyActivated = 1; + cheat->keyActivated = 1; } } } @@ -799,9 +821,9 @@ void Cheats_applyKeyCheats(void) { u32 keys = HID_PAD & 0xFFF; for (int i = 0; i < cheatCount; i++) { - if (cheatDescriptions[i].active && cheatDescriptions[i].keyActivated - && (cheatDescriptions[i].keyCombo & keys) == keys) { - Cheat_mapMemoryAndApplyCheat(pid, i); + if (cheats[i]->active && cheats[i]->keyActivated + && (cheats[i]->keyCombo & keys) == keys) { + Cheat_mapMemoryAndApplyCheat(pid, cheats[i]); } } } @@ -850,12 +872,9 @@ void RosalinaMenu_Cheats(void) { && page * CHEATS_PER_MENU_PAGE + i < cheatCount; i++) { char buf[65] = { 0 }; - const char * checkbox = ( - cheatDescriptions[i].active ? "(x) " : "( ) "); - const char * keyAct = ( - cheatDescriptions[i].keyActivated ? "*" : " "); - sprintf(buf, "%s%s%s", checkbox, keyAct, - cheatDescriptions[i].name); + const char * checkbox = (cheats[i]->active ? "(x) " : "( ) "); + const char * keyAct = (cheats[i]->keyActivated ? "*" : " "); + sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[i]->name); Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, buf); Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, @@ -879,15 +898,14 @@ void RosalinaMenu_Cheats(void) { if (pressed & BUTTON_B) break; else if (pressed & BUTTON_A) { - if (cheatDescriptions[selected].active) { - cheatDescriptions[selected].active = 0; + if (cheats[selected]->active) { + cheats[selected]->active = 0; } else { - Cheat_mapMemoryAndApplyCheat(pid, selected); + Cheat_mapMemoryAndApplyCheat(pid, cheats[selected]); } hasKeyActivated = 0; for (int i = 0; i < cheatCount; i++) { - if (cheatDescriptions[i].active - && cheatDescriptions[i].keyActivated) { + if (cheats[i]->active && cheats[i]->keyActivated) { hasKeyActivated = 1; break; } From 0e67b0f0266df037f3bba45a494832f87c10015f Mon Sep 17 00:00:00 2001 From: Duckbill Date: Fri, 22 Dec 2017 12:39:09 +0300 Subject: [PATCH 03/17] Moved key combo calculation to loading cheat phase --- sysmodules/rosalina/source/menus/cheats.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 018f772..6f2dc66 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -118,7 +118,7 @@ u8 Cheat_getNextTypeE(const CheatDescription* cheat) { >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); } -void Cheat_applyCheat(CheatDescription* const cheat) { +void Cheat_applyCheat(const CheatDescription* const cheat) { cheat_state.index = 0; cheat_state.offset = 0; cheat_state.data = 0; @@ -130,8 +130,6 @@ void Cheat_applyCheat(CheatDescription* const cheat) { cheat_state.ifCount = 0; cheat_state.storedIfCount = 0; - cheat->keyCombo = 0; - while (cheat_state.index < cheat->codesCount) { u32 skipExecution = cheat_state.ifStack & 0x00000001; u32 arg0 = (u32) ((cheat->codes[cheat_state.index] >> 32) @@ -585,7 +583,6 @@ void Cheat_applyCheat(CheatDescription* const cheat) { case 0x0D: // DD Type { - cheat->keyCombo |= (arg1 & 0xFFF); u32 newSkip; if ((HID_PAD & arg1) == arg1) { newSkip = 0; @@ -763,7 +760,8 @@ void loadCheatsIntoMemory(u64 titleId) { tmp = (tmp << 8) + buffer[k]; } Cheats_addCode(cheat, tmp); - if (((tmp >> 56) & 0xFF) == 0xDD) { + if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { + cheat->keyCombo |= (tmp & 0xFFF); cheat->keyActivated = 1; } } From 5def0c18e23afe8387f85aafbdd2b75f773bcde8 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Fri, 22 Dec 2017 14:46:46 +0300 Subject: [PATCH 04/17] Cheat file format changed from binary to plaintext --- sysmodules/rosalina/include/menus/cheats.h | 5 +- sysmodules/rosalina/source/menu.c | 2 +- sysmodules/rosalina/source/menus/cheats.c | 214 +++++++++++++++++++-- 3 files changed, 204 insertions(+), 17 deletions(-) diff --git a/sysmodules/rosalina/include/menus/cheats.h b/sysmodules/rosalina/include/menus/cheats.h index d082339..bcc6fff 100644 --- a/sysmodules/rosalina/include/menus/cheats.h +++ b/sysmodules/rosalina/include/menus/cheats.h @@ -24,6 +24,8 @@ * reasonable ways as different from the original version. */ +/* This file was entirely written by Duckbill */ + #pragma once #include <3ds/types.h> @@ -31,5 +33,4 @@ #define CHEATS_PER_MENU_PAGE 18 void RosalinaMenu_Cheats(void); -u32 Cheats_GetCurrentPID(u64* titleId); -void Cheats_applyKeyCheats(); +void Cheat_applyKeyCheats(); diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index 7d46c6a..bba67c2 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -161,7 +161,7 @@ void menuThreadMain(void) else { if (HID_PAD & 0xFFF) { - Cheats_applyKeyCheats(); + Cheat_applyKeyCheats(); } } svcSleepThread(50 * 1000 * 1000LL); diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 6f2dc66..c6f188e 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -1,3 +1,31 @@ +/* + * This file is part of Luma3DS + * Copyright (C) 2016-2017 Aurora Wright, TuxSH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + * + * Additional Terms 7.b and 7.c of GPLv3 apply to this file: + * * Requiring preservation of specified reasonable legal notices or + * author attributions in that material or in the Appropriate Legal + * Notices displayed by works containing it. + * * Prohibiting misrepresentation of the origin of that material, + * or requiring that modified versions of such material be marked in + * reasonable ways as different from the original version. + */ + +/* This file was entirely written by Duckbill */ + #include <3ds.h> #include "menus/cheats.h" #include "memory.h" @@ -16,7 +44,6 @@ typedef struct CheatProcessInfo { } CheatProcessInfo; typedef struct CheatDescription { - u64 titleId; u32 active; u32 keyActivated; u32 keyCombo; @@ -26,7 +53,9 @@ typedef struct CheatDescription { } CheatDescription; CheatDescription* cheats[1024] = { 0 }; -u8 cheatBuffer[65536] = { 0 }; +u8 cheatFileBuffer[16384] = { 0 }; +u32 cheatFilePos = 0; +u8 cheatBuffer[16384] = { 0 }; static CheatProcessInfo cheatinfo[0x40] = { 0 }; @@ -703,7 +732,7 @@ static bool Cheat_openLumaFile(IFile *file, const char *path) { return R_SUCCEEDED(Cheat_fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ)); } -CheatDescription* Cheats_allocCheat() { +CheatDescription* Cheat_allocCheat() { CheatDescription* cheat; if (cheatCount == 0) { cheat = (CheatDescription*) cheatBuffer; @@ -712,18 +741,175 @@ CheatDescription* Cheats_allocCheat() { cheat = (CheatDescription *) ((u8*) (prev) + sizeof(CheatDescription) + sizeof(u64) * (prev->codesCount)); } + cheat->active = 0; + cheat->codesCount = 0; + cheat->keyActivated = 0; + cheat->keyCombo = 0; + cheat->name[0] = '\0'; cheats[cheatCount] = cheat; cheatCount++; return cheat; } -void Cheats_addCode(CheatDescription* cheat, u64 code) { - cheat->codes[cheat->codesCount] = code; - (cheat->codesCount)++; +void Cheat_addCode(CheatDescription* cheat, u64 code) { + if (cheat) { + cheat->codes[cheat->codesCount] = code; + (cheat->codesCount)++; + } } -void loadCheatsIntoMemory(u64 titleId) { +Result Cheat_readLine(char* line) { + Result res = 0; + + char c = '\0'; + u32 idx = 0; + while (R_SUCCEEDED(res)) { + c = cheatFileBuffer[cheatFilePos++]; + res = c ? 0 : -1; + if (R_SUCCEEDED(res) && c != '\0') { + if (c == '\n' || c == '\r' || idx >= 1023) { + line[idx++] = '\0'; + return idx; + } else { + line[idx++] = c; + } + } else { + if (idx > 0) { + line[idx++] = '\0'; + return idx; + } + } + } + return res; +} + +bool Cheat_isCodeLine(const char *line) { + s32 len = strnlen(line, 1023); + if (len != 17) { + return false; + } + if (line[8] != ' ') { + return false; + } + + int i; + for (i = 0; i < 8; i++) { + char c = line[i]; + if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') + || ('a' <= c && c <= 'f'))) { + return false; + } + } + + for (i = 9; i < 17; i++) { + char c = line[i]; + if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') + || ('a' <= c && c <= 'f'))) { + return false; + } + } + + return true; +} + +u64 Cheat_getCode(const char *line) { + u64 tmp = 0; + int i; + for (i = 0; i < 8; i++) { + char c = line[i]; + u8 code = 0; + if ('0' <= c && c <= '9') { + code = c - '0'; + } + if ('A' <= c && c <= 'F') { + code = c - 'A' + 10; + } + if ('a' <= c && c <= 'f') { + code = c - 'a' + 10; + } + tmp <<= 4; + tmp |= (code & 0xF); + } + + for (i = 9; i < 17; i++) { + char c = line[i]; + u8 code = 0; + if ('0' <= c && c <= '9') { + code = c - '0'; + } + if ('A' <= c && c <= 'F') { + code = c - 'A' + 10; + } + if ('a' <= c && c <= 'f') { + code = c - 'a' + 10; + } + tmp <<= 4; + tmp |= (code & 0xF); + } + + return tmp; +} + +void Cheat_loadCheatsIntoMemory(u64 titleId) { + cheatCount = 0; + cheatTitleInfo = titleId; + hasKeyActivated = 0; + + char path[] = "/luma/titles/0000000000000000/cheats.txt"; + Cheat_progIdToStr(path + 28, titleId); + + IFile file; + + if (!Cheat_openLumaFile(&file, path)) + return; + + u64 fileLen = 0; + IFile_GetSize(&file, &fileLen); + if (fileLen > 16384) { + fileLen = 16384; + } + + u64 total; + IFile_Read(&file, &total, cheatFileBuffer, fileLen); + IFile_Close(&file); + for (int i = fileLen; i < 16384; i++) { + cheatFileBuffer[i] = 0; + } + + char line[1024] = { 0 }; + strncpy(line, "asasd", 39); + Result res = 0; + CheatDescription* cheat = 0; + cheatFilePos = 0; + do { + res = Cheat_readLine(line); + if (R_SUCCEEDED(res)) { + s32 lineLen = strnlen(line, 1023); + if (!lineLen) { + continue; + } + if (line[0] == '#') { + continue; + } + if (Cheat_isCodeLine(line)) { + if (cheat) { + u64 tmp = Cheat_getCode(line); + Cheat_addCode(cheat, tmp); + if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { + cheat->keyCombo |= (tmp & 0xFFF); + cheat->keyActivated = 1; + } + } + } else { + cheat = Cheat_allocCheat(); + strncpy(cheat->name, line, 39); + } + } + } while (R_SUCCEEDED(res)); +} + +void loadCheatsIntoMemoryBin(u64 titleId) { cheatCount = 0; cheatTitleInfo = titleId; hasKeyActivated = 0; @@ -742,7 +928,7 @@ void loadCheatsIntoMemory(u64 titleId) { IFile_Read(&file, &total, buffer, 1); u8 cc = buffer[0]; for (u8 i = 0; i < cc; i++) { - CheatDescription* cheat = Cheats_allocCheat(); + CheatDescription* cheat = Cheat_allocCheat(); cheat->active = 0; IFile_Read(&file, &total, buffer, 1); u8 nameLen = buffer[0]; @@ -759,7 +945,7 @@ void loadCheatsIntoMemory(u64 titleId) { for (u8 k = 1; k < 8; k++) { tmp = (tmp << 8) + buffer[k]; } - Cheats_addCode(cheat, tmp); + Cheat_addCode(cheat, tmp); if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { cheat->keyCombo |= (tmp & 0xFFF); cheat->keyActivated = 1; @@ -770,7 +956,7 @@ void loadCheatsIntoMemory(u64 titleId) { IFile_Close(&file); } -u32 Cheats_GetCurrentPID(u64* titleId) { +u32 Cheat_GetCurrentPID(u64* titleId) { s32 processAmount = Cheats_FetchProcessInfo(); s32 index = -1; @@ -794,7 +980,7 @@ u32 Cheats_GetCurrentPID(u64* titleId) { } } -void Cheats_applyKeyCheats(void) { +void Cheat_applyKeyCheats(void) { if (!cheatCount) { return; } @@ -803,7 +989,7 @@ void Cheats_applyKeyCheats(void) { } u64 titleId = 0; - u32 pid = Cheats_GetCurrentPID(&titleId); + u32 pid = Cheat_GetCurrentPID(&titleId); if (!titleId) { cheatCount = 0; @@ -828,11 +1014,11 @@ void Cheats_applyKeyCheats(void) { void RosalinaMenu_Cheats(void) { u64 titleId = 0; - u32 pid = Cheats_GetCurrentPID(&titleId); + u32 pid = Cheat_GetCurrentPID(&titleId); if (titleId != 0) { if (cheatTitleInfo != titleId) { - loadCheatsIntoMemory(titleId); + Cheat_loadCheatsIntoMemory(titleId); } } From 78791f7b6674765c4e3b913dd1f7e9179ca91b9e Mon Sep 17 00:00:00 2001 From: Duckbill Date: Mon, 25 Dec 2017 13:45:09 +0300 Subject: [PATCH 05/17] Paging fixes --- sysmodules/rosalina/source/menus/cheats.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index c6f188e..cad08cf 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -1056,14 +1056,14 @@ void RosalinaMenu_Cheats(void) { && page * CHEATS_PER_MENU_PAGE + i < cheatCount; i++) { char buf[65] = { 0 }; - const char * checkbox = (cheats[i]->active ? "(x) " : "( ) "); - const char * keyAct = (cheats[i]->keyActivated ? "*" : " "); - sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[i]->name); + s32 j = page * CHEATS_PER_MENU_PAGE + i; + const char * checkbox = (cheats[j]->active ? "(x) " : "( ) "); + const char * keyAct = (cheats[j]->keyActivated ? "*" : " "); + sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, buf); Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, - page * CHEATS_PER_MENU_PAGE + i == selected ? - '>' : ' '); + j == selected ? '>' : ' '); } Draw_FlushFramebuffer(); From 1b440f7f3bcb5ca4a570d890772171c5f97c50c7 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Mon, 25 Dec 2017 13:57:20 +0300 Subject: [PATCH 06/17] Skip empty cheats --- sysmodules/rosalina/source/menus/cheats.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index cad08cf..94f747e 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -878,7 +878,6 @@ void Cheat_loadCheatsIntoMemory(u64 titleId) { } char line[1024] = { 0 }; - strncpy(line, "asasd", 39); Result res = 0; CheatDescription* cheat = 0; cheatFilePos = 0; @@ -902,7 +901,14 @@ void Cheat_loadCheatsIntoMemory(u64 titleId) { } } } else { - cheat = Cheat_allocCheat(); + if (!cheat) { + cheat = Cheat_allocCheat(); + } else { + if (cheat->codesCount > 0) { + // Add new cheat only if previous has body. In other case just rewrite it's name + cheat = Cheat_allocCheat(); + } + } strncpy(cheat->name, line, 39); } } From cb945612a35d62b306fe9c4fae5bcbfeceb3b7f1 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Mon, 25 Dec 2017 14:16:57 +0300 Subject: [PATCH 07/17] Remove ast empty cheat from list --- sysmodules/rosalina/source/menus/cheats.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 94f747e..cd3bdad 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -913,6 +913,10 @@ void Cheat_loadCheatsIntoMemory(u64 titleId) { } } } while (R_SUCCEEDED(res)); + + if ((cheatCount > 0) && (cheats[cheatCount - 1]->codesCount == 0)) { + cheatCount--; // Remove last empty cheat + } } void loadCheatsIntoMemoryBin(u64 titleId) { From fd80294bf26f855a83279d18c196263db5f10bdb Mon Sep 17 00:00:00 2001 From: Duckbill Date: Sun, 31 Dec 2017 11:26:18 +0300 Subject: [PATCH 08/17] Fix buffer overflow in case of very long cheats.txt file --- sysmodules/rosalina/source/menus/cheats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index cd3bdad..0498643 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -866,8 +866,8 @@ void Cheat_loadCheatsIntoMemory(u64 titleId) { u64 fileLen = 0; IFile_GetSize(&file, &fileLen); - if (fileLen > 16384) { - fileLen = 16384; + if (fileLen > 16383) { + fileLen = 16383; } u64 total; From ca4685cc42ab8032c392a8c3c7f23f8315f06fe8 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Tue, 2 Jan 2018 14:23:45 +0300 Subject: [PATCH 09/17] Range checks added --- sysmodules/rosalina/source/menus/cheats.c | 117 +++++++++------------- 1 file changed, 48 insertions(+), 69 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 0498643..15117d6 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -45,6 +45,7 @@ typedef struct CheatProcessInfo { typedef struct CheatDescription { u32 active; + u32 valid; u32 keyActivated; u32 keyCombo; char name[40]; @@ -52,6 +53,10 @@ typedef struct CheatDescription { u64 codes[0]; } CheatDescription; +u32 codeStartAddress, heapStartAddress; +u32 codeTotalSize, heapTotalSize; + + CheatDescription* cheats[1024] = { 0 }; u8 cheatFileBuffer[16384] = { 0 }; u32 cheatFilePos = 0; @@ -112,14 +117,36 @@ u64 cheatTitleInfo = -1ULL; char failureReason[64]; -void Cheat_write8(u32 offset, u8 value) { - *((u8*) (cheat_state.offset + offset)) = value; +bool Cheat_isValidAddress(u32 address) { + if (codeStartAddress <= address && address <= codeStartAddress + codeTotalSize) { + return true; + } + if (heapStartAddress <= address && address <= heapStartAddress + heapTotalSize) { + return true; + } + return false; } -void Cheat_write16(u32 offset, u16 value) { - *((u16*) (cheat_state.offset + offset)) = value; + +bool Cheat_write8(u32 offset, u8 value) { + if (Cheat_isValidAddress(cheat_state.offset + offset)) { + *((u8*) (cheat_state.offset + offset)) = value; + return true; + } + return false; } -void Cheat_write32(u32 offset, u32 value) { - *((u32*) (cheat_state.offset + offset)) = value; +bool Cheat_write16(u32 offset, u16 value) { + if (Cheat_isValidAddress(cheat_state.offset + offset)) { + *((u16*) (cheat_state.offset + offset)) = value; + return true; + } + return false; +} +bool Cheat_write32(u32 offset, u32 value) { + if (Cheat_isValidAddress(cheat_state.offset + offset)) { + *((u32*) (cheat_state.offset + offset)) = value; + return true; + } + return false; } u8 Cheat_read8(u32 offset) { @@ -147,7 +174,7 @@ u8 Cheat_getNextTypeE(const CheatDescription* cheat) { >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); } -void Cheat_applyCheat(const CheatDescription* const cheat) { +u32 Cheat_applyCheat(const CheatDescription* const cheat) { cheat_state.index = 0; cheat_state.offset = 0; cheat_state.data = 0; @@ -166,7 +193,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { u32 arg1 = (u32) ((cheat->codes[cheat_state.index]) & 0x00000000FFFFFFFFULL); if (arg0 == 0 && arg1 == 0) { - goto end_main_loop; + return 0; } u32 code = ((arg0 >> 28) & 0x0F); u32 subcode = ((arg0 >> 24) & 0x0F); @@ -177,7 +204,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { // Format: 0XXXXXXX YYYYYYYY // Description: 32bit write of YYYYYYYY to 0XXXXXXX. if (!skipExecution) { - Cheat_write32((arg0 & 0x0FFFFFFF), arg1); + if (!Cheat_write32((arg0 & 0x0FFFFFFF), arg1)) return 0; } break; case 0x1: @@ -185,7 +212,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { // Format: 1XXXXXXX 0000YYYY // Description: 16bit write of YYYY to 0XXXXXXX. if (!skipExecution) { - Cheat_write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF)); + if (!Cheat_write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; } break; case 0x2: @@ -193,7 +220,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { // Format: 2XXXXXXX 000000YY // Description: 8bit write of YY to 0XXXXXXX. if (!skipExecution) { - Cheat_write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF)); + if (!Cheat_write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; } break; case 0x3: @@ -537,7 +564,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { // Note: used with the C, D3, and D9 types. // Example: D3000000 023D6B28 if (!skipExecution) { - Cheat_write32(arg1, cheat_state.data); + if (!Cheat_write32(arg1, cheat_state.data)) return 0; cheat_state.offset += 4; } break; @@ -549,7 +576,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { // Note: used with the C, D3, and DA types. // Example: D7000000 023D6B28 if (!skipExecution) { - Cheat_write16(arg1, (u16) (cheat_state.data & 0xFFFF)); + if (!Cheat_write16(arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; cheat_state.offset += 2; } break; @@ -561,7 +588,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { // Note: used with the C, D3, and DB types. // Example: D8000000 023D6B28 if (!skipExecution) { - Cheat_write8(arg1, (u8) (cheat_state.data & 0xFF)); + if (!Cheat_write8(arg1, (u8) (cheat_state.data & 0xFF))) return 0; cheat_state.offset += 1; } break; @@ -625,7 +652,7 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { } break; default: - goto end_main_loop; + return 0; } break; case 0xE: @@ -644,18 +671,18 @@ void Cheat_applyCheat(const CheatDescription* const cheat) { for (u32 i = 0; i < count; i++) { u8 byte = Cheat_getNextTypeE(cheat); if (!skipExecution) { - Cheat_write8(beginOffset + i, byte); + if (!Cheat_write8(beginOffset + i, byte)) return 0; } } cheat_state.index = cheat_state.typeELine; } break; default: - goto end_main_loop; + return 0; } cheat_state.index++; } - end_main_loop: ; + return 1; } Result Cheat_mapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { @@ -664,9 +691,7 @@ Result Cheat_mapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { res = svcOpenProcess(&processHandle, pid); if (R_SUCCEEDED(res)) { - u32 codeStartAddress, heapStartAddress; u32 codeDestAddress, heapDestAddress; - u32 codeTotalSize, heapTotalSize; s64 textStartAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; @@ -694,7 +719,7 @@ Result Cheat_mapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { heapStartAddress, heapTotalSize); if (R_SUCCEEDED(codeRes | heapRes)) { - Cheat_applyCheat(cheat); + cheat->valid = Cheat_applyCheat(cheat); if (R_SUCCEEDED(codeRes)) svcUnmapProcessMemoryEx(processHandle, codeDestAddress, @@ -742,6 +767,7 @@ CheatDescription* Cheat_allocCheat() { + sizeof(u64) * (prev->codesCount)); } cheat->active = 0; + cheat->valid = 1; cheat->codesCount = 0; cheat->keyActivated = 0; cheat->keyCombo = 0; @@ -919,53 +945,6 @@ void Cheat_loadCheatsIntoMemory(u64 titleId) { } } -void loadCheatsIntoMemoryBin(u64 titleId) { - cheatCount = 0; - cheatTitleInfo = titleId; - hasKeyActivated = 0; - - char path[] = "/luma/titles/0000000000000000/cheats.bin"; - Cheat_progIdToStr(path + 28, titleId); - - IFile file; - - if (!Cheat_openLumaFile(&file, path)) - return; - - u8 buffer[8]; - u64 total; - - IFile_Read(&file, &total, buffer, 1); - u8 cc = buffer[0]; - for (u8 i = 0; i < cc; i++) { - CheatDescription* cheat = Cheat_allocCheat(); - cheat->active = 0; - IFile_Read(&file, &total, buffer, 1); - u8 nameLen = buffer[0]; - IFile_Read(&file, &total, cheat->name, nameLen); - cheat->name[nameLen] = '\0'; - IFile_Read(&file, &total, buffer, 1); - u8 codeCount = buffer[0]; - cheat->codesCount = 0; - cheat->keyActivated = 0; - cheat->keyCombo = 0; - for (u8 j = 0; j < codeCount; j++) { - IFile_Read(&file, &total, buffer, 8); - u64 tmp = buffer[0]; - for (u8 k = 1; k < 8; k++) { - tmp = (tmp << 8) + buffer[k]; - } - Cheat_addCode(cheat, tmp); - if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { - cheat->keyCombo |= (tmp & 0xFFF); - cheat->keyActivated = 1; - } - } - } - - IFile_Close(&file); -} - u32 Cheat_GetCurrentPID(u64* titleId) { s32 processAmount = Cheats_FetchProcessInfo(); @@ -1071,7 +1050,7 @@ void RosalinaMenu_Cheats(void) { const char * keyAct = (cheats[j]->keyActivated ? "*" : " "); sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); - Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, buf); + Draw_DrawString(30, 30 + i * SPACING_Y, cheats[j]->valid ? COLOR_WHITE : COLOR_RED, buf); Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, j == selected ? '>' : ' '); } From d28642d2c3815f4ad5aa5f89de2f187bcffde306 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Wed, 3 Jan 2018 00:27:44 +0300 Subject: [PATCH 10/17] More range checks and separate code and heap allocation --- sysmodules/rosalina/source/menus/cheats.c | 130 +++++++++++++++------- 1 file changed, 91 insertions(+), 39 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 15117d6..3e173e6 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -149,14 +149,26 @@ bool Cheat_write32(u32 offset, u32 value) { return false; } -u8 Cheat_read8(u32 offset) { - return *((u8*) (cheat_state.offset + offset)); +bool Cheat_read8(u32 offset, u8* retValue) { + if (Cheat_isValidAddress(cheat_state.offset + offset)) { + *retValue = *((u8*) (cheat_state.offset + offset)); + return true; + } + return false; } -u16 Cheat_read16(u32 offset) { - return *((u16*) (cheat_state.offset + offset)); +bool Cheat_read16(u32 offset, u16* retValue) { + if (Cheat_isValidAddress(cheat_state.offset + offset)) { + *retValue = *((u16*) (cheat_state.offset + offset)); + return true; + } + return false; } -u32 Cheat_read32(u32 offset) { - return *((u32*) (cheat_state.offset + offset)); +bool Cheat_read32(u32 offset, u32* retValue) { + if (Cheat_isValidAddress(cheat_state.offset + offset)) { + *retValue = *((u32*) (cheat_state.offset + offset)); + return true; + } + return false; } u8 typeEMapping[] = { 4 << 3, 5 << 3, 6 << 3, 7 << 3, 0 << 3, 1 << 3, 2 << 3, 3 @@ -231,7 +243,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Example: 323D6B28 10000000 { u32 newSkip; - if (Cheat_read32(arg0 & 0x0FFFFFFF) < arg1) { + u32 value = 0; + if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value < arg1) { newSkip = 0; } else { newSkip = 1; @@ -250,7 +264,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Example: 423D6B28 10000000 { u32 newSkip; - if (Cheat_read32(arg0 & 0x0FFFFFFF) > arg1) { + u32 value = 0; + if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value > arg1) { newSkip = 0; } else { newSkip = 1; @@ -269,7 +285,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Example: 523D6B28 10000000 { u32 newSkip; - if (Cheat_read32(arg0 & 0x0FFFFFFF) == arg1) { + u32 value = 0; + if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value == arg1) { newSkip = 0; } else { newSkip = 1; @@ -288,7 +306,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Example: 623D6B28 10000000 { u32 newSkip; - if (Cheat_read32(arg0 & 0x0FFFFFFF) != arg1) { + u32 value = 0; + if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value != arg1) { newSkip = 0; } else { newSkip = 1; @@ -311,7 +331,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { if (mask == 0) { mask = 0xFFFF; } - if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) < (arg1 & 0xFFFF)) { + u16 value = 0; + if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & mask) < (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -334,7 +356,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { if (mask == 0) { mask = 0xFFFF; } - if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) > (arg1 & 0xFFFF)) { + u16 value = 0; + if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & mask) > (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -357,7 +381,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { if (mask == 0) { mask = 0xFFFF; } - if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) == (arg1 & 0xFFFF)) { + u16 value = 0; + if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & mask) == (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -380,7 +406,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { if (mask == 0) { mask = 0xFFFF; } - if ((Cheat_read16(arg0 & 0x0FFFFFFF) & mask) != (arg1 & 0xFFFF)) { + u16 value = 0; + if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & mask) != (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -600,7 +628,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Note: used with the D5 and D6 types. // Example: D9000000 023D6B28 if (!skipExecution) { - cheat_state.data = Cheat_read32(arg1); + u32 value = 0; + if (!Cheat_read32(arg1, &value)) return 0; + cheat_state.data = value; } break; case 0x0A: @@ -611,7 +641,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Note: used with the D5 and D7 types. // Example: DA000000 023D6B28 if (!skipExecution) { - cheat_state.data = Cheat_read16(arg1); + u16 value = 0; + if (!Cheat_read16(arg1, &value)) return 0; + cheat_state.data = value; } break; case 0x0B: @@ -622,7 +654,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // Note: used with the D5 and D8 types. // Example: DB000000 023D6B28 if (!skipExecution) { - cheat_state.data = Cheat_read8(arg1); + u8 value = 0; + if (!Cheat_read8(arg1, &value)) return 0; + cheat_state.data = value; } break; case 0x0C: @@ -640,7 +674,7 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { // DD Type { u32 newSkip; - if ((HID_PAD & arg1) == arg1) { + if (arg1 == 0 || (HID_PAD & arg1) == arg1) { newSkip = 0; } else { newSkip = 1; @@ -715,24 +749,37 @@ Result Cheat_mapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, codeStartAddress, codeTotalSize); + if (R_FAILED(codeRes)) { + codeStartAddress = codeTotalSize = 0; + } + Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, heapStartAddress, heapTotalSize); + if (R_FAILED(heapRes)) { + heapStartAddress = heapTotalSize = 0; + } - if (R_SUCCEEDED(codeRes | heapRes)) { + + if (R_SUCCEEDED(codeRes) || R_SUCCEEDED(heapRes)) { cheat->valid = Cheat_applyCheat(cheat); - if (R_SUCCEEDED(codeRes)) + if (R_SUCCEEDED(codeRes)) { svcUnmapProcessMemoryEx(processHandle, codeDestAddress, codeTotalSize); - if (R_SUCCEEDED(heapRes)) + } + if (R_SUCCEEDED(heapRes)) { svcUnmapProcessMemoryEx(processHandle, heapDestAddress, heapTotalSize); - + } svcCloseHandle(processHandle); cheat->active = 1; } else { svcCloseHandle(processHandle); + sprintf(failureReason, "Can not map any memory"); + return codeRes; } + } else { + sprintf(failureReason, "Open process failed"); } return res; } @@ -1033,28 +1080,33 @@ void RosalinaMenu_Cheats(void) { } else { s32 selected = 0, page = 0, pagePrev = 0; + Result r = 0; do { Draw_Lock(); - if (page != pagePrev) { + if (page != pagePrev || R_FAILED(r)) { Draw_ClearFramebuffer(); } - Draw_DrawFormattedString(10, 10, COLOR_TITLE, "Cheat list"); + if (R_SUCCEEDED(r)) { + Draw_DrawFormattedString(10, 10, COLOR_TITLE, "Cheat list"); - for (s32 i = 0; - i < CHEATS_PER_MENU_PAGE - && page * CHEATS_PER_MENU_PAGE + i < cheatCount; - i++) { - char buf[65] = { 0 }; - s32 j = page * CHEATS_PER_MENU_PAGE + i; - const char * checkbox = (cheats[j]->active ? "(x) " : "( ) "); - const char * keyAct = (cheats[j]->keyActivated ? "*" : " "); - sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); + for (s32 i = 0; + i < CHEATS_PER_MENU_PAGE + && page * CHEATS_PER_MENU_PAGE + i < cheatCount; + i++) { + char buf[65] = { 0 }; + s32 j = page * CHEATS_PER_MENU_PAGE + i; + const char * checkbox = (cheats[j]->active ? "(x) " : "( ) "); + const char * keyAct = (cheats[j]->keyActivated ? "*" : " "); + sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); - Draw_DrawString(30, 30 + i * SPACING_Y, cheats[j]->valid ? COLOR_WHITE : COLOR_RED, buf); - Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, - j == selected ? '>' : ' '); + Draw_DrawString(30, 30 + i * SPACING_Y, cheats[j]->valid ? COLOR_WHITE : COLOR_RED, buf); + Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, + j == selected ? '>' : ' '); + } + } else { + Draw_DrawFormattedString(10, 10, COLOR_TITLE, "ERROR: %08x", r); + Draw_DrawFormattedString(10, 30, COLOR_RED, failureReason); } - Draw_FlushFramebuffer(); Draw_Unlock(); @@ -1070,11 +1122,11 @@ void RosalinaMenu_Cheats(void) { if (pressed & BUTTON_B) break; - else if (pressed & BUTTON_A) { + else if ((pressed & BUTTON_A) && R_SUCCEEDED(r)) { if (cheats[selected]->active) { cheats[selected]->active = 0; } else { - Cheat_mapMemoryAndApplyCheat(pid, cheats[selected]); + r = Cheat_mapMemoryAndApplyCheat(pid, cheats[selected]); } hasKeyActivated = 0; for (int i = 0; i < cheatCount; i++) { From 0f4d66dd6163a345a77c80dc8b8aa227b94e3e5d Mon Sep 17 00:00:00 2001 From: Duckbill Date: Wed, 3 Jan 2018 11:48:10 +0300 Subject: [PATCH 11/17] Try to load cheats if there aren't any on every open of cheats menu. --- sysmodules/rosalina/source/menus/cheats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 3e173e6..2b6c1d5 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -1053,7 +1053,7 @@ void RosalinaMenu_Cheats(void) { u32 pid = Cheat_GetCurrentPID(&titleId); if (titleId != 0) { - if (cheatTitleInfo != titleId) { + if (cheatTitleInfo != titleId || cheatCount == 0) { Cheat_loadCheatsIntoMemory(titleId); } } From 7e8da0d2363de6cb4dd9d942ae8e9634502984af Mon Sep 17 00:00:00 2001 From: Duckbill Date: Wed, 10 Jan 2018 09:53:36 +0300 Subject: [PATCH 12/17] Possible out of bounds fix --- sysmodules/rosalina/source/menus/cheats.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 2b6c1d5..84708cc 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -113,36 +113,35 @@ CheatState cheat_state = { 0 }; u8 cheatCount = 0; u8 hasKeyActivated = 0; u64 cheatTitleInfo = -1ULL; -//CheatDescription cheatDescriptions[0x20] = { 0 }; char failureReason[64]; -bool Cheat_isValidAddress(u32 address) { - if (codeStartAddress <= address && address <= codeStartAddress + codeTotalSize) { +bool Cheat_isValidAddress(u32 address, u32 size) { + if (codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) { return true; } - if (heapStartAddress <= address && address <= heapStartAddress + heapTotalSize) { + if (heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) { return true; } return false; } bool Cheat_write8(u32 offset, u8 value) { - if (Cheat_isValidAddress(cheat_state.offset + offset)) { + if (Cheat_isValidAddress(cheat_state.offset + offset, 1)) { *((u8*) (cheat_state.offset + offset)) = value; return true; } return false; } bool Cheat_write16(u32 offset, u16 value) { - if (Cheat_isValidAddress(cheat_state.offset + offset)) { + if (Cheat_isValidAddress(cheat_state.offset + offset, 2)) { *((u16*) (cheat_state.offset + offset)) = value; return true; } return false; } bool Cheat_write32(u32 offset, u32 value) { - if (Cheat_isValidAddress(cheat_state.offset + offset)) { + if (Cheat_isValidAddress(cheat_state.offset + offset, 4)) { *((u32*) (cheat_state.offset + offset)) = value; return true; } @@ -150,21 +149,21 @@ bool Cheat_write32(u32 offset, u32 value) { } bool Cheat_read8(u32 offset, u8* retValue) { - if (Cheat_isValidAddress(cheat_state.offset + offset)) { + if (Cheat_isValidAddress(cheat_state.offset + offset, 1)) { *retValue = *((u8*) (cheat_state.offset + offset)); return true; } return false; } bool Cheat_read16(u32 offset, u16* retValue) { - if (Cheat_isValidAddress(cheat_state.offset + offset)) { + if (Cheat_isValidAddress(cheat_state.offset + offset, 2)) { *retValue = *((u16*) (cheat_state.offset + offset)); return true; } return false; } bool Cheat_read32(u32 offset, u32* retValue) { - if (Cheat_isValidAddress(cheat_state.offset + offset)) { + if (Cheat_isValidAddress(cheat_state.offset + offset, 4)) { *retValue = *((u32*) (cheat_state.offset + offset)); return true; } From ec7ae35da1e6b5d02d8f99ad9bea5a90afad15a8 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Fri, 12 Jan 2018 10:46:50 +0300 Subject: [PATCH 13/17] Fixes for masked 16-bit cheat opcodes, based on existing cheats. --- sysmodules/rosalina/source/menus/cheats.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 84708cc..aa77355 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -327,12 +327,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { { u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - if (mask == 0) { - mask = 0xFFFF; - } u16 value = 0; if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & mask) < (arg1 & 0xFFFF)) { + if ((value & (~mask)) < (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -352,12 +349,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { { u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - if (mask == 0) { - mask = 0xFFFF; - } u16 value = 0; if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & mask) > (arg1 & 0xFFFF)) { + if ((value & (~mask)) > (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -377,12 +371,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { { u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - if (mask == 0) { - mask = 0xFFFF; - } u16 value = 0; if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & mask) == (arg1 & 0xFFFF)) { + if ((value & (~mask)) == (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; @@ -402,12 +393,9 @@ u32 Cheat_applyCheat(const CheatDescription* const cheat) { { u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - if (mask == 0) { - mask = 0xFFFF; - } u16 value = 0; if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & mask) != (arg1 & 0xFFFF)) { + if ((value & (~mask)) != (arg1 & 0xFFFF)) { newSkip = 0; } else { newSkip = 1; From 3e67e64faa57037135b2caf9ec0c152fd63ad921 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Sat, 13 Jan 2018 13:51:28 +0300 Subject: [PATCH 14/17] Fixes after review on github --- sysmodules/rosalina/include/menus/cheats.h | 2 +- sysmodules/rosalina/source/menu.c | 2 +- sysmodules/rosalina/source/menus/cheats.c | 2175 +++++++++++--------- 3 files changed, 1165 insertions(+), 1014 deletions(-) diff --git a/sysmodules/rosalina/include/menus/cheats.h b/sysmodules/rosalina/include/menus/cheats.h index bcc6fff..17228dc 100644 --- a/sysmodules/rosalina/include/menus/cheats.h +++ b/sysmodules/rosalina/include/menus/cheats.h @@ -33,4 +33,4 @@ #define CHEATS_PER_MENU_PAGE 18 void RosalinaMenu_Cheats(void); -void Cheat_applyKeyCheats(); +void Cheat_ApplyKeyCheats(); diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index 9d5b8bf..f9a2569 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -161,7 +161,7 @@ void menuThreadMain(void) else { if (HID_PAD & 0xFFF) { - Cheat_applyKeyCheats(); + Cheat_ApplyKeyCheats(); } } svcSleepThread(50 * 1000 * 1000LL); diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index aa77355..c7cf0c4 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -38,25 +38,26 @@ #define MAKE_QWORD(hi,low) \ ((u64) ((((u64)(hi)) << 32) | (low))) -typedef struct CheatProcessInfo { - u32 pid; - u64 titleId; +typedef struct CheatProcessInfo +{ + u32 pid; + u64 titleId; } CheatProcessInfo; -typedef struct CheatDescription { - u32 active; - u32 valid; - u32 keyActivated; - u32 keyCombo; - char name[40]; - u32 codesCount; - u64 codes[0]; +typedef struct CheatDescription +{ + u32 active; + u32 valid; + u32 keyActivated; + u32 keyCombo; + char name[40]; + u32 codesCount; + u64 codes[0]; } CheatDescription; u32 codeStartAddress, heapStartAddress; u32 codeTotalSize, heapTotalSize; - CheatDescription* cheats[1024] = { 0 }; u8 cheatFileBuffer[16384] = { 0 }; u32 cheatFilePos = 0; @@ -64,48 +65,49 @@ u8 cheatBuffer[16384] = { 0 }; static CheatProcessInfo cheatinfo[0x40] = { 0 }; -s32 Cheats_FetchProcessInfo(void) { - u32 pidList[0x40]; - s32 processAmount; +static s32 Cheats_FetchProcessInfo(void) +{ + u32 pidList[0x40]; + s32 processAmount; - s64 sa, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + s64 sa, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; - svcGetProcessList(&processAmount, pidList, 0x40); + svcGetProcessList(&processAmount, pidList, 0x40); - for (s32 i = 0; i < processAmount; i++) { - Handle processHandle; - Result res = svcOpenProcess(&processHandle, pidList[i]); - if (R_FAILED(res)) - continue; + for (s32 i = 0; i < processAmount; i++) + { + Handle processHandle; + Result res = svcOpenProcess(&processHandle, pidList[i]); + if (R_FAILED(res)) continue; - cheatinfo[i].pid = pidList[i]; - svcGetProcessInfo((s64 *) &cheatinfo[i].titleId, processHandle, - 0x10001); - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - svcGetProcessInfo(&sa, processHandle, 0x10005); + cheatinfo[i].pid = pidList[i]; + svcGetProcessInfo((s64 *) &cheatinfo[i].titleId, processHandle, 0x10001); + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + svcGetProcessInfo(&sa, processHandle, 0x10005); - svcCloseHandle(processHandle); - } + svcCloseHandle(processHandle); + } - return processAmount; + return processAmount; } -typedef struct CheatState { - u32 index; - u32 offset; - u32 data; - u8 typeELine; - u8 typeEIdx; +typedef struct CheatState +{ + u32 index; + u32 offset; + u32 data; + u8 typeELine; + u8 typeEIdx; - s8 loopLine; - u32 loopCount; + s8 loopLine; + u32 loopCount; - u32 ifStack; - u32 storedStack; - u8 ifCount; - u8 storedIfCount; + u32 ifStack; + u32 storedStack; + u8 ifCount; + u8 storedIfCount; } CheatState; @@ -116,1035 +118,1184 @@ u64 cheatTitleInfo = -1ULL; char failureReason[64]; -bool Cheat_isValidAddress(u32 address, u32 size) { - if (codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) { - return true; - } - if (heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) { - return true; - } - return false; +static bool Cheat_IsValidAddress(u32 address, u32 size) +{ + if (codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) + { + return true; + } + if (heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) + { + return true; + } + return false; } -bool Cheat_write8(u32 offset, u8 value) { - if (Cheat_isValidAddress(cheat_state.offset + offset, 1)) { - *((u8*) (cheat_state.offset + offset)) = value; - return true; - } - return false; -} -bool Cheat_write16(u32 offset, u16 value) { - if (Cheat_isValidAddress(cheat_state.offset + offset, 2)) { - *((u16*) (cheat_state.offset + offset)) = value; - return true; - } - return false; -} -bool Cheat_write32(u32 offset, u32 value) { - if (Cheat_isValidAddress(cheat_state.offset + offset, 4)) { - *((u32*) (cheat_state.offset + offset)) = value; - return true; - } - return false; +static bool Cheat_Write8(u32 offset, u8 value) +{ + if (Cheat_IsValidAddress(cheat_state.offset + offset, 1)) + { + *((u8*) (cheat_state.offset + offset)) = value; + return true; + } + return false; } -bool Cheat_read8(u32 offset, u8* retValue) { - if (Cheat_isValidAddress(cheat_state.offset + offset, 1)) { - *retValue = *((u8*) (cheat_state.offset + offset)); - return true; - } - return false; -} -bool Cheat_read16(u32 offset, u16* retValue) { - if (Cheat_isValidAddress(cheat_state.offset + offset, 2)) { - *retValue = *((u16*) (cheat_state.offset + offset)); - return true; - } - return false; -} -bool Cheat_read32(u32 offset, u32* retValue) { - if (Cheat_isValidAddress(cheat_state.offset + offset, 4)) { - *retValue = *((u32*) (cheat_state.offset + offset)); - return true; - } - return false; +static bool Cheat_Write16(u32 offset, u16 value) +{ + if (Cheat_IsValidAddress(cheat_state.offset + offset, 2)) + { + *((u16*) (cheat_state.offset + offset)) = value; + return true; + } + return false; } -u8 typeEMapping[] = { 4 << 3, 5 << 3, 6 << 3, 7 << 3, 0 << 3, 1 << 3, 2 << 3, 3 - << 3 }; - -u8 Cheat_getNextTypeE(const CheatDescription* cheat) { - - if (cheat_state.typeEIdx == 7) { - cheat_state.typeEIdx = 0; - cheat_state.typeELine++; - } else { - cheat_state.typeEIdx++; - } - return (u8) ((cheat->codes[cheat_state.typeELine] - >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); +static bool Cheat_Write32(u32 offset, u32 value) +{ + if (Cheat_IsValidAddress(cheat_state.offset + offset, 4)) + { + *((u32*) (cheat_state.offset + offset)) = value; + return true; + } + return false; } -u32 Cheat_applyCheat(const CheatDescription* const cheat) { - cheat_state.index = 0; - cheat_state.offset = 0; - cheat_state.data = 0; - cheat_state.index = 0; - cheat_state.loopCount = 0; - cheat_state.loopLine = -1; - cheat_state.ifStack = 0; - cheat_state.storedStack = 0; - cheat_state.ifCount = 0; - cheat_state.storedIfCount = 0; - - while (cheat_state.index < cheat->codesCount) { - u32 skipExecution = cheat_state.ifStack & 0x00000001; - u32 arg0 = (u32) ((cheat->codes[cheat_state.index] >> 32) - & 0x00000000FFFFFFFFULL); - u32 arg1 = (u32) ((cheat->codes[cheat_state.index]) - & 0x00000000FFFFFFFFULL); - if (arg0 == 0 && arg1 == 0) { - return 0; - } - u32 code = ((arg0 >> 28) & 0x0F); - u32 subcode = ((arg0 >> 24) & 0x0F); - - switch (code) { - case 0x0: - // 0 Type - // Format: 0XXXXXXX YYYYYYYY - // Description: 32bit write of YYYYYYYY to 0XXXXXXX. - if (!skipExecution) { - if (!Cheat_write32((arg0 & 0x0FFFFFFF), arg1)) return 0; - } - break; - case 0x1: - // 1 Type - // Format: 1XXXXXXX 0000YYYY - // Description: 16bit write of YYYY to 0XXXXXXX. - if (!skipExecution) { - if (!Cheat_write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; - } - break; - case 0x2: - // 2 Type - // Format: 2XXXXXXX 000000YY - // Description: 8bit write of YY to 0XXXXXXX. - if (!skipExecution) { - if (!Cheat_write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; - } - break; - case 0x3: - // 3 Type - // Format: 3XXXXXXXX YYYYYYYY - // Description: 32bit if less than. - // Simple: If the value at address 0XXXXXXX is less than the value YYYYYYYY. - // Example: 323D6B28 10000000 - { - u32 newSkip; - u32 value = 0; - if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; - if (value < arg1) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0x4: - // 4 Type - // Format: 4XXXXXXXX YYYYYYYY - // Description: 32bit if greater than. - // Simple: If the value at address 0XXXXXXX is greater than the value YYYYYYYY. - // Example: 423D6B28 10000000 - { - u32 newSkip; - u32 value = 0; - if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; - if (value > arg1) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0x5: - // 5 Type - // Format: 5XXXXXXXX YYYYYYYY - // Description: 32bit if equal to. - // Simple: If the value at address 0XXXXXXX is equal to the value YYYYYYYY. - // Example: 523D6B28 10000000 - { - u32 newSkip; - u32 value = 0; - if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; - if (value == arg1) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0x6: - // 6 Type - // Format: 3XXXXXXXX YYYYYYYY - // Description: 32bit if not equal to. - // Simple: If the value at address 0XXXXXXX is not equal to the value YYYYYYYY. - // Example: 623D6B28 10000000 - { - u32 newSkip; - u32 value = 0; - if (!Cheat_read32(arg0 & 0x0FFFFFFF, &value)) return 0; - if (value != arg1) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0x7: - // 7 Type - // Format: 7XXXXXXXX 0000YYYY - // Description: 16bit if less than. - // Simple: If the value at address 0XXXXXXX is less than the value YYYY. - // Example: 723D6B28 00005400 - { - u32 newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & (~mask)) < (arg1 & 0xFFFF)) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0x8: - // 8 Type - // Format: 8XXXXXXXX 0000YYYY - // Description: 16bit if greater than. - // Simple: If the value at address 0XXXXXXX is greater than the value YYYY. - // Example: 823D6B28 00005400 - { - u32 newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & (~mask)) > (arg1 & 0xFFFF)) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0x9: - // 9 Type - // Format: 9XXXXXXXX 0000YYYY - // Description: 16bit if equal to. - // Simple: If the value at address 0XXXXXXX is equal to the value YYYY. - // Example: 923D6B28 00005400 - { - u32 newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & (~mask)) == (arg1 & 0xFFFF)) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - case 0xA: - // A Type - // Format: AXXXXXXXX 0000YYYY - // Description: 16bit if not equal to. - // Simple: If the value at address 0XXXXXXX is not equal to the value YYYY. - // Example: A23D6B28 00005400 - { - u32 newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - if (!Cheat_read16(arg0 & 0x0FFFFFFF, &value)) return 0; - if ((value & (~mask)) != (arg1 & 0xFFFF)) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - - case 0xB: - // B Type - // Format: BXXXXXXX 00000000 - // Description: Loads offset register. - if (!skipExecution) { - cheat_state.offset = (arg0 & 0x0FFFFFFF); - } - break; - case 0xC: - // C Type - // Format: C0000000 ZZZZZZZZ - // Description: Repeat following lines at specified offset. - // Simple: used to write a value to an address, and then continues to write that value Z number of times to all addresses at an offset determined by the (D6, D7, D8, or DC) type following it. - // Note: used with the D6, D7, D8, and DC types. C types can not be nested. - // Example: - - // C0000000 00000005 - // 023D6B28 0009896C - // DC000000 00000010 - // D2000000 00000000 - - cheat_state.loopLine = cheat_state.index; - cheat_state.loopCount = arg1; - cheat_state.storedStack = cheat_state.ifStack; - cheat_state.storedIfCount = cheat_state.ifCount; - break; - case 0xD: - switch (subcode) { - case 0x00: - // D0 Type - // Format: D0000000 00000000 - // Description: ends most recent conditional. - // Simple: type 3 through A are all "conditionals," the conditional most recently executed before this line will be terminated by it. - // Example: - - // 94000130 FFFB0000 - // 74000100 FF00000C - // 023D6B28 0009896C - // D0000000 00000000 - - // The 7 type line would be terminated. - if (cheat_state.loopLine != -1) { - if (cheat_state.ifCount > 0 - && cheat_state.ifCount - > cheat_state.storedIfCount) { - cheat_state.ifStack >>= 1; - cheat_state.ifCount--; - } else { - - if (cheat_state.loopCount > 0) { - cheat_state.loopCount--; - if (cheat_state.loopCount == 0) { - cheat_state.loopLine = -1; - } else { - if (cheat_state.loopLine != -1) { - cheat_state.index = cheat_state.loopLine; - } - } - } - } - } else { - if (cheat_state.ifCount > 0) { - cheat_state.ifStack >>= 1; - cheat_state.ifCount--; - } - } - break; - case 0x01: - // D1 Type - // Format: D1000000 00000000 - // Description: ends repeat block. - // Simple: will end all conditionals within a C type code, along with the C type itself. - // Example: - - // 94000130 FFFB0000 - // C0000000 00000010 - // 8453DA0C 00000200 - // 023D6B28 0009896C - // D6000000 00000005 - // D1000000 00000000 - - // The C line, 8 line, 0 line, and D6 line would be terminated. - if (cheat_state.loopCount > 0) { - cheat_state.ifStack = cheat_state.storedStack; - cheat_state.ifCount = cheat_state.storedIfCount; - cheat_state.loopCount--; - if (cheat_state.loopCount == 0) { - cheat_state.loopLine = -1; - } else { - if (cheat_state.loopLine != -1) { - cheat_state.index = cheat_state.loopLine; - } - } - } - break; - case 0x02: - // D2 Type - // Format: D2000000 00000000 - // Description: ends all conditionals/repeats before it and sets offset and stored to zero. - // Simple: ends all lines. - // Example: - - // 94000130 FEEF0000 - // C0000000 00000010 - // 8453DA0C 00000200 - // 023D6B28 0009896C - // D6000000 00000005 - // D2000000 00000000 - - // All lines would terminate. - if (cheat_state.loopCount > 0) { - cheat_state.loopCount--; - if (cheat_state.loopCount == 0) { - cheat_state.data = 0; - cheat_state.offset = 0; - cheat_state.loopLine = -1; - - cheat_state.ifStack = 0; - cheat_state.ifCount = 0; - } else { - if (cheat_state.loopLine != -1) { - cheat_state.index = cheat_state.loopLine; - } - } - } else { - cheat_state.data = 0; - cheat_state.offset = 0; - cheat_state.ifStack = 0; - cheat_state.ifCount = 0; - } - break; - case 0x03: - // D3 Type - // Format: D3000000 XXXXXXXX - // Description: sets offset. - // Simple: loads the address X so that lines after can modify the value at address X. - // Note: used with the D4, D5, D6, D7, D8, and DC types. - // Example: D3000000 023D6B28 - if (!skipExecution) { - cheat_state.offset = arg1; - } - break; - case 0x04: - // D4 Type - // Format: D4000000 YYYYYYYY - // Description: adds to the stored address' value. - // Simple: adds to the value at the address defined by lines D3, D9, DA, and DB. - // Note: used with the D3, D9, DA, DB, DC types. - // Example: D4000000 00000025 - if (!skipExecution) { - cheat_state.data += arg1; - } - break; - case 0x05: - // D5 Type - // Format: D5000000 YYYYYYYY - // Description: sets the stored address' value. - // Simple: makes the value at the address defined by lines D3, D9, DA, and DB to YYYYYYYY. - // Note: used with the D3, D9, DA, DB, and DC types. - // Example: D5000000 34540099 - if (!skipExecution) { - cheat_state.data = arg1; - } - break; - case 0x06: - // D6 Type - // Format: D6000000 XXXXXXXX - // Description: 32bit store and increment by 4. - // Simple: stores the value at address XXXXXXXX and to addresses in increments of 4. - // Note: used with the C, D3, and D9 types. - // Example: D3000000 023D6B28 - if (!skipExecution) { - if (!Cheat_write32(arg1, cheat_state.data)) return 0; - cheat_state.offset += 4; - } - break; - case 0x07: - // D7 Type - // Format: D7000000 XXXXXXXX - // Description: 16bit store and increment by 2. - // Simple: stores 2 bytes of the value at address XXXXXXXX and to addresses in increments of 2. - // Note: used with the C, D3, and DA types. - // Example: D7000000 023D6B28 - if (!skipExecution) { - if (!Cheat_write16(arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; - cheat_state.offset += 2; - } - break; - case 0x08: - // D8 Type - // Format: D8000000 XXXXXXXX - // Description: 8bit store and increment by 1. - // Simple: stores 1 byte of the value at address XXXXXXXX and to addresses in increments of 1. - // Note: used with the C, D3, and DB types. - // Example: D8000000 023D6B28 - if (!skipExecution) { - if (!Cheat_write8(arg1, (u8) (cheat_state.data & 0xFF))) return 0; - cheat_state.offset += 1; - } - break; - case 0x09: - // D9 Type - // Format: D9000000 XXXXXXXX - // Description: 32bit load. - // Simple: loads the value from address X. - // Note: used with the D5 and D6 types. - // Example: D9000000 023D6B28 - if (!skipExecution) { - u32 value = 0; - if (!Cheat_read32(arg1, &value)) return 0; - cheat_state.data = value; - } - break; - case 0x0A: - // DA Type - // Format: DA000000 XXXXXXXX - // Description: 16bit load. - // Simple: loads 2 bytes from address X. - // Note: used with the D5 and D7 types. - // Example: DA000000 023D6B28 - if (!skipExecution) { - u16 value = 0; - if (!Cheat_read16(arg1, &value)) return 0; - cheat_state.data = value; - } - break; - case 0x0B: - // DB Type - // Format: DB000000 XXXXXXXX - // Description: 8bit load. - // Simple: loads 1 byte from address X. - // Note: used with the D5 and D8 types. - // Example: DB000000 023D6B28 - if (!skipExecution) { - u8 value = 0; - if (!Cheat_read8(arg1, &value)) return 0; - cheat_state.data = value; - } - break; - case 0x0C: - // DC Type - // Format: DC000000 VVVVVVVV - // Description: 32bit store and increment by V. - // Simple: stores the value at address(es) before it and to addresses in increments of V. - // Note: used with the C, D3, D5, D9, D8, DB types. - // Example: DC000000 00000100 - if (!skipExecution) { - cheat_state.offset += arg1; - } - break; - case 0x0D: - // DD Type - { - u32 newSkip; - if (arg1 == 0 || (HID_PAD & arg1) == arg1) { - newSkip = 0; - } else { - newSkip = 1; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); - cheat_state.ifCount++; - } - break; - default: - return 0; - } - break; - case 0xE: - // E Type - // Format: - // EXXXXXXX UUUUUUUU - // YYYYYYYY YYYYYYYY - - // Description: writes Y to X for U bytes. - - { - u32 beginOffset = (arg0 & 0x0FFFFFFF); - u32 count = arg1; - cheat_state.typeELine = cheat_state.index; - cheat_state.typeEIdx = 7; - for (u32 i = 0; i < count; i++) { - u8 byte = Cheat_getNextTypeE(cheat); - if (!skipExecution) { - if (!Cheat_write8(beginOffset + i, byte)) return 0; - } - } - cheat_state.index = cheat_state.typeELine; - } - break; - default: - return 0; - } - cheat_state.index++; - } - return 1; +static bool Cheat_Read8(u32 offset, u8* retValue) +{ + if (Cheat_IsValidAddress(cheat_state.offset + offset, 1)) + { + *retValue = *((u8*) (cheat_state.offset + offset)); + return true; + } + return false; } -Result Cheat_mapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { - Handle processHandle; - Result res; - res = svcOpenProcess(&processHandle, pid); - if (R_SUCCEEDED(res)) { - - u32 codeDestAddress, heapDestAddress; - - s64 textStartAddress, textTotalRoundedSize, rodataTotalRoundedSize, - dataTotalRoundedSize; - - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - - svcGetProcessInfo(&textStartAddress, processHandle, 0x10005); - - codeTotalSize = (u32) (textTotalRoundedSize + rodataTotalRoundedSize - + dataTotalRoundedSize); - codeDestAddress = codeStartAddress = (u32) textStartAddress; //should be 0x00100000 - - MemInfo info; - PageInfo out; - - heapDestAddress = heapStartAddress = 0x08000000; - svcQueryProcessMemory(&info, &out, processHandle, heapStartAddress); - heapTotalSize = info.size; - - Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, - codeStartAddress, codeTotalSize); - if (R_FAILED(codeRes)) { - codeStartAddress = codeTotalSize = 0; - } - - Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, - heapStartAddress, heapTotalSize); - if (R_FAILED(heapRes)) { - heapStartAddress = heapTotalSize = 0; - } - - - if (R_SUCCEEDED(codeRes) || R_SUCCEEDED(heapRes)) { - cheat->valid = Cheat_applyCheat(cheat); - - if (R_SUCCEEDED(codeRes)) { - svcUnmapProcessMemoryEx(processHandle, codeDestAddress, - codeTotalSize); - } - if (R_SUCCEEDED(heapRes)) { - svcUnmapProcessMemoryEx(processHandle, heapDestAddress, - heapTotalSize); - } - svcCloseHandle(processHandle); - cheat->active = 1; - } else { - svcCloseHandle(processHandle); - sprintf(failureReason, "Can not map any memory"); - return codeRes; - } - } else { - sprintf(failureReason, "Open process failed"); - } - return res; +static bool Cheat_Read16(u32 offset, u16* retValue) +{ + if (Cheat_IsValidAddress(cheat_state.offset + offset, 2)) + { + *retValue = *((u16*) (cheat_state.offset + offset)); + return true; + } + return false; } -void Cheat_progIdToStr(char *strEnd, u64 progId) { - while (progId > 0) { - static const char hexDigits[] = "0123456789ABCDEF"; - *strEnd-- = hexDigits[(u32) (progId & 0xF)]; - progId >>= 4; - } +static bool Cheat_Read32(u32 offset, u32* retValue) +{ + if (Cheat_IsValidAddress(cheat_state.offset + offset, 4)) + { + *retValue = *((u32*) (cheat_state.offset + offset)); + return true; + } + return false; } -Result Cheat_fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, - int flags) { - FS_Path filePath = { PATH_ASCII, strnlen(path, 255) + 1, path }, - archivePath = { PATH_EMPTY, 1, (u8 *) "" }; +static u8 typeEMapping[] = { 4 << 3, 5 << 3, 6 << 3, 7 << 3, 0 << 3, 1 << 3, 2 << 3, 3 << 3 }; - return IFile_Open(file, archiveId, archivePath, filePath, flags); +static u8 Cheat_GetNextTypeE(const CheatDescription* cheat) +{ + + if (cheat_state.typeEIdx == 7) + { + cheat_state.typeEIdx = 0; + cheat_state.typeELine++; + } + else + { + cheat_state.typeEIdx++; + } + return (u8) ((cheat->codes[cheat_state.typeELine] >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); } -static bool Cheat_openLumaFile(IFile *file, const char *path) { - return R_SUCCEEDED(Cheat_fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ)); +static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) +{ + cheat_state.index = 0; + cheat_state.offset = 0; + cheat_state.data = 0; + cheat_state.index = 0; + cheat_state.loopCount = 0; + cheat_state.loopLine = -1; + cheat_state.ifStack = 0; + cheat_state.storedStack = 0; + cheat_state.ifCount = 0; + cheat_state.storedIfCount = 0; + + while (cheat_state.index < cheat->codesCount) + { + u32 skipExecution = cheat_state.ifStack & 0x00000001; + u32 arg0 = (u32) ((cheat->codes[cheat_state.index] >> 32) & 0x00000000FFFFFFFFULL); + u32 arg1 = (u32) ((cheat->codes[cheat_state.index]) & 0x00000000FFFFFFFFULL); + if (arg0 == 0 && arg1 == 0) + { + return 0; + } + u32 code = ((arg0 >> 28) & 0x0F); + u32 subcode = ((arg0 >> 24) & 0x0F); + + switch (code) + { + case 0x0: + // 0 Type + // Format: 0XXXXXXX YYYYYYYY + // Description: 32bit write of YYYYYYYY to 0XXXXXXX. + if (!skipExecution) + { + if (!Cheat_Write32((arg0 & 0x0FFFFFFF), arg1)) return 0; + } + break; + case 0x1: + // 1 Type + // Format: 1XXXXXXX 0000YYYY + // Description: 16bit write of YYYY to 0XXXXXXX. + if (!skipExecution) + { + if (!Cheat_Write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; + } + break; + case 0x2: + // 2 Type + // Format: 2XXXXXXX 000000YY + // Description: 8bit write of YY to 0XXXXXXX. + if (!skipExecution) + { + if (!Cheat_Write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; + } + break; + case 0x3: + // 3 Type + // Format: 3XXXXXXXX YYYYYYYY + // Description: 32bit if less than. + // Simple: If the value at address 0XXXXXXX is less than the value YYYYYYYY. + // Example: 323D6B28 10000000 + { + u32 newSkip; + u32 value = 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value < arg1) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x4: + // 4 Type + // Format: 4XXXXXXXX YYYYYYYY + // Description: 32bit if greater than. + // Simple: If the value at address 0XXXXXXX is greater than the value YYYYYYYY. + // Example: 423D6B28 10000000 + { + u32 newSkip; + u32 value = 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value > arg1) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x5: + // 5 Type + // Format: 5XXXXXXXX YYYYYYYY + // Description: 32bit if equal to. + // Simple: If the value at address 0XXXXXXX is equal to the value YYYYYYYY. + // Example: 523D6B28 10000000 + { + u32 newSkip; + u32 value = 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value == arg1) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x6: + // 6 Type + // Format: 3XXXXXXXX YYYYYYYY + // Description: 32bit if not equal to. + // Simple: If the value at address 0XXXXXXX is not equal to the value YYYYYYYY. + // Example: 623D6B28 10000000 + { + u32 newSkip; + u32 value = 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (value != arg1) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x7: + // 7 Type + // Format: 7XXXXXXXX 0000YYYY + // Description: 16bit if less than. + // Simple: If the value at address 0XXXXXXX is less than the value YYYY. + // Example: 723D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + u16 value = 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & (~mask)) < (arg1 & 0xFFFF)) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x8: + // 8 Type + // Format: 8XXXXXXXX 0000YYYY + // Description: 16bit if greater than. + // Simple: If the value at address 0XXXXXXX is greater than the value YYYY. + // Example: 823D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + u16 value = 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & (~mask)) > (arg1 & 0xFFFF)) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0x9: + // 9 Type + // Format: 9XXXXXXXX 0000YYYY + // Description: 16bit if equal to. + // Simple: If the value at address 0XXXXXXX is equal to the value YYYY. + // Example: 923D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + u16 value = 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & (~mask)) == (arg1 & 0xFFFF)) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + case 0xA: + // A Type + // Format: AXXXXXXXX 0000YYYY + // Description: 16bit if not equal to. + // Simple: If the value at address 0XXXXXXX is not equal to the value YYYY. + // Example: A23D6B28 00005400 + { + u32 newSkip; + u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); + u16 value = 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if ((value & (~mask)) != (arg1 & 0xFFFF)) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + + case 0xB: + // B Type + // Format: BXXXXXXX 00000000 + // Description: Loads offset register. + if (!skipExecution) + { + cheat_state.offset = (arg0 & 0x0FFFFFFF); + } + break; + case 0xC: + // C Type + // Format: C0000000 ZZZZZZZZ + // Description: Repeat following lines at specified offset. + // Simple: used to write a value to an address, and then continues to write that value Z number of times to all addresses at an offset determined by the (D6, D7, D8, or DC) type following it. + // Note: used with the D6, D7, D8, and DC types. C types can not be nested. + // Example: + + // C0000000 00000005 + // 023D6B28 0009896C + // DC000000 00000010 + // D2000000 00000000 + + cheat_state.loopLine = cheat_state.index; + cheat_state.loopCount = arg1; + cheat_state.storedStack = cheat_state.ifStack; + cheat_state.storedIfCount = cheat_state.ifCount; + break; + case 0xD: + switch (subcode) + { + case 0x00: + // D0 Type + // Format: D0000000 00000000 + // Description: ends most recent conditional. + // Simple: type 3 through A are all "conditionals," the conditional most recently executed before this line will be terminated by it. + // Example: + + // 94000130 FFFB0000 + // 74000100 FF00000C + // 023D6B28 0009896C + // D0000000 00000000 + + // The 7 type line would be terminated. + if (cheat_state.loopLine != -1) + { + if (cheat_state.ifCount > 0 && cheat_state.ifCount > cheat_state.storedIfCount) + { + cheat_state.ifStack >>= 1; + cheat_state.ifCount--; + } + else + { + + if (cheat_state.loopCount > 0) + { + cheat_state.loopCount--; + if (cheat_state.loopCount == 0) + { + cheat_state.loopLine = -1; + } + else + { + if (cheat_state.loopLine != -1) + { + cheat_state.index = cheat_state.loopLine; + } + } + } + } + } + else + { + if (cheat_state.ifCount > 0) + { + cheat_state.ifStack >>= 1; + cheat_state.ifCount--; + } + } + break; + case 0x01: + // D1 Type + // Format: D1000000 00000000 + // Description: ends repeat block. + // Simple: will end all conditionals within a C type code, along with the C type itself. + // Example: + + // 94000130 FFFB0000 + // C0000000 00000010 + // 8453DA0C 00000200 + // 023D6B28 0009896C + // D6000000 00000005 + // D1000000 00000000 + + // The C line, 8 line, 0 line, and D6 line would be terminated. + if (cheat_state.loopCount > 0) + { + cheat_state.ifStack = cheat_state.storedStack; + cheat_state.ifCount = cheat_state.storedIfCount; + cheat_state.loopCount--; + if (cheat_state.loopCount == 0) + { + cheat_state.loopLine = -1; + } + else + { + if (cheat_state.loopLine != -1) + { + cheat_state.index = cheat_state.loopLine; + } + } + } + break; + case 0x02: + // D2 Type + // Format: D2000000 00000000 + // Description: ends all conditionals/repeats before it and sets offset and stored to zero. + // Simple: ends all lines. + // Example: + + // 94000130 FEEF0000 + // C0000000 00000010 + // 8453DA0C 00000200 + // 023D6B28 0009896C + // D6000000 00000005 + // D2000000 00000000 + + // All lines would terminate. + if (cheat_state.loopCount > 0) + { + cheat_state.loopCount--; + if (cheat_state.loopCount == 0) + { + cheat_state.data = 0; + cheat_state.offset = 0; + cheat_state.loopLine = -1; + + cheat_state.ifStack = 0; + cheat_state.ifCount = 0; + } + else + { + if (cheat_state.loopLine != -1) + { + cheat_state.index = cheat_state.loopLine; + } + } + } + else + { + cheat_state.data = 0; + cheat_state.offset = 0; + cheat_state.ifStack = 0; + cheat_state.ifCount = 0; + } + break; + case 0x03: + // D3 Type + // Format: D3000000 XXXXXXXX + // Description: sets offset. + // Simple: loads the address X so that lines after can modify the value at address X. + // Note: used with the D4, D5, D6, D7, D8, and DC types. + // Example: D3000000 023D6B28 + if (!skipExecution) + { + cheat_state.offset = arg1; + } + break; + case 0x04: + // D4 Type + // Format: D4000000 YYYYYYYY + // Description: adds to the stored address' value. + // Simple: adds to the value at the address defined by lines D3, D9, DA, and DB. + // Note: used with the D3, D9, DA, DB, DC types. + // Example: D4000000 00000025 + if (!skipExecution) + { + cheat_state.data += arg1; + } + break; + case 0x05: + // D5 Type + // Format: D5000000 YYYYYYYY + // Description: sets the stored address' value. + // Simple: makes the value at the address defined by lines D3, D9, DA, and DB to YYYYYYYY. + // Note: used with the D3, D9, DA, DB, and DC types. + // Example: D5000000 34540099 + if (!skipExecution) + { + cheat_state.data = arg1; + } + break; + case 0x06: + // D6 Type + // Format: D6000000 XXXXXXXX + // Description: 32bit store and increment by 4. + // Simple: stores the value at address XXXXXXXX and to addresses in increments of 4. + // Note: used with the C, D3, and D9 types. + // Example: D3000000 023D6B28 + if (!skipExecution) + { + if (!Cheat_Write32(arg1, cheat_state.data)) return 0; + cheat_state.offset += 4; + } + break; + case 0x07: + // D7 Type + // Format: D7000000 XXXXXXXX + // Description: 16bit store and increment by 2. + // Simple: stores 2 bytes of the value at address XXXXXXXX and to addresses in increments of 2. + // Note: used with the C, D3, and DA types. + // Example: D7000000 023D6B28 + if (!skipExecution) + { + if (!Cheat_Write16(arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; + cheat_state.offset += 2; + } + break; + case 0x08: + // D8 Type + // Format: D8000000 XXXXXXXX + // Description: 8bit store and increment by 1. + // Simple: stores 1 byte of the value at address XXXXXXXX and to addresses in increments of 1. + // Note: used with the C, D3, and DB types. + // Example: D8000000 023D6B28 + if (!skipExecution) + { + if (!Cheat_Write8(arg1, (u8) (cheat_state.data & 0xFF))) return 0; + cheat_state.offset += 1; + } + break; + case 0x09: + // D9 Type + // Format: D9000000 XXXXXXXX + // Description: 32bit load. + // Simple: loads the value from address X. + // Note: used with the D5 and D6 types. + // Example: D9000000 023D6B28 + if (!skipExecution) + { + u32 value = 0; + if (!Cheat_Read32(arg1, &value)) return 0; + cheat_state.data = value; + } + break; + case 0x0A: + // DA Type + // Format: DA000000 XXXXXXXX + // Description: 16bit load. + // Simple: loads 2 bytes from address X. + // Note: used with the D5 and D7 types. + // Example: DA000000 023D6B28 + if (!skipExecution) + { + u16 value = 0; + if (!Cheat_Read16(arg1, &value)) return 0; + cheat_state.data = value; + } + break; + case 0x0B: + // DB Type + // Format: DB000000 XXXXXXXX + // Description: 8bit load. + // Simple: loads 1 byte from address X. + // Note: used with the D5 and D8 types. + // Example: DB000000 023D6B28 + if (!skipExecution) + { + u8 value = 0; + if (!Cheat_Read8(arg1, &value)) return 0; + cheat_state.data = value; + } + break; + case 0x0C: + // DC Type + // Format: DC000000 VVVVVVVV + // Description: 32bit store and increment by V. + // Simple: stores the value at address(es) before it and to addresses in increments of V. + // Note: used with the C, D3, D5, D9, D8, DB types. + // Example: DC000000 00000100 + if (!skipExecution) + { + cheat_state.offset += arg1; + } + break; + case 0x0D: + // DD Type + { + u32 newSkip; + if (arg1 == 0 || (HID_PAD & arg1) == arg1) + { + newSkip = 0; + } + else + { + newSkip = 1; + } + + cheat_state.ifStack <<= 1; + cheat_state.ifStack |= ((newSkip | skipExecution) & 0x1); + cheat_state.ifCount++; + } + break; + default: + return 0; + } + break; + case 0xE: + // E Type + // Format: + // EXXXXXXX UUUUUUUU + // YYYYYYYY YYYYYYYY + + // Description: writes Y to X for U bytes. + + { + u32 beginOffset = (arg0 & 0x0FFFFFFF); + u32 count = arg1; + cheat_state.typeELine = cheat_state.index; + cheat_state.typeEIdx = 7; + for (u32 i = 0; i < count; i++) + { + u8 byte = Cheat_GetNextTypeE(cheat); + if (!skipExecution) + { + if (!Cheat_Write8(beginOffset + i, byte)) return 0; + } + } + cheat_state.index = cheat_state.typeELine; + } + break; + default: + return 0; + } + cheat_state.index++; + } + return 1; } -CheatDescription* Cheat_allocCheat() { - CheatDescription* cheat; - if (cheatCount == 0) { - cheat = (CheatDescription*) cheatBuffer; - } else { - CheatDescription* prev = cheats[cheatCount - 1]; - cheat = (CheatDescription *) ((u8*) (prev) + sizeof(CheatDescription) - + sizeof(u64) * (prev->codesCount)); - } - cheat->active = 0; - cheat->valid = 1; - cheat->codesCount = 0; - cheat->keyActivated = 0; - cheat->keyCombo = 0; - cheat->name[0] = '\0'; +static Result Cheat_MapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) +{ + Handle processHandle; + Result res; + res = svcOpenProcess(&processHandle, pid); + if (R_SUCCEEDED(res)) + { - cheats[cheatCount] = cheat; - cheatCount++; - return cheat; + u32 codeDestAddress, heapDestAddress; + + s64 textStartAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + svcGetProcessInfo(&textStartAddress, processHandle, 0x10005); + + codeTotalSize = (u32) (textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + codeDestAddress = codeStartAddress = (u32) textStartAddress; //should be 0x00100000 + + MemInfo info; + PageInfo out; + + heapDestAddress = heapStartAddress = 0x08000000; + svcQueryProcessMemory(&info, &out, processHandle, heapStartAddress); + heapTotalSize = info.size; + + Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, codeStartAddress, codeTotalSize); + if (R_FAILED(codeRes)) + { + codeStartAddress = codeTotalSize = 0; + } + + Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, heapStartAddress, heapTotalSize); + if (R_FAILED(heapRes)) + { + heapStartAddress = heapTotalSize = 0; + } + + if (R_SUCCEEDED(codeRes) || R_SUCCEEDED(heapRes)) + { + cheat->valid = Cheat_ApplyCheat(cheat); + + if (R_SUCCEEDED(codeRes)) + { + svcUnmapProcessMemoryEx(processHandle, codeDestAddress, codeTotalSize); + } + if (R_SUCCEEDED(heapRes)) + { + svcUnmapProcessMemoryEx(processHandle, heapDestAddress, heapTotalSize); + } + svcCloseHandle(processHandle); + cheat->active = 1; + } + else + { + svcCloseHandle(processHandle); + sprintf(failureReason, "Can not map any memory"); + return codeRes; + } + } + else + { + sprintf(failureReason, "Open process failed"); + } + return res; } -void Cheat_addCode(CheatDescription* cheat, u64 code) { - if (cheat) { - cheat->codes[cheat->codesCount] = code; - (cheat->codesCount)++; - } +static CheatDescription* Cheat_AllocCheat() +{ + CheatDescription* cheat; + if (cheatCount == 0) + { + cheat = (CheatDescription*) cheatBuffer; + } + else + { + CheatDescription* prev = cheats[cheatCount - 1]; + cheat = (CheatDescription *) ((u8*) (prev) + sizeof(CheatDescription) + sizeof(u64) * (prev->codesCount)); + } + cheat->active = 0; + cheat->valid = 1; + cheat->codesCount = 0; + cheat->keyActivated = 0; + cheat->keyCombo = 0; + cheat->name[0] = '\0'; + + cheats[cheatCount] = cheat; + cheatCount++; + return cheat; } -Result Cheat_readLine(char* line) { - Result res = 0; - - char c = '\0'; - u32 idx = 0; - while (R_SUCCEEDED(res)) { - c = cheatFileBuffer[cheatFilePos++]; - res = c ? 0 : -1; - if (R_SUCCEEDED(res) && c != '\0') { - if (c == '\n' || c == '\r' || idx >= 1023) { - line[idx++] = '\0'; - return idx; - } else { - line[idx++] = c; - } - } else { - if (idx > 0) { - line[idx++] = '\0'; - return idx; - } - } - } - return res; +static void Cheat_AddCode(CheatDescription* cheat, u64 code) +{ + if (cheat) + { + cheat->codes[cheat->codesCount] = code; + (cheat->codesCount)++; + } } -bool Cheat_isCodeLine(const char *line) { - s32 len = strnlen(line, 1023); - if (len != 17) { - return false; - } - if (line[8] != ' ') { - return false; - } +static Result Cheat_ReadLine(char* line) +{ + Result res = 0; - int i; - for (i = 0; i < 8; i++) { - char c = line[i]; - if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') - || ('a' <= c && c <= 'f'))) { - return false; - } - } - - for (i = 9; i < 17; i++) { - char c = line[i]; - if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') - || ('a' <= c && c <= 'f'))) { - return false; - } - } - - return true; + char c = '\0'; + u32 idx = 0; + while (R_SUCCEEDED(res)) + { + c = cheatFileBuffer[cheatFilePos++]; + res = c ? 0 : -1; + if (R_SUCCEEDED(res) && c != '\0') + { + if (c == '\n' || c == '\r' || idx >= 1023) + { + line[idx++] = '\0'; + return idx; + } + else + { + line[idx++] = c; + } + } + else + { + if (idx > 0) + { + line[idx++] = '\0'; + return idx; + } + } + } + return res; } -u64 Cheat_getCode(const char *line) { - u64 tmp = 0; - int i; - for (i = 0; i < 8; i++) { - char c = line[i]; - u8 code = 0; - if ('0' <= c && c <= '9') { - code = c - '0'; - } - if ('A' <= c && c <= 'F') { - code = c - 'A' + 10; - } - if ('a' <= c && c <= 'f') { - code = c - 'a' + 10; - } - tmp <<= 4; - tmp |= (code & 0xF); - } +static bool Cheat_IsCodeLine(const char *line) +{ + s32 len = strnlen(line, 1023); + if (len != 17) + { + return false; + } + if (line[8] != ' ') + { + return false; + } - for (i = 9; i < 17; i++) { - char c = line[i]; - u8 code = 0; - if ('0' <= c && c <= '9') { - code = c - '0'; - } - if ('A' <= c && c <= 'F') { - code = c - 'A' + 10; - } - if ('a' <= c && c <= 'f') { - code = c - 'a' + 10; - } - tmp <<= 4; - tmp |= (code & 0xF); - } + int i; + for (i = 0; i < 8; i++) + { + char c = line[i]; + if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'))) + { + return false; + } + } - return tmp; + for (i = 9; i < 17; i++) + { + char c = line[i]; + if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'))) + { + return false; + } + } + + return true; } -void Cheat_loadCheatsIntoMemory(u64 titleId) { - cheatCount = 0; - cheatTitleInfo = titleId; - hasKeyActivated = 0; +static u64 Cheat_GetCode(const char *line) +{ + u64 tmp = 0; + int i; + for (i = 0; i < 8; i++) + { + char c = line[i]; + u8 code = 0; + if ('0' <= c && c <= '9') + { + code = c - '0'; + } + if ('A' <= c && c <= 'F') + { + code = c - 'A' + 10; + } + if ('a' <= c && c <= 'f') + { + code = c - 'a' + 10; + } + tmp <<= 4; + tmp |= (code & 0xF); + } - char path[] = "/luma/titles/0000000000000000/cheats.txt"; - Cheat_progIdToStr(path + 28, titleId); + for (i = 9; i < 17; i++) + { + char c = line[i]; + u8 code = 0; + if ('0' <= c && c <= '9') + { + code = c - '0'; + } + if ('A' <= c && c <= 'F') + { + code = c - 'A' + 10; + } + if ('a' <= c && c <= 'f') + { + code = c - 'a' + 10; + } + tmp <<= 4; + tmp |= (code & 0xF); + } - IFile file; - - if (!Cheat_openLumaFile(&file, path)) - return; - - u64 fileLen = 0; - IFile_GetSize(&file, &fileLen); - if (fileLen > 16383) { - fileLen = 16383; - } - - u64 total; - IFile_Read(&file, &total, cheatFileBuffer, fileLen); - IFile_Close(&file); - for (int i = fileLen; i < 16384; i++) { - cheatFileBuffer[i] = 0; - } - - char line[1024] = { 0 }; - Result res = 0; - CheatDescription* cheat = 0; - cheatFilePos = 0; - do { - res = Cheat_readLine(line); - if (R_SUCCEEDED(res)) { - s32 lineLen = strnlen(line, 1023); - if (!lineLen) { - continue; - } - if (line[0] == '#') { - continue; - } - if (Cheat_isCodeLine(line)) { - if (cheat) { - u64 tmp = Cheat_getCode(line); - Cheat_addCode(cheat, tmp); - if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { - cheat->keyCombo |= (tmp & 0xFFF); - cheat->keyActivated = 1; - } - } - } else { - if (!cheat) { - cheat = Cheat_allocCheat(); - } else { - if (cheat->codesCount > 0) { - // Add new cheat only if previous has body. In other case just rewrite it's name - cheat = Cheat_allocCheat(); - } - } - strncpy(cheat->name, line, 39); - } - } - } while (R_SUCCEEDED(res)); - - if ((cheatCount > 0) && (cheats[cheatCount - 1]->codesCount == 0)) { - cheatCount--; // Remove last empty cheat - } + return tmp; } -u32 Cheat_GetCurrentPID(u64* titleId) { - s32 processAmount = Cheats_FetchProcessInfo(); +static void Cheat_LoadCheatsIntoMemory(u64 titleId) +{ + cheatCount = 0; + cheatTitleInfo = titleId; + hasKeyActivated = 0; - s32 index = -1; + char path[64] = { 0 }; + sprintf(path, "/luma/titles/%016llX/cheats.txt", titleId); - for (s32 i = 0; i < processAmount; i++) { + IFile file; - if (((u32) (cheatinfo[i].titleId >> 32)) == 0x00040010 - || ((u32) (cheatinfo[i].titleId >> 32) == 0x00040000)) { - index = i; + if (R_FAILED(IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, path), FS_OPEN_READ))) + { + // OK, let's try another source + sprintf(path, "/cheats/%016llX.txt", titleId); + if (R_FAILED(IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, path), FS_OPEN_READ))) return; + }; - break; - } - } + u64 fileLen = 0; + IFile_GetSize(&file, &fileLen); + if (fileLen > 16383) + { + fileLen = 16383; + } - if (index != -1) { - *titleId = cheatinfo[index].titleId; - return cheatinfo[index].pid; - } else { - *titleId = 0; - return 0xFFFFFFFF; - } + u64 total; + IFile_Read(&file, &total, cheatFileBuffer, fileLen); + IFile_Close(&file); + for (int i = fileLen; i < 16384; i++) + { + cheatFileBuffer[i] = 0; + } + + char line[1024] = { 0 }; + Result res = 0; + CheatDescription* cheat = 0; + cheatFilePos = 0; + do + { + res = Cheat_ReadLine(line); + if (R_SUCCEEDED(res)) + { + s32 lineLen = strnlen(line, 1023); + if (!lineLen) + { + continue; + } + if (line[0] == '#') + { + continue; + } + if (Cheat_IsCodeLine(line)) + { + if (cheat) + { + u64 tmp = Cheat_GetCode(line); + Cheat_AddCode(cheat, tmp); + if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) + { + cheat->keyCombo |= (tmp & 0xFFF); + cheat->keyActivated = 1; + } + } + } + else + { + if (!cheat) + { + cheat = Cheat_AllocCheat(); + } + else + { + if (cheat->codesCount > 0) + { + // Add new cheat only if previous has body. In other case just rewrite it's name + cheat = Cheat_AllocCheat(); + } + } + strncpy(cheat->name, line, 39); + } + } + } while (R_SUCCEEDED(res)); + + if ((cheatCount > 0) && (cheats[cheatCount - 1]->codesCount == 0)) + { + cheatCount--; // Remove last empty cheat + } } -void Cheat_applyKeyCheats(void) { - if (!cheatCount) { - return; - } - if (!hasKeyActivated) { - return; - } +static u32 Cheat_GetCurrentPID(u64* titleId) +{ + s32 processAmount = Cheats_FetchProcessInfo(); - u64 titleId = 0; - u32 pid = Cheat_GetCurrentPID(&titleId); + s32 index = -1; - if (!titleId) { - cheatCount = 0; - hasKeyActivated = 0; - return; - } + for (s32 i = 0; i < processAmount; i++) + { - if (titleId != cheatTitleInfo) { - cheatCount = 0; - hasKeyActivated = 0; - return; - } + if (((u32) (cheatinfo[i].titleId >> 32)) == 0x00040010 || ((u32) (cheatinfo[i].titleId >> 32) == 0x00040000)) + { + index = i; - u32 keys = HID_PAD & 0xFFF; - for (int i = 0; i < cheatCount; i++) { - if (cheats[i]->active && cheats[i]->keyActivated - && (cheats[i]->keyCombo & keys) == keys) { - Cheat_mapMemoryAndApplyCheat(pid, cheats[i]); - } - } + break; + } + } + + if (index != -1) + { + *titleId = cheatinfo[index].titleId; + return cheatinfo[index].pid; + } + else + { + *titleId = 0; + return 0xFFFFFFFF; + } } -void RosalinaMenu_Cheats(void) { - u64 titleId = 0; - u32 pid = Cheat_GetCurrentPID(&titleId); +void Cheat_ApplyKeyCheats(void) +{ + if (!cheatCount) + { + return; + } + if (!hasKeyActivated) + { + return; + } - if (titleId != 0) { - if (cheatTitleInfo != titleId || cheatCount == 0) { - Cheat_loadCheatsIntoMemory(titleId); - } - } + u64 titleId = 0; + u32 pid = Cheat_GetCurrentPID(&titleId); - Draw_Lock(); - Draw_ClearFramebuffer(); - Draw_FlushFramebuffer(); - Draw_Unlock(); + if (!titleId) + { + cheatCount = 0; + hasKeyActivated = 0; + return; + } - if (titleId == 0 || cheatCount == 0) { - do { - Draw_Lock(); - Draw_DrawString(10, 10, COLOR_TITLE, "Cheats"); - if (titleId == 0) { - Draw_DrawString(10, 30, COLOR_WHITE, "No suitable title found"); - } else { - Draw_DrawFormattedString(10, 30, COLOR_WHITE, - "No cheats found for title %016llx", titleId); - } + if (titleId != cheatTitleInfo) + { + cheatCount = 0; + hasKeyActivated = 0; + return; + } - Draw_FlushFramebuffer(); - Draw_Unlock(); - } while (!(waitInput() & BUTTON_B) && !terminationRequest); - } else { - s32 selected = 0, page = 0, pagePrev = 0; + u32 keys = HID_PAD & 0xFFF; + for (int i = 0; i < cheatCount; i++) + { + if (cheats[i]->active && cheats[i]->keyActivated && (cheats[i]->keyCombo & keys) == keys) + { + Cheat_MapMemoryAndApplyCheat(pid, cheats[i]); + } + } +} - Result r = 0; - do { - Draw_Lock(); - if (page != pagePrev || R_FAILED(r)) { - Draw_ClearFramebuffer(); - } - if (R_SUCCEEDED(r)) { - Draw_DrawFormattedString(10, 10, COLOR_TITLE, "Cheat list"); +void RosalinaMenu_Cheats(void) +{ + u64 titleId = 0; + u32 pid = Cheat_GetCurrentPID(&titleId); - for (s32 i = 0; - i < CHEATS_PER_MENU_PAGE - && page * CHEATS_PER_MENU_PAGE + i < cheatCount; - i++) { - char buf[65] = { 0 }; - s32 j = page * CHEATS_PER_MENU_PAGE + i; - const char * checkbox = (cheats[j]->active ? "(x) " : "( ) "); - const char * keyAct = (cheats[j]->keyActivated ? "*" : " "); - sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); + if (titleId != 0) + { + if (cheatTitleInfo != titleId || cheatCount == 0) + { + Cheat_LoadCheatsIntoMemory(titleId); + } + } - Draw_DrawString(30, 30 + i * SPACING_Y, cheats[j]->valid ? COLOR_WHITE : COLOR_RED, buf); - Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, - j == selected ? '>' : ' '); - } - } else { - Draw_DrawFormattedString(10, 10, COLOR_TITLE, "ERROR: %08x", r); - Draw_DrawFormattedString(10, 30, COLOR_RED, failureReason); - } - Draw_FlushFramebuffer(); - Draw_Unlock(); + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); - if (terminationRequest) - break; + if (titleId == 0 || cheatCount == 0) + { + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Cheats"); + if (titleId == 0) + { + Draw_DrawString(10, 30, COLOR_WHITE, "No suitable title found"); + } + else + { + Draw_DrawFormattedString(10, 30, COLOR_WHITE, "No cheats found for title %016llX", titleId); + } - u32 pressed; - do { - pressed = waitInputWithTimeout(50); - if (pressed != 0) - break; - } while (pressed == 0 && !terminationRequest); + Draw_FlushFramebuffer(); + Draw_Unlock(); + } while (!(waitInput() & BUTTON_B) && !terminationRequest); + } + else + { + s32 selected = 0, page = 0, pagePrev = 0; - if (pressed & BUTTON_B) - break; - else if ((pressed & BUTTON_A) && R_SUCCEEDED(r)) { - if (cheats[selected]->active) { - cheats[selected]->active = 0; - } else { - r = Cheat_mapMemoryAndApplyCheat(pid, cheats[selected]); - } - hasKeyActivated = 0; - for (int i = 0; i < cheatCount; i++) { - if (cheats[i]->active && cheats[i]->keyActivated) { - hasKeyActivated = 1; - break; - } - } - } else if (pressed & BUTTON_DOWN) - selected++; - else if (pressed & BUTTON_UP) - selected--; - else if (pressed & BUTTON_LEFT) - selected -= CHEATS_PER_MENU_PAGE; - else if (pressed & BUTTON_RIGHT) { - if (selected + CHEATS_PER_MENU_PAGE < cheatCount) - selected += CHEATS_PER_MENU_PAGE; - else if ((cheatCount - 1) / CHEATS_PER_MENU_PAGE == page) - selected %= CHEATS_PER_MENU_PAGE; - else - selected = cheatCount - 1; - } + Result r = 0; + do + { + Draw_Lock(); + if (page != pagePrev || R_FAILED(r)) + { + Draw_ClearFramebuffer(); + } + if (R_SUCCEEDED(r)) + { + Draw_DrawFormattedString(10, 10, COLOR_TITLE, "Cheat list"); - if (selected < 0) - selected = cheatCount - 1; - else if (selected >= cheatCount) - selected = 0; + for (s32 i = 0; i < CHEATS_PER_MENU_PAGE && page * CHEATS_PER_MENU_PAGE + i < cheatCount; i++) + { + char buf[65] = { 0 }; + s32 j = page * CHEATS_PER_MENU_PAGE + i; + const char * checkbox = (cheats[j]->active ? "(x) " : "( ) "); + const char * keyAct = (cheats[j]->keyActivated ? "*" : " "); + sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); - pagePrev = page; - page = selected / CHEATS_PER_MENU_PAGE; - } while (!terminationRequest); - } + Draw_DrawString(30, 30 + i * SPACING_Y, cheats[j]->valid ? COLOR_WHITE : COLOR_RED, buf); + Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, j == selected ? '>' : ' '); + } + } + else + { + Draw_DrawFormattedString(10, 10, COLOR_TITLE, "ERROR: %08x", r); + Draw_DrawFormattedString(10, 30, COLOR_RED, failureReason); + } + Draw_FlushFramebuffer(); + Draw_Unlock(); + + if (terminationRequest) break; + + u32 pressed; + do + { + pressed = waitInputWithTimeout(50); + if (pressed != 0) break; + } while (pressed == 0 && !terminationRequest); + + if (pressed & BUTTON_B) + break; + else if ((pressed & BUTTON_A) && R_SUCCEEDED(r)) + { + if (cheats[selected]->active) + { + cheats[selected]->active = 0; + } + else + { + r = Cheat_MapMemoryAndApplyCheat(pid, cheats[selected]); + } + hasKeyActivated = 0; + for (int i = 0; i < cheatCount; i++) + { + if (cheats[i]->active && cheats[i]->keyActivated) + { + hasKeyActivated = 1; + break; + } + } + } + else if (pressed & BUTTON_DOWN) + selected++; + else if (pressed & BUTTON_UP) + selected--; + else if (pressed & BUTTON_LEFT) + selected -= CHEATS_PER_MENU_PAGE; + else if (pressed & BUTTON_RIGHT) + { + if (selected + CHEATS_PER_MENU_PAGE < cheatCount) + selected += CHEATS_PER_MENU_PAGE; + else if ((cheatCount - 1) / CHEATS_PER_MENU_PAGE == page) + selected %= CHEATS_PER_MENU_PAGE; + else selected = cheatCount - 1; + } + + if (selected < 0) + selected = cheatCount - 1; + else if (selected >= cheatCount) selected = 0; + + pagePrev = page; + page = selected / CHEATS_PER_MENU_PAGE; + } while (!terminationRequest); + } } From 1de27c54f1e576d5b09a0dd6a3cc04641c427ec7 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Sat, 13 Jan 2018 16:02:54 +0300 Subject: [PATCH 15/17] Fix range checks --- sysmodules/rosalina/source/menus/cheats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index c7cf0c4..3fbe273 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -120,11 +120,11 @@ char failureReason[64]; static bool Cheat_IsValidAddress(u32 address, u32 size) { - if (codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) + if (codeStartAddress > 0 && codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) { return true; } - if (heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) + if (heapStartAddress > 0 && heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) { return true; } From c5c8dca14cfd47d815911e780d4b91abe515cd8b Mon Sep 17 00:00:00 2001 From: Duckbill Date: Mon, 15 Jan 2018 21:29:05 +0300 Subject: [PATCH 16/17] Switched from mapping target process memory to svcReadProcessMemory & svcWriteProcessMemory functions. --- sysmodules/rosalina/source/menus/cheats.c | 186 ++++++++++------------ 1 file changed, 86 insertions(+), 100 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 3fbe273..82207ff 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -55,9 +55,6 @@ typedef struct CheatDescription u64 codes[0]; } CheatDescription; -u32 codeStartAddress, heapStartAddress; -u32 codeTotalSize, heapTotalSize; - CheatDescription* cheats[1024] = { 0 }; u8 cheatFileBuffer[16384] = { 0 }; u32 cheatFilePos = 0; @@ -118,75 +115,81 @@ u64 cheatTitleInfo = -1ULL; char failureReason[64]; -static bool Cheat_IsValidAddress(u32 address, u32 size) +static bool Cheat_IsValidAddress(const Handle processHandle, u32 address, u32 size) { - if (codeStartAddress > 0 && codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) - { - return true; - } - if (heapStartAddress > 0 && heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) - { + MemInfo info; + PageInfo out; + + Result res = svcQueryDebugProcessMemory(&info, &out, processHandle, address); + if (R_SUCCEEDED(res) && info.state != MEMSTATE_FREE && info.base_addr > 0 && info.base_addr <= address && address <= info.base_addr + info.size - size) { return true; } return false; } -static bool Cheat_Write8(u32 offset, u8 value) +static u32 ReadWriteBuffer32 = 0; +static u16 ReadWriteBuffer16 = 0; +static u8 ReadWriteBuffer8 = 0; + +static bool Cheat_Write8(const Handle processHandle, u32 offset, u8 value) { - if (Cheat_IsValidAddress(cheat_state.offset + offset, 1)) + if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 1)) { - *((u8*) (cheat_state.offset + offset)) = value; - return true; + *((u8*) (&ReadWriteBuffer8)) = value; + return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer8, cheat_state.offset + offset, 1)); } return false; } -static bool Cheat_Write16(u32 offset, u16 value) +static bool Cheat_Write16(const Handle processHandle, u32 offset, u16 value) { - if (Cheat_IsValidAddress(cheat_state.offset + offset, 2)) + if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 2)) { - *((u16*) (cheat_state.offset + offset)) = value; - return true; + *((u16*) (&ReadWriteBuffer16)) = value; + return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer16, cheat_state.offset + offset, 2)); } return false; } -static bool Cheat_Write32(u32 offset, u32 value) +static bool Cheat_Write32(const Handle processHandle, u32 offset, u32 value) { - if (Cheat_IsValidAddress(cheat_state.offset + offset, 4)) + if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 4)) { - *((u32*) (cheat_state.offset + offset)) = value; - return true; + *((u32*) (&ReadWriteBuffer32)) = value; + return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer32, cheat_state.offset + offset, 4)); } return false; } -static bool Cheat_Read8(u32 offset, u8* retValue) +static bool Cheat_Read8(const Handle processHandle, u32 offset, u8* retValue) { - if (Cheat_IsValidAddress(cheat_state.offset + offset, 1)) + if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 1)) { - *retValue = *((u8*) (cheat_state.offset + offset)); - return true; + Result res = svcReadProcessMemory(&ReadWriteBuffer8, processHandle, cheat_state.offset + offset, 1); + *retValue = *((u8*) (&ReadWriteBuffer8)); + return R_SUCCEEDED(res); } return false; } -static bool Cheat_Read16(u32 offset, u16* retValue) +static bool Cheat_Read16(const Handle processHandle, u32 offset, u16* retValue) { - if (Cheat_IsValidAddress(cheat_state.offset + offset, 2)) + if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 2)) { - *retValue = *((u16*) (cheat_state.offset + offset)); - return true; + Result res = svcReadProcessMemory(&ReadWriteBuffer16, processHandle, cheat_state.offset + offset, 2); + *retValue = *((u16*) (&ReadWriteBuffer16)); + return R_SUCCEEDED(res); } return false; } -static bool Cheat_Read32(u32 offset, u32* retValue) +static bool Cheat_Read32(const Handle processHandle, u32 offset, u32* retValue) { - if (Cheat_IsValidAddress(cheat_state.offset + offset, 4)) + if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 4)) { - *retValue = *((u32*) (cheat_state.offset + offset)); - return true; + Result res = svcReadProcessMemory(&ReadWriteBuffer32, processHandle, cheat_state.offset + offset, 4); + *retValue = *((u32*) (&ReadWriteBuffer32)); + return R_SUCCEEDED(res); } return false; } @@ -208,7 +211,7 @@ static u8 Cheat_GetNextTypeE(const CheatDescription* cheat) return (u8) ((cheat->codes[cheat_state.typeELine] >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); } -static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) +static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* const cheat) { cheat_state.index = 0; cheat_state.offset = 0; @@ -241,7 +244,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) // Description: 32bit write of YYYYYYYY to 0XXXXXXX. if (!skipExecution) { - if (!Cheat_Write32((arg0 & 0x0FFFFFFF), arg1)) return 0; + if (!Cheat_Write32(processHandle, (arg0 & 0x0FFFFFFF), arg1)) return 0; } break; case 0x1: @@ -250,7 +253,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) // Description: 16bit write of YYYY to 0XXXXXXX. if (!skipExecution) { - if (!Cheat_Write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; + if (!Cheat_Write16(processHandle, (arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; } break; case 0x2: @@ -259,7 +262,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) // Description: 8bit write of YY to 0XXXXXXX. if (!skipExecution) { - if (!Cheat_Write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; + if (!Cheat_Write8(processHandle, (arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; } break; case 0x3: @@ -271,7 +274,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if (value < arg1) { newSkip = 0; @@ -295,7 +298,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if (value > arg1) { newSkip = 0; @@ -319,7 +322,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if (value == arg1) { newSkip = 0; @@ -343,7 +346,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if (value != arg1) { newSkip = 0; @@ -368,7 +371,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) < (arg1 & 0xFFFF)) { newSkip = 0; @@ -393,7 +396,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) > (arg1 & 0xFFFF)) { newSkip = 0; @@ -418,7 +421,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) == (arg1 & 0xFFFF)) { newSkip = 0; @@ -443,7 +446,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) != (arg1 & 0xFFFF)) { newSkip = 0; @@ -659,7 +662,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) // Example: D3000000 023D6B28 if (!skipExecution) { - if (!Cheat_Write32(arg1, cheat_state.data)) return 0; + if (!Cheat_Write32(processHandle, arg1, cheat_state.data)) return 0; cheat_state.offset += 4; } break; @@ -672,7 +675,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) // Example: D7000000 023D6B28 if (!skipExecution) { - if (!Cheat_Write16(arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; + if (!Cheat_Write16(processHandle, arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; cheat_state.offset += 2; } break; @@ -685,7 +688,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) // Example: D8000000 023D6B28 if (!skipExecution) { - if (!Cheat_Write8(arg1, (u8) (cheat_state.data & 0xFF))) return 0; + if (!Cheat_Write8(processHandle, arg1, (u8) (cheat_state.data & 0xFF))) return 0; cheat_state.offset += 1; } break; @@ -699,7 +702,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) if (!skipExecution) { u32 value = 0; - if (!Cheat_Read32(arg1, &value)) return 0; + if (!Cheat_Read32(processHandle, arg1, &value)) return 0; cheat_state.data = value; } break; @@ -713,7 +716,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) if (!skipExecution) { u16 value = 0; - if (!Cheat_Read16(arg1, &value)) return 0; + if (!Cheat_Read16(processHandle, arg1, &value)) return 0; cheat_state.data = value; } break; @@ -727,7 +730,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) if (!skipExecution) { u8 value = 0; - if (!Cheat_Read8(arg1, &value)) return 0; + if (!Cheat_Read8(processHandle, arg1, &value)) return 0; cheat_state.data = value; } break; @@ -783,7 +786,7 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) u8 byte = Cheat_GetNextTypeE(cheat); if (!skipExecution) { - if (!Cheat_Write8(beginOffset + i, byte)) return 0; + if (!Cheat_Write8(processHandle, beginOffset + i, byte)) return 0; } } cheat_state.index = cheat_state.typeELine; @@ -797,66 +800,45 @@ static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) return 1; } +static void Cheat_EatEvents(Handle debug) +{ + DebugEventInfo info; + Result r; + + while(true) + { + if((r = svcGetProcessDebugEvent(&info, debug)) != 0) + { + if(r == (s32)(0xd8402009)) + { + break; + } + } + svcContinueDebugEvent(debug, 3); + } +} + static Result Cheat_MapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { Handle processHandle; + Handle debugHandle; Result res; res = svcOpenProcess(&processHandle, pid); if (R_SUCCEEDED(res)) { - - u32 codeDestAddress, heapDestAddress; - - s64 textStartAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; - - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - - svcGetProcessInfo(&textStartAddress, processHandle, 0x10005); - - codeTotalSize = (u32) (textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); - codeDestAddress = codeStartAddress = (u32) textStartAddress; //should be 0x00100000 - - MemInfo info; - PageInfo out; - - heapDestAddress = heapStartAddress = 0x08000000; - svcQueryProcessMemory(&info, &out, processHandle, heapStartAddress); - heapTotalSize = info.size; - - Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, codeStartAddress, codeTotalSize); - if (R_FAILED(codeRes)) + res = svcDebugActiveProcess(&debugHandle, pid); + if (R_SUCCEEDED(res)) { - codeStartAddress = codeTotalSize = 0; - } + Cheat_EatEvents(debugHandle); + cheat->valid = Cheat_ApplyCheat(debugHandle, cheat); - Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, heapStartAddress, heapTotalSize); - if (R_FAILED(heapRes)) - { - heapStartAddress = heapTotalSize = 0; - } - - if (R_SUCCEEDED(codeRes) || R_SUCCEEDED(heapRes)) - { - cheat->valid = Cheat_ApplyCheat(cheat); - - if (R_SUCCEEDED(codeRes)) - { - svcUnmapProcessMemoryEx(processHandle, codeDestAddress, codeTotalSize); - } - if (R_SUCCEEDED(heapRes)) - { - svcUnmapProcessMemoryEx(processHandle, heapDestAddress, heapTotalSize); - } + svcCloseHandle(debugHandle); svcCloseHandle(processHandle); cheat->active = 1; } else { svcCloseHandle(processHandle); - sprintf(failureReason, "Can not map any memory"); - return codeRes; } } else @@ -1073,8 +1055,12 @@ static void Cheat_LoadCheatsIntoMemory(u64 titleId) Cheat_AddCode(cheat, tmp); if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { - cheat->keyCombo |= (tmp & 0xFFF); - cheat->keyActivated = 1; + if (tmp & 0xFFFFFFFF) + { + // Not empty key code + cheat->keyCombo |= (tmp & 0xFFF); + cheat->keyActivated = 1; + } } } } From 1fd689f5da3aef2a95f223d7dee9f0f4fde62716 Mon Sep 17 00:00:00 2001 From: Duckbill Date: Tue, 16 Jan 2018 09:54:55 +0300 Subject: [PATCH 17/17] Revert "Switched from mapping target process memory to svcReadProcessMemory & svcWriteProcessMemory functions." This reverts commit c5c8dca14cfd47d815911e780d4b91abe515cd8b. --- sysmodules/rosalina/source/menus/cheats.c | 188 ++++++++++++---------- 1 file changed, 101 insertions(+), 87 deletions(-) diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index 82207ff..3fbe273 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -55,6 +55,9 @@ typedef struct CheatDescription u64 codes[0]; } CheatDescription; +u32 codeStartAddress, heapStartAddress; +u32 codeTotalSize, heapTotalSize; + CheatDescription* cheats[1024] = { 0 }; u8 cheatFileBuffer[16384] = { 0 }; u32 cheatFilePos = 0; @@ -115,81 +118,75 @@ u64 cheatTitleInfo = -1ULL; char failureReason[64]; -static bool Cheat_IsValidAddress(const Handle processHandle, u32 address, u32 size) +static bool Cheat_IsValidAddress(u32 address, u32 size) { - MemInfo info; - PageInfo out; - - Result res = svcQueryDebugProcessMemory(&info, &out, processHandle, address); - if (R_SUCCEEDED(res) && info.state != MEMSTATE_FREE && info.base_addr > 0 && info.base_addr <= address && address <= info.base_addr + info.size - size) { + if (codeStartAddress > 0 && codeStartAddress <= address && address <= codeStartAddress + codeTotalSize - size) + { + return true; + } + if (heapStartAddress > 0 && heapStartAddress <= address && address <= heapStartAddress + heapTotalSize - size) + { return true; } return false; } -static u32 ReadWriteBuffer32 = 0; -static u16 ReadWriteBuffer16 = 0; -static u8 ReadWriteBuffer8 = 0; - -static bool Cheat_Write8(const Handle processHandle, u32 offset, u8 value) +static bool Cheat_Write8(u32 offset, u8 value) { - if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 1)) + if (Cheat_IsValidAddress(cheat_state.offset + offset, 1)) { - *((u8*) (&ReadWriteBuffer8)) = value; - return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer8, cheat_state.offset + offset, 1)); + *((u8*) (cheat_state.offset + offset)) = value; + return true; } return false; } -static bool Cheat_Write16(const Handle processHandle, u32 offset, u16 value) +static bool Cheat_Write16(u32 offset, u16 value) { - if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 2)) + if (Cheat_IsValidAddress(cheat_state.offset + offset, 2)) { - *((u16*) (&ReadWriteBuffer16)) = value; - return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer16, cheat_state.offset + offset, 2)); + *((u16*) (cheat_state.offset + offset)) = value; + return true; } return false; } -static bool Cheat_Write32(const Handle processHandle, u32 offset, u32 value) +static bool Cheat_Write32(u32 offset, u32 value) { - if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 4)) + if (Cheat_IsValidAddress(cheat_state.offset + offset, 4)) { - *((u32*) (&ReadWriteBuffer32)) = value; - return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer32, cheat_state.offset + offset, 4)); + *((u32*) (cheat_state.offset + offset)) = value; + return true; } return false; } -static bool Cheat_Read8(const Handle processHandle, u32 offset, u8* retValue) +static bool Cheat_Read8(u32 offset, u8* retValue) { - if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 1)) + if (Cheat_IsValidAddress(cheat_state.offset + offset, 1)) { - Result res = svcReadProcessMemory(&ReadWriteBuffer8, processHandle, cheat_state.offset + offset, 1); - *retValue = *((u8*) (&ReadWriteBuffer8)); - return R_SUCCEEDED(res); + *retValue = *((u8*) (cheat_state.offset + offset)); + return true; } return false; } -static bool Cheat_Read16(const Handle processHandle, u32 offset, u16* retValue) +static bool Cheat_Read16(u32 offset, u16* retValue) { - if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 2)) + if (Cheat_IsValidAddress(cheat_state.offset + offset, 2)) { - Result res = svcReadProcessMemory(&ReadWriteBuffer16, processHandle, cheat_state.offset + offset, 2); - *retValue = *((u16*) (&ReadWriteBuffer16)); - return R_SUCCEEDED(res); + *retValue = *((u16*) (cheat_state.offset + offset)); + return true; } return false; } -static bool Cheat_Read32(const Handle processHandle, u32 offset, u32* retValue) +static bool Cheat_Read32(u32 offset, u32* retValue) { - if (Cheat_IsValidAddress(processHandle, cheat_state.offset + offset, 4)) + if (Cheat_IsValidAddress(cheat_state.offset + offset, 4)) { - Result res = svcReadProcessMemory(&ReadWriteBuffer32, processHandle, cheat_state.offset + offset, 4); - *retValue = *((u32*) (&ReadWriteBuffer32)); - return R_SUCCEEDED(res); + *retValue = *((u32*) (cheat_state.offset + offset)); + return true; } return false; } @@ -211,7 +208,7 @@ static u8 Cheat_GetNextTypeE(const CheatDescription* cheat) return (u8) ((cheat->codes[cheat_state.typeELine] >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); } -static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* const cheat) +static u32 Cheat_ApplyCheat(const CheatDescription* const cheat) { cheat_state.index = 0; cheat_state.offset = 0; @@ -244,7 +241,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* // Description: 32bit write of YYYYYYYY to 0XXXXXXX. if (!skipExecution) { - if (!Cheat_Write32(processHandle, (arg0 & 0x0FFFFFFF), arg1)) return 0; + if (!Cheat_Write32((arg0 & 0x0FFFFFFF), arg1)) return 0; } break; case 0x1: @@ -253,7 +250,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* // Description: 16bit write of YYYY to 0XXXXXXX. if (!skipExecution) { - if (!Cheat_Write16(processHandle, (arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; + if (!Cheat_Write16((arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; } break; case 0x2: @@ -262,7 +259,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* // Description: 8bit write of YY to 0XXXXXXX. if (!skipExecution) { - if (!Cheat_Write8(processHandle, (arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; + if (!Cheat_Write8((arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; } break; case 0x3: @@ -274,7 +271,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; if (value < arg1) { newSkip = 0; @@ -298,7 +295,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; if (value > arg1) { newSkip = 0; @@ -322,7 +319,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; if (value == arg1) { newSkip = 0; @@ -346,7 +343,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* { u32 newSkip; u32 value = 0; - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read32(arg0 & 0x0FFFFFFF, &value)) return 0; if (value != arg1) { newSkip = 0; @@ -371,7 +368,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) < (arg1 & 0xFFFF)) { newSkip = 0; @@ -396,7 +393,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) > (arg1 & 0xFFFF)) { newSkip = 0; @@ -421,7 +418,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) == (arg1 & 0xFFFF)) { newSkip = 0; @@ -446,7 +443,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* u32 newSkip; u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); u16 value = 0; - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; + if (!Cheat_Read16(arg0 & 0x0FFFFFFF, &value)) return 0; if ((value & (~mask)) != (arg1 & 0xFFFF)) { newSkip = 0; @@ -662,7 +659,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* // Example: D3000000 023D6B28 if (!skipExecution) { - if (!Cheat_Write32(processHandle, arg1, cheat_state.data)) return 0; + if (!Cheat_Write32(arg1, cheat_state.data)) return 0; cheat_state.offset += 4; } break; @@ -675,7 +672,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* // Example: D7000000 023D6B28 if (!skipExecution) { - if (!Cheat_Write16(processHandle, arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; + if (!Cheat_Write16(arg1, (u16) (cheat_state.data & 0xFFFF))) return 0; cheat_state.offset += 2; } break; @@ -688,7 +685,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* // Example: D8000000 023D6B28 if (!skipExecution) { - if (!Cheat_Write8(processHandle, arg1, (u8) (cheat_state.data & 0xFF))) return 0; + if (!Cheat_Write8(arg1, (u8) (cheat_state.data & 0xFF))) return 0; cheat_state.offset += 1; } break; @@ -702,7 +699,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* if (!skipExecution) { u32 value = 0; - if (!Cheat_Read32(processHandle, arg1, &value)) return 0; + if (!Cheat_Read32(arg1, &value)) return 0; cheat_state.data = value; } break; @@ -716,7 +713,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* if (!skipExecution) { u16 value = 0; - if (!Cheat_Read16(processHandle, arg1, &value)) return 0; + if (!Cheat_Read16(arg1, &value)) return 0; cheat_state.data = value; } break; @@ -730,7 +727,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* if (!skipExecution) { u8 value = 0; - if (!Cheat_Read8(processHandle, arg1, &value)) return 0; + if (!Cheat_Read8(arg1, &value)) return 0; cheat_state.data = value; } break; @@ -786,7 +783,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* u8 byte = Cheat_GetNextTypeE(cheat); if (!skipExecution) { - if (!Cheat_Write8(processHandle, beginOffset + i, byte)) return 0; + if (!Cheat_Write8(beginOffset + i, byte)) return 0; } } cheat_state.index = cheat_state.typeELine; @@ -800,45 +797,66 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, const CheatDescription* return 1; } -static void Cheat_EatEvents(Handle debug) -{ - DebugEventInfo info; - Result r; - - while(true) - { - if((r = svcGetProcessDebugEvent(&info, debug)) != 0) - { - if(r == (s32)(0xd8402009)) - { - break; - } - } - svcContinueDebugEvent(debug, 3); - } -} - static Result Cheat_MapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) { Handle processHandle; - Handle debugHandle; Result res; res = svcOpenProcess(&processHandle, pid); if (R_SUCCEEDED(res)) { - res = svcDebugActiveProcess(&debugHandle, pid); - if (R_SUCCEEDED(res)) - { - Cheat_EatEvents(debugHandle); - cheat->valid = Cheat_ApplyCheat(debugHandle, cheat); - svcCloseHandle(debugHandle); + u32 codeDestAddress, heapDestAddress; + + s64 textStartAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + svcGetProcessInfo(&textStartAddress, processHandle, 0x10005); + + codeTotalSize = (u32) (textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + codeDestAddress = codeStartAddress = (u32) textStartAddress; //should be 0x00100000 + + MemInfo info; + PageInfo out; + + heapDestAddress = heapStartAddress = 0x08000000; + svcQueryProcessMemory(&info, &out, processHandle, heapStartAddress); + heapTotalSize = info.size; + + Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, codeStartAddress, codeTotalSize); + if (R_FAILED(codeRes)) + { + codeStartAddress = codeTotalSize = 0; + } + + Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, heapStartAddress, heapTotalSize); + if (R_FAILED(heapRes)) + { + heapStartAddress = heapTotalSize = 0; + } + + if (R_SUCCEEDED(codeRes) || R_SUCCEEDED(heapRes)) + { + cheat->valid = Cheat_ApplyCheat(cheat); + + if (R_SUCCEEDED(codeRes)) + { + svcUnmapProcessMemoryEx(processHandle, codeDestAddress, codeTotalSize); + } + if (R_SUCCEEDED(heapRes)) + { + svcUnmapProcessMemoryEx(processHandle, heapDestAddress, heapTotalSize); + } svcCloseHandle(processHandle); cheat->active = 1; } else { svcCloseHandle(processHandle); + sprintf(failureReason, "Can not map any memory"); + return codeRes; } } else @@ -1055,12 +1073,8 @@ static void Cheat_LoadCheatsIntoMemory(u64 titleId) Cheat_AddCode(cheat, tmp); if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) { - if (tmp & 0xFFFFFFFF) - { - // Not empty key code - cheat->keyCombo |= (tmp & 0xFFF); - cheat->keyActivated = 1; - } + cheat->keyCombo |= (tmp & 0xFFF); + cheat->keyActivated = 1; } } }