Skip to content
This repository was archived by the owner on Mar 2, 2022. It is now read-only.

Commit

Permalink
Implemented first part of the patchlayout(still work in progress)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hartie95 committed Jul 31, 2015
1 parent cdffb5e commit 3ea4790
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 3 deletions.
4 changes: 3 additions & 1 deletion include/patches.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ int patchRegionFree();
int patchMenu();
int patchNs();
//int patchDlp();
int changeSerial();
int changeSerial();

void test();
2 changes: 2 additions & 0 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ int main(int argc, char **argv) {

short exitLoop=false;

test();
while(platformIsRunning()&&exitLoop==false) {
//Todo: replace with switch case
inputPoll();
Expand Down Expand Up @@ -132,6 +133,7 @@ int main(int argc, char **argv) {
break;
}
}


if(inputIsPressed(BUTTON_START)) {
applyPatches(patchlist);
Expand Down
330 changes: 328 additions & 2 deletions source/patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,53 @@ void PatchSrvAccess()
*/
//-----------------------------------------------------------------------------

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 nandTypesStruct
{
u32 System:1;
u32 Emu:1;
u32 placeholder:6;
} nands;

typedef struct patchStruct
{
char version;
u32 patchNameSize;
u32 descriptionSize;
u32 processNameSize;
u32 originalcodeSize;
u32 patchcodeSize;
u32 processType;
u32 minKernelVersion;
u32 maxKernelVersion;
regions regionsSupported;
nands nandCompability;
u8 patchType;
u32 startAddressProcess;
u32 startAddressGlobal;
u32 searchAreaSize;
u32 numberOfReplacements;
char binaryData[];
} patch;

patch filePatch;

patch* loadedPatches[256];
u32 numberOfLoadedPatches;

patch* tmpPatch;

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);
Expand Down Expand Up @@ -155,20 +202,299 @@ int patchRegionFree()
return 0;
}

int findAndPatchCode_test(patch* _patch)
{
const u32 startAddress=_patch->startAddressProcess;
const u32 area=_patch->searchAreaSize;

short titleIdSize=_patch->processNameSize;
unsigned int titleIdPosition=_patch->patchNameSize+_patch->descriptionSize;
char titleId[_patch->processNameSize];
memcpy(titleId,&(_patch->binaryData[titleIdPosition]),_patch->processNameSize);

unsigned char originalcode[_patch->originalcodeSize];
unsigned int originalCodePosition=_patch->patchNameSize+_patch->descriptionSize+_patch->processNameSize;
memcpy(originalcode,&(_patch->binaryData[originalCodePosition]),_patch->originalcodeSize);

u32 patchcodeSize=_patch->patchcodeSize;
char patchcode[patchcodeSize];
unsigned int patchCodePosition=originalCodePosition+_patch->originalcodeSize;

This comment has been minimized.

Copy link
@Syphurith

Syphurith Aug 1, 2015

Hi @hartmannaf would you please replace all unsigned int to u32 to make it a little shorter? also unsigned char to u8. Cause you have those definitions already?

This comment has been minimized.

Copy link
@Hartie95

Hartie95 Aug 1, 2015

Author Owner

Yes, I will clean up the code later today, after that I will implement the other functions needed for the patch types and rewrite the menu generation. Don't know how much time I will need for it.

This comment has been minimized.

Copy link
@Syphurith

Syphurith Aug 1, 2015

Just do it step by step. You could clean it file after file.
This u32, unsigned int, or other type names are just naming problem. Not severe.

memcpy(patchcode,&(_patch->binaryData[patchCodePosition]),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;
}
}

This comment has been minimized.

Copy link
@Syphurith

Syphurith Aug 1, 2015

Eh.. I recall this from rxTools myThread.c isn't it. However it is due to a timing related patch job. I don't know if this is really need to be done in such a way when all stuffs already loaded totally. Thanks at least you could keep this if not cause too much time.

This comment has been minimized.

Copy link
@Hartie95

Hartie95 Aug 1, 2015

Author Owner

In rxtools for the timing it is mostly the big area that is searched. Maybe it could be improved, but that could be done later

This comment has been minimized.

Copy link
@Syphurith

Syphurith Aug 1, 2015

Roxas told me that the region-free he implemented is timing related.
I did write a ugly memmem implementation for it but own build does not run properly.
Yeh you could always test out new implementations - users can not easily find it out.


//Apply patches, if the address was found
if(destination!=nullptr)
memcpy(destination, patchcode, patchcodeSize);
/*else
return 2;
*/
return 0;
}

int patchMenu()
{
/*static patch menuPatch=
// patch Homemenu to show out of region applications
// 9.0.0 Address: 0x00101B8C;
{
0x00 ,//short version;
17 ,//short patchNameSize;
49 ,//short descriptionSize;
4 ,//short processNameSize
16 ,//short originalcodeSize;
8 ,//short patchcodeSize;
0x01 ,//short processType;
0x00 ,//u32 minKernelVersion;
0xffffffff ,//u32 maxKernelVersion;
{1,1,1,1,1,1,1,1},//regions regionssupported;
0x00 ,//short nandCompability;
0x00 ,//short patchType;
0x00100000 ,//u32 startAddressProcess;
0x26A00000 ,//u32 startAddressGlobal;
0x00100000 ,//u32 searchAreaSize;
0x01 ,//u32 numberOfReplacements
// /*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"

// BYTE binaryData[];
//};


// memcpy(menuPatch.binaryData,binary,sizeof(binary));
// Set generell informations for patching
static const char * titleId = "menu";
/* static const char * titleId = "menu";
static const u32 startAddress = 0x00100000;
// 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));
findAndPatchCode(titleId, 4, startAddress, 0x00100000, originalcode, patchcode, sizeof(patchcode));*/
/* const u32 startAddress=_patch->startAddressProcess;
const u32 area=_patch->searchAreaSize;
short titleIdSize=_patch->patchNameSize;
unsigned int titleIdPosition=_patch->patchNameSize+_patch->descriptionSize;
unsigned int originalCodePosition=_patch->patchNameSize+_patch->descriptionSize+_patch->processNameSize;
u32 patchcodeSize=_patch->patchcodeSize;
unsigned int patchCodePosition=originalCodePosition+_patch->originalcodeSize;
*/
//findAndPatchCode(&_patch->binaryData[titleIdPosition], 4, _patch->startAddressProcess, 0x00100000, &_patch->binaryData[originalCodePosition], &_patch->binaryData[patchCodePosition], _patch->patchcodeSize);
for(u32 i = 0; i<numberOfLoadedPatches;i++)
{
findAndPatchCode_test(loadedPatches[i]);
}
return 0;
}
#include <ctrcommon/gpu.hpp>
#include <ctrcommon/fs.hpp>

#include <sys/dirent.h>
#include <sys/stat.h>
using namespace std;

static const string patchesFolder="sdmc:/fmp/patches/";
static const string patchExtension=".patch";

void createDefaultPatches()
{
// check if the patches Folder exists
if(!fsExists(patchesFolder))
mkdir(patchesFolder.c_str(), 0777);

// 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";

static patch* menuPatch=(patch*)malloc(sizeof(patch)+sizeof(menuBytes));

menuPatch->version = 0x00;
menuPatch->patchNameSize = 17;
menuPatch->descriptionSize = 49;
menuPatch->processNameSize = 4;
menuPatch->originalcodeSize = 16;
menuPatch->patchcodeSize = 8;
menuPatch->processType = 0x01;
menuPatch->minKernelVersion = 0x0;
menuPatch->maxKernelVersion = 0x0;
menuPatch->regionsSupported = {1,1,1,1,1,1,1,0};
menuPatch->nandCompability = {1,1,0};
menuPatch->patchType = 0x00;
menuPatch->startAddressProcess = 0x00100000;
menuPatch->startAddressGlobal = 0x26A00000;
menuPatch->searchAreaSize = 0x00100000;
menuPatch->numberOfReplacements = 0x01;

memcpy(menuPatch->binaryData, menuBytes, sizeof(menuBytes));

string menuPatchFileName="menu"+patchExtension;

string filepath=patchesFolder+menuPatchFileName;
FILE *file = fopen(filepath.c_str(),"w");
if (file == NULL)
{
file = fopen(filepath.c_str(),"c");
}
fwrite(menuPatch,1,(sizeof(patch)+sizeof(menuBytes)),file);
fclose(file);



// Patch nim to stop automatic update download(could be unstable)
// 9.0.0 Address: 0x0000EA00
char nimBytes[]=/*patchName*/ "e-shop spoof"
/*description*/ "Patches nim for E-Shop access"
/*processname*/ "nim"
/*OriginalCode*/ "\x25\x79\x0B\x99\x00\x24\x00\x2D\x29\xD0\x16\x4D\x2D\x68\x01\x91"
/*patchBegin*/ "\xE3\xA0\x00\x00";

static patch* nimPatch=(patch*)malloc(sizeof(patch)+sizeof(nimBytes));

nimPatch->version = 0x00;
nimPatch->patchNameSize = 12;
nimPatch->descriptionSize = 29;
nimPatch->processNameSize = 3;
nimPatch->originalcodeSize = 16;
nimPatch->patchcodeSize = 2;
nimPatch->processType = 0x01;
nimPatch->minKernelVersion = 0x0;
nimPatch->maxKernelVersion = 0xFFFFFFFF;
nimPatch->regionsSupported = {1,1,1,1,1,1,1,0};
nimPatch->nandCompability = {1,1,0};
nimPatch->patchType = 0x00;
nimPatch->startAddressProcess = 0x00001000;
nimPatch->startAddressGlobal = 0x26A00000;
nimPatch->searchAreaSize = 0x00100000;
nimPatch->numberOfReplacements = 0x01;

memcpy(nimPatch->binaryData, nimBytes, sizeof(nimBytes));

string nimPatchFileName="nim"+patchExtension;

filepath=patchesFolder+nimPatchFileName;
file = fopen(filepath.c_str(),"w");
if (file == NULL)
{
file = fopen(filepath.c_str(),"c");
}
fwrite(nimPatch,1,(sizeof(patch)+sizeof(nimBytes)),file);
fclose(file);
}

bool isPatch(struct dirent* file)
{
u32 nameLength=strlen(file->d_name);
if (nameLength >= patchExtension.size() && strcmp(file->d_name + nameLength - patchExtension.size(), patchExtension.c_str()) == 0) {
return true;
}

return false;
}

int getNumberOfPatchFiles(DIR* dir)
{
u32 numberOfFiles=0;
struct dirent *currenElement;
while ((currenElement = readdir(dir)) != NULL)
{
if(isPatch(currenElement))
numberOfFiles++;
}
seekdir(dir,SEEK_SET);
return numberOfFiles;
}

patch* loadPatch(FILE* file)
{
patch* loadedPatch=nullptr;
if(file != NULL)
{
fseek(file, 0L, SEEK_END);
u32 fileSize = ftell(file);
fseek(file, 0L, SEEK_SET);

loadedPatch=(patch*)malloc(fileSize);
if(loadedPatch!=nullptr)
{
fread(loadedPatch,1,fileSize,file);
}
fclose(file);
}
return loadedPatch;
}

void test()
{
createDefaultPatches();

DIR *dir;
dir = opendir(patchesFolder.c_str());
if (dir)
{
u32 numberOfPatchFiles=getNumberOfPatchFiles(dir);
FILE* patchFiles[numberOfPatchFiles];

closedir(dir);
dir = opendir(patchesFolder.c_str());
numberOfLoadedPatches=0;
struct dirent *currenElement;
while ((currenElement = readdir(dir)) != NULL)
{
if(isPatch(currenElement))
{
string filepath=patchesFolder+currenElement->d_name;
FILE* file = fopen(filepath.c_str(),"rb");
patch* tmp=loadPatch(file);
if(tmp!=nullptr)
{
loadedPatches[numberOfLoadedPatches]=tmp;
numberOfLoadedPatches++;
}
}
}
//numberOfLoadedPatches=1;
//tmpPatch=loadPatch(file);
//loadedPatches=(patch**)malloc(sizeof(patch*)*numberOfPatchFiles);

/*for(u32 i=0;i<numberOfPatchFiles;i++)
{
patch* tmp=loadPatch(patchFiles[i]);
if(tmp!=nullptr)
tmpPatch=tmp;
}*/
}
closedir(dir);
}

int patchNs()
{
Expand Down

3 comments on commit 3ea4790

@Syphurith
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good this is not too hacky as what i expected.. If i do understand in a wrong way, could you please tell me where you are feeling uneasy for this commit?

@Hartie95
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementing is not finished, and the test function loads the patches :)

@Syphurith
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mean findAndPatchCode_test i don't find much problems.
And for the layout.. Oh it could be improved to make loading patches easier.
Just load it sequently, you don't really need to use the structure while loading (not while writing of course).
Eh if you do really like OO a lot, you could ignore such things..

Please sign in to comment.