diff --git a/.gitignore b/.gitignore index e40b50e..d211038 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ output build *.cia +# ignore visual studio project files +*.opensdf +*.sdf +*.sln +*.suo +*.vcxproj +*.vcxproj.filters +*.vcxproj.user + +*.log diff --git a/Makefile b/Makefile index b4ca3df..452a188 100644 --- a/Makefile +++ b/Makefile @@ -8,4 +8,4 @@ endif # ENABLE_EXCEPTIONS: Enable C++ exceptions. #--------------------------------------------------------------------------------- -include $(DEVKITPRO)/ctrcommon/tools/make_base \ No newline at end of file +include $(DEVKITPRO)/citrus/tools/make_base \ No newline at end of file diff --git a/README.md b/README.md index bce5dbb..34d4fc9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ Free multi Patcher ================================== -This application for the 3DS allows to patch systemmodules while using system or emunand,and with and without using firmlaunch. Because of this it allows E-Shop access on all 9.x firmware verions and regionfree cias in Pasta and other CFWs +This application for the 3DS allows to patch systemmodules while using system or emunand and with and without using firmlaunch. Because of this it allows E-Shop access on all 9.x firmware verions and regionfree in Pasta and other CFWs. +It also allows other peoples to create, add and share own patches using the patchlayout defined by this [wiki page](https://github.com/hartmannaf/Free-multi-Patcher/wiki/patchlayout) ### Dependencies @@ -11,4 +12,5 @@ This application for the 3DS allows to patch systemmodules while using system or ### Credits * base application: [YGW Eshop Spoofer (Y a Gateway!?)](https://github.com/felipejfc/ygw-eshop-spoofer) by [felipejfc](https://github.com/felipejfc) -* region free: [rxtools](https://github.com/roxas75/rxTools) by [roxas](https://github.com/roxas75/rxTools) +* region free: [rxtools](https://github.com/roxas75/rxTools) by [roxas](https://github.com/roxas75) +* CVer and NVER reading [3ds_homemenuhax](https://github.com/yellows8/3ds_homemenuhax) by [yellows8](https://github.com/yellows8) diff --git a/include/binaryLayouts.h b/include/binaryLayouts.h new file mode 100644 index 0000000..c169ac0 --- /dev/null +++ b/include/binaryLayouts.h @@ -0,0 +1,61 @@ +#pragma once + +#include <3ds.h> +#include "constants.h" +#include "device.h" + +/*Patchlayout defined by https://github.com/hartmannaf/Free-multi-Patcher/wiki/patchlayout */ + +//placeholder for possible later types of emunand +typedef struct nandTypesStruct +{ + u32 System : 1; + u32 Emu : 1; + u32 placeholder : 6; +} nands; + +typedef struct patchStruct +{ + u32 version; //0 for development, 1 after first release + u32 patchSize; + u32 patchNameSize; + u32 descriptionSize; + u32 processNameSize; + u32 originalcodeSize; + u32 patchcodeSize; + u32 processType; //ARM9 = 0, ARM11 = 1 + kernelVersion minKernelVersion; + kernelVersion maxKernelVersion; + firmwareVersion minFirmwareVersion; + firmwareVersion maxFirmwareVersion; + devices devicesSupported; + regions regionsSupported; + nands nandCompability; + u32 patchType; //0->search code, 1->overwrite code, 2->search String, 3->overwrite string + u32 startAddressProcess; + u32 startAddressGlobal; + u32 searchAreaSize; //0 overwrite all apearences + u32 patchOffset; //strings offset between each character, code offset where to patch based on originalcode + u32 numberOfReplacements; + char binaryData[]; +} binPatch; + + +/*PatchCollectionlayout defined by https://github.com/hartmannaf/Free-multi-Patcher/wiki/patchCollectionlayout */ + +typedef struct patchCollectionStruct +{ + u32 version; + u32 collectionNameSize; + u32 descriptionSize; + u32 numberOfPatches; + u32 processType; + kernelVersion minKernelVersion; + kernelVersion maxKernelVersion; + firmwareVersion minFirmwareVersion; + firmwareVersion maxFirmwareVersion; + devices devicesSupported; + regions regionsSupported; + nands nandCompability; + char binaryData[]; +} binPatchCollection; \ No newline at end of file diff --git a/include/collectionEntry.h b/include/collectionEntry.h new file mode 100644 index 0000000..a87a497 --- /dev/null +++ b/include/collectionEntry.h @@ -0,0 +1,15 @@ +#pragma once + +#include "patchCollections.h" +#include "defaultMenuEntrys.h" + + +class CollectionEntry : protected YesNoMenuEntry, protected NavigationMenuEntry +{ +protected: + PatchCollection* collection; +public: + CollectionEntry(PatchCollection* collection, MenuManagerM* manager,MenuM* parentMenu); + int sideAction(); + virtual std::string getRow(); +}; \ No newline at end of file diff --git a/include/constants.h b/include/constants.h index fc7f5a5..71a34b7 100644 --- a/include/constants.h +++ b/include/constants.h @@ -2,6 +2,10 @@ #include <3ds.h> +#include +#include +#include + extern u32 curr_kproc_addr; extern u32 kproc_start; extern u32 kproc_size; @@ -9,4 +13,26 @@ extern u32 kproc_num; extern u32 kproc_codeset_offset; extern u32 kproc_pid_offset; -void SaveVersionConstants(); \ No newline at end of file +void SaveVersionConstants(); + +//Application Constands +static const std::string applicationFolder = "sdmc:/fmp/"; + +static const std::string patchesFolder = applicationFolder+"patches/"; +static const std::string patchExtension = ".patch"; +static const std::string patchCollectionExtension = ".collection"; + +static const std::string settingsFolder=applicationFolder+"settings/"; +static const std::string settingsExtension =".cfg"; +static const std::string globalSettingsFileName = "settings"; + +static const std::string mainUrl = "http://fmp.hartie95.de/"; +static const std::string mainDownloadUrl = mainUrl + "updates/"; +static const std::string versionCheckUrl = mainUrl + "version.txt"; + +static const std::string mainDownloadUrlDev = mainUrl + "devUpdates/"; +static const std::string VersionCheckUrlDev = mainUrl + "devVersion.txt"; + +static const u32 version=0x00060471; + +std::string generateVersionString(u32 version); diff --git a/include/defaultMenuEntrys.h b/include/defaultMenuEntrys.h new file mode 100644 index 0000000..d9a3288 --- /dev/null +++ b/include/defaultMenuEntrys.h @@ -0,0 +1,69 @@ +#pragma once + +#include <3ds.h> +#include + +#include +#include "workaround.h" + +#define MAXNAMELENGTH 29 + +class MenuEntry +{ +private: +protected: + std::string name; + char type; + std::string description; + u32 maxNameLength = MAXNAMELENGTH; + u32 maxDescriptionLength = 40; + MenuEntry(){ + + } +public: + MenuEntry(std::string name, std::string description); + virtual int sideAction(); + virtual int aAction(); + virtual std::string getRow(); + void setName(std::string name); + void setDescription(std::string description); + std::string getName(); + std::string getDescription(); +}; + +class BackMenuEntry : protected MenuEntry +{ +private: + MenuManagerM* manager; +public: + BackMenuEntry(MenuManagerM* manager,std::string name, std::string description); + int aAction(); + void back(); +}; + +class NavigationMenuEntry : virtual protected MenuEntry +{ +protected: + MenuM* menu; + MenuManagerM* manager; + NavigationMenuEntry(){}; +public: + NavigationMenuEntry(MenuManagerM* manager,MenuM* menu,std::string name, std::string description); + int aAction(); + void navigate(); +}; + +class YesNoMenuEntry : virtual protected MenuEntry +{ +private: +protected: + bool* value; + std::string getValueString(bool value); + YesNoMenuEntry(){ + + } +public: + YesNoMenuEntry(bool* value,std::string name, std::string description); + virtual int sideAction(); + virtual std::string getRow(); +}; \ No newline at end of file diff --git a/include/device.h b/include/device.h new file mode 100644 index 0000000..15e002a --- /dev/null +++ b/include/device.h @@ -0,0 +1,60 @@ +#pragma once + +#include <3ds.h> + +typedef struct kernelVersionStruct +{ + u8 unknown; + u8 revision; + u8 minor; + u8 major; +}kernelVersion; + +typedef struct firmwareVersionStruct +{ + u8 major; + u8 minor; + u8 revision; + u8 nver; +}firmwareVersion; + +typedef struct devicesStruct +{ + u32 old3DS : 1; + u32 old3DSXL : 1; + u32 old2DS : 1; + u32 new3DS : 1; + u32 new3DSXL : 1; + u32 placeholder : 3; +} devices; + +//Australia is not used, instead it uses European region +typedef struct regionsStruct +{ + u32 japan : 1; + u32 northAmerica : 1; + u32 europe : 1; + u32 australia : 1; + u32 china : 1; + u32 korea : 1; + u32 taiwan : 1; + u32 placeholder : 1; +} regions; + +typedef struct deviceInformationsStruct +{ + u8 modelID; + u8 region; + kernelVersion kernelversion; + firmwareVersion firmwareversion; +} deviceInformations; + + +extern deviceInformations device; + +int initDeviceInformations(); + +int setModelID(); +int setDeviceRegion(); +int setFirmwareVersion(); +int setKernelVersion(); diff --git a/include/helpers.h b/include/helpers.h new file mode 100644 index 0000000..841dd15 --- /dev/null +++ b/include/helpers.h @@ -0,0 +1,9 @@ +#pragma once + +#include <3ds.h> +#include +#include + +void* loadFile(FILE* file, size_t minSize, size_t* fileSize); +bool checkFolder(std::string name); +std::string getStringFromDownload(size_t downloadSize, u8* downloadResult); \ No newline at end of file diff --git a/include/menu.h b/include/menu.h index f1a3ce9..6493026 100644 --- a/include/menu.h +++ b/include/menu.h @@ -1,39 +1,40 @@ +#pragma once + +#ifndef MENU_H +#define MENU_H + #include <3ds.h> -#include -#include +#include #include "constants.h" #include +#include +#include + +#include "defaultMenuEntrys.h" + +class MenuManager; -#define SETTING 0 -#define SAVE 1 -#define PLACEHOLDER 254 -#define EXIT 255 +class Menu : MenuM +{ +private: + Menu* parentMenu; + MenuManager* parentManager; + unsigned int currentSelection; + std::vector menuEntrys; +public: + Menu(MenuManager* parentManager,Menu* parentMenu); + MenuManager* getParentManager(); + Menu* getParentMenu(); + void addEntry(MenuEntry* entry); -#define ESHOPSPOOF 0 -#define REGIONFREE 1 -#define NOAUTODL 2 -#define SERIALCHANGE 3 + void menuChangeSelection(std::string direction); + short getNumberOfEntrys(); + void selectionDoSiteAction(); + void selectionDoAAction(); + Menu* back(); -struct menuEntry{ - std::string name; - std::string description; - short type; + void drawMenu(); }; -static const menuEntry menu[]={ {"e-shop spoof ", "Patches nim for E-Shop access ", SETTING}, - {"region patch ", "Patches the home menu to show out of\nregion games and nim to ignore out of\nregion Updates", SETTING}, - {"no auto download ", "Patches nim to stop automatic update\ndownload\n(Might be unstable)", SETTING}, - {"serial patch ", "Patches the serial to allow E-Shop \nacces after region change\n(not implemented)", PLACEHOLDER}, - {"save", "Save current selection for later use", SAVE}, - {"exit", "Exit without applying patches ", EXIT} - }; - -static const short numberOfEntries = sizeof(menu)/sizeof(menuEntry); - -void menuChageSelection(std::string direction); -void menuChangeStatusOfSelection(bool patchlist[]); -short getSelectionType(); -short getNumberOfPatches(); -void drowTop(); -void drawMenu(bool patchlist[]); \ No newline at end of file +#endif \ No newline at end of file diff --git a/include/menuManager.h b/include/menuManager.h new file mode 100644 index 0000000..94f54af --- /dev/null +++ b/include/menuManager.h @@ -0,0 +1,42 @@ +#pragma once +#ifndef MENUMANAGER_H +#define MENUMANAGER_H + +#include <3ds.h> +#include +#include +#include + +//class Menu; +#include "menu.h" +#include "workaround.h" + + +class MenuManager : MenuManagerM +{ +private: + std::vector menuPages; + Menu* mainPage; + Menu* currentPage; + bool* exit; + std::string versionString; + + void setActivePage(Menu* page); + +public: + MenuManager(bool* exit); + + void ManageInput(); + + void back(); + void navigateTo(MenuM* targetPage); + void navigateTo(Menu* targetPage); + void addPage(Menu* Page, std::string name); + void addPage(Menu* Page, Menu* parent, std::string name); + Menu* getMainPage(); + + void drawMenu(); + void drawTop(); +}; + +#endif \ No newline at end of file diff --git a/include/patchCollections.h b/include/patchCollections.h new file mode 100644 index 0000000..aadb12f --- /dev/null +++ b/include/patchCollections.h @@ -0,0 +1,51 @@ +#pragma once + +#include <3ds.h> +#include + +#include "patches.h" +#include "binaryLayouts.h" + +void createDefaultCollections(); + +class PatchCollection +{ +private: + std::string collectionName; + std::string description; + + kernelVersion minKernelVersion; + kernelVersion maxKernelVersion; + firmwareVersion minFirmwareVersion; + firmwareVersion maxFirmwareVersion; + devices devicesSupported; + regions regionsSupported; + nands nandCompability; + + u32 numberOfPatches; + + std::vector collectionPatches; + + bool enabled; + +public: + PatchCollection(binPatchCollection* collection); + ~PatchCollection(); + std::string getCollectionName(); + std::string getDescription(); + + kernelVersion getMinKernelVersion(); + kernelVersion getMaxKernelVersion(); + firmwareVersion getMinFirmwareVersion(); + firmwareVersion getMaxFirmwareVersion(); + devices getDevicesSupported(); + regions getRegionsSupported(); + nands getNandCompability(); + + u32 getNumberOfPatches(); + std::vector* getAllPatches(); + + bool changeStatus(); + bool changeStatus(bool status); + bool isEnabled(); +}; \ No newline at end of file diff --git a/include/patchEntry.h b/include/patchEntry.h new file mode 100644 index 0000000..7ca28fb --- /dev/null +++ b/include/patchEntry.h @@ -0,0 +1,15 @@ +#pragma once + +#include "defaultMenuEntrys.h" +#include "patches.h" + + +class PatchEntry : protected YesNoMenuEntry +{ +protected: + Patch* patch; +public: + PatchEntry(Patch* patch); + int sideAction(); +}; + diff --git a/include/patchManager.h b/include/patchManager.h new file mode 100644 index 0000000..5e160de --- /dev/null +++ b/include/patchManager.h @@ -0,0 +1,53 @@ +#pragma once +#include <3ds.h> + +#include +#include "patches.h" +#include "patchCollections.h" +#include "menuManager.h" +#include "device.h" +#include "settings.h" + + +class PatchManager +{ +private: + std::vector loadedPatches; + std::vector loadedCollections; + Settings* patchSettings; + + bool isType(struct dirent* file, std::string extension); + bool isPatch(struct dirent* file); + bool isCollection(struct dirent* file); + + void applyPatches(std::vector* patchList); + void findAndReplaceCode(Patch* _patch); + void replaceCodeAt(Patch* _patch); + void usePointerAndReplaceCode(Patch* _patch); + void findAndReplaceString(Patch* _patch); + void replaceStringAt(Patch* _patch); + void usePointerAndReplaceString(Patch* _patch); + + void* getProcessAddress(u32 startAddress, u32 processNameSize, const char* processName); + void* getProcessAddress(u32 startAddress, u32 processNameSize, char* processName); + + bool checkCompatibility(Patch* _patch); + bool checkCompatibility(PatchCollection* _collection); + + bool checkKernelVersion(kernelVersion min, kernelVersion max); + bool checkFirmwareVersion(firmwareVersion min, firmwareVersion max); + bool isRegionSupported(regions _regions); + bool isDeviceTypeSupported(devices _devices); + +public: + PatchManager(); + void loadPatchFiles(); + int createPatchPage(MenuManager* menuManager); + + binPatch* loadPatch(FILE* file); + binPatchCollection* loadCollection(FILE* file); + + int applyPatches(); + int saveSettings(); + int loadSettings(); +}; diff --git a/include/patches.h b/include/patches.h index 695fa3d..9651692 100644 --- a/include/patches.h +++ b/include/patches.h @@ -1,15 +1,73 @@ #pragma once #include <3ds.h> +#include "constants.h" +#include "binaryLayouts.h" /*int PatchPid(); int UnpatchPid(); void ReinitSrv(); void PatchSrvAccess();*/ -int patchNimEshop(); -int patchNimAutoUpdate(); -int patchRegionFree(); -int patchMenu(); -int patchNs(); -//int patchDlp(); -int changeSerial(); \ No newline at end of file + +void createDefaultPatches(); + +typedef struct codeStruct +{ + u32 codeSize; + u8* code; +} code; + +class Patch +{ +private: + std::string patchName; + std::string description; + std::string processName; + + kernelVersion minKernelVersion; + kernelVersion maxKernelVersion; + firmwareVersion minFirmwareVersion; + firmwareVersion maxFirmwareVersion; + devices devicesSupported; + regions regionsSupported; + nands nandCompability; + + u8 patchType; + u32 startAddressProcess; + u32 startAddressGlobal; + u32 searchAreaSize; + u32 numberOfReplacements; + u32 patchOffset; + code originalCode; + code patchCode; + + bool enabled; + +public: + Patch(binPatch*); + ~Patch(); + std::string getPatchName(); + std::string getDescription(); + std::string getProcessName(); + + kernelVersion getMinKernelVersion(); + kernelVersion getMaxKernelVersion(); + firmwareVersion getMinFirmwareVersion(); + firmwareVersion getMaxFirmwareVersion(); + devices getDevicesSupported(); + regions getRegionsSupported(); + nands getNandCompability(); + + u8 getPatchType(); + u32 getStartAddressProcess(); + u32 getStartAddressGlobal(); + u32 getSearchAreaSize(); + u32 getNumberOfReplacements(); + u32 getPatchOffset(); + code getOriginalCode(); + code getPatchCode(); + + bool changeStatus(); + bool changeStatus(bool status); + bool isEnabled(); +}; \ No newline at end of file diff --git a/include/saveEntrys.h b/include/saveEntrys.h new file mode 100644 index 0000000..8ab6690 --- /dev/null +++ b/include/saveEntrys.h @@ -0,0 +1,24 @@ +#pragma once + +#include "defaultMenuEntrys.h" +#include "settings.h" +#include "patchManager.h" + + +class SaveEntry : protected MenuEntry +{ +protected: + Settings* settings; +public: + SaveEntry(Settings* settings); + int aAction(); +}; + +class PatchSaveEntry : protected MenuEntry +{ +protected: + PatchManager* patchManager; +public: + PatchSaveEntry(PatchManager* manager); + int aAction(); +}; \ No newline at end of file diff --git a/include/settings.h b/include/settings.h new file mode 100644 index 0000000..4a4c150 --- /dev/null +++ b/include/settings.h @@ -0,0 +1,36 @@ +#pragma once +#include <3ds.h> +#include +#include +#include "menuManager.h" + +#define SETTINGS_AUTOBOOT "EnableAutoboot" +#define SETTINGSMAP std::map + +bool initGlobalSettings(); + +#define ALREADYEXIST 1 +#define ADDED 2 +#define ERROR 3 +#define EMPTYKEY 4 + +class Settings +{ +private: + SETTINGSMAP settings; + std::string name; +public: + Settings(std::string configName); + bool loadSettings(std::string configName); + Result addElement(std::string elementName, u32 value); + Result updateElement(std::string elementName, u32 value); + bool removeElement(std::string elementName); + bool saveSettings(); + bool hasElement(std::string key); + u32 getValue(std::string elementName); + u32* getValuePointer(std::string elementName); + u32 getNumberOfElements(); + bool createMenuPage(MenuManager* menuManager); +}; + +extern Settings* globalSettings; diff --git a/include/updater.h b/include/updater.h new file mode 100644 index 0000000..2d1e734 --- /dev/null +++ b/include/updater.h @@ -0,0 +1,36 @@ +#pragma once + +#include <3ds.h> +#include +#include "menuManager.h" +#include "settings.h" + +#define SETTINGS_BOOT_CHECK "CheckForUpdateAtBoot" +#define SETTINGS_UPDATE_NOTIFICATION "EnableUpdateNotifications" +#define SETTINGS_LAST_NOTIFICATION "lastVersionNotification" +#define SETTINGS_DEV_BUILDS "enableDevelopmentBuilds" + +class Updater +{ +private: + Menu* menuPage; + Settings* updaterSettings; + bool* exitLoop; + u32 onlineVersion; + std::string onlineVersionString; + bool installEntryAdded; + + Result createMenuPage(MenuManager* manager); + Result checkVersion(); + Result createUpdateNotification(); + Result downloadUpdate(); + std::string getChangelog(); + Result installUpdate(); + + Result download(std::string* url,size_t* filesize,u8** file); + +public: + Updater(MenuManager* manager,bool* exitLoop); + Result checkForUpdate(); + Result updateApplication(); +}; diff --git a/include/updaterEntry.h b/include/updaterEntry.h new file mode 100644 index 0000000..85c4fe5 --- /dev/null +++ b/include/updaterEntry.h @@ -0,0 +1,16 @@ +#pragma once + +#include "defaultMenuEntrys.h" +#include "updater.h" + +typedef Result(Updater::*actionFunction)(); + +class UpdaterMenuEntry : protected MenuEntry +{ +private: + actionFunction aFunction; + Updater* updater; +public: + UpdaterMenuEntry(actionFunction function, Updater* updater, std::string name, std::string description); + int aAction(); +}; diff --git a/include/workaround.h b/include/workaround.h new file mode 100644 index 0000000..1f470a6 --- /dev/null +++ b/include/workaround.h @@ -0,0 +1,14 @@ +#pragma once + +#include <3ds.h> + +class MenuM{ +}; + +class MenuManagerM{ + public: + virtual void back(){ + } + virtual void navigateTo(MenuM* targetPage){ + } +}; diff --git a/release/FreemultiPatcher 0.5.zip b/release/FreemultiPatcher 0.5.zip deleted file mode 100644 index cc2bc6c..0000000 Binary files a/release/FreemultiPatcher 0.5.zip and /dev/null differ diff --git a/release/FreemultiPatcher-0.6-Beta3(65).rar b/release/FreemultiPatcher-0.6-Beta3(65).rar new file mode 100644 index 0000000..6421606 Binary files /dev/null and b/release/FreemultiPatcher-0.6-Beta3(65).rar differ diff --git a/source/collectionEntry.cpp b/source/collectionEntry.cpp new file mode 100644 index 0000000..f4e3483 --- /dev/null +++ b/source/collectionEntry.cpp @@ -0,0 +1,41 @@ +#include "collectionEntry.h" +#include "menu.h" +#include "patchEntry.h" +#include "../include/patchEntry.h" + +using namespace std; + +CollectionEntry::CollectionEntry(PatchCollection* collection,MenuManagerM* manager,MenuM* parentMenu) +{ + this->value = new bool(); + this->collection = collection; + this->type = 'C'; + this->setName(this->collection->getCollectionName()); + this->setDescription(this->collection->getDescription()); + *this->value = this->collection->isEnabled(); + this->manager = manager; + this->menu = (MenuM*)new Menu((MenuManager*)this->manager,(Menu*)parentMenu); + + vector* collectionPatches = collection->getAllPatches(); + + + for (std::vector::iterator it = collectionPatches->begin(); it != collectionPatches->end(); ++it) + { + Patch* currentPatch = (*it); + PatchEntry* currentEntry = new PatchEntry(currentPatch);; + ((Menu*)this->menu)->addEntry((MenuEntry*)currentEntry); + } +} + +int CollectionEntry::sideAction() +{ + if (this->collection == nullptr) + return 1; + *this->value = this->collection->changeStatus(); + return 0; +} + +string CollectionEntry::getRow() +{ + return this->YesNoMenuEntry::getRow(); +} \ No newline at end of file diff --git a/source/constants.cpp b/source/constants.cpp index ec59e51..c809264 100644 --- a/source/constants.cpp +++ b/source/constants.cpp @@ -1,3 +1,5 @@ +#include + #include "constants.h" #include "kernel11.h" @@ -39,7 +41,7 @@ void SaveVersionConstants() u32 kversion = *(vu32*)0x1FF80000; // KERNEL_VERSION register u8 is_n3ds = 0; - APT_CheckNew3DS(NULL, &is_n3ds); + APT_CheckNew3DS(&is_n3ds); if (kversion < 0x022C0600) { kproc_size = 0x260; @@ -60,3 +62,21 @@ void SaveVersionConstants() KernelBackdoor(ScanKProcList); } + + +std::string generateVersionString(u32 version) +{ + //Generates Version String for the UI + u8 major = (u8)((version & 0xff000000) >> 24); + u8 minor = (u8)((version & 0xff0000) >> 16); + u8 revision = (u8)((version & 0xff00) >> 8); //BetaRelease ID + u8 build = (u8)version & 0xff;//internal build ID + + std::stringstream versionStream; + versionStream << "v" << std::hex << (u32)major + << "." << std::hex << (u32)minor; + //Check for beta release + if (build < 0xff) + versionStream << "-Beta" << std::hex << (u32)revision << "(" << std::hex << (u32)build << ")"; + return versionStream.str(); +} diff --git a/source/defaultMenuEntrys.cpp b/source/defaultMenuEntrys.cpp new file mode 100644 index 0000000..47e1345 --- /dev/null +++ b/source/defaultMenuEntrys.cpp @@ -0,0 +1,135 @@ +#include "defaultMenuEntrys.h" + +using namespace std; + +MenuEntry::MenuEntry(std::string name, std::string description) +{ + this->type = ' '; + this->setName(name); + this->setDescription(description); +} + +int MenuEntry::sideAction() +{ + return 0; +} + +int MenuEntry::aAction() +{ + return 0; +} +void MenuEntry::setName(string name) +{ + int length = name.size(); + string returnString = name; + + for (u32 i = length; i < this->maxNameLength; i++) + { + returnString += " "; + } + this->name = returnString; +} + +void MenuEntry::setDescription(string description) +{ + u32 lastSpace = 0; + u32 lastBreak = 0; + u32 size = description.size(); + for (u32 i = 0; i < size; i++) + { + if (description.at(i) == ' ') + { + lastSpace = i; + } + if (i - lastBreak >= this->maxDescriptionLength) + { + lastBreak = lastSpace; + description[lastSpace] = '\n'; + } + } + this->description=description; +} + + +string MenuEntry::getName() +{ + return this->name; +} + +string MenuEntry::getDescription() +{ + return this->description; +} +string MenuEntry::getRow() +{ + string returnString=""; + returnString += this->type; + returnString += " "; + returnString += this->name; + return returnString; +} + +BackMenuEntry::BackMenuEntry(MenuManagerM* manager,string name, string description):MenuEntry(name, description) +{ + this->manager = manager; +} + +int BackMenuEntry::aAction() +{ + this->back(); + return 0; +} + +void BackMenuEntry::back() +{ + this->manager->back(); +} + +NavigationMenuEntry::NavigationMenuEntry(MenuManagerM* manager,MenuM* menu,std::string name, std::string description):MenuEntry(name, description) +{ + this->manager = manager; + this->menu = menu; +} + +int NavigationMenuEntry::aAction() +{ + this->navigate(); + return 0; +} + +void NavigationMenuEntry::navigate() +{ + this->manager->navigateTo(this->menu); +} + + +YesNoMenuEntry::YesNoMenuEntry(bool* value,std::string name, std::string description) :MenuEntry(name, description) +{ + if(value==nullptr) + value=new bool(true); + this->value = value; +} + +string YesNoMenuEntry::getValueString(bool value) +{ + if(value==true) + return "on "; + else + return "off"; +} + +int YesNoMenuEntry::sideAction() +{ + if(this->value==nullptr) + return 1; + *this->value=!*this->value; + return 0; +} + +string YesNoMenuEntry::getRow() +{ + string returnString = MenuEntry::getRow(); + + returnString+=" "+getValueString(*this->value); + return returnString; +} \ No newline at end of file diff --git a/source/device.cpp b/source/device.cpp new file mode 100644 index 0000000..4f9cd6b --- /dev/null +++ b/source/device.cpp @@ -0,0 +1,61 @@ +#include "device.h" + + +#include +#include +#include + +using namespace std; + +deviceInformations device; + +int initDeviceInformations() +{ + device.modelID = 255; + device.region = 255; + device.kernelversion = { 0, 0, 0, 0 }; + device.firmwareversion = { 0,0,0,0 }; + + setModelID(); + setDeviceRegion(); + setFirmwareVersion(); + setKernelVersion(); + + return 0; +} + +int setModelID() +{ + return CFGU_GetSystemModel(&device.modelID); + +} + +int setDeviceRegion() +{ + return CFGU_SecureInfoGetRegion(&device.region); +} + + +int setFirmwareVersion() +{ + Result ret = 0; + OS_VersionBin nver_versionbin; + OS_VersionBin cver_versionbin; + memset(&nver_versionbin, 0, sizeof(OS_VersionBin)); + memset(&cver_versionbin, 0, sizeof(OS_VersionBin)); + ret = osGetSystemVersionData(&nver_versionbin, &cver_versionbin); + + device.firmwareversion.major = cver_versionbin.mainver; + device.firmwareversion.minor = cver_versionbin.minor; + device.firmwareversion.revision = cver_versionbin.build; + device.firmwareversion.nver = nver_versionbin.mainver; + return ret; +} + + +int setKernelVersion() +{ + u32 kernelValue = osGetKernelVersion(); + device.kernelversion = *(kernelVersion*)&kernelValue; + return 0; +} \ No newline at end of file diff --git a/source/helpers.cpp b/source/helpers.cpp new file mode 100644 index 0000000..427b448 --- /dev/null +++ b/source/helpers.cpp @@ -0,0 +1,53 @@ +#include "helpers.h" +#include +#include "malloc.h" +#include + +using namespace std; +using namespace ctr; + +void* loadFile(FILE* file, size_t minSize,size_t* fileSize) +{ + if (fileSize == nullptr) + fileSize = new size_t(); + *fileSize = 0; + void* loadedFile = nullptr; + if (file != NULL) + { + fseek(file, 0L, SEEK_END); + *fileSize = ftell(file); + fseek(file, 0L, SEEK_SET); + + if (*fileSize < minSize) + return nullptr; + + loadedFile = (void*)malloc(*fileSize); + if (loadedFile != nullptr) + { + fread(loadedFile, 1, *fileSize, file); + } + fclose(file); + } + return loadedFile; +} + +bool checkFolder(string name) +{ + if (!fs::exists(name)) + mkdir(name.c_str(), 0777); + return true; +} + + +std::string getStringFromDownload(size_t downloadSize, u8* downloadResult) +{ + string resultString = ""; + char urlString[downloadSize + 1]; + for (u32 i = 0; i -#include -#include -#include -#include #include <3ds.h> -#include "constants.h" -#include -#include "patches.h" -#include "kernel11.h" -#include "kobjects.h" -#include "menu.h" -#include - -using namespace std; -#define log(...) fprintf(stderr, __VA_ARGS__) +#include +#include +#include -static const string settingsFolder="sdmc:/fmp/"; -static const string settingsFileName="settings.cfg"; +#include "patchManager.h" +#include "menuManager.h" +#include "updater.h" +#include "device.h" +#include "settings.h" +#include "helpers.h" -bool applyPatches(bool patchlist[]){ - SaveVersionConstants(); - //PatchSrvAccess(); - gputDrawString("srv patched", (gpuGetViewportWidth() - gputGetStringWidth("srv patched", 8)) / 2, 130, 8, 8, 0 ,0 ,0); - - if(patchlist[ESHOPSPOOF]==true) - { - if(!KernelBackdoor(patchNimEshop)){ - gputDrawString("patch applied!", (gpuGetViewportWidth() - gputGetStringWidth("patch applied!", 8)) / 2, 70, 8, 8, 0 ,0 ,0); - } - } - - if(patchlist[REGIONFREE]==true) - { - if(!KernelBackdoor(patchRegionFree)){ - gputDrawString("patch applied!", (gpuGetViewportWidth() - gputGetStringWidth("patch applied!", 8)) / 2 + 25, 70, 8, 8, 0 ,0 ,0); - } - } - - if(patchlist[NOAUTODL]==true) - { - if(!KernelBackdoor(patchNimAutoUpdate)){ - gputDrawString("patch applied!", (gpuGetViewportWidth() - gputGetStringWidth("patch applied!", 8)) / 2 + 50, 70, 8, 8, 0 ,0 ,0); - } - } - - //will crash - /*if(patchlist[SERIALCHANGE]==true) - { - if(!KernelBackdoor(changeSerial)){ - gputDrawString("patch applied!", (gpuGetViewportWidth() - gputGetStringWidth("patch applied!", 8)) / 2 + 50, 70, 8, 8, 0 ,0 ,0); - } - }*/ +#include "kernel11.h" - HB_FlushInvalidateCache(); // Just to be sure! +using namespace std; +using namespace ctr; - return true; -} +PatchManager* patchManager; +MenuManager* menuManager; +Updater* updater; -bool loadSettings(bool patchlist[],short numberOfPatches) +int applyPatches() { - string filepath=settingsFolder+settingsFileName; - FILE *file = fopen(filepath.c_str(),"rb"); - if(file != NULL) - { - fread(patchlist,1,sizeof(patchlist)/sizeof(bool),file); - fclose(file); - } - return true; + return patchManager->applyPatches(); } -bool saveSettings(bool patchlist[]) +int test() { - if(!fsExists(settingsFolder)) - mkdir(settingsFolder.c_str(), 0777); - - string filepath=settingsFolder+settingsFileName; - FILE *file = fopen(filepath.c_str(),"w"); - if (file == NULL) - { - file = fopen(filepath.c_str(),"c"); - } - fwrite(patchlist,1,sizeof(patchlist)/sizeof(bool),file); - fclose(file); - return true; + return 0; } -int main(int argc, char **argv) { - if(!platformInit()) { +int init(int argc) +{ + if (!core::init(argc)) { + return 1; + } + httpcInit(); + newsInit(); + cfguInit(); + pmInit(); + + checkFolder(applicationFolder); + SaveVersionConstants(); + initDeviceInformations(); + initGlobalSettings(); + return 0; - } - short numberOfPatches=getNumberOfPatches(); - bool patchlist[numberOfPatches]; +} - for (int i = 0; i < numberOfPatches; i++) - { - patchlist[i]=true; - } +int cleanup() +{ + HB_FlushInvalidateCache(); // Just to be sure! - loadSettings(patchlist,numberOfPatches); - - short exitLoop=false; + httpcExit(); + newsExit(); + cfguExit(); + pmExit(); - while(platformIsRunning()&&exitLoop==false) { - //Todo: replace with switch case - inputPoll(); + core::exit(); + return 0; +} - if(inputIsPressed(BUTTON_UP)) - { - menuChageSelection("up"); - } - else if(inputIsPressed(BUTTON_DOWN)) - { - menuChageSelection("down"); +int main(int argc, char **argv) { + if(init(argc)!=0) { + return 0; } - - if(inputIsPressed(BUTTON_LEFT)||inputIsPressed(BUTTON_RIGHT)) + + bool exitLoop = false; + bool autoboot = false; + menuManager = new MenuManager(&exitLoop); + + patchManager = new PatchManager(); + + patchManager->createPatchPage(menuManager); + globalSettings->createMenuPage(menuManager); + updater = new Updater(menuManager,&exitLoop); + autoboot = globalSettings->getValue(SETTINGS_AUTOBOOT); + if ( autoboot == true) + { + for (u32 i = 100000; i > 0 && core::running()&&autoboot==true; i--) + { + hid::poll(); + if (hid::pressed(hid::BUTTON_L)) + autoboot = false; + } + if (autoboot == true) + { + KernelBackdoor(&applyPatches); + cleanup(); + return 0; + } + + } + + while(core::running()&&exitLoop==false) { - menuChangeStatusOfSelection(patchlist); - } - - if(inputIsPressed(BUTTON_A)) { - short selectionType=getSelectionType(); - switch(selectionType) - { - case SAVE: - saveSettings(patchlist); - break; - case EXIT: - exitLoop=true; - break; - } - } - - if(inputIsPressed(BUTTON_START)) { - applyPatches(patchlist); - exitLoop=true; + //Todo: replace with switch case + menuManager->ManageInput(); + + if(hid::pressed(hid::BUTTON_SELECT)) + { + test(); + } + + if (hid::pressed(hid::BUTTON_START)) + { + KernelBackdoor(&applyPatches); + exitLoop = true; + } + + menuManager->drawMenu(); } - drowTop(); - drawMenu(patchlist); - gpuSwapBuffers(true); - } + cleanup(); - platformCleanup(); - return 0; -} \ No newline at end of file + return 0; +} diff --git a/source/menu.cpp b/source/menu.cpp index 86f5de7..0fff4c1 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -1,114 +1,131 @@ #include +#include +#include + #include "menu.h" -#include +#include "workaround.h" using namespace std; +using namespace ctr; + +Menu::Menu(MenuManager* parentManager, Menu* parentMenu) +{ + this->currentSelection = 0; + this->parentManager = parentManager; + this->parentMenu = parentMenu; + + string backName=""; + if(this->parentMenu==nullptr) + backName="exit"; + else + backName="back"; -static int selection = 0; + BackMenuEntry* BackEntry = new BackMenuEntry((MenuManagerM*)this->parentManager,backName,""); + this->menuEntrys.push_back((MenuEntry*)BackEntry); +} -string getValueString(bool value) +void Menu::addEntry(MenuEntry* entry) { - if(value==true) - return "on "; - else - return "off"; + if(entry!=nullptr) + { + std::vector::iterator it; + + it = this->menuEntrys.end(); + it--; + it = this->menuEntrys.insert ( it , entry); + } } -void menuChageSelection(string direction) +MenuManager* Menu::getParentManager() { - if(direction=="up") - { - if(selection>0) - selection --; - } - else if(direction=="down") - { - if(selectionparentManager; } -void menuChangeStatusOfSelection(bool patchlist[]) +Menu* Menu::getParentMenu() { - if(menu[selection].type==SETTING) - { - patchlist[selection]=!patchlist[selection]; - } + return this->parentMenu; } -short getSelectionType() + +void Menu::menuChangeSelection(string direction) { - return menu[selection].type; + if(direction=="up") + { + if(this->currentSelection > 0) + this->currentSelection --; + } + else if(direction=="down") + { + if(this->currentSelection < this->menuEntrys.size()-1) + this->currentSelection ++; + } } -short getNumberOfPatches() +void Menu::selectionDoAAction() { - short numberOfPatches = 0; - for (int i = 0; i < numberOfEntries; i++) - { - if(menu[i].type==SETTING) + if(this->menuEntrys.size() > 0) { - numberOfPatches++; + this->menuEntrys.at(this->currentSelection)->aAction(); } - } - return numberOfPatches; } -void drowTop() +void Menu::selectionDoSiteAction() { - const string title = "Eshop/Region spoofer by hartie95"; - const string credit = "based on Ygw eshop spoofer by felipejfc"; - stringstream usageStream; - usageStream << "Usage:\n" << "\n"; - usageStream << "Start - Apply patches and exit" << "\n"; - usageStream << "A - Use selection" << "\n"; - usageStream << "Up/Down - Change selection" << "\n"; - usageStream << "Left/Right - Modify selection" << "\n"; - - string usage = usageStream.str(); - - gpuClear(); - gpuViewport(TOP_SCREEN, 0, 0, TOP_WIDTH, TOP_HEIGHT); - gputOrtho(0, TOP_WIDTH, 0, TOP_HEIGHT, -1, 1); - gpuClearColor(0xFF, 0xFF, 0xFF, 0xFF); - gputDrawString(title, (gpuGetViewportWidth() - gputGetStringWidth(title, 12)) / 2, (gpuGetViewportHeight() - gputGetStringHeight(title, 12))/2+25, 12, 12, 0 , 0 , 0); - gputDrawString(credit, (gpuGetViewportWidth() - gputGetStringWidth(credit, 8)) / 2, (gpuGetViewportHeight() - gputGetStringHeight(credit, 8))/2+12, 8, 8, 0, 0, 0); - gputDrawString(usage, (gpuGetViewportWidth() - gputGetStringWidth(usage, 8)) / 2, (gpuGetViewportHeight() - gputGetStringHeight(usage, 8))/2-75, 8, 8, 0 , 0 , 0); - - gpuFlushBuffer(); + if(this->menuEntrys.size() > 0) + { + this->menuEntrys.at(this->currentSelection)->sideAction(); + } +} + +Menu* Menu::back() +{ + this->currentSelection = 0; + return this->parentMenu; } -void drawMenu(bool patchlist[]) +short Menu::getNumberOfEntrys() { - stringstream menuStream; - for(int i = 0; i < numberOfEntries; i++) - { - if(i==selection) - menuStream << "-> "; - else - menuStream << " "; - - menuStream << menu[i].name; - if(menu[i].type==SETTING) - { - menuStream << " "; - menuStream << getValueString(patchlist[i]); - } - menuStream << "\n"; - } - - stringstream descriptionStream; - descriptionStream << menu[selection].description; + return this->menuEntrys.size(); +} + +void Menu::drawMenu() +{ + stringstream menuStream; + unsigned int i=0; + for(std::vector::iterator it = menuEntrys.begin(); it != menuEntrys.end(); ++it) + { + if(i == this->currentSelection) + menuStream << "-> "; + else + menuStream << " "; + + menuStream <<(*it)->getRow(); + menuStream << "\n"; + i++; + } + + stringstream descriptionStream; + descriptionStream << menuEntrys.at(this->currentSelection)->getDescription(); - string menu = menuStream.str(); - string description = descriptionStream.str(); - - gpuClear(); - gpuViewport(BOTTOM_SCREEN, 0, 0, BOTTOM_WIDTH, BOTTOM_HEIGHT); - gputOrtho(0, BOTTOM_WIDTH, 0, BOTTOM_HEIGHT, -1, 1); - gpuClearColor(0xFF, 0xFF, 0xFF, 0xFF); - gputDrawString(menu, (gpuGetViewportWidth() ) / 8, (gpuGetViewportHeight() - gputGetStringHeight(menu, 8))/2 +50 , 8, 8, 0, 0, 0); - gputDrawString(description, (gpuGetViewportWidth() - gputGetStringWidth(description, 8)) / 2, (gpuGetViewportHeight() - gputGetStringHeight(description, 8))/2 -75 , 8, 8, 0, 0, 0); - - gpuFlushBuffer(); -} \ No newline at end of file + string menu = menuStream.str(); + string description = descriptionStream.str(); + + u32 screenWidth; + u32 screenHeight; + gpu::setViewport(gpu::SCREEN_BOTTOM, 0, 0, gpu::BOTTOM_WIDTH, gpu::BOTTOM_HEIGHT); + gput::setOrtho(0, gpu::BOTTOM_WIDTH, 0, gpu::BOTTOM_HEIGHT, -1, 1); + gpu::setClearColor(0xFF, 0xFF, 0xFF, 0xFF); + gpu::clear(); + + gpu::getViewportWidth(&screenWidth); + gpu::getViewportHeight(&screenHeight); + + gput::drawString(menu, 15, screenHeight -30-gput::getStringHeight(menu, 8) , 8, 8, 0, 0, 0); + gput::drawString(description, 25, 50-gput::getStringHeight(description, 8), 8, 8, 0, 0, 0); + + gpu::flushCommands(); + gpu::flushBuffer(); + + gpu::swapBuffers(true); +} + diff --git a/source/menuManager.cpp b/source/menuManager.cpp new file mode 100644 index 0000000..21cb5ea --- /dev/null +++ b/source/menuManager.cpp @@ -0,0 +1,218 @@ +#include +#include +#include + +#include "menuManager.h" +#include "patchManager.h" +#include "device.h" + +using namespace std; +using namespace ctr; + +MenuManager::MenuManager(bool* exit) +{ + this->mainPage=new Menu(this,nullptr); + this->currentPage=this->mainPage; + + this->menuPages.push_back(this->mainPage); + + //Generates Version String for the UI + this->versionString = generateVersionString(version); + + this->exit=exit; +} + +void MenuManager::ManageInput() +{ + hid::poll(); + + if(hid::pressed(hid::BUTTON_UP)) + { + currentPage->menuChangeSelection("up"); + } + else if(hid::pressed(hid::BUTTON_DOWN)) + { + currentPage->menuChangeSelection("down"); + } + + if(hid::pressed(hid::BUTTON_LEFT)|| hid::pressed(hid::BUTTON_RIGHT)) + { + currentPage->selectionDoSiteAction(); + } + + if(hid::pressed(hid::BUTTON_A)) { + currentPage->selectionDoAAction(); + } + + if(hid::pressed(hid::BUTTON_B)) { + this->back(); + } +} + +void MenuManager::back() +{ + this->setActivePage(this->currentPage->back()); +} + +void MenuManager::navigateTo(MenuM* targetPage) +{ + navigateTo((Menu*) targetPage); +} + +void MenuManager::navigateTo(Menu* targetPage) +{ + this->currentPage=targetPage; +} + +void MenuManager::addPage(Menu* page, string name) +{ + addPage(page,this->mainPage,name); +} + +void MenuManager::addPage(Menu* page, Menu* parent, string name) +{ + this->menuPages.push_back(page); + NavigationMenuEntry* newPage= new NavigationMenuEntry((MenuManagerM*)this,(MenuM*)page,name,""); + parent->addEntry((MenuEntry*)newPage); +} + +void MenuManager::setActivePage(Menu* page) +{ + if(page==nullptr) + *this->exit=true; + else + this->currentPage=page; +} + +Menu* MenuManager::getMainPage() +{ + return this->mainPage; +} + + +void MenuManager::drawMenu() +{ + this->drawTop(); + this->currentPage->drawMenu(); +} + +string getModel() +{ + string model = ""; + switch (device.modelID) + { + case 0: + model = "old 3DS"; + break; + case 1: + model = "old 3DS XL"; + break; + case 3: + model = "2DS"; + break; + case 2: + model = "new 3DS"; + break; + case 4: + model = "new 3DS XL"; + break; + } + return model + "\n"; +} + +string getRegion() +{ + string region = ""; + switch (device.region) + { + case 0: + region = "J"; + break; + case 1: + region = "U"; + break; + case 2: + region = "E"; + break; + case 3: + region = "AUS"; + break; + case 4: + region = "C"; + break; + case 5: + region = "K"; + break; + case 6: + region = "T"; + break; + default: + break; + } + return region; +} + +string checkFirmwareVersion() +{ + std::stringstream stream; + stream << "fw: "; + stream << (u32)device.firmwareversion.major; + stream << "."; + stream << (u32)device.firmwareversion.minor; + stream << "."; + stream << (u32)device.firmwareversion.revision; + stream << "-"; + stream << (u32)device.firmwareversion.nver; + stream << " "; + stream << getRegion(); + std::string result(stream.str()); + return result + "\n"; +} + +string checkKernelVersion() +{ + std::stringstream stream; + stream << "kernel: "; + stream << (u32)device.kernelversion.major; + stream << "."; + stream << (u32)device.kernelversion.minor; + stream << "-"; + stream << (u32)device.kernelversion.revision; + std::string result(stream.str()); + return result+"\n"; +} + +void MenuManager::drawTop() +{ + string deviceInformations = "Model: " + getModel() + checkKernelVersion()+checkFirmwareVersion(); + const string title = "Free Multi Patcher by hartie95"; + const string credit = "based on Ygw eshop spoofer by felipejfc"; + stringstream usageStream; + usageStream << "Usage:\n" << "\n"; + usageStream << "Start - Apply patches and exit" << "\n"; + usageStream << "A - Use selection" << "\n"; + usageStream << "B - Go Back" << "\n"; + usageStream << "Up/Down - Change selection" << "\n"; + usageStream << "Left/Right - Modify selection" << "\n"; + + string usage = usageStream.str(); + + u32 screenWidth; + u32 screenHeight; + + gpu::setViewport(gpu::SCREEN_TOP, 0, 0, gpu::TOP_WIDTH, gpu::TOP_HEIGHT); + gput::setOrtho(0, gpu::TOP_WIDTH, 0, gpu::TOP_HEIGHT, -1, 1); + gpu::setClearColor(0xFF, 0xFF, 0xFF, 0xFF); + gpu::clear(); + + gpu::getViewportWidth(&screenWidth); + gpu::getViewportHeight(&screenHeight); + + gput::drawString(title, (screenWidth - gput::getStringWidth(title, 12)) / 2, (screenHeight - gput::getStringHeight(title, 12))/2+55, 12, 12, 0 , 0 , 0); + gput::drawString(credit, (screenWidth - gput::getStringWidth(credit, 8)) / 2, (screenHeight - gput::getStringHeight(credit, 8))/2+42, 8, 8, 0, 0, 0); + gput::drawString(deviceInformations, (screenWidth - gput::getStringWidth(deviceInformations, 8)) / 2, (screenHeight - gput::getStringHeight(deviceInformations, 8)) / 2-20, 8, 8, 10, 10, 10); + gput::drawString(usage, (screenWidth - gput::getStringWidth(usage, 8)) / 2, (screenHeight -gput::getStringHeight(usage, 8))/2-75, 8, 8, 0 , 0 , 0); + gput::drawString(versionString, screenWidth - gput::getStringWidth(versionString, 8)-5, gput::getStringHeight(versionString, 8), 8, 8, 0, 0, 0); + gpu::flushCommands(); + gpu::flushBuffer(); +} \ No newline at end of file diff --git a/source/patchCollections.cpp b/source/patchCollections.cpp new file mode 100644 index 0000000..db9a97f --- /dev/null +++ b/source/patchCollections.cpp @@ -0,0 +1,258 @@ +#include +#include +#include + +#include "patchCollections.h" + +using namespace std; + +binPatch* loadPatch(void* ptr) +{ + binPatch* loadedPatch = nullptr; + if (ptr != NULL && ptr!=nullptr) + { + u32 size = ((binPatch*)ptr)->patchSize; + if (size < sizeof(binPatch)) + return nullptr; + + loadedPatch = (binPatch*)malloc(size); + if (loadedPatch != nullptr) + { + memcpy(loadedPatch, ptr, size); + } + } + return loadedPatch; +} + +PatchCollection::PatchCollection(binPatchCollection* collection) +{ + this->collectionName.assign(collection->binaryData, collection->collectionNameSize); + this->description.assign(&(collection->binaryData[collection->collectionNameSize]), collection->descriptionSize); + + this->minKernelVersion = collection->minKernelVersion; + this->maxKernelVersion = collection->maxKernelVersion; + this->minFirmwareVersion = collection->minFirmwareVersion; + this->maxFirmwareVersion = collection->maxFirmwareVersion; + this->devicesSupported = collection->devicesSupported; + this->regionsSupported = collection->regionsSupported; + this->nandCompability = collection->nandCompability; + + this->numberOfPatches = collection->numberOfPatches; + + u32 patchPosition = collection->collectionNameSize + collection->descriptionSize+1; + for (u32 i = 0; i < this->numberOfPatches; i++) + { + binPatch *patchPtr = loadPatch(&collection->binaryData[patchPosition]); + if (patchPtr != nullptr) + { + Patch* tmpPatch = new Patch(patchPtr); + if (tmpPatch != nullptr) + { + this->collectionPatches.push_back(tmpPatch); + } + patchPosition += patchPtr->patchSize; + free(patchPtr); + } + else + break; + } + + this->changeStatus(true); +} + +PatchCollection::~PatchCollection() +{ + +} + + +string PatchCollection::getCollectionName() +{ + return this->collectionName; +} + +string PatchCollection::getDescription() +{ + return this->description; +} + + +kernelVersion PatchCollection::getMinKernelVersion() +{ + return this->minKernelVersion; +} + +kernelVersion PatchCollection::getMaxKernelVersion() +{ + return this->maxKernelVersion; +} + +firmwareVersion PatchCollection::getMinFirmwareVersion() +{ + return this->minFirmwareVersion; +} + +firmwareVersion PatchCollection::getMaxFirmwareVersion() +{ + return this->maxFirmwareVersion; +} + +devices PatchCollection::getDevicesSupported() +{ + return this->devicesSupported; +} + +regions PatchCollection::getRegionsSupported() +{ + return this->regionsSupported; +} + +nands PatchCollection::getNandCompability() +{ + return this->nandCompability; +} + +u32 PatchCollection::getNumberOfPatches() +{ + return this->numberOfPatches; +} + +std::vector* PatchCollection::getAllPatches() +{ + return &this->collectionPatches; +} + +bool PatchCollection::changeStatus() +{ + return this->changeStatus(!this->enabled); +} + +bool PatchCollection::changeStatus(bool status) +{ + this->enabled = status; + return this->enabled; +} + +bool PatchCollection::isEnabled() +{ + return this->enabled; +} + +void createDefaultCollections() +{ + FILE *file; + + // create the default patch files + // patch Homemenu to show out of region applications + // 9.0.0 Address: 0x00101B8C; + char menuBytes[] =/*patchName*/ "region patch menu" + /*description*/ "Patches the home menu to show out of region games" + /*processname*/ "menu" + /*OriginalCode*/"\x00\x00\x55\xE3\x01\x10\xA0\xE3\x11\x00\xA0\xE1\x03\x00\x00\x0A" + /*patchBegin*/ "\x01\x00\xA0\xE3\x70\x80\xBD\xE8"; + + u32 menuPatchSize = sizeof(binPatch) + sizeof(menuBytes); + binPatch* menuPatch = (binPatch*)malloc(menuPatchSize); + + menuPatch->version = 0x00; + menuPatch->patchSize = menuPatchSize; + menuPatch->patchNameSize = 17; + menuPatch->descriptionSize = 49; + menuPatch->processNameSize = 4; + menuPatch->originalcodeSize = 16; + menuPatch->patchcodeSize = 8; + menuPatch->processType = 0x01; + menuPatch->minKernelVersion = { 0x00, 0x00, 0x00, 0x00 }; + menuPatch->maxKernelVersion = { 0xFF, 0xFF, 0xFF, 0xFF }; + menuPatch->minFirmwareVersion = { 4, 0, 0, 0 }; + menuPatch->maxFirmwareVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + menuPatch->devicesSupported = {1,1,1,1,1,0}; + menuPatch->regionsSupported = {1,1,1,1,1,1,1,0}; + menuPatch->nandCompability = { 1, 1, 0 }; + menuPatch->patchType = 0x00; + menuPatch->startAddressProcess = 0x00100000; + menuPatch->startAddressGlobal = 0x26960000; + menuPatch->searchAreaSize = 0x001A0000; + menuPatch->patchOffset = 0x00; + menuPatch->numberOfReplacements = 0x01; + menuPatch->patchOffset = 0; + + memcpy(menuPatch->binaryData, menuBytes, sizeof(menuBytes)); + + + // patch NS to return update doesnt need to be installed intead of CVer not found error code after Update Check + // 9.0.0 Addresses: 0x00102acc, 0x001894f4; + char nsBytes[] = /*patchName*/ "region patch ns" + /*description*/ "Patches the ns to ignore out of region updates" + /*processname*/ "ns" + /*OriginalCode*/"\x0C\x18\xE1\xD8" + /*patchBegin*/ "\x0B\x18\x21\xC8"; + + u32 nsPatchSize = sizeof(binPatch) + sizeof(nsBytes); + binPatch* nsPatch = (binPatch*)malloc(nsPatchSize); + + nsPatch->version = 0x00; + nsPatch->patchSize = nsPatchSize; + nsPatch->patchNameSize = 15; + nsPatch->descriptionSize = 46; + nsPatch->processNameSize = 2; + nsPatch->originalcodeSize = 4; + nsPatch->patchcodeSize = 4; + nsPatch->processType = 0x01; + nsPatch->minKernelVersion = { 0x00, 0x00, 0x00, 0x00 }; + nsPatch->maxKernelVersion = { 0xFF, 0xFF, 0xFF, 0xFF }; + nsPatch->minFirmwareVersion = { 4, 0, 0, 0 }; + nsPatch->maxFirmwareVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + nsPatch->devicesSupported = { 1, 1, 1, 1, 1, 0 }; + nsPatch->regionsSupported = { 1, 1, 1, 1, 1, 1, 1, 0 }; + nsPatch->nandCompability = { 1, 1, 0 }; + nsPatch->patchType = 0x00; + nsPatch->patchOffset = 0x00; + nsPatch->startAddressProcess = 0x00018000; + nsPatch->startAddressGlobal = 0x26A00000; + nsPatch->searchAreaSize = 0x00050000; + nsPatch->numberOfReplacements = 0x02; + nsPatch->patchOffset = 0; + + memcpy(nsPatch->binaryData, nsBytes, sizeof(nsBytes)); + + + char collectionBytes[] =/*patchName*/ "regionfree collection" + /*description*/ "Patches the home menu and ns to allow the usage of out of region games"; + + u32 regionfreeSize = sizeof(binPatchCollection) + sizeof(collectionBytes) + menuPatchSize + nsPatchSize; + binPatchCollection* regionfree = (binPatchCollection*)malloc(regionfreeSize); + + regionfree->version = 0x00; + regionfree->collectionNameSize = 21; + regionfree->descriptionSize = 70; + regionfree->numberOfPatches = 2; + regionfree->processType = 0x01; + regionfree->minKernelVersion = { 0x00, 0x00, 0x00, 0x00 }; + regionfree->maxKernelVersion = { 0xFF, 0xFF, 0xFF, 0xFF }; + regionfree->minFirmwareVersion = { 4, 0, 0, 0 }; + regionfree->maxFirmwareVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + regionfree->devicesSupported = { 1, 1, 1, 1, 1, 0 }; + regionfree->regionsSupported = { 1, 1, 1, 1, 1, 1, 1, 0 }; + regionfree->nandCompability = { 1, 1, 0 }; + + memcpy(regionfree->binaryData, collectionBytes, sizeof(collectionBytes)); + memcpy(®ionfree->binaryData[sizeof(collectionBytes)], menuPatch, menuPatchSize); + memcpy(®ionfree->binaryData[sizeof(collectionBytes) + menuPatchSize], nsPatch, nsPatchSize); + + string collectionFileName = "regionFree" + patchCollectionExtension; + + string filepath = patchesFolder + collectionFileName; + file = fopen(filepath.c_str(), "wb"); + if (file == NULL) + { + file = fopen(filepath.c_str(), "cb"); + } + fwrite(regionfree, 1, regionfreeSize, file); + fclose(file); + + + free(nsPatch); + free(menuPatch); + free(regionfree); +} \ No newline at end of file diff --git a/source/patchEntry.cpp b/source/patchEntry.cpp new file mode 100644 index 0000000..1ac1108 --- /dev/null +++ b/source/patchEntry.cpp @@ -0,0 +1,21 @@ +#include "patchEntry.h" + +using namespace std; + +PatchEntry::PatchEntry(Patch* patch) +{ + this->value=new bool(); + this->patch=patch; + this->type = 'P'; + this->setName(this->patch->getPatchName()); + this->setDescription(this->patch->getDescription()); + *this->value=this->patch->isEnabled(); +} + +int PatchEntry::sideAction() +{ + if(this->patch==nullptr) + return 1; + *this->value=this->patch->changeStatus(); + return 0; +} \ No newline at end of file diff --git a/source/patchManager.cpp b/source/patchManager.cpp new file mode 100644 index 0000000..d196631 --- /dev/null +++ b/source/patchManager.cpp @@ -0,0 +1,590 @@ +#include +#include + +#include +#include +#include +#include + +#include "patchManager.h" +#include "constants.h" +#include "kernel11.h" +#include "kobjects.h" + +#include "patchEntry.h" +#include "collectionEntry.h" +#include "saveEntrys.h" + +#include "helpers.h" + +using namespace std; +using namespace ctr; + + +bool ignoreFirmware = false; +bool ignoreKernel = false; +bool ignoreRegion = false; +bool ignoreDeviceType = false; +bool ignoreFirmwareCollection = false; +bool ignoreKernelCollection = false; +bool ignoreRegionCollection = false; +bool ignoreDeviceTypeCollection = false; + +const string patchcfgName = "patch"; + +void* stringcpy(void* destination, void* string, size_t stringSize, u32 offset) +{ + if (destination == nullptr || string == nullptr) + return nullptr; + + if (stringSize == 0) + return destination; + + u8* destinationByte = (u8*)destination; + u8* stringByte = (u8*)string; + + for (u32 i = 0; i < stringSize; i++) + { + *(destinationByte) = *stringByte; + stringByte++; + destinationByte += 1 + offset; + } + return destination; +} + +PatchManager::PatchManager() +{ + checkFolder(patchesFolder); + createDefaultPatches(); + createDefaultCollections(); + this->loadPatchFiles(); + this->patchSettings = new Settings(patchcfgName); + this->loadSettings(); +} + +void PatchManager::loadPatchFiles() +{ + DIR *dir; + dir = opendir(patchesFolder.c_str()); + if (dir) + { + struct dirent *currenElement; + while ((currenElement = readdir(dir)) != NULL) + { + if(isPatch(currenElement)) + { + string filepath=patchesFolder+currenElement->d_name; + FILE* file = fopen(filepath.c_str(),"rb"); + binPatch* tmp=loadPatch(file); + + if(tmp!=nullptr) + { + loadedPatches.push_back(new Patch(tmp)); + free(tmp); + } + } + else if(isCollection(currenElement)) + { + string filepath = patchesFolder + currenElement->d_name; + FILE* file = fopen(filepath.c_str(), "rb"); + binPatchCollection* tmp = loadCollection(file); + + if (tmp != nullptr) + { + PatchCollection* tmpCollection = new PatchCollection(tmp); + + loadedCollections.push_back(tmpCollection); + free(tmp); + } + } + } + } + closedir(dir); +} + +int PatchManager::createPatchPage(MenuManager* menuManager) +{ + Menu* page=new Menu(menuManager,menuManager->getMainPage()); + + PatchCollection* currentCollection; + for (std::vector::iterator it = loadedCollections.begin(); it != loadedCollections.end(); ++it) + { + currentCollection = (*it); + CollectionEntry* entry = new CollectionEntry(currentCollection,(MenuManagerM*)menuManager,(MenuM*)page); + page->addEntry((MenuEntry*)entry); + } + + Patch* currentPatch; + for(std::vector::iterator it = loadedPatches.begin(); it != loadedPatches.end(); ++it) + { + currentPatch = (*it); + PatchEntry* entry=new PatchEntry(currentPatch); + page->addEntry((MenuEntry*)entry); + } + PatchSaveEntry* saveButton = new PatchSaveEntry(this); + page->addEntry((MenuEntry*)saveButton); + + menuManager->addPage(page,page->getParentMenu(),"Manage Patches"); + return 0; +} + +bool PatchManager::isType(struct dirent* file, string extension) +{ + u32 nameLength = strlen(file->d_name); + if (nameLength >= extension.size()) + { + u32 extensionStart = nameLength - extension.size(); + if (strcmp(file->d_name + extensionStart, extension.c_str()) == 0) + { + return true; + } + } + return false; +} + +bool PatchManager::isPatch(struct dirent* file) +{ + return isType(file, patchExtension); +} + +bool PatchManager::isCollection(struct dirent* file) +{ + return isType(file, patchCollectionExtension); +} + + +binPatch* PatchManager::loadPatch(FILE* file) +{ + binPatch* loadedPatch = (binPatch*)loadFile(file, sizeof(binPatch),nullptr); + return loadedPatch; +} + +binPatchCollection* PatchManager::loadCollection(FILE* file) +{ + binPatchCollection* loadedCollection = (binPatchCollection*)loadFile(file, (sizeof(binPatch) + sizeof(binPatchCollection)),nullptr); + return loadedCollection; +} + +int PatchManager::applyPatches() +{ + ignoreFirmware = (bool) globalSettings->getValue("ignoreFirmware"); + ignoreKernel = (bool) globalSettings->getValue("ignoreKernel"); + ignoreRegion = (bool) globalSettings->getValue("ignoreRegion"); + ignoreDeviceType = (bool) globalSettings->getValue("ignoreDeviceType"); + ignoreFirmwareCollection = (bool) globalSettings->getValue("ignoreFirmwareCollection"); + ignoreKernelCollection = (bool) globalSettings->getValue("ignoreKernelCollection"); + ignoreRegionCollection = (bool) globalSettings->getValue("ignoreRegionCollection"); + ignoreDeviceTypeCollection = (bool) globalSettings->getValue("ignoreDeviceTypeCollection"); + PatchCollection* currentCollection; + for (std::vector::iterator it = loadedCollections.begin(); it != loadedCollections.end(); ++it) + { + currentCollection = (*it); + if (currentCollection == nullptr) + continue; + + if (!currentCollection->isEnabled() || !checkCompatibility(currentCollection)) + continue; + + vector* patchList = currentCollection->getAllPatches(); + applyPatches(patchList); + } + + applyPatches(&loadedPatches); + + return 0; +} + +void PatchManager::applyPatches(vector* patchList) +{ + if (patchList == nullptr) + return; + + Patch* currentPatch = nullptr; + for (std::vector::iterator it = patchList->begin(); it != patchList->end(); ++it) + { + currentPatch = (*it); + if (currentPatch == nullptr || currentPatch==NULL) + continue; + + if (!currentPatch->isEnabled() || !checkCompatibility(currentPatch)) + continue; + + switch (currentPatch->getPatchType()) + { + case 0: + this->findAndReplaceCode(currentPatch); + break; + case 1: + this->replaceCodeAt(currentPatch); + break; + case 2: + this->usePointerAndReplaceCode(currentPatch); + break; + case 3: + this->findAndReplaceString(currentPatch); + break; + case 4: + this->replaceStringAt(currentPatch); + break; + case 5: + this->usePointerAndReplaceString(currentPatch); + break; + default: + break; + } + } +} + +void* PatchManager::getProcessAddress(u32 startAddress, u32 processNameSize, const char* processName) +{ + KCodeSet* code_set = FindTitleCodeSet(processName,processNameSize); + if (code_set == nullptr) + return nullptr; + + return (void*) FindCodeOffsetKAddr(code_set, startAddress); +} + +void PatchManager::findAndReplaceCode(Patch* _patch) +{ + if (_patch == nullptr) + return; + + u32 numberOfReplaces = _patch->getNumberOfReplacements(); + u32 codeShift = _patch->getPatchOffset(); + + u32 area = _patch->getSearchAreaSize(); + + string processName = _patch->getProcessName(); + + code originalCode = _patch->getOriginalCode(); + code patchCode = _patch->getPatchCode(); + + if (numberOfReplaces<1 || area<1 || originalCode.codeSize < 1 || patchCode.codeSize <1) + return; + + u8 * startAddressPointer = (u8 *)getProcessAddress(_patch->getStartAddressProcess(), processName.size(), processName.c_str()); + + if(startAddressPointer==nullptr) + return; + + u8 * destination=nullptr; + u32 numberOfFounds=0; + + for(u32 i = 0; i < area && numberOfFoundsgetStartAddressProcess(); + + const char* processName = _patch->getProcessName().c_str(); + u32 processNameSize = _patch->getProcessName().size(); + + code patchCode = _patch->getPatchCode(); + + u8 * destinationPointer = (u8 *)getProcessAddress(destination, processNameSize, processName); + if (destinationPointer == nullptr) + return; + + memcpy(destinationPointer, patchCode.code, patchCode.codeSize); + + return; +} + +void PatchManager::usePointerAndReplaceCode(Patch* _patch) +{ + const u32 pointerAddress = _patch->getStartAddressProcess(); + + const char* processName = _patch->getProcessName().c_str(); + u32 processNameSize = _patch->getProcessName().size(); + + code patchCode = _patch->getPatchCode(); + u32 internalAddress = *(u32 *)getProcessAddress(pointerAddress, processNameSize, processName); + u8 * destinationPointer = (u8 *)getProcessAddress(internalAddress, processNameSize, processName); + if (destinationPointer == nullptr) + return; + + memcpy(destinationPointer, patchCode.code, patchCode.codeSize); + + return; +} + +void PatchManager::findAndReplaceString(Patch* _patch) +{ + u32 numberOfReplaces = _patch->getNumberOfReplacements(); + u32 stringCharacterOffset = _patch->getPatchOffset(); + + const u32 startAddress = _patch->getStartAddressProcess(); + const u32 area = _patch->getSearchAreaSize(); + + const char* processName = _patch->getProcessName().c_str(); + u32 processNameSize = _patch->getProcessName().size(); + + code originalCode = _patch->getOriginalCode(); + code patchCode = _patch->getPatchCode(); + + + u8 * startAddressPointer = (u8 *)getProcessAddress(startAddress, processNameSize, processName); + if (startAddressPointer == nullptr) + return; + u8 * destination = nullptr; + u32 numberOfFounds = 0; + + for (u32 i = 0; i < area && numberOfFounds <= numberOfReplaces; i++) + { + //check for the original code position + bool found = true; + for (u32 x = 0; x < originalCode.codeSize && found == true; x += 1 + stringCharacterOffset) + { + if ((*((startAddressPointer + i + x)) != *(&originalCode.code[x]))) + found = false; + } + if (found == true) + { + //Apply patches, if the addresses was found /*TODO*/ + destination = startAddressPointer + i; + stringcpy(destination, patchCode.code, patchCode.codeSize,stringCharacterOffset); + numberOfFounds++; + } + } + return; +} + +void PatchManager::replaceStringAt(Patch* _patch) +{ + u32 stringCharacterOffset = _patch->getPatchOffset(); + const u32 destination = _patch->getStartAddressProcess(); + + const char* processName = _patch->getProcessName().c_str(); + u32 processNameSize = _patch->getProcessName().size(); + + code patchCode = _patch->getPatchCode(); + + u8 * destinationPointer = (u8 *)getProcessAddress(destination, processNameSize, processName); + if (destinationPointer == nullptr) + return; + + stringcpy(destinationPointer, patchCode.code, patchCode.codeSize, stringCharacterOffset); + + return; +} + + +void PatchManager::usePointerAndReplaceString(Patch* _patch) +{ + u32 stringCharacterOffset = _patch->getPatchOffset(); + const u32 pointerAddress = _patch->getStartAddressProcess(); + + const char* processName = _patch->getProcessName().c_str(); + u32 processNameSize = _patch->getProcessName().size(); + + code patchCode = _patch->getPatchCode(); + u32 internalAddress = *(u32 *)getProcessAddress(pointerAddress, processNameSize, processName); + u8 * destinationPointer = (u8 *)getProcessAddress(internalAddress, processNameSize, processName); + if (destinationPointer == nullptr) + return; + + stringcpy(destinationPointer, patchCode.code, patchCode.codeSize, stringCharacterOffset); + + return; +} + + +bool PatchManager::checkCompatibility(Patch* _patch) +{ + if (_patch == nullptr) + return false; + + bool compatibleDevice = isDeviceTypeSupported(_patch->getDevicesSupported()); + bool compatibleFirmware = checkFirmwareVersion(_patch->getMinFirmwareVersion(), _patch->getMaxFirmwareVersion()); + bool compatibleKernel = checkKernelVersion(_patch->getMinKernelVersion(), _patch->getMaxKernelVersion()); + bool compatibleRegion = isRegionSupported(_patch->getRegionsSupported()); + + bool compatible = (compatibleDevice || ignoreDeviceType) + && (compatibleFirmware || ignoreFirmware) + && (compatibleKernel || ignoreKernel) + && (compatibleRegion || ignoreRegion); + + return compatible; +} + +bool PatchManager::checkCompatibility(PatchCollection* _collection) +{ + if (_collection == nullptr) + return false; + + bool compatibleDevice = isDeviceTypeSupported(_collection->getDevicesSupported()); + bool compatibleFirmware = checkFirmwareVersion(_collection->getMinFirmwareVersion(), _collection->getMaxFirmwareVersion()); + bool compatibleKernel = checkKernelVersion(_collection->getMinKernelVersion(), _collection->getMaxKernelVersion()); + bool compatibleRegion = isRegionSupported(_collection->getRegionsSupported()); + + bool compatible = (compatibleDevice || ignoreDeviceTypeCollection) + && (compatibleFirmware || ignoreFirmwareCollection) + && (compatibleKernel || ignoreKernelCollection) + && (compatibleRegion || ignoreRegionCollection); + + return compatible; +} + +bool checkMin(u8 numbers[], u32 numbersSize, u8 minNumbers[], u32 minNumbersSize) +{ + if (numbersSize != minNumbersSize) + return false; + + if (numbers == nullptr || minNumbers == nullptr) + return false; + + for (u32 i = 0; i < numbersSize;i++) + { + if (numbers[i] > minNumbers[i]) + return true; + if (numbers[i] < minNumbers[i]) + return false; + } + return true; +} + +bool checkMax(u8 numbers[], u32 numbersSize, u8 maxNumbers[], u32 maxNumbersSize) +{ + if (numbersSize != maxNumbersSize) + return false; + + if (numbers == nullptr || maxNumbers == nullptr) + return false; + + for (u32 i = 0; i < numbersSize; i++) + { + if (numbers[i] < maxNumbers[i]) + return true; + if (numbers[i] > maxNumbers[i]) + return false; + } + return true; +} + +bool PatchManager::checkKernelVersion(kernelVersion min, kernelVersion max) +{ + u8 kernelVersionArray[3] = { device.kernelversion.major, device.kernelversion.minor, device.kernelversion.revision}; + u8 minVersionArray[3] = { min.major, min.minor, min.revision }; + u8 maxVersionArray[3] = { max.major, max.minor, max.revision }; + return checkMin(kernelVersionArray, 3, minVersionArray, 3) && checkMax(kernelVersionArray, 3, maxVersionArray, 3); + +} + +bool PatchManager::checkFirmwareVersion(firmwareVersion min, firmwareVersion max) +{ + u8 cverVersionArray[3] = { device.firmwareversion.major, device.firmwareversion.minor, device.firmwareversion.revision }; + u8 minVersionArray[3] = { min.major, min.minor, min.revision }; + u8 maxVersionArray[3] = { max.major, max.minor, max.revision }; + bool ret= checkMin(cverVersionArray, 3, minVersionArray, 3) && checkMax(cverVersionArray, 3, maxVersionArray, 3); + ret= ret&checkMin(&device.firmwareversion.nver, 1, &min.nver, 1) && checkMax(&device.firmwareversion.nver, 1, &max.nver, 1); + return ret; +} + +bool PatchManager::isRegionSupported(regions _regions) +{ + bool supported = false; + switch (device.region) + { + case 0: + supported = _regions.japan; + break; + case 1: + supported = _regions.northAmerica; + break; + case 2: + supported = _regions.europe; + break; + case 3: + supported = _regions.australia; + break; + case 4: + supported = _regions.china; + break; + case 5: + supported = _regions.korea; + break; + case 6: + supported = _regions.taiwan; + break; + default: + break; + } + return supported; + +} + +bool PatchManager::isDeviceTypeSupported(devices _devices) +{ + bool supported = false; + switch (device.modelID) + { + case 0: + supported = _devices.old3DS; + break; + case 1: + supported = _devices.old3DSXL; + break; + case 3: + supported = _devices.old2DS; + break; + case 2: + supported = _devices.new3DS; + break; + case 4: + supported = _devices.new3DSXL; + break; + default: + break; + } + return supported; +} + + +int PatchManager::saveSettings() +{ + for (std::vector::iterator it = loadedCollections.begin(); it != loadedCollections.end(); ++it) + { + this->patchSettings->updateElement((*it)->getCollectionName(), (*it)->isEnabled()); + } + + for (std::vector::iterator it = loadedPatches.begin(); it != loadedPatches.end(); ++it) + { + this->patchSettings->updateElement((*it)->getPatchName(),(*it)->isEnabled()); + } + this->patchSettings->saveSettings(); + return 0; +} + +int PatchManager::loadSettings() +{ + this->patchSettings->loadSettings(patchcfgName); + for (std::vector::iterator it = loadedCollections.begin(); it != loadedCollections.end(); ++it) + { + if(this->patchSettings->hasElement((*it)->getCollectionName())) + (*it)->changeStatus(this->patchSettings->getValue((*it)->getCollectionName())); + } + + for (std::vector::iterator it = loadedPatches.begin(); it != loadedPatches.end(); ++it) + { + if (this->patchSettings->hasElement((*it)->getPatchName())) + (*it)->changeStatus(this->patchSettings->getValue((*it)->getPatchName())); + } + return 0; +} \ No newline at end of file diff --git a/source/patches.cpp b/source/patches.cpp index a3bd063..c1347fb 100644 --- a/source/patches.cpp +++ b/source/patches.cpp @@ -1,209 +1,212 @@ +#include #include +#include #include -#include -#include <3ds.h> -#include "constants.h" #include "patches.h" -#include "kernel11.h" -#include "kobjects.h" -//----------------------------------------------------------------------------- -/* -u32 self_pid = 0; +using namespace std; +using namespace ctr; -int PatchPid() + +Patch::Patch(binPatch *_patch) { - *(u32*)(curr_kproc_addr + kproc_pid_offset) = 0; - return 0; + u32 processNamePosition=_patch->patchNameSize+_patch->descriptionSize; + + this->patchName.assign(_patch->binaryData,_patch->patchNameSize); + this->description.assign(&(_patch->binaryData[_patch->patchNameSize]),_patch->descriptionSize); + this->processName.assign(&(_patch->binaryData[processNamePosition]),_patch->processNameSize); + + this->minKernelVersion = _patch->minKernelVersion; + this->maxKernelVersion = _patch->maxKernelVersion; + this->minFirmwareVersion = _patch->minFirmwareVersion; + this->maxFirmwareVersion = _patch->maxFirmwareVersion; + this->devicesSupported = _patch->devicesSupported; + this->regionsSupported = _patch->regionsSupported; + this->nandCompability = _patch->nandCompability; + + this->patchType = _patch->patchType; + this->startAddressProcess = _patch->startAddressProcess; + this->startAddressGlobal = _patch->startAddressGlobal; + this->searchAreaSize = _patch->searchAreaSize; + this->numberOfReplacements = _patch->numberOfReplacements; + this->patchOffset = _patch->patchOffset; + + u32 originalcodeSize=_patch->originalcodeSize; + u8* originalcode = (u8*) malloc(originalcodeSize); + u32 originalCodePosition=_patch->patchNameSize+_patch->descriptionSize+_patch->processNameSize; + memcpy(originalcode,&(_patch->binaryData[originalCodePosition]),originalcodeSize); + this->originalCode={originalcodeSize, originalcode}; + + u32 patchcodeSize=_patch->patchcodeSize; + u8* patchcode = (u8*) malloc(patchcodeSize); + u32 patchCodePosition=originalCodePosition+originalcodeSize; + memcpy(patchcode,&(_patch->binaryData[patchCodePosition]),patchcodeSize); + this->patchCode={patchcodeSize, patchcode}; + + this->changeStatus(true); } -int UnpatchPid() +Patch::~Patch() { - *(u32*)(curr_kproc_addr + kproc_pid_offset) = self_pid; - return 0; + free(this->originalCode.code); + free(this->patchCode.code); } -void ReinitSrv() +string Patch::getPatchName() { - srvExit(); - srvInit(); + return this->patchName; } -void PatchSrvAccess() +string Patch::getDescription() { - svcGetProcessId(&self_pid, 0xFFFF8001); - printf("Current process id: %lu\n", self_pid); + return this->description; +} - printf("Patching srv access..."); - KernelBackdoor(PatchPid); - ReinitSrv(); +string Patch::getProcessName() +{ + return this->processName; +} - u32 new_pid; - svcGetProcessId(&new_pid, 0xFFFF8001); - printf("%s\n", new_pid == 0 ? "succeeded!" : "failed!"); - // Cleanup; won't take effect until srv is reinitialized - KernelBackdoor(UnpatchPid); +kernelVersion Patch::getMinKernelVersion() +{ + return this->minKernelVersion; } -*/ -//----------------------------------------------------------------------------- -int findAndPatchCode( const char* titleId, short titleIdSize, const u32 startAddress, const u32 area, unsigned char originalcode[], const char patchcode[],u32 patchcodeSize) -{ - KCodeSet* code_set = FindTitleCodeSet(titleId,titleIdSize); - if (code_set == nullptr) - return 1; - - unsigned char * startAddressPointer = (unsigned char*)FindCodeOffsetKAddr(code_set, startAddress); - unsigned char * destination=nullptr; - for(unsigned int i = 0; i < area && destination==nullptr; i+=4) - { - //check for the original code position - if( (*((unsigned int*)(startAddressPointer + i + 0x0)) == *((unsigned int*)&originalcode[0x0])) && - (*((unsigned int*)(startAddressPointer + i + 0x4)) == *((unsigned int*)&originalcode[0x4])) && - (*((unsigned int*)(startAddressPointer + i + 0x8)) == *((unsigned int*)&originalcode[0x8])) && - (*((unsigned int*)(startAddressPointer + i + 0xC)) == *((unsigned int*)&originalcode[0xC]))) - { - destination = startAddressPointer + i; - } - } - - //Apply patches, if the address was found - if(destination!=nullptr) - memcpy(destination, patchcode, patchcodeSize); - else - return 2; - - return 0; +kernelVersion Patch::getMaxKernelVersion() +{ + return this->maxKernelVersion; } -int findAndReplace( const char * titleId, short titleIdSize, const u32 startAddress, const u32 area, short numberOfReplaces, unsigned char originalcode[],u32 originalcodeSize,const char patchcode[],u32 patchcodeSize) +firmwareVersion Patch::getMinFirmwareVersion() { - KCodeSet* code_set = FindTitleCodeSet(titleId,titleIdSize); - if (code_set == nullptr) - return 1; + return this->minFirmwareVersion; +} - int numberOfFounds=0; - unsigned char * startAddressPointer = (unsigned char*)FindCodeOffsetKAddr(code_set, startAddress); - unsigned char * destination[numberOfReplaces]; - - for(int i=0;imaxFirmwareVersion; +} - for(unsigned int i = 0; i < area && numberOfFounds<=numberOfReplaces; i+=4) - { - //check for the original code position - bool found=true; - for(unsigned int x = 0;xdevicesSupported; } -int patchNimEshop() +regions Patch::getRegionsSupported() { - // Set generell informations for patching - static const char * titleId = "nim"; - static const u32 startAddress = 0x00001000; + return this->regionsSupported; +} - // Patch nim to answer, that no update is available - // 9.0.0 Address: 0x0000DD28 - static unsigned char originalcode[] = { 0x35, 0x22, 0x10, 0xB5, 0xD2, 0x01, 0x80, 0x18, 0x00, 0x79, 0x00, 0x28, 0x03, 0xD0, 0x08, 0x46}; - static const char patchcode[] = { 0x00, 0x20, 0x08, 0x60, 0x70, 0x47 }; - findAndPatchCode(titleId, 3, startAddress, 0x00010000, originalcode, patchcode, sizeof(patchcode)); +nands Patch::getNandCompability() +{ + return this->nandCompability; +} - return 0; + +u8 Patch::getPatchType() +{ + return this->patchType; } -int patchNimAutoUpdate() +u32 Patch::getStartAddressProcess() { - // Set generell informations for patching - static const char * titleId = "nim"; - static const u32 startAddress = 0x00001000; + return this->startAddressProcess; +} - // Patch nim to stop automatic update download(could be unstable) - // 9.0.0 Address: 0x0000EA00 - static unsigned char originalcode[] = { 0x25, 0x79, 0x0B, 0x99, 0x00, 0x24, 0x00, 0x2D, 0x29, 0xD0, 0x16, 0x4D, 0x2D, 0x68, 0x01, 0x91}; - static char patchcode[] = { 0xE3, 0xA0, 0x00, 0x00 }; - findAndPatchCode(titleId, 3, startAddress, 0x00010000, originalcode, patchcode, sizeof(patchcode)); +u32 Patch::getStartAddressGlobal() +{ + return this->startAddressGlobal; +} - return 0; +u32 Patch::getSearchAreaSize() +{ + return this->searchAreaSize; } -int patchRegionFree() +u32 Patch::getNumberOfReplacements() { - patchMenu(); - patchNs(); - return 0; + return this->numberOfReplacements; } -int patchMenu() +u32 Patch::getPatchOffset() { - // Set generell informations for patching - static const char * titleId = "menu"; - static const u32 startAddress = 0x00100000; + return this->patchOffset; +} - // patch Homemenu to show out of region applications - // 9.0.0 Address: 0x00101B8C; - static unsigned char originalcode[] = { 0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3, 0x11, 0x00, 0xA0, 0xE1, 0x03, 0x00, 0x00, 0x0A }; - static char patchcode[] = { 0x01, 0x00, 0xA0, 0xE3, 0x70, 0x80, 0xBD, 0xE8 }; - findAndPatchCode(titleId, 4, startAddress, 0x00100000, originalcode, patchcode, sizeof(patchcode)); +code Patch::getOriginalCode() +{ + return this->originalCode; +} - return 0; +code Patch::getPatchCode() +{ + return this->patchCode; } -int patchNs() + +bool Patch::changeStatus() { - // Set generell informations for patching - static const char * titleId = "ns"; - static const u32 startAddress = 0x00018000; + return this->changeStatus(!this->enabled); +} - // patch NS to return update doesnt need to be installed intead of CVer not found error code after Update Check - // 9.0.0 Addresses: 0x00102acc, 0x001894f4; - static char patchcode[] = { 0x0B, 0x18, 0x21, 0xC8 }; - static unsigned char originalcode[] = { 0x0C, 0x18, 0xE1, 0xD8 }; - findAndReplace(titleId, 2, startAddress, 0x00010000, 2, originalcode, sizeof(originalcode), patchcode, sizeof(patchcode)); +bool Patch::changeStatus(bool status) +{ + this->enabled=status; + return this->enabled; +} - return 0; +bool Patch::isEnabled() +{ + return this->enabled; } + + +//----------------------------------------------------------------------------- /* -Todo: find offsets -int patchDlp() -{ - // Set generell informations for patching - static const char * titleId = "dlp"; - static const u32 startAddress = 0x00008000; +u32 self_pid = 0; - // patch NS to return update doesnt need to be installed intead of CVer not found error code after Update Check - // 9.0.0 Addresses: 0x00102acc, 0x001894f4; - static char patchcode[] = { 0x0B, 0x18, 0x21, 0xC8 }; - static unsigned char originalcode[] = { 0x0C, 0x18, 0xE1, 0xD8 }; - findAndReplace(titleId, 2, startAddress, 0x00010000, 2, originalcode, sizeof(originalcode), patchcode, sizeof(patchcode)); +int PatchPid() +{ + *(u32*)(curr_kproc_addr + kproc_pid_offset) = 0; + return 0; +} +int UnpatchPid() +{ + *(u32*)(curr_kproc_addr + kproc_pid_offset) = self_pid; return 0; -}*/ +} + +void ReinitSrv() +{ + srvExit(); + srvInit(); +} + +void PatchSrvAccess() +{ + svcGetProcessId(&self_pid, 0xFFFF8001); + printf("Current process id: %lu\n", self_pid); + + printf("Patching srv access..."); + KernelBackdoor(PatchPid); + ReinitSrv(); + + u32 new_pid; + svcGetProcessId(&new_pid, 0xFFFF8001); + printf("%s\n", new_pid == 0 ? "succeeded!" : "failed!"); + + // Cleanup; won't take effect until srv is reinitialized + KernelBackdoor(UnpatchPid); +} +*/ +//----------------------------------------------------------------------------- /* Todo: -//doesnt work atm(crashes)*/ +doesnt work atm(crashes) int changeSerial() { // Target title id @@ -222,4 +225,105 @@ int changeSerial() findAndReplace(titleIdAct, 3, startAddressAct, 0x00000030, 1, orgSerial, sizeof(orgSerial), serial, sizeof(serial)); return 0; +}*/ + +void createDefaultPatches() +{ + FILE *file ; + string filepath=""; + + // Patch nim to answer, that no update is available(doesnt affect updating in systemsettings) + // 9.0.0 Address: 0x0000DD28 + char nimSpoofBytes[]= /*patchName*/ "e-shop spoof" + /*description*/ "Patches nim for E-Shop access" + /*processname*/ "nim" + /*OriginalCode*/"\x35\x22\x10\xB5\xD2\x01\x80\x18\x00\x79\x00\x28\x03\xD0\x08\x46" + /*patchBegin*/ "\x00\x20\x08\x60\x70\x47"; + + u32 nimSpoofSize = sizeof(binPatch) + sizeof(nimSpoofBytes); + binPatch* nimSpoofPatch = (binPatch*)malloc(nimSpoofSize); + + nimSpoofPatch->version = 0x00; + nimSpoofPatch->patchSize = nimSpoofSize; + nimSpoofPatch->patchNameSize = 12; + nimSpoofPatch->descriptionSize = 29; + nimSpoofPatch->processNameSize = 3; + nimSpoofPatch->originalcodeSize = 16; + nimSpoofPatch->patchcodeSize = 6; + nimSpoofPatch->processType = 0x01; + nimSpoofPatch->minKernelVersion = {0x00, 0x00, 0x00, 0x00}; + nimSpoofPatch->maxKernelVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + nimSpoofPatch->minFirmwareVersion = { 9, 0, 0, 20 }; + nimSpoofPatch->maxFirmwareVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + nimSpoofPatch->devicesSupported = {1,1,1,1,1,0}; + nimSpoofPatch->regionsSupported = {1,1,1,1,1,1,1,0}; + nimSpoofPatch->nandCompability = {1,1,0}; + nimSpoofPatch->patchType = 0x00; + nimSpoofPatch->startAddressProcess = 0x00001000; + nimSpoofPatch->startAddressGlobal = 0x26A00000; + nimSpoofPatch->searchAreaSize = 0x00100000; + nimSpoofPatch->numberOfReplacements = 0x01; + nimSpoofPatch->patchOffset = 0; + + memcpy(nimSpoofPatch->binaryData, nimSpoofBytes, sizeof(nimSpoofBytes)); + + string nimSpoofPatchFileName="nimSpoof"+patchExtension; + + filepath=patchesFolder+nimSpoofPatchFileName; + file = fopen(filepath.c_str(),"wb"); + if (file == NULL) + { + file = fopen(filepath.c_str(),"cb"); + } + fwrite(nimSpoofPatch, 1, (nimSpoofSize), file); + fclose(file); + free(nimSpoofPatch); + + + // Patch nim to stop automatic update download(could be unstable) + // 9.0.0 Address: 0x0000EA00 + char nimUpdateBytes[]= /*patchName*/ "no auto download" + /*description*/ "Patch nim to stop automatic update download(could be unstable)" + /*processname*/ "nim" + /*OriginalCode*/"\x25\x79\x0B\x99\x00\x24\x00\x2D\x29\xD0\x16\x4D\x2D\x68\x01\x91" + /*patchBegin*/ "\xE3\xA0\x00\x00"; + + u32 nimUpdateSize = sizeof(binPatch) + sizeof(nimUpdateBytes); + binPatch* nimUpdatePatch = (binPatch*)malloc(nimUpdateSize); + + nimUpdatePatch->version = 0x00; + nimUpdatePatch->patchSize = nimUpdateSize; + nimUpdatePatch->patchNameSize = 16; + nimUpdatePatch->descriptionSize = 62; + nimUpdatePatch->processNameSize = 3; + nimUpdatePatch->originalcodeSize = 16; + nimUpdatePatch->patchcodeSize = 4; + nimUpdatePatch->processType = 0x01; + nimUpdatePatch->minKernelVersion = {0x00, 0x00, 0x00, 0x00}; + nimUpdatePatch->maxKernelVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + nimUpdatePatch->minFirmwareVersion = { 4, 0, 0, 0 }; + nimUpdatePatch->maxFirmwareVersion = {0xFF, 0xFF, 0xFF, 0xFF}; + nimUpdatePatch->devicesSupported = {1,1,1,1,1,0}; + nimUpdatePatch->regionsSupported = {1,1,1,1,1,1,1,0}; + nimUpdatePatch->nandCompability = {1,1,0}; + nimUpdatePatch->patchType = 0x00; + nimUpdatePatch->startAddressProcess = 0x00001000; + nimUpdatePatch->startAddressGlobal = 0x26A00000; + nimUpdatePatch->searchAreaSize = 0x00010000; + nimUpdatePatch->numberOfReplacements = 0x01; + nimUpdatePatch->patchOffset = 0; + + memcpy(nimUpdatePatch->binaryData, nimUpdateBytes, sizeof(nimUpdateBytes)); + + string nimUpdatePatchFileName="nimUpdate"+patchExtension; + + filepath=patchesFolder+nimUpdatePatchFileName; + file = fopen(filepath.c_str(),"wb"); + if (file == NULL) + { + file = fopen(filepath.c_str(),"cb"); + } + fwrite(nimUpdatePatch, 1, (nimUpdateSize), file); + fclose(file); + free(nimUpdatePatch); } diff --git a/source/saveEntrys.cpp b/source/saveEntrys.cpp new file mode 100644 index 0000000..24f4ab3 --- /dev/null +++ b/source/saveEntrys.cpp @@ -0,0 +1,33 @@ +#include "saveEntrys.h" + +using namespace std; + + +SaveEntry::SaveEntry(Settings* settings) :MenuEntry("save", "") +{ + if (settings != nullptr) + { + this->settings = settings; + } +} + +int SaveEntry::aAction() +{ + if(this->settings!=nullptr) + return this->settings->saveSettings(); + return 2; +} + + +PatchSaveEntry::PatchSaveEntry(PatchManager* manager) :MenuEntry("save", "") +{ + if (manager != nullptr) + { + this->patchManager = manager; + } +} + +int PatchSaveEntry::aAction() +{ + return this->patchManager->saveSettings(); +} diff --git a/source/settings.cpp b/source/settings.cpp new file mode 100644 index 0000000..5851056 --- /dev/null +++ b/source/settings.cpp @@ -0,0 +1,189 @@ +#include <3ds.h> +#include +#include "settings.h" +#include "constants.h" +#include "helpers.h" +#include "stdlib.h" + +#include "saveEntrys.h" + +using namespace std; +using namespace ctr; + +Settings* globalSettings; + +//placeholder for possible later types of emunand +typedef struct settingsElementStruct +{ + u32 value; + char name[MAXNAMELENGTH+1]; +}settingsElement; + + +bool initGlobalSettings() +{ + globalSettings = new Settings(globalSettingsFileName); + globalSettings->addElement("ignoreFirmware",false); + globalSettings->addElement("ignoreKernel", false); + globalSettings->addElement("ignoreRegion", false); + globalSettings->addElement("ignoreDeviceType", false); + globalSettings->addElement("ignoreFirmwareCollection", false); + globalSettings->addElement("ignoreKernelCollection", false); + globalSettings->addElement("ignoreRegionCollection", false); + globalSettings->addElement("ignoreDeviceTypeCollection", false); + globalSettings->addElement(SETTINGS_AUTOBOOT, false); + globalSettings->loadSettings(globalSettingsFileName); + return true; +} + +Settings::Settings(std::string configName) +{ + this->name = configName; + loadSettings(configName); +} + +bool Settings::loadSettings(std::string configName) +{ + if (configName == "") + return false; + + if (!checkFolder(settingsFolder)) + return false; + + this->name = configName; + + string filepath = settingsFolder+configName+settingsExtension; + FILE *file = fopen(filepath.c_str(), "rb"); + if (file != NULL) + { + size_t fileSize = 0; + settingsElement* elements= (settingsElement*) loadFile(file, 0, &fileSize); + u32 numberOfElements = fileSize / sizeof(settingsElement); + for (u32 i = 0;i < numberOfElements;i++) + { + string* tmp = new string(elements[i].name); + this->updateElement(*tmp, elements[i].value); + } + free(elements); + } + return true; +} + +Result Settings::addElement(std::string key, u32 value) +{ + if (key != "") + { + if (!hasElement(key)) + { + settings.insert({ key, value }); + if (hasElement(key)) + return ADDED; + else + return ERROR; + } + else + { + return ALREADYEXIST; + } + } + return EMPTYKEY; +} + +bool Settings::hasElement(string key) +{ + SETTINGSMAP::iterator it = settings.find(key); + if (it == settings.end()) + return false; + else + return true; +} + +Result Settings::updateElement(std::string key, u32 value) +{ + if (key != "") + { + if (hasElement(key)) + { + SETTINGSMAP::iterator it = settings.find(key); + it->second = value; + return true; + } + else + return addElement(key, value); + } + return ERROR; +} + +bool Settings::removeElement(std::string key) +{ + settings.erase(key); + return true; +} + +bool Settings::saveSettings() +{ + if (!checkFolder(settingsFolder)) + return false; + + string filepath = settingsFolder + this->name + settingsExtension; + FILE *file = fopen(filepath.c_str(), "wb"); + if (file == NULL) + { + file = fopen(filepath.c_str(), "cb"); + } + if (file == NULL) + return false; + u32 elementsSize = settings.size()*sizeof(settingsElement); + settingsElement* elements = (settingsElement*) malloc(elementsSize); + u32 i = 0; + memset(elements, 0, elementsSize); + for (SETTINGSMAP::iterator it = settings.begin(); it != settings.end(); ++it) + { + if (it->first == "") + continue; + memcpy(&elements[i].name, it->first.c_str(), it->first.size()); + elements[i].value = it->second; + i++; + } + + fwrite(elements, 1, elementsSize, file); + fclose(file); + free(elements); + return true; +} + +u32 Settings::getValue(std::string elementName) +{ + if(this->hasElement(elementName)) + return settings.find(elementName)->second; + else return 0; +} + +u32* Settings::getValuePointer(std::string elementName) +{ + if (this->hasElement(elementName)) + return &settings.find(elementName)->second; + else return nullptr; +} + +u32 Settings::getNumberOfElements() +{ + return this->settings.size(); +} + +bool Settings::createMenuPage(MenuManager* menuManager) +{ + Menu* page = new Menu(menuManager, menuManager->getMainPage()); + + for (SETTINGSMAP::iterator it = settings.begin(); it != settings.end(); ++it) + { + YesNoMenuEntry* entry = new YesNoMenuEntry((bool*)&(it->second), it->first, ""); + page->addEntry((MenuEntry*)entry); + } + page->addEntry((MenuEntry*)new SaveEntry(this)); + + + menuManager->addPage(page, page->getParentMenu(), "Settings"); + + return true; +} diff --git a/source/updater.cpp b/source/updater.cpp new file mode 100644 index 0000000..8bb70d7 --- /dev/null +++ b/source/updater.cpp @@ -0,0 +1,266 @@ +#include "updater.h" +#include "constants.h" +#include "settings.h" +#include +#include +#include +#include "saveEntrys.h" +#include "updaterEntry.h" +#include "helpers.h" + + +using namespace std; +using namespace ctr; + +Updater::Updater(MenuManager* manager, bool* exitLoop) +{ + this->onlineVersion = 0; + this->onlineVersionString = ""; + this->menuPage = nullptr; + this->exitLoop = exitLoop; + + + this->updaterSettings = new Settings("Updater"); + this->updaterSettings->addElement(SETTINGS_BOOT_CHECK, false); + this->updaterSettings->addElement(SETTINGS_UPDATE_NOTIFICATION, false); + this->updaterSettings->addElement(SETTINGS_DEV_BUILDS, false); + this->updaterSettings->addElement(SETTINGS_LAST_NOTIFICATION, version); + this->updaterSettings->loadSettings("Updater"); + + this->createMenuPage(manager); + + if (this->updaterSettings->getValue(SETTINGS_BOOT_CHECK)) + this->checkForUpdate(); +} + + +Result Updater::checkForUpdate() +{ + Result ret = checkVersion(); + if (this->onlineVersion > version) + { + if (this->updaterSettings->getValue(SETTINGS_UPDATE_NOTIFICATION)) + this->createUpdateNotification(); + if (this->installEntryAdded == false) + { + MenuEntry* entry = (MenuEntry*) new UpdaterMenuEntry(&Updater::updateApplication, this, "Update application", "Downloads and installs Updates.\nThe application will close itself after sucess."); + menuPage->addEntry((MenuEntry*)entry); + installEntryAdded = true; + } + } + return ret; +} + + +Result Updater::updateApplication() +{ + Result res = 0; + if (this->onlineVersion == 0) + this->checkVersion(); + if (this->onlineVersion>version) + { + res = this->downloadUpdate(); + if (res == 0) + res = this->installUpdate(); + } + return res; +} + + +Result Updater::createMenuPage(MenuManager* manager) +{ + this->menuPage = new Menu(manager, manager->getMainPage()); + MenuEntry* entry= (MenuEntry*)new YesNoMenuEntry((bool*)this->updaterSettings->getValuePointer(SETTINGS_BOOT_CHECK), + "Auto check for Updates", + "Always check online for new versions at start"); + menuPage->addEntry((MenuEntry*)entry); + + entry = (MenuEntry*)new YesNoMenuEntry((bool*)this->updaterSettings->getValuePointer(SETTINGS_UPDATE_NOTIFICATION), + "Create update notifications", + "Create update notifikations in the homemenu for new Versions"); + menuPage->addEntry((MenuEntry*)entry); + + entry = (MenuEntry*)new YesNoMenuEntry((bool*)this->updaterSettings->getValuePointer(SETTINGS_DEV_BUILDS), + "Enable DevelopmentBuilds", + "This enables Development builds.\n Warning these builds could be broken"); + menuPage->addEntry((MenuEntry*)entry); + + entry = (MenuEntry*) new SaveEntry(this->updaterSettings); + menuPage->addEntry((MenuEntry*)entry); + + entry = (MenuEntry*) new UpdaterMenuEntry(&Updater::checkForUpdate, this, "Check for Updates", "Check online for new Updates"); + menuPage->addEntry((MenuEntry*)entry); + + manager->addPage(this->menuPage, "Updater"); + + return 0; +} + + +Result Updater::checkVersion() +{ + this->onlineVersion = 0; + this->onlineVersionString = ""; + size_t downloadSize = 0; + u8* downloadResult = nullptr; + const string* currentVersionCheck = &versionCheckUrl; + if (this->updaterSettings->getValue(SETTINGS_DEV_BUILDS)) + currentVersionCheck = &VersionCheckUrlDev; + Result res = download((string*)currentVersionCheck, &downloadSize, &downloadResult); + if (res == 0) + { + this->onlineVersionString = getStringFromDownload(downloadSize, downloadResult); + this->onlineVersion = (int)strtol(onlineVersionString.c_str(), NULL, 16); + free(downloadResult); + } + return res; +} + + +Result Updater::createUpdateNotification() +{ + if (this->updaterSettings->getValue(SETTINGS_LAST_NOTIFICATION) < this->onlineVersion) + { + const char title8[] = { "A New Version is available" }; + string message = "A new version is available:\n" + generateVersionString(this->onlineVersion) + "\n\nPlease install it directly inside of \nthe fpm or download it from\nhttp://fmp.hartie95.de/releases\n"; + + string changelog = this->getChangelog(); + if (changelog != "") + message += "\nChangelog:\n"+changelog; + + u32 messageSize = message.size(); + u16 title16[sizeof(title8)]; + u16 message16[messageSize + 1]; + for (u32 i = 0; i < sizeof(title8); i++) + { + title16[i] = (u16)title8[i]; + } + for (u32 i = 0; i < messageSize; i++) + { + message16[i] = (u16)message.at(i); + } + message16[messageSize] = (u16)'\0'; + + NEWS_AddNotification(title16, sizeof(title8), message16, messageSize, nullptr, 0, false); + this->updaterSettings->updateElement(SETTINGS_LAST_NOTIFICATION, this->onlineVersion); + this->updaterSettings->saveSettings(); + } + return 0; +} + + +Result Updater::downloadUpdate() +{ + size_t downloadSize = 0; + u8* downloadResult = nullptr; + string url = mainDownloadUrl + this->onlineVersionString + ".txt"; + if (this->updaterSettings->getValue(SETTINGS_DEV_BUILDS)) + url = mainDownloadUrlDev+this->onlineVersionString+".txt"; + Result res = download(&url,&downloadSize,&downloadResult); + + if (res == 0) + { + string ciaUrl = getStringFromDownload(downloadSize, downloadResult); + free(downloadResult); + res = download(&ciaUrl, &downloadSize, &downloadResult); + if (res == 0) + { + string UpdateFileName = this->onlineVersionString + ".cia"; + + string filepath = applicationFolder + UpdateFileName; + FILE* file = fopen(filepath.c_str(), "wb"); + if (file == NULL) + { + file = fopen(filepath.c_str(), "cb"); + } + fwrite(downloadResult, 1, (downloadSize), file); + fclose(file); + free(downloadResult); + } + } + + return 0; +} + + +string Updater::getChangelog() +{ + size_t downloadSize = 0; + u8* downloadResult = nullptr; + string changelog = ""; + string fileName = this->onlineVersionString + ".log"; + string url = mainDownloadUrl; + if (this->updaterSettings->getValue(SETTINGS_DEV_BUILDS)) + url = mainDownloadUrlDev; + url += fileName; + + Result res = download(&url, &downloadSize, &downloadResult); + + if (res == 0) + { + changelog = getStringFromDownload(downloadSize, downloadResult); + } + return changelog; +} + + +Result Updater::installUpdate() +{ + string UpdateFileName = this->onlineVersionString + ".cia"; + + string filepath = applicationFolder + UpdateFileName; + /*App applicationInformation = appGetCiaInfo(filepath, SD);*/ + FILE* fd = fopen(filepath.c_str(), "r"); + if (!fd) { + return 1; + } + + struct stat st; + fstat(fileno(fd), &st); + + app::install(fs::SD, fd,(u64) st.st_size, NULL); + if (!err::has()) + *exitLoop = true; + return 0; +} + + +Result Updater::download(std::string* url, size_t* filesize, u8** file) +{ + httpcContext context; + Result ret = 0; + Result res = 1; + u32 statuscode = 0; + char * cUrl = (char*)url->c_str(); + ret = httpcOpenContext(&context, cUrl, 0); + if (ret == 0) + { + ret = httpcBeginRequest(&context); + if (ret == 0) + { + ret = httpcGetResponseStatusCode(&context, &statuscode, 0); + if (ret == 0 && statuscode == 200) + { + u32 contentsize = 0; + ret = httpcGetDownloadSizeState(&context, NULL, &contentsize); + if (ret == 0) + { + *file = (u8*)malloc(contentsize); + memset(*file, 0, contentsize); + ret = httpcDownloadData(&context, *file, contentsize, NULL); + if (ret == 0) + { + *filesize = contentsize; + res = 0; + httpcCloseContext(&context); + } + else + { + free(*file); + } + } + } + } + } + return res; +} diff --git a/source/updaterEntry.cpp b/source/updaterEntry.cpp new file mode 100644 index 0000000..65a7899 --- /dev/null +++ b/source/updaterEntry.cpp @@ -0,0 +1,15 @@ +#include "updaterEntry.h" + +UpdaterMenuEntry::UpdaterMenuEntry(actionFunction function, Updater* updater, std::string name, std::string description) : MenuEntry(name, description) +{ + this->aFunction = function; + this->updater = updater; +} + +int UpdaterMenuEntry::aAction() +{ + Result res = 0; + if (this->aFunction != nullptr) + res = (this->updater->*this->aFunction)(); + return res; +}