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-09-06 13:47:04 +02:00
|
|
|
static void 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-09-06 13:47:04 +02:00
|
|
|
for(u32 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-10-10 15:53:56 +02:00
|
|
|
if(found == NULL) svcBreak(USERBREAK_ASSERT);
|
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-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-07-02 14:44:01 +02:00
|
|
|
static 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-09-23 00:08:15 +02:00
|
|
|
static 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-07-01 20:27:28 +02:00
|
|
|
static void 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-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-09-15 19:53:51 +02:00
|
|
|
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= size)
|
2016-07-01 20:27:28 +02:00
|
|
|
{
|
2016-09-03 19:11:44 +02:00
|
|
|
u64 total;
|
2016-09-15 19:53:51 +02:00
|
|
|
IFile_Read(&file, &total, code, fileSize);
|
2016-10-10 15:53:56 +02:00
|
|
|
|
|
|
|
if(total != fileSize) svcBreak(USERBREAK_ASSERT);
|
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-09-15 19:53:51 +02:00
|
|
|
static void 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-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-09-20 16:16:18 +02:00
|
|
|
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize > 5 && fileSize < 9)
|
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-09-20 15:16:19 +02:00
|
|
|
if(R_SUCCEEDED(IFile_Read(&file, &total, buf, 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-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-04-15 03:34:08 +02:00
|
|
|
static 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-04-15 03:34:08 +02:00
|
|
|
static void 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
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
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 void 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-04-15 03:34:08 +02:00
|
|
|
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080};
|
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-04-15 03:34:08 +02:00
|
|
|
if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] &&
|
|
|
|
cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F &&
|
|
|
|
*(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == 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-03 19:02:38 +01:00
|
|
|
*((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; //mov r0, =regionId
|
|
|
|
*((u32 *)cmdPos + 5) = 0xE5C40008; //strb r0, [r4, 8]
|
|
|
|
*((u32 *)cmdPos + 6) = 0xE3B00000; //movs r0, 0 (result code) ('s' not needed but nvm)
|
|
|
|
*((u32 *)cmdPos + 7) = 0xE5840004; //str r0, [r4, 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
|
|
|
|
|
|
|
//The remaining, not patched, function code will do the rest for us
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-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-03 18:55:40 +01:00
|
|
|
static const u8 regionFreePattern[] = {
|
|
|
|
0x0A, 0x0C, 0x00, 0x10
|
|
|
|
},
|
|
|
|
regionFreePatch[] = {
|
|
|
|
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
|
|
|
};
|
|
|
|
|
|
|
|
//Patch SMDH region checks
|
|
|
|
patchMemory(code, size,
|
|
|
|
regionFreePattern,
|
|
|
|
sizeof(regionFreePattern), -31,
|
|
|
|
regionFreePatch,
|
|
|
|
sizeof(regionFreePatch), 1
|
|
|
|
);
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
static const u8 fpdVerPattern[] = {
|
|
|
|
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-03 18:55:40 +01:00
|
|
|
u8 *off = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
|
2016-09-08 02:12:29 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
if(off == NULL) svcBreak(USERBREAK_ASSERT);
|
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
|
|
|
|
if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
|
|
|
|
}
|
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))
|
|
|
|
{
|
|
|
|
static const u16 verPattern[] = u"Ve";
|
|
|
|
static u16 *verString;
|
|
|
|
u32 verStringSize = 0,
|
|
|
|
currentNand = BOOTCFG_NAND;
|
2016-04-08 23:28:40 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
u16 customVerString[19];
|
|
|
|
loadCustomVerString(customVerString, &verStringSize, currentNand);
|
2016-10-10 17:30:53 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
if(verStringSize != 0) verString = customVerString;
|
|
|
|
else
|
2016-03-29 22:43:15 +02:00
|
|
|
{
|
2016-11-03 18:55:40 +01:00
|
|
|
verStringSize = 8;
|
|
|
|
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" };
|
|
|
|
|
|
|
|
verString = (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
|
|
|
|
patchMemory(code, size,
|
|
|
|
verPattern,
|
|
|
|
sizeof(verPattern) - 2, 0,
|
|
|
|
verString,
|
|
|
|
verStringSize, 1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004013000008002LL) //NS
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
|
|
|
if(progVer >= 0xD)
|
2016-03-29 22:43:15 +02:00
|
|
|
{
|
|
|
|
static const u8 stopCartUpdatesPattern[] = {
|
|
|
|
0x0C, 0x18, 0xE1, 0xD8
|
2016-10-10 17:30:53 +02:00
|
|
|
},
|
|
|
|
stopCartUpdatesPatch[] = {
|
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)
|
|
|
|
patchMemory(code, size,
|
2016-03-29 22:43:15 +02:00
|
|
|
stopCartUpdatesPattern,
|
|
|
|
sizeof(stopCartUpdatesPattern), 0,
|
|
|
|
stopCartUpdatesPatch,
|
|
|
|
sizeof(stopCartUpdatesPatch), 2
|
2016-03-29 17:43:53 +02:00
|
|
|
);
|
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
|
|
|
{
|
|
|
|
static const u8 cfgN3dsCpuPattern[] = {
|
2016-11-03 18:55:40 +01:00
|
|
|
0x0C, 0x00, 0x94, 0x15
|
2016-04-12 15:25:36 +02:00
|
|
|
};
|
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
u32 *off = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
|
2016-04-12 15:25:36 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
if(off == NULL) svcBreak(USERBREAK_ASSERT);
|
2016-10-10 15:53:56 +02:00
|
|
|
|
2016-04-12 15:25:36 +02:00
|
|
|
//Patch N3DS CPU Clock and L2 cache setting
|
2016-11-03 18:55:40 +01:00
|
|
|
*(off - 4) = 0xE1A00000;
|
|
|
|
*(off + 3) = 0xE3A00000 | cpuSetting;
|
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
|
|
|
{
|
|
|
|
static const u8 secureinfoSigCheckPattern[] = {
|
|
|
|
0x06, 0x46, 0x10, 0x48
|
|
|
|
},
|
|
|
|
secureinfoSigCheckPatch[] = {
|
|
|
|
0x00, 0x26
|
|
|
|
};
|
|
|
|
|
|
|
|
//Disable SecureInfo signature check
|
|
|
|
patchMemory(code, size,
|
|
|
|
secureinfoSigCheckPattern,
|
|
|
|
sizeof(secureinfoSigCheckPattern), 0,
|
|
|
|
secureinfoSigCheckPatch,
|
|
|
|
sizeof(secureinfoSigCheckPatch), 1
|
|
|
|
);
|
|
|
|
|
|
|
|
if(secureInfoExists())
|
2016-03-29 22:43:15 +02:00
|
|
|
{
|
2016-11-03 18:55:40 +01:00
|
|
|
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_",
|
|
|
|
secureinfoFilenamePatch[] = u"C";
|
2016-03-29 22:43:15 +02:00
|
|
|
|
2016-11-03 18:55:40 +01:00
|
|
|
//Use SecureInfo_C
|
2016-04-02 18:48:31 +02:00
|
|
|
patchMemory(code, size,
|
2016-11-03 18:55:40 +01:00
|
|
|
secureinfoFilenamePattern,
|
|
|
|
sizeof(secureinfoFilenamePattern) - 2,
|
|
|
|
sizeof(secureinfoFilenamePattern) - 2,
|
|
|
|
secureinfoFilenamePatch,
|
|
|
|
sizeof(secureinfoFilenamePatch) - 2, 2
|
2016-03-29 17:43:53 +02:00
|
|
|
);
|
2016-05-14 15:35:59 +02:00
|
|
|
}
|
2016-11-03 18:55:40 +01:00
|
|
|
}
|
2016-05-14 15:35:59 +02:00
|
|
|
|
2016-11-03 19:02:38 +01:00
|
|
|
else if(progId == 0x0004013000003702LL && progVer > 0) //RO
|
2016-11-03 18:55:40 +01:00
|
|
|
{
|
|
|
|
static const u8 sigCheckPattern[] = {
|
|
|
|
0x20, 0xA0, 0xE1, 0x8B
|
|
|
|
},
|
|
|
|
sha256ChecksPattern1[] = {
|
|
|
|
0xE1, 0x30, 0x40, 0x2D
|
|
|
|
},
|
|
|
|
sha256ChecksPattern2[] = {
|
|
|
|
0x2D, 0xE9, 0x01, 0x70
|
|
|
|
},
|
|
|
|
stub[] = {
|
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
|
|
|
|
patchMemory(code, size,
|
|
|
|
sigCheckPattern,
|
|
|
|
sizeof(sigCheckPattern), -9,
|
|
|
|
stub,
|
|
|
|
sizeof(stub), 1
|
|
|
|
);
|
|
|
|
|
|
|
|
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
|
|
|
|
patchMemory(code, size,
|
|
|
|
sha256ChecksPattern1,
|
|
|
|
sizeof(sha256ChecksPattern1), 1,
|
|
|
|
stub,
|
|
|
|
sizeof(stub), 1
|
|
|
|
);
|
|
|
|
|
|
|
|
patchMemory(code, size,
|
|
|
|
sha256ChecksPattern2,
|
|
|
|
sizeof(sha256ChecksPattern2), -2,
|
|
|
|
stub,
|
|
|
|
sizeof(stub), 1
|
|
|
|
);
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
static const u8 unitinfoCheckPattern1[] = {
|
|
|
|
0x00, 0xD0, 0xE5, 0xDB
|
|
|
|
},
|
|
|
|
unitinfoCheckPattern2[] = {
|
|
|
|
0x14, 0x00, 0xD0, 0xE5, 0x01
|
|
|
|
},
|
|
|
|
unitinfoCheckPatch[] = {
|
|
|
|
0x00, 0x00, 0xA0, 0xE3
|
|
|
|
};
|
|
|
|
|
|
|
|
patchMemory(code, size,
|
|
|
|
unitinfoCheckPattern1,
|
|
|
|
sizeof(unitinfoCheckPattern1), -1,
|
|
|
|
unitinfoCheckPatch,
|
|
|
|
sizeof(unitinfoCheckPatch), 1
|
|
|
|
);
|
|
|
|
|
|
|
|
patchMemory(code, size,
|
|
|
|
unitinfoCheckPattern2,
|
|
|
|
sizeof(unitinfoCheckPattern2), 0,
|
|
|
|
unitinfoCheckPatch,
|
|
|
|
sizeof(unitinfoCheckPatch), 3
|
|
|
|
);
|
|
|
|
}
|
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
|
|
|
|
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;
|
|
|
|
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-03 18:55:40 +01:00
|
|
|
if(CFGU_GetConfigInfoBlk2_endPos != 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-03 18:55:40 +01:00
|
|
|
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
|
|
|
|
if(regionId != 0xFF) 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-08-26 18:44:39 +02:00
|
|
|
}
|