2016-03-29 17:43:53 +02:00
|
|
|
#include <3ds.h>
|
|
|
|
#include "patcher.h"
|
2016-09-06 14:09:29 +02:00
|
|
|
#include "memory.h"
|
|
|
|
#include "strings.h"
|
2016-03-29 17:43:53 +02:00
|
|
|
#include "ifile.h"
|
2016-08-29 17:51:03 +02:00
|
|
|
#include "CFWInfo.h"
|
2016-03-29 17:43:53 +02:00
|
|
|
|
2016-08-28 13:49:15 +02:00
|
|
|
static CFWInfo info;
|
2016-03-29 17:43:53 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
u32 i;
|
|
|
|
|
|
|
|
for(i = 0; i < count; i++)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-04-02 18:48:31 +02:00
|
|
|
u8 *found = memsearch(start, pattern, size, patSize);
|
2016-04-02 17:58:06 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
if(found == NULL) break;
|
2016-03-29 17:43:53 +02:00
|
|
|
|
2016-04-02 18:48:31 +02:00
|
|
|
memcpy(found + offset, replace, repSize);
|
2016-03-29 17:43:53 +02:00
|
|
|
|
|
|
|
u32 at = (u32)(found - start);
|
|
|
|
|
2016-04-11 17:57:22 +02:00
|
|
|
if(at + patSize > size) break;
|
2016-03-29 17:43:53 +02:00
|
|
|
|
2016-04-11 17:57:22 +02:00
|
|
|
size -= at + patSize;
|
2016-04-02 18:48:31 +02:00
|
|
|
start = found + patSize;
|
2016-03-29 17:43:53 +02:00
|
|
|
}
|
2016-11-06 14:45:45 +01:00
|
|
|
|
|
|
|
return i;
|
2016-04-18 20:50:52 +02:00
|
|
|
}
|
|
|
|
|
2016-10-14 18:03:17 +02:00
|
|
|
static Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-09-11 19:17:56 +02:00
|
|
|
FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path},
|
2016-05-09 03:41:00 +02:00
|
|
|
archivePath = {PATH_EMPTY, 1, (u8 *)""};
|
|
|
|
|
|
|
|
return IFile_Open(file, archiveId, archivePath, filePath, flags);
|
2016-03-29 17:43:53 +02:00
|
|
|
}
|
|
|
|
|
2016-10-14 18:03:17 +02:00
|
|
|
static Result openLumaFile(IFile *file, const char *path)
|
|
|
|
{
|
|
|
|
Result res = fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ);
|
|
|
|
|
|
|
|
if((u32)res == 0xC88044AB) res = fileOpen(file, ARCHIVE_NAND_RW, path, FS_OPEN_READ); //Returned if SD is not mounted
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
static inline void loadCFWInfo(void)
|
2016-08-20 18:45:56 +02:00
|
|
|
{
|
|
|
|
static bool infoLoaded = false;
|
2016-08-26 18:44:39 +02:00
|
|
|
|
2016-08-20 18:45:56 +02:00
|
|
|
if(!infoLoaded)
|
|
|
|
{
|
|
|
|
svcGetCFWInfo(&info);
|
2016-08-28 13:49:15 +02:00
|
|
|
|
2016-08-20 18:45:56 +02:00
|
|
|
IFile file;
|
2016-11-03 18:55:40 +01:00
|
|
|
if(LOADERFLAG(ISSAFEMODE) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
|
2016-08-20 18:45:56 +02:00
|
|
|
IFile_Close(&file);
|
2016-08-26 18:44:39 +02:00
|
|
|
|
|
|
|
infoLoaded = true;
|
2016-08-20 18:45:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-04 22:28:33 +01:00
|
|
|
static inline bool secureInfoExists(void)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-07-02 14:44:01 +02:00
|
|
|
static bool exists = false;
|
2016-03-29 17:43:53 +02:00
|
|
|
|
2016-07-02 14:44:01 +02:00
|
|
|
if(!exists)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-04-18 20:50:52 +02:00
|
|
|
IFile file;
|
|
|
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
|
|
|
|
{
|
2016-07-02 14:44:01 +02:00
|
|
|
exists = true;
|
2016-04-18 20:50:52 +02:00
|
|
|
IFile_Close(&file);
|
|
|
|
}
|
2016-03-29 17:43:53 +02:00
|
|
|
}
|
|
|
|
|
2016-07-02 14:44:01 +02:00
|
|
|
return exists;
|
2016-03-29 17:43:53 +02:00
|
|
|
}
|
|
|
|
|
2016-11-04 22:28:33 +01:00
|
|
|
static inline void loadCustomVerString(u16 *out, u32 *verStringSize, u32 currentNand)
|
2016-09-13 23:01:38 +02:00
|
|
|
{
|
2016-09-23 00:08:15 +02:00
|
|
|
static const char *paths[] = { "/luma/customversion_sys.txt",
|
|
|
|
"/luma/customversion_emu.txt",
|
|
|
|
"/luma/customversion_emu2.txt",
|
|
|
|
"/luma/customversion_emu3.txt",
|
|
|
|
"/luma/customversion_emu4.txt" };
|
2016-09-13 23:01:38 +02:00
|
|
|
|
|
|
|
IFile file;
|
2016-09-15 19:53:51 +02:00
|
|
|
|
2016-10-14 18:03:17 +02:00
|
|
|
if(R_SUCCEEDED(openLumaFile(&file, paths[currentNand])))
|
2016-09-13 23:01:38 +02:00
|
|
|
{
|
|
|
|
u64 fileSize;
|
|
|
|
|
2016-09-20 16:16:18 +02:00
|
|
|
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= 62)
|
2016-09-13 23:01:38 +02:00
|
|
|
{
|
2016-09-17 00:03:09 +02:00
|
|
|
u8 buf[fileSize];
|
2016-09-13 23:01:38 +02:00
|
|
|
u64 total;
|
|
|
|
|
2016-09-15 19:53:51 +02:00
|
|
|
if(R_SUCCEEDED(IFile_Read(&file, &total, buf, fileSize)))
|
|
|
|
{
|
2016-09-17 00:03:09 +02:00
|
|
|
static const u8 bom[] = {0xEF, 0xBB, 0xBF};
|
2016-09-16 13:29:14 +02:00
|
|
|
u32 finalSize = 0;
|
2016-09-16 03:14:37 +02:00
|
|
|
|
2016-09-17 14:34:25 +02:00
|
|
|
//Convert from UTF-8 to UTF-16 (Nintendo doesn't support 4-byte UTF-16, so 4-byte UTF-8 is unsupported)
|
|
|
|
for(u32 increase, fileSizeTmp = (u32)fileSize, i = (fileSizeTmp > 2 && memcmp(buf, bom, 3) == 0) ? 3 : 0;
|
|
|
|
i < fileSizeTmp && finalSize < 19; i += increase, finalSize++)
|
2016-09-16 03:14:37 +02:00
|
|
|
{
|
2016-09-20 16:16:18 +02:00
|
|
|
if((buf[i] & 0x80) == 0 && !(buf[i] == 0xA || buf[i] == 0xD))
|
2016-09-16 03:14:37 +02:00
|
|
|
{
|
|
|
|
increase = 1;
|
2016-09-17 14:34:25 +02:00
|
|
|
out[finalSize] = (u16)buf[i];
|
2016-09-16 03:14:37 +02:00
|
|
|
}
|
|
|
|
else if((buf[i] & 0xE0) == 0xC0 && i + 1 < fileSizeTmp && (buf[i + 1] & 0xC0) == 0x80)
|
|
|
|
{
|
|
|
|
increase = 2;
|
2016-09-17 14:34:25 +02:00
|
|
|
out[finalSize] = (u16)(((buf[i] & 0x1F) << 6) | (buf[i + 1] & 0x3F));
|
2016-09-16 03:14:37 +02:00
|
|
|
}
|
|
|
|
else if((buf[i] & 0xF0) == 0xE0 && i + 2 < fileSizeTmp && (buf[i + 1] & 0xC0) == 0x80 && (buf[i + 2] & 0xC0) == 0x80)
|
|
|
|
{
|
|
|
|
increase = 3;
|
2016-09-17 14:34:25 +02:00
|
|
|
out[finalSize] = (u16)(((buf[i] & 0xF) << 12) | ((buf[i + 1] & 0x3F) << 6) | (buf[i + 2] & 0x3F));
|
2016-09-16 03:14:37 +02:00
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
|
2016-09-18 18:31:16 +02:00
|
|
|
if(finalSize > 0)
|
|
|
|
{
|
|
|
|
if(finalSize > 5 && finalSize < 19) out[finalSize++] = 0;
|
|
|
|
*verStringSize = finalSize * 2;
|
|
|
|
}
|
2016-09-15 19:53:51 +02:00
|
|
|
}
|
2016-09-13 23:01:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
IFile_Close(&file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
2016-06-05 20:43:49 +02:00
|
|
|
{
|
|
|
|
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
|
|
|
|
If it exists it should be a decompressed binary code file */
|
2016-07-01 20:27:28 +02:00
|
|
|
|
2016-06-05 20:43:49 +02:00
|
|
|
char path[] = "/luma/code_sections/0000000000000000.bin";
|
|
|
|
progIdToStr(path + 35, progId);
|
|
|
|
|
|
|
|
IFile file;
|
2016-11-09 16:33:54 +01:00
|
|
|
u32 ret = 0;
|
2016-07-01 20:27:28 +02:00
|
|
|
|
2016-10-14 18:03:17 +02:00
|
|
|
if(R_SUCCEEDED(openLumaFile(&file, path)))
|
2016-06-05 20:43:49 +02:00
|
|
|
{
|
2016-09-03 19:11:44 +02:00
|
|
|
u64 fileSize;
|
2016-07-01 20:27:28 +02:00
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = 1;
|
|
|
|
else
|
2016-07-01 20:27:28 +02:00
|
|
|
{
|
2016-09-03 19:11:44 +02:00
|
|
|
u64 total;
|
2016-10-10 15:53:56 +02:00
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) ret = 1;
|
2016-07-01 20:27:28 +02:00
|
|
|
}
|
2016-09-13 23:01:38 +02:00
|
|
|
|
|
|
|
IFile_Close(&file);
|
2016-06-05 20:43:49 +02:00
|
|
|
}
|
2016-11-09 16:33:54 +01:00
|
|
|
|
|
|
|
return ret;
|
2016-06-05 20:43:49 +02:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
static inline u32 loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
2016-06-05 20:43:49 +02:00
|
|
|
{
|
|
|
|
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
|
|
|
|
If it exists it should contain, for example, "EUR IT" */
|
|
|
|
|
|
|
|
char path[] = "/luma/locales/0000000000000000.txt";
|
|
|
|
progIdToStr(path + 29, progId);
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
|
|
|
IFile file;
|
2016-11-09 16:33:54 +01:00
|
|
|
u32 ret = 0;
|
2016-09-15 19:53:51 +02:00
|
|
|
|
2016-10-14 18:03:17 +02:00
|
|
|
if(R_SUCCEEDED(openLumaFile(&file, path)))
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-09-13 23:01:38 +02:00
|
|
|
u64 fileSize;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8) ret = 1;
|
|
|
|
else
|
2016-04-14 17:10:55 +02:00
|
|
|
{
|
2016-09-20 15:16:19 +02:00
|
|
|
char buf[fileSize];
|
2016-09-13 23:01:38 +02:00
|
|
|
u64 total;
|
2016-04-14 17:10:55 +02:00
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) ret = 1;
|
|
|
|
else
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-09-15 19:53:51 +02:00
|
|
|
for(u32 i = 0; i < 7; i++)
|
2016-09-13 23:01:38 +02:00
|
|
|
{
|
|
|
|
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
|
|
|
|
|
|
|
if(memcmp(buf, regions[i], 3) == 0)
|
|
|
|
{
|
|
|
|
*regionId = (u8)i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-17 14:34:25 +02:00
|
|
|
|
2016-09-15 19:53:51 +02:00
|
|
|
for(u32 i = 0; i < 12; i++)
|
2016-09-13 23:01:38 +02:00
|
|
|
{
|
|
|
|
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
|
2016-04-14 17:10:55 +02:00
|
|
|
|
2016-09-13 23:01:38 +02:00
|
|
|
if(memcmp(buf + 4, languages[i], 2) == 0)
|
|
|
|
{
|
|
|
|
*languageId = (u8)i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
2016-04-14 17:10:55 +02:00
|
|
|
}
|
2016-09-13 23:01:38 +02:00
|
|
|
|
|
|
|
IFile_Close(&file);
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
2016-11-09 16:33:54 +01:00
|
|
|
|
|
|
|
return ret;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
|
2016-11-04 22:28:33 +01:00
|
|
|
static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
/* HANS:
|
|
|
|
Look for error code which is known to be stored near cfg:u handle
|
|
|
|
this way we can find the right candidate
|
|
|
|
(handle should also be stored right after end of candidate function) */
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
u32 n = 0,
|
|
|
|
possible[24];
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
if(*(u32 *)pos == 0xD8A103F9)
|
|
|
|
{
|
|
|
|
for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++)
|
|
|
|
if(*l <= 0x10000000) possible[n++] = *l;
|
|
|
|
}
|
|
|
|
}
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
|
|
|
|
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
|
2016-04-15 03:34:08 +02:00
|
|
|
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1])
|
|
|
|
{
|
|
|
|
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
for(u32 i = 0; i < n; i++)
|
|
|
|
if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
CFGU_GetConfigInfoBlk2_endPos += 4;
|
|
|
|
}
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
return NULL;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
static inline u32 patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4;
|
|
|
|
CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
|
|
|
|
CFGU_GetConfigInfoBlk2_startPos -= 2);
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
if(*(u32 *)languageBlkIdPos == 0xA0002)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 17:53:40 +02:00
|
|
|
if(instr[3] == 0xEB) //We're looking for BL
|
2016-04-15 03:34:08 +02:00
|
|
|
{
|
2016-04-15 17:53:40 +02:00
|
|
|
u8 *calledFunction = instr;
|
2016-07-02 14:44:01 +02:00
|
|
|
u32 i = 0;
|
|
|
|
bool found;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 17:53:40 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2;
|
|
|
|
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
|
|
|
|
s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
|
|
|
|
|
|
|
|
calledFunction += offset;
|
|
|
|
|
|
|
|
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
while(i < 2 && !found && calledFunction[3] == 0xEA);
|
|
|
|
|
|
|
|
if(found)
|
2016-04-15 03:34:08 +02:00
|
|
|
{
|
2016-11-03 19:02:38 +01:00
|
|
|
*((u32 *)instr - 1) = 0xE3A00000 | languageId; //mov r0, sp => mov r0, =languageId
|
|
|
|
*(u32 *)instr = 0xE5CD0000; //bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
|
|
|
|
*((u32 *)instr + 1) = 0xE3B00000; //(1 or 2 instructions) => movs r0, 0 (result code)
|
2016-04-15 03:34:08 +02:00
|
|
|
|
|
|
|
//We're done
|
2016-11-09 16:33:54 +01:00
|
|
|
return 0;
|
2016-04-15 03:34:08 +02:00
|
|
|
}
|
|
|
|
}
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-11-09 16:33:54 +01:00
|
|
|
|
|
|
|
return 1;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
|
2016-11-09 16:33:54 +01:00
|
|
|
static inline u32 patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-04-15 03:34:08 +02:00
|
|
|
for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4)
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-11-09 16:33:54 +01:00
|
|
|
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D0F70, 0xE3A00802};
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-04-15 03:34:08 +02:00
|
|
|
u32 *cmp = (u32 *)cmdPos;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-11-09 17:01:56 +01:00
|
|
|
if(*cmp == cfgSecureInfoGetRegionCmdPattern[1])
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-11-09 16:33:54 +01:00
|
|
|
for(u32 i = 1; i < 4; i++)
|
2016-11-09 17:01:56 +01:00
|
|
|
if((*(cmp - i) & 0xFFFF0FFF) == cfgSecureInfoGetRegionCmdPattern[0] && *((u16 *)cmdPos + 5) == 0xE59F &&
|
|
|
|
*(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset)
|
2016-11-09 16:33:54 +01:00
|
|
|
{
|
2016-11-09 17:01:56 +01:00
|
|
|
cmp[3] = 0xE3A00000 | regionId; //mov r0, =regionId
|
|
|
|
cmp[4] = 0xE5C40008; //strb r0, [r4, 8]
|
|
|
|
cmp[5] = 0xE3B00000; //movs r0, 0 (result code) ('s' not needed but nvm)
|
|
|
|
cmp[6] = 0xE5840004; //str r0, [r4, 4]
|
2016-11-09 16:33:54 +01:00
|
|
|
|
|
|
|
//The remaining, not patched, function code will do the rest for us
|
|
|
|
return 0;
|
|
|
|
}
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
}
|
2016-11-09 16:33:54 +01:00
|
|
|
|
|
|
|
return 1;
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-08-17 23:47:30 +02:00
|
|
|
loadCFWInfo();
|
2016-11-06 14:45:45 +01:00
|
|
|
u32 res = 0;
|
2016-08-26 18:44:39 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
if(((progId == 0x0004003000008F02LL || //USA Home Menu
|
|
|
|
progId == 0x0004003000008202LL || //JPN Home Menu
|
|
|
|
progId == 0x0004003000009802LL) //EUR Home Menu
|
|
|
|
&& progVer > 4) ||
|
|
|
|
(progId == 0x000400300000A902LL //KOR Home Menu
|
|
|
|
&& progVer > 0) ||
|
|
|
|
progId == 0x000400300000A102LL || //CHN Home Menu
|
|
|
|
progId == 0x000400300000B102LL) //TWN Home Menu
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x0A, 0x0C, 0x00, 0x10
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
patch[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
|
|
|
};
|
|
|
|
|
|
|
|
//Patch SMDH region checks
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
2016-11-06 14:52:10 +01:00
|
|
|
sizeof(pattern), -31,
|
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 1
|
|
|
|
)) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-03-31 01:38:28 +02:00
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004013000003202LL) //FRIENDS
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x42, 0xE0, 0x1E, 0xFF
|
|
|
|
};
|
2016-03-29 22:43:15 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
u8 mostRecentFpdVer = 8;
|
2016-09-08 02:12:29 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
u8 *off = memsearch(code, pattern, size, sizeof(pattern));
|
2016-09-08 02:12:29 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
if(off == NULL) res++;
|
2016-04-08 23:28:40 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
//Allow online access to work with old friends modules
|
2016-11-06 14:45:45 +01:00
|
|
|
else if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-10-10 15:53:56 +02:00
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if((progId == 0x0004001000021000LL || //USA MSET
|
|
|
|
progId == 0x0004001000020000LL || //JPN MSET
|
|
|
|
progId == 0x0004001000022000LL || //EUR MSET
|
|
|
|
progId == 0x0004001000026000LL || //CHN MSET
|
|
|
|
progId == 0x0004001000027000LL || //KOR MSET
|
|
|
|
progId == 0x0004001000028000LL) //TWN MSET
|
2016-11-03 18:55:40 +01:00
|
|
|
&& CONFIG(PATCHVERSTRING))
|
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u16 pattern[] = u"Ve";
|
|
|
|
static u16 *patch;
|
|
|
|
u32 patchSize = 0,
|
2016-11-03 18:55:40 +01:00
|
|
|
currentNand = BOOTCFG_NAND;
|
2016-04-08 23:28:40 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
u16 customVerString[19];
|
2016-11-06 14:45:45 +01:00
|
|
|
loadCustomVerString(customVerString, &patchSize, currentNand);
|
2016-10-10 17:30:53 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
if(patchSize != 0) patch = customVerString;
|
2016-11-03 18:55:40 +01:00
|
|
|
else
|
2016-03-29 22:43:15 +02:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
patchSize = 8;
|
2016-11-03 18:55:40 +01:00
|
|
|
u32 currentFirm = BOOTCFG_FIRM;
|
|
|
|
|
|
|
|
static u16 *verStringsNands[] = { u" Sys",
|
|
|
|
u" Emu",
|
|
|
|
u"Emu2",
|
|
|
|
u"Emu3",
|
|
|
|
u"Emu4" },
|
|
|
|
|
|
|
|
*verStringsEmuSys[] = { u"EmuS",
|
|
|
|
u"Em2S",
|
|
|
|
u"Em3S",
|
|
|
|
u"Em4S" },
|
|
|
|
|
|
|
|
*verStringsSysEmu[] = { u"SysE",
|
|
|
|
u"SyE2",
|
|
|
|
u"SyE3",
|
|
|
|
u"SyE4" };
|
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
patch = (currentFirm != 0) == (currentNand != 0) ? verStringsNands[currentNand] :
|
|
|
|
(!currentNand ? verStringsSysEmu[currentFirm - 1] : verStringsEmuSys[currentNand - 1]);
|
2016-03-29 22:43:15 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
//Patch Ver. string
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
|
|
|
sizeof(pattern) - 2, 0,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
patchSize, 1
|
|
|
|
)) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004013000008002LL) //NS
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
2016-11-03 19:36:08 +01:00
|
|
|
if(progVer > 4)
|
2016-03-29 22:43:15 +02:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-03-29 22:43:15 +02:00
|
|
|
0x0C, 0x18, 0xE1, 0xD8
|
2016-10-10 17:30:53 +02:00
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
patch[] = {
|
2016-03-29 22:43:15 +02:00
|
|
|
0x0B, 0x18, 0x21, 0xC8
|
|
|
|
};
|
|
|
|
|
2016-04-02 18:48:31 +02:00
|
|
|
//Disable updates from foreign carts (makes carts region-free)
|
2016-11-06 14:52:10 +01:00
|
|
|
u32 ret = patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
|
|
|
sizeof(pattern), 0,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 2
|
|
|
|
);
|
|
|
|
|
|
|
|
if(ret == 0 || (ret == 1 && progVer > 0xB)) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-04-02 17:58:06 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
if(LOADERFLAG(ISN3DS))
|
|
|
|
{
|
2016-09-11 19:17:56 +02:00
|
|
|
u32 cpuSetting = MULTICONFIG(NEWCPU);
|
2016-04-19 17:17:39 +02:00
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
if(cpuSetting != 0)
|
2016-04-12 15:25:36 +02:00
|
|
|
{
|
2016-11-06 14:52:10 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x0C, 0x00, 0x94, 0x15
|
2016-04-12 15:25:36 +02:00
|
|
|
};
|
|
|
|
|
2016-11-06 14:52:10 +01:00
|
|
|
u32 *off = (u32 *)memsearch(code, pattern, size, sizeof(pattern));
|
2016-04-12 15:25:36 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
if(off == NULL) res++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Patch N3DS CPU Clock and L2 cache setting
|
2016-11-08 17:39:54 +01:00
|
|
|
*(off - 4) = *(off - 3);
|
|
|
|
*(off - 3) = *(off - 1);
|
|
|
|
memcpy(off - 1, off, 16);
|
|
|
|
*(off + 3) = 0xE3800000 | cpuSetting;
|
2016-11-06 14:45:45 +01:00
|
|
|
}
|
2016-04-12 15:25:36 +02:00
|
|
|
}
|
2016-03-29 17:43:53 +02:00
|
|
|
}
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-03-29 22:43:15 +02:00
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004013000001702LL) //CFG
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x06, 0x46, 0x10, 0x48
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
patch[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x00, 0x26
|
|
|
|
};
|
|
|
|
|
|
|
|
//Disable SecureInfo signature check
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
|
|
|
sizeof(pattern), 0,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 1
|
|
|
|
)) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
|
|
|
|
if(secureInfoExists())
|
2016-03-29 22:43:15 +02:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u16 pattern[] = u"Sec",
|
|
|
|
patch[] = u"C";
|
2016-03-29 22:43:15 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
//Use SecureInfo_C
|
2016-11-06 14:52:10 +01:00
|
|
|
if(patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
|
|
|
sizeof(pattern) - 2, 22,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch) - 2, 2
|
|
|
|
) != 2) res++;
|
2016-05-14 15:35:59 +02:00
|
|
|
}
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-11-05 17:46:47 +01:00
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004013000003702LL && progVer > 0) //RO
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x20, 0xA0, 0xE1, 0x8B
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern2[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0xE1, 0x30, 0x40, 0x2D
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern3[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x2D, 0xE9, 0x01, 0x70
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
patch[] = {
|
2016-11-03 19:02:38 +01:00
|
|
|
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 //mov r0, #0; bx lr
|
2016-11-03 18:55:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
//Disable CRR0 signature (RSA2048 with SHA256) check
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
|
|
|
sizeof(pattern), -9,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 1
|
|
|
|
)) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
|
|
|
|
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern2,
|
|
|
|
sizeof(pattern2), 1,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 1
|
|
|
|
)) res++;
|
|
|
|
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern3,
|
|
|
|
sizeof(pattern3), -2,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 1
|
|
|
|
)) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-10-10 17:30:53 +02:00
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) //ErrDisp
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
2016-11-06 14:45:45 +01:00
|
|
|
static const u8 pattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x00, 0xD0, 0xE5, 0xDB
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern2[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x14, 0x00, 0xD0, 0xE5, 0x01
|
|
|
|
},
|
2016-11-06 14:45:45 +01:00
|
|
|
patch[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x00, 0x00, 0xA0, 0xE3
|
|
|
|
};
|
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
//Patch UNITINFO checks to make ErrDisp more verbose
|
2016-11-06 14:52:10 +01:00
|
|
|
if(!patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern,
|
|
|
|
sizeof(pattern), -1,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 1
|
|
|
|
)) res++;
|
|
|
|
|
2016-11-06 14:52:10 +01:00
|
|
|
if(patchMemory(code, size,
|
2016-11-06 14:45:45 +01:00
|
|
|
pattern2,
|
|
|
|
sizeof(pattern2), 0,
|
2016-11-06 14:52:10 +01:00
|
|
|
patch,
|
2016-11-06 14:45:45 +01:00
|
|
|
sizeof(patch), 3
|
|
|
|
) != 3) res++;
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-10-10 17:30:53 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
|
|
|
|
{
|
|
|
|
//External .code section loading
|
2016-11-09 16:33:54 +01:00
|
|
|
res += loadTitleCodeSection(progId, code, size);
|
2016-10-10 17:30:53 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
//Language emulation
|
|
|
|
u8 regionId = 0xFF,
|
|
|
|
languageId = 0xFF;
|
2016-11-09 16:33:54 +01:00
|
|
|
res += loadTitleLocaleConfig(progId, ®ionId, &languageId);
|
2016-09-06 13:43:00 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
if(regionId != 0xFF || regionId != 0xFF)
|
2016-05-28 16:13:22 +02:00
|
|
|
{
|
2016-11-03 18:55:40 +01:00
|
|
|
u32 CFGUHandleOffset;
|
|
|
|
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
|
2016-11-06 14:45:45 +01:00
|
|
|
if(CFGU_GetConfigInfoBlk2_endPos == NULL) res++;
|
|
|
|
else
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
{
|
2016-11-09 16:33:54 +01:00
|
|
|
if(languageId != 0xFF) res += patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
|
|
|
|
if(regionId != 0xFF) res += patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
|
2016-04-27 04:52:23 +02:00
|
|
|
}
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-03-29 17:43:53 +02:00
|
|
|
}
|
2016-11-06 14:45:45 +01:00
|
|
|
|
|
|
|
if(res != 0) svcBreak(USERBREAK_ASSERT);
|
2016-08-26 18:44:39 +02:00
|
|
|
}
|