1
0
Fork 0

Created preliminary usage of all sections

Updated error system
This commit is contained in:
JoshuaMKW 2020-10-03 15:25:18 -05:00
parent 6c8d2c464d
commit ea8e76dae9
4 changed files with 197 additions and 142 deletions

View file

@ -245,7 +245,7 @@ if __name__ == "__main__":
codeHandler.optimizeList = args.optimize
with open(resource_path(os.path.join('bin', 'geckoloader.bin')), 'rb') as kernelfile:
geckoKernel = KernelLoader(kernelfile)
geckoKernel = KernelLoader(kernelfile, parser)
if args.init is not None:
geckoKernel.initAddress = int(args.init, 16)
@ -270,7 +270,7 @@ if __name__ == "__main__":
if not os.path.isdir(TMPDIR):
os.mkdir(TMPDIR)
geckoKernel.build(parser, args.codelist, dolFile, codeHandler, TMPDIR, dest)
geckoKernel.build(args.codelist, dolFile, codeHandler, TMPDIR, dest)
sys.exit(0)

View file

@ -8,7 +8,7 @@ from io import BytesIO
import tools
from fileutils import *
from dolreader import DolFile
from dolreader import DolFile, SectionCountFullError
try:
import chardet
@ -176,9 +176,7 @@ class GCT(object):
except RuntimeError:
self.codeList.seek(-8, 1)
length = GCT.determine_codelength(codetype, info)
while length > 0:
codelist += self.codeList.read(1)
length -= 1
codelist += self.codeList.read(length)
self.codeList = BytesIO(codelist)
self.size = len(self.codeList.getbuffer())
@ -220,7 +218,7 @@ class CodeHandler(object):
f.seek(0)
def gecko_parser(self, geckoText) -> str:
def gecko_self(self, geckoText) -> str:
with open(r'{}'.format(geckoText), 'rb') as gecko:
result = chardet.detect(gecko.read())
encodeType = result['encoding']
@ -315,12 +313,13 @@ class CodeHandler(object):
class KernelLoader(object):
def __init__(self, f):
def __init__(self, f, cli: tools.CommandLineParser=None):
self._rawData = BytesIO(f.read())
self._initDataList = None
self._gpModDataList = None
self._gpDiscDataList = None
self._gpKeyAddrList = None
self._cli = cli
self.patchJob = None
self.initAddress = None
self.protect = False
@ -328,6 +327,14 @@ class KernelLoader(object):
self.quiet = False
self.encrypt = False
def error(self, msg: str, exit=True):
if self._cli is not None:
self._cli.error(msg, exit)
else:
print(msg)
if exit:
sys.exit(1)
def set_variables(self, entryPoint: list, baseOffset: int=0):
self._rawData.seek(0)
@ -425,7 +432,14 @@ class KernelLoader(object):
self._rawData.seek(0)
_kernelData = self._rawData.getvalue()
try:
dolFile.append_text_sections([(_kernelData, self.initAddress)])
except SectionCountFullError:
try:
dolFile.append_data_sections([(_kernelData, self.initAddress)])
except SectionCountFullError:
self.error(tools.color_text('There are no unused sections left for GeckoLoader to use!', defaultColor=tools.TREDLIT))
dolFile.entryPoint = self.initAddress
def patch_legacy(self, codeHandler: CodeHandler, dolFile: DolFile):
@ -434,7 +448,13 @@ class KernelLoader(object):
_handlerData = codeHandler._rawData.getvalue() + codeHandler.geckoCodes.codeList.getvalue()
try:
dolFile.append_text_sections([(_handlerData, codeHandler.initAddress)])
except SectionCountFullError:
try:
dolFile.append_data_sections([(_handlerData, codeHandler.initAddress)])
except SectionCountFullError:
self.error(tools.color_text('There are no unused sections left for GeckoLoader to use!', defaultColor=tools.TREDLIT))
def protect_game(self, codeHandler: CodeHandler):
_oldpos = codeHandler.geckoCodes.codeList.tell()
@ -473,11 +493,11 @@ class KernelLoader(object):
codeHandler.geckoCodes.codeList.seek(_oldpos)
@timer
def build(self, parser: tools.CommandLineParser, gctFile, dolFile: DolFile, codeHandler: CodeHandler, tmpdir, dump):
def build(self, gctFile, dolFile: DolFile, codeHandler: CodeHandler, tmpdir, dump):
with open(dump, 'wb+') as final:
if dolFile.get_full_size() < 0x100:
parser.error(tools.color_text('DOL header is corrupted. Please provide a clean file\n', defaultColor=tools.TREDLIT), exit=False)
self.error(tools.color_text('DOL header is corrupted. Please provide a clean file\n', defaultColor=tools.TREDLIT), exit=False)
return
oldStart = dolFile.entryPoint
@ -489,7 +509,7 @@ class KernelLoader(object):
if '.' in gctFile:
if os.path.splitext(gctFile)[1].lower() == '.txt':
with open(os.path.join(tmpdir, 'gct.bin'), 'wb+') as temp:
temp.write(bytes.fromhex('00D0C0DE'*2 + codeHandler.gecko_parser(gctFile) + 'F000000000000000'))
temp.write(bytes.fromhex('00D0C0DE'*2 + codeHandler.gecko_self(gctFile) + 'F000000000000000'))
temp.seek(0)
codeHandler.geckoCodes = GCT(temp)
foundData = True
@ -505,7 +525,7 @@ class KernelLoader(object):
for file in os.listdir(gctFile):
if os.path.isfile(os.path.join(gctFile, file)):
if os.path.splitext(file)[1].lower() == '.txt':
temp.write(bytes.fromhex(codeHandler.gecko_parser(os.path.join(gctFile, file))))
temp.write(bytes.fromhex(codeHandler.gecko_self(os.path.join(gctFile, file))))
foundData = True
elif os.path.splitext(file)[1].lower() == '.gct':
with open(os.path.join(gctFile, file), 'rb') as gct:
@ -519,7 +539,7 @@ class KernelLoader(object):
codeHandler.geckoCodes = GCT(temp)
if not foundData:
parser.error(tools.color_text('No valid gecko code file found\n', defaultColor=tools.TREDLIT), exit=False)
self.error(tools.color_text('No valid gecko code file found\n', defaultColor=tools.TREDLIT), exit=False)
return
if self.protect and self.patchJob == "ARENA":
@ -563,9 +583,9 @@ class KernelLoader(object):
legacy = False
if not hooked:
parser.error(tools.color_text('Failed to find a hook address. Try using option --codehook to use your own address\n', defaultColor=tools.TREDLIT))
self.error(tools.color_text('Failed to find a hook address. Try using option --codehook to use your own address\n', defaultColor=tools.TREDLIT))
elif codeHandler.allocation < codeHandler.geckoCodes.size:
parser.error(tools.color_text('\n :: Error: Allocated codespace was smaller than the given codelist.\n', defaultColor=tools.TYELLOW))
self.error(tools.color_text('\n :: Error: Allocated codespace was smaller than the given codelist.\n', defaultColor=tools.TYELLOW))
dolFile.save(final)
@ -582,13 +602,13 @@ class KernelLoader(object):
print('')
if legacy == False:
info = [f' :: Start of game modified to address 0x{self.initAddress:X}',
f' :: Game function "__init_registers()" located at address 0x{oldStart:X}',
f' :: Game function "__start()" located at address 0x{oldStart:X}',
f' :: Allocation is 0x{codeHandler.allocation:X}; codelist size is 0x{codeHandler.geckoCodes.size:X}',
f' :: Codehandler hooked at 0x{codeHandler.hookAddress:X}',
f' :: Codehandler is of type "{codeHandler.type}"',
f' :: Of the 7 text sections in this DOL file, {len(dolFile.textSections)} are now being used']
else:
info = [f' :: Game function "__init_registers()" located at address 0x{oldStart:X}',
info = [f' :: Game function "__start()" located at address 0x{oldStart:X}',
f' :: Allocation is 0x{codeHandler.allocation:X}; codelist size is 0x{codeHandler.geckoCodes.size:X}',
f' :: Codehandler hooked at 0x{codeHandler.hookAddress:X}',
f' :: Codehandler is of type "{codeHandler.type}"',
@ -611,7 +631,7 @@ def resource_path(relative_path: str):
return os.path.join(base_path, relative_path)
def determine_codehook(dolFile: DolFile, codeHandler: CodeHandler, hook=False):
if codeHandler.hookAddress == None:
if codeHandler.hookAddress is None:
if not assert_code_hook(dolFile, codeHandler):
return False
@ -665,7 +685,7 @@ def insert_code_hook(dolFile: DolFile, codeHandler: CodeHandler, address: int):
ppc = read_uint32(dolFile)
if ((ppc >> 24) & 0xFF) > 0x3F and ((ppc >> 24) & 0xFF) < 0x48:
raise NotImplementedError(tools.color_text("Hooking the codehandler to a conditional non spr branch is unsupported", defaultColor=tools.TREDLIT))
raise NotImplementedError(tools.color_text('Hooking the codehandler to a conditional non spr branch is unsupported', defaultColor=tools.TREDLIT))
dolFile.seek(-4, 1)
dolFile.insert_branch(codeHandler.startAddress, address, lk=0)

View file

@ -34,16 +34,17 @@ using f64 = double;
__attribute__((noreturn)) int main();
struct CodeList {
struct CodeList
{
u16 mBaseASM;
u16 mUpperBase;
u16 mOffsetASM;
u16 mLowerOffset;
};
struct Info {
struct Info
{
const u32 allocsize;
const u32 loaderSize;
@ -51,14 +52,14 @@ struct Info {
const u32 codeSize;
const u32 *codehandlerHook;
const u32 crypted;
};
class DiscHeader {
class DiscHeader
{
public:
enum class TVMODE {
enum class TVMODE
{
NTSC,
PAL,
DEBUG,
@ -66,7 +67,9 @@ public:
MPAL,
PAL60
};
struct MetaData {
struct MetaData
{
const u8 mDiscID; //0x0000
const u16 mGameCode; //0x0001
@ -97,7 +100,7 @@ public:
u32 mCurrentOSContext; //0x00C0
u32 mPreviousOSMask; //0x00C4
u32 mCurrentOSMask; //0x00C8
TVMODE mTVMode; //0x00CC
DiscHeader::TVMODE mTVMode; //0x00CC
u32 mARAMSize; //0x00D0
void *mCurOSContextLogical; //0x00D4
void *mDefaultOSThreadLogical; //0x00D8
@ -109,15 +112,19 @@ public:
u32 mSimulatedMemSize; //0x00F0
u8 *mBi2HeaderLoc; //0x00F4
u32 mBusClockSpeed; //0x00F8
u32 mCPUClockSpeed; //00x00FC
u32 _04[0x3010 / 4];
u32 mCPUClockSpeed; //0x00FC
u32 _04[0x3010 / 4]; //0x0100
u8 *mWiiHeap; //0x3110
};
static MetaData sMetaData;
enum class CONSOLETYPE { Gamecube, Wii, Unknown };
enum class CONSOLETYPE
{
Gamecube,
Wii,
Unknown
};
inline u32 getGameID() { return ((u32)sMetaData.mDiscID << 24) | ((u32)sMetaData.mGameCode << 8) | ((u32)sMetaData.mRegionCode); }
inline u16 getMakerID() { return sMetaData.mMakerCode; }
@ -126,10 +133,12 @@ public:
CONSOLETYPE detectHomeConsole()
{
if (sMetaData.mGCNMagic) {
if (sMetaData.mGCNMagic)
{
return CONSOLETYPE::Gamecube;
}
else if (sMetaData.mWiiMagic) {
else if (sMetaData.mWiiMagic)
{
return CONSOLETYPE::Wii;
}
@ -138,15 +147,19 @@ public:
inline void setHeap(u32 alloc)
{
if (sMetaData.mBi2HeaderLoc < sMetaData.mOSArenaHi) {
if (sMetaData.mBi2HeaderLoc < sMetaData.mOSArenaHi)
{
sMetaData.mOSArenaHi = sMetaData.mBi2HeaderLoc - alloc;
if (this->detectHomeConsole() == DiscHeader::CONSOLETYPE::Wii) {
if (this->detectHomeConsole() == DiscHeader::CONSOLETYPE::Wii)
{
sMetaData.mWiiHeap = sMetaData.mBi2HeaderLoc - alloc;
}
}
else {
else
{
sMetaData.mOSArenaHi = sMetaData.mWiiHeap - alloc;
if (this->detectHomeConsole() == DiscHeader::CONSOLETYPE::Wii) {
if (this->detectHomeConsole() == DiscHeader::CONSOLETYPE::Wii)
{
sMetaData.mWiiHeap -= alloc;
}
}
@ -163,7 +176,8 @@ Info gpModInfo = {
0x43525054,
};
inline u32 extractBranchAddr(u32* bAddr) {
inline u32 extractBranchAddr(u32 *bAddr)
{
s32 offset;
if (*bAddr & 0x2000000)
offset = (*bAddr & 0x3FFFFFD) - 0x4000000;
@ -172,16 +186,19 @@ inline u32 extractBranchAddr(u32* bAddr) {
return (u32)bAddr + offset;
}
namespace Memory {
namespace Memory
{
static void memcpy(u8 *to, u8 *from, s32 size)
{
for (s32 i = 0; i < size; ++i) {
for (s32 i = 0; i < size; ++i)
{
*to++ = *from++;
}
}
namespace Cache {
namespace Cache
{
static inline void flushAddr(void *addr)
{
@ -193,7 +210,8 @@ namespace Memory {
{
size += 31 + (((u32)addr & 31) > 0);
for (u32 i = 0; i < (size >> 5); ++i) {
for (u32 i = 0; i < (size >> 5); ++i)
{
flushAddr((void *)(addr + (i << 5)));
}
}
@ -208,14 +226,16 @@ namespace Memory {
{
size += 31 + (((u32)addr & 31) > 0);
for (u32 i = 0; i < (size >> 5); ++i) {
for (u32 i = 0; i < (size >> 5); ++i)
{
storeAddr((void *)(addr + (i << 5)));
}
}
}
} // namespace Cache
namespace Direct {
namespace Direct
{
template <typename T>
static inline void write(T *addr, T value)
@ -230,16 +250,18 @@ namespace Memory {
Direct::write<u32>((u32 *)(addr), ((((u32)(to) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | lk));
}
}
} // namespace Direct
namespace Search {
namespace Search
{
static u32 *array(u32 *start, u32 *end, u32 arrayLength, const u32 *hookData)
{
u32 index = 0;
/*Loop through the games RAM, make sure we don't find our own hook data by accident*/
for (u32 i = 0; &start[i] < end; ++i) {
for (u32 i = 0; &start[i] < end; ++i)
{
/*If the data matches, increase the index counter and continue search,
else set index to 0 and continue searching*/
if (start[i] == hookData[index])
@ -257,8 +279,10 @@ namespace Memory {
template <typename T>
static T *single(T *start, T *end, T match)
{
for (u32 i = 0; &start[i] < end; ++i) {
if (start[i] == match) {
for (u32 i = 0; &start[i] < end; ++i)
{
if (start[i] == match)
{
return &start[i];
}
}
@ -272,9 +296,10 @@ namespace Memory {
Direct::branch(Search::single<u32>(start, start + 0x500, targetVal), hookTo, lk);
}
}
} // namespace Search
class Crypt {
class Crypt
{
private:
u32 key;
@ -313,16 +338,22 @@ namespace Memory {
{
auto key = this->getKey();
for (u32 i = 0; i < size; ++i) {
for (u32 i = 0; i < size; ++i)
{
dest[i] = buffer[i] ^ key;
key += i << 3;
}
}
};
enum class Space : u32 { Start = 0x80000000, End = 0x81800000, Size = 0x1800000 };
enum class Space : u32
{
Start = 0x80000000,
End = 0x81800000,
Size = 0x1800000
};
}
} // namespace Memory
Memory::Crypt gpCryptor = {0x43595054};
@ -336,11 +367,13 @@ static void initMods()
codelistPointer->mLowerOffset = ((u32)sDisc.sMetaData.mOSArenaHi + gpModInfo.handlerSize) & 0xFFFF;
/*Copy codelist to the new allocation*/
if (gpModInfo.crypted) {
if (gpModInfo.crypted)
{
Memory::memcpy(sDisc.sMetaData.mOSArenaHi, (u8 *)&gpModInfo + sizeof(Info) + 4, gpModInfo.handlerSize);
gpCryptor.xorCrypt((u32 *)(sDisc.sMetaData.mOSArenaHi + gpModInfo.handlerSize), (u32 *)((u8 *)&gpModInfo + sizeof(Info) + gpModInfo.handlerSize + 4), gpModInfo.codeSize >> 2);
}
else {
else
{
Memory::memcpy(sDisc.sMetaData.mOSArenaHi, (u8 *)&gpModInfo + sizeof(Info) + 4, gpModInfo.handlerSize + gpModInfo.codeSize);
}
@ -349,7 +382,6 @@ static void initMods()
auto returnAddress = extractBranchAddr((u32 *)gpModInfo.codehandlerHook);
auto ppc = *gpModInfo.codehandlerHook;
/*Write hook branch*/
Memory::Direct::branch((void *)gpModInfo.codehandlerHook, (void *)((u32)sDisc.sMetaData.mOSArenaHi + 0xA8), false); //entryhook
@ -363,20 +395,23 @@ static void initMods()
call((void *)((u32)(sDisc.sMetaData.mOSArenaHi) + 0xA8))();
/*Write original instruction or translate offset data if a branch*/
if (((ppc >> 24) & 0xFF) > 0x47 && ((ppc >> 24) & 0xFF) < 0x4C) {
if (((ppc >> 24) & 0xFF) > 0x47 && ((ppc >> 24) & 0xFF) < 0x4C)
{
Memory::Direct::branch((void *)fillInField, (void *)returnAddress, ppc & 1);
} else {
}
else
{
Memory::Direct::write(fillInField, ppc);
}
/*Write branch back to the hook address + 4*/
Memory::Direct::branch((void *)&fillInField[1], (void *)(&gpModInfo.codehandlerHook[1]), false); //return
}
int main()
{
if (sDisc.detectHomeConsole() != DiscHeader::CONSOLETYPE::Unknown) {
if (sDisc.detectHomeConsole() != DiscHeader::CONSOLETYPE::Unknown)
{
initMods();
}
__start();

View file

@ -9,13 +9,13 @@ class Updater(object):
self.gitReleases = 'https://github.com/{}/{}/releases'
def request_release_data(self):
'''Returns "soup" data of the repository releases tab'''
""" Returns soup data of the repository releases tab """
with request.urlopen(self.gitReleases.format(self.owner, self.repo)) as response:
html = response.read()
return html
def get_newest_version(self) -> str:
'''Returns newest release version'''
""" Returns newest release version """
try:
response = self.request_release_data()
soup = BeautifulSoup(response, 'html.parser')