diff --git a/src/main/java/libKonogonka/fs/other/System2/KernelMap.java b/src/main/java/libKonogonka/fs/other/System2/KernelMap.java index 27f5d62..13e21f2 100644 --- a/src/main/java/libKonogonka/fs/other/System2/KernelMap.java +++ b/src/main/java/libKonogonka/fs/other/System2/KernelMap.java @@ -25,33 +25,78 @@ import org.apache.logging.log4j.Logger; public class KernelMap { private final static Logger log = LogManager.getLogger(KernelMap.class); - - private final int textStartOffset; - private final int textEndOffset; - private final int rodataStartOffset; - private final int rodataEndOffset; - private final int dataStartOffset; - private final int dataEndOffset; - private final int bssStartOffset; - private final int bssEndOffset; - private final int ini1Offset; - private final int dynamicOffset; - private final int initArrayStartOffset; - private final int initArrayEndOffset; - public KernelMap(byte[] mapBytes, int offset){ - textStartOffset = Converter.getLEint(mapBytes, offset); - textEndOffset = Converter.getLEint(mapBytes, offset + 0x4); - rodataStartOffset = Converter.getLEint(mapBytes, offset + 0x8); - rodataEndOffset = Converter.getLEint(mapBytes, offset + 0xC); - dataStartOffset = Converter.getLEint(mapBytes, offset + 0x10); - dataEndOffset = Converter.getLEint(mapBytes, offset + 0x14); - bssStartOffset = Converter.getLEint(mapBytes, offset + 0x18); - bssEndOffset = Converter.getLEint(mapBytes, offset + 0x1C); - ini1Offset = Converter.getLEint(mapBytes, offset + 0x20); - dynamicOffset = Converter.getLEint(mapBytes, offset + 0x24); - initArrayStartOffset = Converter.getLEint(mapBytes, offset + 0x28); - initArrayEndOffset = Converter.getLEint(mapBytes, offset + 0x2C); + private int textStartOffset; + private int textEndOffset; + private int rodataStartOffset; + private int rodataEndOffset; + private int dataStartOffset; + private int dataEndOffset; + private int bssStartOffset; + private int bssEndOffset; + private int ini1Offset; + private int dynamicOffset; + private int initArrayStartOffset; + private int initArrayEndOffset; + private int systemRegistersOffset; // 17.0.0+ + + private KernelMap() { } + + /** + * Construct KernelMap + * + * @return null if mapBytes is an invalid data set and KernelMap object otherwise + */ + public static KernelMap constructKernelMap(byte[] mapBytes, int offset, int maxSize) { + KernelMap kernelMap = new KernelMap(); + kernelMap.textStartOffset = Converter.getLEint(mapBytes, offset); + if (kernelMap.textStartOffset != 0) + return null; + kernelMap.textEndOffset = Converter.getLEint(mapBytes, offset + 0x4); + kernelMap.rodataStartOffset = Converter.getLEint(mapBytes, offset + 0x8); + kernelMap.rodataEndOffset = Converter.getLEint(mapBytes, offset + 0xC); + kernelMap.dataStartOffset = Converter.getLEint(mapBytes, offset + 0x10); + kernelMap.dataEndOffset = Converter.getLEint(mapBytes, offset + 0x14); + kernelMap.bssStartOffset = Converter.getLEint(mapBytes, offset + 0x18); + kernelMap.bssEndOffset = Converter.getLEint(mapBytes, offset + 0x1C); + kernelMap.ini1Offset = Converter.getLEint(mapBytes, offset + 0x20); // 0x08d000 + kernelMap.dynamicOffset = Converter.getLEint(mapBytes, offset + 0x24); + kernelMap.initArrayStartOffset = Converter.getLEint(mapBytes, offset + 0x28); + kernelMap.initArrayEndOffset = Converter.getLEint(mapBytes, offset + 0x2C); + kernelMap.systemRegistersOffset = Converter.getLEint(mapBytes, offset + 0x30); + + // taken from hactool + if (kernelMap.textStartOffset >= kernelMap.textEndOffset) + return null; + if ((kernelMap.textEndOffset & 0xFFF) > 0) + return null; + if (kernelMap.textEndOffset > kernelMap.rodataStartOffset) + return null; + if ((kernelMap.rodataStartOffset & 0xFFF) > 0) + return null; + if (kernelMap.rodataStartOffset >= kernelMap.rodataEndOffset) + return null; + if ((kernelMap.rodataEndOffset & 0xFFF) > 0) + return null; + if (kernelMap.rodataEndOffset > kernelMap.dataStartOffset) + return null; + if ((kernelMap.dataStartOffset & 0xFFF) > 0) + return null; + if (kernelMap.dataStartOffset >= kernelMap.dataEndOffset) + return null; + if (kernelMap.dataEndOffset > kernelMap.bssStartOffset) + return null; + if (kernelMap.bssStartOffset > kernelMap.bssEndOffset) + return null; + if (kernelMap.bssEndOffset > kernelMap.ini1Offset) + return null; + /* + if (kernelMap.ini1Offset > maxSize - 0x80) + return null; + */ + System.out.println("FOUND AT:" + RainbowDump.formatDecHexString(offset)); + kernelMap.printDebug(); + return kernelMap; } public int getTextStartOffset() { return textStartOffset; } @@ -67,52 +112,20 @@ public class KernelMap { public int getInitArrayStartOffset() { return initArrayStartOffset; } public int getInitArrayEndOffset() { return initArrayEndOffset; } - //taken from hactool - public boolean isValid(long maxSize) { // section0 size - if (textStartOffset != 0) - return false; - if (textStartOffset >= textEndOffset) - return false; - if ((textEndOffset & 0xFFF) > 0) - return false; - if (textEndOffset > rodataStartOffset) - return false; - if ((rodataStartOffset & 0xFFF) > 0) - return false; - if (rodataStartOffset >= rodataEndOffset) - return false; - if ((rodataEndOffset & 0xFFF) > 0) - return false; - if (rodataEndOffset > dataStartOffset) - return false; - if ((dataStartOffset & 0xFFF) > 0) - return false; - if (dataStartOffset >= dataEndOffset) - return false; - if (dataEndOffset > bssStartOffset) - return false; - if (bssStartOffset > bssEndOffset) - return false; - if (bssEndOffset > ini1Offset) - return false; - if (ini1Offset > maxSize - 0x80) - return false; - - return true; - } - public void printDebug(){ + public void printDebug() { log.debug("_ Kernel map _\n" + - " .text Start Offset " + RainbowDump.formatDecHexString(textStartOffset) + "\n" + - " .text End Offset " + RainbowDump.formatDecHexString(textEndOffset) + "\n" + - " .rodata Start Offset " + RainbowDump.formatDecHexString(rodataStartOffset) + "\n" + - " .rodata End Offset " + RainbowDump.formatDecHexString(rodataEndOffset) + "\n" + - " .data Start Offset " + RainbowDump.formatDecHexString(dataStartOffset) + "\n" + - " .data End Offset " + RainbowDump.formatDecHexString(dataEndOffset) + "\n" + - " .bss Start Offset " + RainbowDump.formatDecHexString(bssStartOffset) + "\n" + - " .bss End Offset " + RainbowDump.formatDecHexString(bssEndOffset) + "\n" + - " INI1 Offset " + RainbowDump.formatDecHexString(ini1Offset) + "\n" + - " Dynamic Offset " + RainbowDump.formatDecHexString(dynamicOffset) + "\n" + - " Init array Start Offset " + RainbowDump.formatDecHexString(initArrayStartOffset) + "\n" + - " Init array End Offset " + RainbowDump.formatDecHexString(initArrayEndOffset)); + " .text Start Offset " + RainbowDump.formatDecHexString(textStartOffset) + "\n" + + " .text End Offset " + RainbowDump.formatDecHexString(textEndOffset) + "\n" + + " .rodata Start Offset " + RainbowDump.formatDecHexString(rodataStartOffset) + "\n" + + " .rodata End Offset " + RainbowDump.formatDecHexString(rodataEndOffset) + "\n" + + " .data Start Offset " + RainbowDump.formatDecHexString(dataStartOffset) + "\n" + + " .data End Offset " + RainbowDump.formatDecHexString(dataEndOffset) + "\n" + + " .bss Start Offset " + RainbowDump.formatDecHexString(bssStartOffset) + "\n" + + " .bss End Offset " + RainbowDump.formatDecHexString(bssEndOffset) + "\n" + + " INI1 Offset " + RainbowDump.formatDecHexString(ini1Offset) + "\n" + + " Dynamic Offset " + RainbowDump.formatDecHexString(dynamicOffset) + "\n" + + " Init array Start Offset " + RainbowDump.formatDecHexString(initArrayStartOffset) + "\n" + + " Init array End Offset " + RainbowDump.formatDecHexString(initArrayEndOffset) + "\n" + + " System registers offset (FW 17.0.0+) " + RainbowDump.formatDecHexString(systemRegistersOffset)); } } diff --git a/src/main/java/libKonogonka/fs/other/System2/System2Provider.java b/src/main/java/libKonogonka/fs/other/System2/System2Provider.java index bdce424..b63d8f2 100644 --- a/src/main/java/libKonogonka/fs/other/System2/System2Provider.java +++ b/src/main/java/libKonogonka/fs/other/System2/System2Provider.java @@ -18,7 +18,9 @@ */ package libKonogonka.fs.other.System2; +import libKonogonka.Converter; import libKonogonka.KeyChainHolder; +import libKonogonka.RainbowDump; import libKonogonka.fs.ExportAble; import libKonogonka.fs.other.System2.ini1.Ini1Provider; import libKonogonka.aesctr.InFileStreamProducer; @@ -112,12 +114,26 @@ public class System2Provider extends ExportAble { throw new Exception("Read failure " + actuallyRead); byteBuffer.put(block); } - byte[] searchField = byteBuffer.array(); - for (int i = 0; i < 1024; i += 4) { - kernelMap = new KernelMap(searchField, i); - if (kernelMap.isValid(header.getSection0size())) - return; + + if (Converter.getLEint(searchField, 3) == 0x14){ // If FW 17.0.0+ + // Calculate new location of the 'kernel beginning' + int branchTarget = (Converter.getLEint(searchField, 0) & 0x00FFFFFF) << 2; + + int toSkip = branchTarget - 0x1000; + System.out.println("To skip = " + toSkip + " "); + if (toSkip != stream.skip(toSkip)) + throw new Exception("Unable to skip offset of " + toSkip); + + // TODO: really cursed shit + throw new Exception("FW 17+ not supported. WIP"); + } + else { + for (int i = 0; i < 0x1000; i += 4) { + kernelMap = KernelMap.constructKernelMap(searchField, i, header.getSection0size()); + if (kernelMap != null) + return; + } } throw new Exception("Kernel map not found"); }