Rework NSO0 related classes. Added option to pick one of the ELF's sections (.text, .data or .rodata) unpacked without pre-dumping it on disk.
All checks were successful
continuous-integration/drone/push Build is passing

Clean 'System.out.print*'
This commit is contained in:
Dmitry Isaenko 2022-12-10 00:26:21 +03:00
parent 91ab6fd74b
commit 53af386738
15 changed files with 462 additions and 284 deletions

View file

@ -2,7 +2,7 @@
![License](https://img.shields.io/badge/License-GPLv3-blue.svg) [![Build Status](https://ci.redrise.ru/api/badges/desu/libKonogonka/status.svg)](https://ci.redrise.ru/desu/libKonogonka)
Library to work with NS-specific files / filesystem images. Ex-backend of [konogonka](https://github.com/developersu/konogonka) ([independent source location](https://git.redrise.ru/desu/konogonka))
Library made to work with NS-specific files / filesystem images. Separated backend of [konogonka](https://github.com/developersu/konogonka) ([independent source location](https://git.redrise.ru/desu/konogonka))
### Let's stay in touch
@ -20,8 +20,8 @@ You can get this application from independent source location: [https://git.redr
#### Thanks
* Switch brew wiki
* Original ScriesM software
* [Switch brew](https://switchbrew.org) wiki
* Original [ScriesM software](https://github.com/SciresM/)
* roothorick, [shchmue](https://github.com/shchmue/), He, other Team AtlasNX discord members for their advices, notes and examples!
### System requirements
@ -31,3 +31,7 @@ JRE/JDK 8u60 or higher.
### Build
See .drone.yml
### Install on local host (local maven repo)
`# mvn instal`

View file

@ -25,13 +25,13 @@
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284272"
inkscape:cx="378.30212"
inkscape:cy="70.5339"
inkscape:window-width="2266"
inkscape:window-height="1414"
inkscape:window-x="1305"
inkscape:window-y="546"
inkscape:window-maximized="0"
inkscape:cx="378.65567"
inkscape:cy="71.06423"
inkscape:window-width="3754"
inkscape:window-height="2127"
inkscape:window-x="1166"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="false" />
<defs
@ -164,17 +164,59 @@
style="fill:#ffffff;fill-opacity:1;stroke-width:0.495873"
d="m 23.094714,131.98367 c -0.01603,0.002 -0.03159,0.009 -0.04392,0.0212 l -2.970361,2.97191 a 1.3654379,1.7456499 3.0525799 0 1 0.15658,0.77825 1.3654379,1.7456499 3.0525799 0 1 -0.405144,1.25574 l 0.882634,0.88212 c 0.02822,0.0282 0.0736,0.0282 0.101803,0 l 1.578714,-1.57924 4.230233,4.22765 -5.007963,5.76296 c -0.02618,0.0301 -0.02286,0.0751 0.0072,0.10128 l 0.638204,0.55449 c 0.03012,0.0262 0.07512,0.0234 0.101286,-0.007 l 4.963004,-5.71025 5.706629,5.70353 c 0.02822,0.0282 0.0736,0.0282 0.101803,0 l 0.597895,-0.59841 c 0.02822,-0.0282 0.02822,-0.0736 0,-0.10181 l -5.75572,-5.7521 3.962549,-4.55941 0.388606,0.33796 c 0.03011,0.0262 1.846533,0.7774 2.807063,0.87385 -0.112556,-1.06415 -1.083514,-2.79639 -1.113628,-2.82256 l -0.388605,-0.33797 0.06046,-0.0692 c 0.02619,-0.0301 0.02289,-0.0756 -0.0072,-0.10181 l -0.638719,-0.55449 c -0.03011,-0.0262 -0.07512,-0.0234 -0.101286,0.007 l -0.06046,0.0692 -1.531173,-1.33066 c -0.03011,-0.0262 -0.07564,-0.023 -0.101802,0.007 l -1.599386,1.8402 c -0.02618,0.0301 -0.02289,0.0756 0.0072,0.1018 l 1.531689,1.33067 -3.917073,4.5067 -4.18114,-4.17907 1.78232,-1.78336 c 0.0282,-0.0282 0.02821,-0.0736 0,-0.1018 l -1.724443,-1.72341 c -0.01411,-0.0141 -0.03227,-0.0212 -0.05064,-0.0212 -0.0023,0 -0.0049,-2.1e-4 -0.0072,0 z" />
</g>
<text
xml:space="preserve"
style="font-size:10.5833px;line-height:1.25;font-family:Terminus;-inkscape-font-specification:'Terminus, Normal';stroke-width:0.264583;filter:url(#filter3747)"
x="44.007172"
y="147.82162"
id="text2788"><tspan
sodipodi:role="line"
id="tspan2786"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;stroke-width:0.264583"
x="44.007172"
y="147.82162">libKonogonka</tspan></text>
<g
aria-label="libKonogonka"
id="text2788"
style="font-size:10.5833px;line-height:1.25;font-family:Terminus;-inkscape-font-specification:'Terminus, Normal';stroke-width:0.264583;filter:url(#filter3747)">
<path
d="m 48.274372,147.82162 h -2.286 v -17.77999 h 2.286 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path871" />
<path
d="m 54.522779,133.47062 h -2.286 v -2.38759 h 2.286 z m 0,14.351 h -2.286 v -12.2936 h 2.286 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path873" />
<path
d="m 69.686586,138.75382 v 5.0546 q 0,1.1176 -0.3302,1.9304 -0.3302,0.8128 -0.8382,1.27 -0.4826,0.4318 -1.2954,0.6858 -0.8128,0.254 -1.524,0.3048 -0.7112,0.0762 -1.7272,0.0762 -1.3208,0 -2.159,-0.127 -0.8382,-0.127 -1.6764,-0.5334 -0.8382,-0.4064 -1.2446,-1.2954 -0.4064,-0.9144 -0.4064,-2.3114 v -13.76679 h 2.286 v 3.68299 q 0,0.4826 -0.0254,1.4732 0,0.9652 0,1.4478 0.1016,-0.5842 1.0414,-0.9652 0.9652,-0.4064 2.8194,-0.4064 5.08,0 5.08,3.4798 z m -2.3368,5.3848 v -4.826 q 0,-1.5748 -0.7366,-1.9812 -0.7366,-0.4318 -2.6162,-0.4318 -1.8034,0 -2.5146,0.4826 -0.7112,0.4826 -0.7112,1.9304 v 4.826 q 0,1.5494 0.6858,2.0066 0.7112,0.4318 2.5654,0.4318 1.8796,0 2.5908,-0.4318 0.7366,-0.4572 0.7366,-2.0066 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path875" />
<path
d="m 86.933198,147.82162 h -3.2004 l -7.874,-8.763 7.366,-7.72159 h 2.9718 l -7.4168,7.61999 z m -11.1252,0 h -2.4638 v -16.48459 h 2.4638 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path877" />
<path
d="m 99.53158,139.66822 v 4.2672 q 0,1.143 -0.2794,1.9304 -0.2794,0.7874 -0.7112,1.2192 -0.4318,0.4318 -1.2446,0.6604 -0.7874,0.2286 -1.524,0.2794 -0.7112,0.0508 -1.905,0.0508 -1.524,0 -2.3876,-0.1016 -0.8382,-0.1016 -1.7018,-0.4826 -0.8382,-0.4064 -1.2192,-1.27 -0.3556,-0.8636 -0.3556,-2.286 v -4.2672 q 0,-1.2192 0.2794,-2.0574 0.3048,-0.8382 0.7112,-1.2954 0.4318,-0.4572 1.2446,-0.6858 0.8128,-0.254 1.4986,-0.3048 0.7112,-0.0508 1.9304,-0.0508 1.2192,0 1.905,0.0508 0.7112,0.0508 1.524,0.3048 0.8128,0.2286 1.2192,0.6858 0.4318,0.4572 0.7112,1.2954 0.3048,0.8382 0.3048,2.0574 z m -2.3368,4.5974 v -4.9784 q 0,-1.7018 -0.6858,-2.1082 -0.6858,-0.4064 -2.6416,-0.4064 -1.9558,0 -2.6416,0.4064 -0.6858,0.4064 -0.6858,2.1082 v 4.9784 q 0,0.8128 0.1778,1.2954 0.1778,0.4826 0.6604,0.7112 0.4826,0.2032 0.9906,0.254 0.508,0.0508 1.4986,0.0508 0.9906,0 1.4986,-0.0508 0.508,-0.0508 0.9906,-0.254 0.4826,-0.2286 0.6604,-0.7112 0.1778,-0.4826 0.1778,-1.2954 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path879" />
<path
d="m 113.6794,147.82162 h -2.286 v -8.89 q 0,-0.4572 -0.0762,-0.762 -0.0762,-0.3048 -0.3302,-0.6096 -0.2286,-0.3302 -0.8128,-0.4826 -0.5588,-0.1778 -1.4224,-0.1778 -2.0066,0 -2.6924,0.4318 -0.6858,0.4318 -0.6858,1.6002 v 8.89 h -2.286 v -12.2936 h 2.286 v 1.4986 q 0.3556,-1.7526 4.0386,-1.7526 2.4384,0 3.3528,0.889 0.9144,0.8636 0.9144,2.6416 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path881" />
<path
d="m 128.513,139.66822 v 4.2672 q 0,1.143 -0.2794,1.9304 -0.2794,0.7874 -0.7112,1.2192 -0.4318,0.4318 -1.2446,0.6604 -0.7874,0.2286 -1.524,0.2794 -0.7112,0.0508 -1.905,0.0508 -1.524,0 -2.3876,-0.1016 -0.8382,-0.1016 -1.7018,-0.4826 -0.8382,-0.4064 -1.2192,-1.27 -0.3556,-0.8636 -0.3556,-2.286 v -4.2672 q 0,-1.2192 0.2794,-2.0574 0.3048,-0.8382 0.7112,-1.2954 0.4318,-0.4572 1.2446,-0.6858 0.8128,-0.254 1.4986,-0.3048 0.7112,-0.0508 1.9304,-0.0508 1.2192,0 1.905,0.0508 0.7112,0.0508 1.524,0.3048 0.8128,0.2286 1.2192,0.6858 0.4318,0.4572 0.7112,1.2954 0.3048,0.8382 0.3048,2.0574 z m -2.3368,4.5974 v -4.9784 q 0,-1.7018 -0.6858,-2.1082 -0.6858,-0.4064 -2.6416,-0.4064 -1.9558,0 -2.6416,0.4064 -0.6858,0.4064 -0.6858,2.1082 v 4.9784 q 0,0.8128 0.1778,1.2954 0.1778,0.4826 0.6604,0.7112 0.4826,0.2032 0.9906,0.254 0.508,0.0508 1.4986,0.0508 0.9906,0 1.4986,-0.0508 0.508,-0.0508 0.9906,-0.254 0.4826,-0.2286 0.6604,-0.7112 0.1778,-0.4826 0.1778,-1.2954 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path883" />
<path
d="m 142.55921,135.52802 v 13.462 q 0,2.6162 -1.4732,3.5052 -1.4478,0.9144 -4.3688,0.9144 -2.6162,0 -4.2418,-0.2794 v -1.6256 q 2.921,0.3556 4.445,0.3556 1.7526,0 2.54,-0.5588 0.8128,-0.5588 0.8128,-1.8542 v -2.9464 q -0.0508,0.8636 -1.1938,1.2192 -1.1176,0.3556 -2.5654,0.3556 -2.8448,0 -3.8862,-0.8382 -1.016,-0.8382 -1.016,-2.8956 v -5.0038 q 0,-2.1844 1.1684,-3.1242 1.1938,-0.9398 3.8862,-0.9398 3.2004,0 3.7592,1.4478 v -1.1938 z m -2.286,8.9662 v -5.5626 q 0,-1.1938 -0.6604,-1.6256 -0.635,-0.4572 -2.667,-0.4572 -1.905,0 -2.4892,0.4318 -0.5842,0.4318 -0.5842,1.651 v 5.5626 q 0,1.27 0.6096,1.6764 0.635,0.381 2.5146,0.381 1.7272,0 2.4892,-0.4064 0.7874,-0.4318 0.7874,-1.651 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path885" />
<path
d="m 157.39282,139.66822 v 4.2672 q 0,1.143 -0.2794,1.9304 -0.2794,0.7874 -0.7112,1.2192 -0.4318,0.4318 -1.2446,0.6604 -0.7874,0.2286 -1.524,0.2794 -0.7112,0.0508 -1.905,0.0508 -1.524,0 -2.3876,-0.1016 -0.8382,-0.1016 -1.7018,-0.4826 -0.8382,-0.4064 -1.2192,-1.27 -0.3556,-0.8636 -0.3556,-2.286 v -4.2672 q 0,-1.2192 0.2794,-2.0574 0.3048,-0.8382 0.7112,-1.2954 0.4318,-0.4572 1.2446,-0.6858 0.8128,-0.254 1.4986,-0.3048 0.7112,-0.0508 1.9304,-0.0508 1.2192,0 1.905,0.0508 0.7112,0.0508 1.524,0.3048 0.8128,0.2286 1.2192,0.6858 0.4318,0.4572 0.7112,1.2954 0.3048,0.8382 0.3048,2.0574 z m -2.3368,4.5974 v -4.9784 q 0,-1.7018 -0.6858,-2.1082 -0.6858,-0.4064 -2.6416,-0.4064 -1.9558,0 -2.6416,0.4064 -0.6858,0.4064 -0.6858,2.1082 v 4.9784 q 0,0.8128 0.1778,1.2954 0.1778,0.4826 0.6604,0.7112 0.4826,0.2032 0.9906,0.254 0.508,0.0508 1.4986,0.0508 0.9906,0 1.4986,-0.0508 0.508,-0.0508 0.9906,-0.254 0.4826,-0.2286 0.6604,-0.7112 0.1778,-0.4826 0.1778,-1.2954 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path887" />
<path
d="m 171.54064,147.82162 h -2.286 v -8.89 q 0,-0.4572 -0.0762,-0.762 -0.0762,-0.3048 -0.3302,-0.6096 -0.2286,-0.3302 -0.8128,-0.4826 -0.5588,-0.1778 -1.4224,-0.1778 -2.0066,0 -2.6924,0.4318 -0.6858,0.4318 -0.6858,1.6002 v 8.89 h -2.286 v -12.2936 h 2.286 v 1.4986 q 0.3556,-1.7526 4.0386,-1.7526 2.4384,0 3.3528,0.889 0.9144,0.8636 0.9144,2.6416 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path889" />
<path
d="m 186.52665,147.82162 h -2.8448 l -5.6134,-6.731 5.1816,-5.5626 h 2.794 l -5.334,5.5626 z m -8.7376,0 h -2.286 v -17.77999 h 2.286 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path891" />
<path
d="m 198.26144,147.82162 h -2.2098 v -1.1684 q -0.2794,1.4224 -3.7084,1.4224 -2.54,0 -3.5306,-0.762 -0.9652,-0.7874 -0.9652,-3.1496 0,-2.0574 0.9144,-2.8194 0.9144,-0.7874 3.5306,-0.7874 h 3.683 v -1.9558 q 0,-1.016 -0.635,-1.3716 -0.6096,-0.3556 -2.3368,-0.3556 -1.8796,0 -4.2164,0.3048 v -1.6764 q 2.5146,-0.2286 4.5466,-0.2286 3.0988,0 4.0132,0.762 0.9144,0.7366 0.9144,3.0988 z m -2.286,-2.4892 v -3.3528 h -3.5306 q -1.5748,0 -1.9812,0.4064 -0.381,0.4064 -0.381,1.8542 0,1.2954 0.4064,1.8288 0.4318,0.508 1.778,0.508 h 0.4572 q 0.6604,0 1.0922,-0.0254 0.4572,-0.0254 1.016,-0.127 0.5588,-0.127 0.8382,-0.381 0.3048,-0.2794 0.3048,-0.7112 z"
style="font-size:25.4px;font-family:Play;-inkscape-font-specification:'Play, Normal';fill:#ffffff"
id="path893" />
</g>
<g
id="g939">
<path

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

13
pom.xml
View file

@ -70,6 +70,13 @@
<version>2.19.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-pure-java</artifactId>
<version>1.8.0</version>
<scope>compile</scope>
</dependency>
<!-- testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
@ -89,11 +96,7 @@
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-pure-java</artifactId>
<version>1.8.0</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>

View file

@ -22,7 +22,11 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.charset.StandardCharsets;
/* ANSI_BLACK = "\u001B[30m";
ANSI_YELLOW = "\u001B[33m";
ANSI_PURPLE = "\u001B[35m";
ANSI_CYAN = "\u001B[36m";
ANSI_WHITE = "\u001B[37m"; */
/**
* Debug tool like hexdump <3
*/
@ -30,14 +34,9 @@ public class RainbowDump {
private final static Logger log = LogManager.getLogger(Converter.class);
private static final String ANSI_RESET = "\u001B[0m";
private static final String ANSI_BLACK = "\u001B[30m";
private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m";
private static final String ANSI_YELLOW = "\u001B[33m";
private static final String ANSI_BLUE = "\u001B[34m";
private static final String ANSI_PURPLE = "\u001B[35m";
private static final String ANSI_CYAN = "\u001B[36m";
private static final String ANSI_WHITE = "\u001B[37m";
private static StringBuilder stringBuilder;
public static void hexDumpUTF8(byte[] byteArray){
@ -80,7 +79,13 @@ public class RainbowDump {
}
private static void printChars(byte[] byteArray, int pointer){
for (int j = pointer-16; j < pointer; j++){
int j;
if (pointer < 16)
j = 0;
else
j = pointer-16;
for (; j < pointer; j++){
if ((byteArray[j] > 21) && (byteArray[j] < 126)) // man ascii
stringBuilder.append((char) byteArray[j]);
else if (byteArray[j] == 0x0a)
@ -92,18 +97,22 @@ public class RainbowDump {
}
}
public static void hexDumpUTF8Legacy(byte[] byteArray){
StringBuilder stringBuilderLegacy = new StringBuilder("HexDumpUTF8Legacy");
stringBuilderLegacy.append(ANSI_BLUE);
if (byteArray == null || byteArray.length == 0)
return;
System.out.print(ANSI_BLUE);
for (int i=0; i < byteArray.length; i++)
System.out.printf("%02d-", i%100);
System.out.println(">"+ANSI_RED+byteArray.length+ANSI_RESET);
stringBuilderLegacy.append(String.format("%02d-", i%100));
stringBuilderLegacy.append(">" + ANSI_RED).append(byteArray.length).append(ANSI_RESET).append("\n");
for (byte b: byteArray)
System.out.printf("%02x ", b);
System.out.println();
System.out.print(new String(byteArray, StandardCharsets.UTF_8)+"\n");
stringBuilderLegacy.append(String.format("%02x ", b));
stringBuilderLegacy.append("\n")
.append(new String(byteArray, StandardCharsets.UTF_8))
.append("\n");
log.debug(stringBuilderLegacy.toString());
}
public static void binDumpInt(int value){
@ -111,7 +120,7 @@ public class RainbowDump {
}
public static void binDumpLong(long value){
System.out.println(String.format("%64s", Long.toBinaryString( value )).replace(' ', '0')+" | "+value);
log.debug(String.format("%64s", Long.toBinaryString( value )).replace(' ', '0')+" | "+value);
}
public static String formatDecHexString(long value){

View file

@ -19,6 +19,8 @@
package libKonogonka.Tools.NPDM;
import libKonogonka.Converter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@ -73,6 +75,7 @@ for (byte i = 0; i < 16; i++){
*/
public class KernelAccessControlProvider {
private final static Logger log = LogManager.getLogger(KernelAccessControlProvider.class);
private static final int KERNELFLAGS = 3,
SYSCALLMASK = 4,
@ -85,7 +88,7 @@ public class KernelAccessControlProvider {
DEBUGFLAGS = 16;
// RAW data
private LinkedList<Integer> rawData;
private final LinkedList<Integer> rawData;
// Kernel flags
private boolean kernelFlagsAvailable;
private int kernelFlagCpuIdHi,
@ -93,13 +96,13 @@ public class KernelAccessControlProvider {
kernelFlagThreadPrioHi,
kernelFlagThreadPrioLo;
// Syscall Masks as index | mask - order AS IS. [0] = bit5; [1] = bit6
private LinkedHashMap<Byte, byte[]> syscallMasks; // Index, Mask
private final LinkedHashMap<Byte, byte[]> syscallMasks; // Index, Mask
// MapIoOrNormalRange
private LinkedHashMap<byte[], Boolean> mapIoOrNormalRange; // alt page+num, RO flag
private final LinkedHashMap<byte[], Boolean> mapIoOrNormalRange; // alt page+num, RO flag
// MapNormalPage (RW)
private byte[] mapNormalPage; // TODO: clarify is possible to have multiple
// InterruptPair
private LinkedHashMap<Integer, byte[][]> interruptPairs; // Number; irq0, irq2
private final LinkedHashMap<Integer, byte[][]> interruptPairs; // Number; irq0, irq2
// Application type
private int applicationType;
// KernelReleaseVersion
@ -142,42 +145,42 @@ public class KernelAccessControlProvider {
kernelFlagCpuIdLo = block >> 16 & 0b11111111;
kernelFlagThreadPrioHi = block >> 10 & 0b111111;
kernelFlagThreadPrioLo = block >> 4 & 0b111111;
//System.out.println("KERNELFLAGS "+kernelFlagCpuIdHi+" "+kernelFlagCpuIdLo+" "+kernelFlagThreadPrioHi+" "+kernelFlagThreadPrioLo);
//log.debug("KERNELFLAGS "+kernelFlagCpuIdHi+" "+kernelFlagCpuIdLo+" "+kernelFlagThreadPrioHi+" "+kernelFlagThreadPrioLo);
break;
case SYSCALLMASK:
byte maskTableIndex = (byte) (block >> 29 & 0b111); // declared as byte; max value could be 7; min - 0;
byte[] mask = new byte[24]; // Consider as bit.
//System.out.println("SYSCALLMASK ind: "+maskTableIndex);
//log.debug("SYSCALLMASK ind: "+maskTableIndex);
for (int k = 28; k >= 5; k--) {
mask[k-5] = (byte) (block >> k & 1); // Only 1 or 0 possible
//System.out.print(mask[k-5]);
//log.debug(" " + mask[k-5]);
}
//System.out.println();
//log.debug();
syscallMasks.put(maskTableIndex, mask);
break;
case MAPIOORNORMALRANGE:
byte[] altStPgNPgNum = new byte[24];
//System.out.println("MAPIOORNORMALRANGE Flag: "+((block >> 31 & 1) != 0));
//log.debug("MAPIOORNORMALRANGE Flag: "+((block >> 31 & 1) != 0));
for (int k = 30; k >= 7; k--){
altStPgNPgNum[k-7] = (byte) (block >> k & 1); // Only 1 or 0 possible
//System.out.print(altStPgNPgNum[k-7]);
//log.debug(" " + altStPgNPgNum[k-7]);
}
mapIoOrNormalRange.put(altStPgNPgNum, (block >> 31 & 1) != 0);
//System.out.println();
//log.debug();
break;
case MAPNORMALPAGE_RW:
//System.out.println("MAPNORMALPAGE_RW\t");
//log.debug("MAPNORMALPAGE_RW\t");
mapNormalPage = new byte[24];
for (int k = 31; k >= 8; k--){
mapNormalPage[k-8] = (byte) (block >> k & 1);
//System.out.print(mapNormalPage[k-8]);
//log.debug(" " + mapNormalPage[k-8]);
}
//System.out.println();
//log.debug();
break;
case INTERRUPTPAIR:
//System.out.println("INTERRUPTPAIR");
//log.debug("INTERRUPTPAIR");
//RainbowHexDump.octDumpInt(block);
byte[][] pair = new byte[2][];
byte[] irq0 = new byte[10];
@ -193,26 +196,26 @@ public class KernelAccessControlProvider {
break;
case APPLICATIONTYPE:
applicationType = block >> 14 & 0b111;
//System.out.println("APPLICATIONTYPE "+applicationType);
//log.debug("APPLICATIONTYPE "+applicationType);
break;
case KERNELRELEASEVERSION:
//System.out.println("KERNELRELEASEVERSION\t"+(block >> 19 & 0b111111111111)+"."+(block >> 15 & 0b1111)+".X");
//log.debug("KERNELRELEASEVERSION\t"+(block >> 19 & 0b111111111111)+"."+(block >> 15 & 0b1111)+".X");
isKernelRelVersionAvailable = true;
kernelRelVersionMajor = (block >> 19 & 0b111111111111);
kernelRelVersionMinor = (block >> 15 & 0b1111);
break;
case HANDLETABLESIZE:
handleTableSize = block >> 16 & 0b1111111111;
//System.out.println("HANDLETABLESIZE "+handleTableSize);
//log.debug("HANDLETABLESIZE "+handleTableSize);
break;
case DEBUGFLAGS:
debugFlagsAvailable = true;
canBeDebugged = (block >> 17 & 1) != 0;
canDebugOthers = (block >> 18 & 1) != 0;
//System.out.println("DEBUGFLAGS "+canBeDebugged+" "+canDebugOthers);
//log.debug("DEBUGFLAGS "+canBeDebugged+" "+canDebugOthers);
break;
default:
System.out.println("UNKNOWN\t\t"+block+" "+type);
log.error("UNKNOWN\t\t"+block+" "+type);
}
}
}

View file

@ -0,0 +1,174 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of libKonogonka.
libKonogonka is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
libKonogonka is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with libKonogonka. If not, see <https://www.gnu.org/licenses/>.
*/
package libKonogonka.Tools.NSO;
import libKonogonka.Converter;
import libKonogonka.RainbowDump;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import static libKonogonka.Converter.getLEint;
public class NSO0Header {
private final static Logger log = LogManager.getLogger(NSO0Header.class);
private String magic;
private int version;
private byte[] upperReserved;
private int flags;
private SegmentHeader textSegmentHeader;
private int moduleNameOffset; // note: could be unsigned int; consider 'long'
private SegmentHeader rodataSegmentHeader;
private int moduleNameSize;
private SegmentHeader dataSegmentHeader;
private int bssSize; // note: could be unsigned int; consider 'long'
private byte[] moduleId;
private int textCompressedSize;
private int rodataCompressedSize;
private int dataCompressedSize;
private byte[] bottomReserved;
private SegmentHeaderRelative _api_infoRelative;
private SegmentHeaderRelative _dynstrRelative;
private SegmentHeaderRelative _dynsymRelative;
private byte[] textHash;
private byte[] rodataHash;
private byte[] dataHash;
public NSO0Header(byte[] headerBytes) throws Exception{
if (headerBytes.length < 0x100)
throw new Exception("Incorrect NSO0 header size");
parse(headerBytes);
}
private void parse(byte[] knownStartingBytes) throws Exception{
this.magic = new String(knownStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
if (! magic.equals("NSO0")){
throw new Exception("Bad magic");
}
this.version = getLEint(knownStartingBytes, 0x4);
this.upperReserved = Arrays.copyOfRange(knownStartingBytes, 0x8, 0xC);
this.flags = getLEint(knownStartingBytes, 0xC);
this.textSegmentHeader = new SegmentHeader(knownStartingBytes, 0x10);
this.moduleNameOffset = Converter.getLEint(knownStartingBytes, 0x1C);
this.rodataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x20);
this.moduleNameSize = Converter.getLEint(knownStartingBytes, 0x2C);
this.dataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x30);
this.bssSize = Converter.getLEint(knownStartingBytes, 0x3C);
this.moduleId = Arrays.copyOfRange(knownStartingBytes, 0x40, 0x60);
this.textCompressedSize = Converter.getLEint(knownStartingBytes, 0x60);
this.rodataCompressedSize = Converter.getLEint(knownStartingBytes, 0x64);
this.dataCompressedSize = Converter.getLEint(knownStartingBytes, 0x68);
this.bottomReserved = Arrays.copyOfRange(knownStartingBytes, 0x6C, 0x88);
this._api_infoRelative = new SegmentHeaderRelative(knownStartingBytes, 0x88);
this._dynstrRelative = new SegmentHeaderRelative(knownStartingBytes, 0x90);
this._dynsymRelative = new SegmentHeaderRelative(knownStartingBytes, 0x98);
this.textHash = Arrays.copyOfRange(knownStartingBytes, 0xA0, 0xC0);
this.rodataHash = Arrays.copyOfRange(knownStartingBytes, 0xC0, 0xE0);
this.dataHash = Arrays.copyOfRange(knownStartingBytes, 0xE0, 0x100);
}
/* API */
public String getMagic() { return magic; }
public int getVersion() {return version; }
public byte[] getUpperReserved() { return upperReserved; }
public int getFlags() { return flags; }
public boolean isTextCompressFlag(){ return (flags & 0b000001) == 1; }
public boolean isRoCompressFlag(){ return (flags & 0b000010) >> 1 == 1; }
public boolean isDataCompressFlag(){ return (flags & 0b000100 ) >> 2 == 1; }
public boolean isTextHashFlag(){ return (flags & 0b001000 ) >> 3 == 1; }
public boolean isRoHashFlag(){ return (flags & 0b010000 ) >> 4 == 1; }
public boolean isDataHashFlag(){ return (flags & 0b100000 ) >> 5 == 1; }
public SegmentHeader getTextSegmentHeader() { return textSegmentHeader; }
public int getModuleNameOffset() { return moduleNameOffset; }
public SegmentHeader getRodataSegmentHeader() { return rodataSegmentHeader; }
public int getModuleNameSize() { return moduleNameSize; }
public SegmentHeader getDataSegmentHeader() { return dataSegmentHeader; }
public int getBssSize() { return bssSize; }
public byte[] getModuleId() { return moduleId; }
public int getTextCompressedSize() { return textCompressedSize; }
public int getRodataCompressedSize() { return rodataCompressedSize; }
public int getDataCompressedSize() { return dataCompressedSize; }
public byte[] getBottomReserved() { return bottomReserved; }
public SegmentHeaderRelative get_api_infoRelative() { return _api_infoRelative; }
public SegmentHeaderRelative get_dynstrRelative() { return _dynstrRelative; }
public SegmentHeaderRelative get_dynsymRelative() { return _dynsymRelative; }
public byte[] getTextHash() { return textHash; }
public byte[] getRodataHash() { return rodataHash; }
public byte[] getDataHash() { return dataHash; }
public void printDebug(){
log.debug(".:: NSO0 Provider ::.\n" +
" ============================================================= \n" +
"Magic \"NSO0\" " + magic + "\n" +
"Version (always 0) " + version + "\n" +
"Reserved " + Converter.byteArrToHexString(upperReserved) + "\n" +
"Flags " + Converter.intToBinaryString(flags) + "\n" +
" |- 0. .text Compress " + isTextCompressFlag() + "\n" +
" |- 1. .rodata Compress " + isRoCompressFlag() + "\n" +
" |- 2. .data Compress " + isDataCompressFlag() + "\n" +
" |- 3. .text Hash " + isTextHashFlag() + "\n" +
" |- 4. .rodata Hash " + isRoHashFlag() + "\n" +
" |- 5. .data Hash " + isDataHashFlag() + "\n" +
" +++\n"+
"SegmentHeader for .text\n" +
" |- File Offset - - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSegmentOffset()) + "\n" +
" |- Memory Offset - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getMemoryOffset()) + "\n" +
" |- Size As Decompressed - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSizeAsDecompressed()) + "\n" +
"ModuleNameOffset (calculated by sizeof(header)) " + RainbowDump.formatDecHexString(moduleNameOffset) + "\n" +
" +++\n"+
"SegmentHeader for .rodata\n" +
" |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSegmentOffset()) + "\n" +
" |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getMemoryOffset()) + "\n" +
" |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSizeAsDecompressed()) + "\n" +
"ModuleNameSize " + RainbowDump.formatDecHexString(moduleNameSize) + "\n" +
" +++\n"+
"SegmentHeader for .data\n" +
" |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSegmentOffset()) + "\n" +
" |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getMemoryOffset()) + "\n" +
" |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSizeAsDecompressed()) + "\n" +
" .bss Size " + RainbowDump.formatDecHexString(bssSize) + "\n" + // Block Started by Symbol
"Module ID (aka Build ID) " + Converter.byteArrToHexString(moduleId) + "\n" +
" .text Size (compressed) " + RainbowDump.formatDecHexString(textCompressedSize) + "\n" +
" .rodata Size (compressed) " + RainbowDump.formatDecHexString(rodataCompressedSize) + "\n" +
" .data Size (compressed) " + RainbowDump.formatDecHexString(dataCompressedSize) + "\n" +
"Reserved " + Converter.byteArrToHexString(bottomReserved) + "\n" +
" xxx\n"+
"SegmentHeaderRelative for .api_info\n" +
" |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getOffset()) + "\n" +
" |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getSize()) + "\n" +
" xxx\n"+
"SegmentHeaderRelative for .dynstr\n" +
" |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getOffset()) + "\n" +
" |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getSize()) + "\n" +
" xxx\n"+
"SegmentHeaderRelative for .dynsym\n" +
" |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getOffset()) + "\n" +
" |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getSize()) + "\n" +
" xxx\n"+
".text decompressed' SHA-256 hash " + Converter.byteArrToHexString(textHash) + "\n" +
".rodata decompressed' SHA-256 hash " + Converter.byteArrToHexString(rodataHash) + "\n" +
".data decompressed' SHA-256 hash " + Converter.byteArrToHexString(dataHash) + "\n" +
" ============================================================= "
);
}
}

View file

@ -18,45 +18,15 @@
*/
package libKonogonka.Tools.NSO;
import libKonogonka.Converter;
import libKonogonka.RainbowDump;
import libKonogonka.ctraes.InFileStreamProducer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.BufferedInputStream;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import static libKonogonka.Converter.getLEint;
public class NSO0Provider {
private final static Logger log = LogManager.getLogger(NSO0Provider.class);
private final InFileStreamProducer producer;
private String magic;
private int version;
private byte[] upperReserved;
private int flags;
private SegmentHeader textSegmentHeader;
private int moduleNameOffset; // note: could be unsigned int; consider 'long'
private SegmentHeader rodataSegmentHeader;
private int moduleNameSize;
private SegmentHeader dataSegmentHeader;
private int bssSize; // note: could be unsigned int; consider 'long'
private byte[] moduleId;
private int textCompressedSize;
private int rodataCompressedSize;
private int dataCompressedSize;
private byte[] bottomReserved;
private SegmentHeaderRelative _api_infoRelative;
private SegmentHeaderRelative _dynstrRelative;
private SegmentHeaderRelative _dynsymRelative;
private byte[] textHash;
private byte[] rodataHash;
private byte[] dataHash;
private final NSO0Header header;
/* Encrypted */
public NSO0Provider(InFileStreamProducer producer) throws Exception {
@ -65,7 +35,7 @@ public class NSO0Provider {
byte[] knownStartingBytes = new byte[0x100];
if (0x100 != stream.read(knownStartingBytes))
throw new Exception("Reading stream suddenly ended while trying to read starting 0x100 bytes");
parse(knownStartingBytes);
this.header = new NSO0Header(knownStartingBytes);
}
}
@ -82,123 +52,26 @@ public class NSO0Provider {
byte[] knownStartingBytes = new byte[0x100];
if (0x100 != stream.read(knownStartingBytes))
throw new Exception("Reading stream suddenly ended while trying to read starting 0x100 bytes");
parse(knownStartingBytes);
this.header = new NSO0Header(knownStartingBytes);
}
}
private void parse(byte[] knownStartingBytes) throws Exception{
this.magic = new String(knownStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
if (! magic.equals("NSO0")){
throw new Exception("Bad magic");
}
this.version = getLEint(knownStartingBytes, 0x4);
this.upperReserved = Arrays.copyOfRange(knownStartingBytes, 0x8, 0xC);
this.flags = getLEint(knownStartingBytes, 0xC);
this.textSegmentHeader = new SegmentHeader(knownStartingBytes, 0x10);
this.moduleNameOffset = Converter.getLEint(knownStartingBytes, 0x1C);
this.rodataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x20);
this.moduleNameSize = Converter.getLEint(knownStartingBytes, 0x2C);
this.dataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x30);
this.bssSize = Converter.getLEint(knownStartingBytes, 0x3C);
this.moduleId = Arrays.copyOfRange(knownStartingBytes, 0x40, 0x60);
this.textCompressedSize = Converter.getLEint(knownStartingBytes, 0x60);
this.rodataCompressedSize = Converter.getLEint(knownStartingBytes, 0x64);
this.dataCompressedSize = Converter.getLEint(knownStartingBytes, 0x68);
this.bottomReserved = Arrays.copyOfRange(knownStartingBytes, 0x6C, 0x88);
this._api_infoRelative = new SegmentHeaderRelative(knownStartingBytes, 0x88);
this._dynstrRelative = new SegmentHeaderRelative(knownStartingBytes, 0x90);
this._dynsymRelative = new SegmentHeaderRelative(knownStartingBytes, 0x98);
this.textHash = Arrays.copyOfRange(knownStartingBytes, 0xA0, 0xC0);
this.rodataHash = Arrays.copyOfRange(knownStartingBytes, 0xC0, 0xE0);
this.dataHash = Arrays.copyOfRange(knownStartingBytes, 0xE0, 0x100);
public NSO0Header getHeader() {
return header;
}
public void exportAsDecompressedNSO0(String saveToLocation) throws Exception{
NSO0Unpacker.unpack(this, producer, saveToLocation);
NSO0Unpacker.unpack(header, producer, saveToLocation);
}
/* API */
public String getMagic() { return magic; }
public int getVersion() {return version; }
public byte[] getUpperReserved() { return upperReserved; }
public int getFlags() { return flags; }
public boolean isTextCompressFlag(){ return (flags & 0b000001) == 1; }
public boolean isRoCompressFlag(){ return (flags & 0b000010) >> 1 == 1; }
public boolean isDataCompressFlag(){ return (flags & 0b000100 ) >> 2 == 1; }
public boolean isTextHashFlag(){ return (flags & 0b001000 ) >> 3 == 1; }
public boolean isRoHashFlag(){ return (flags & 0b010000 ) >> 4 == 1; }
public boolean isDataHashFlag(){ return (flags & 0b100000 ) >> 5 == 1; }
public SegmentHeader getTextSegmentHeader() { return textSegmentHeader; }
public int getModuleNameOffset() { return moduleNameOffset; }
public SegmentHeader getRodataSegmentHeader() { return rodataSegmentHeader; }
public int getModuleNameSize() { return moduleNameSize; }
public SegmentHeader getDataSegmentHeader() { return dataSegmentHeader; }
public int getBssSize() { return bssSize; }
public byte[] getModuleId() { return moduleId; }
public int getTextCompressedSize() { return textCompressedSize; }
public int getRodataCompressedSize() { return rodataCompressedSize; }
public int getDataCompressedSize() { return dataCompressedSize; }
public byte[] getBottomReserved() { return bottomReserved; }
public SegmentHeaderRelative get_api_infoRelative() { return _api_infoRelative; }
public SegmentHeaderRelative get_dynstrRelative() { return _dynstrRelative; }
public SegmentHeaderRelative get_dynsymRelative() { return _dynsymRelative; }
public byte[] getTextHash() { return textHash; }
public byte[] getRodataHash() { return rodataHash; }
public byte[] getDataHash() { return dataHash; }
public NSO0Raw getAsDecompressedNSO0() throws Exception{
return NSO0Unpacker.getNSO0Raw(header, producer);
}
/**
* Prints header.printDebug()
* */
public void printDebug(){
log.debug(".:: NSO0 Provider ::.\n" +
" ============================================================= \n" +
"Magic \"NSO0\" " + magic + "\n" +
"Version (always 0) " + version + "\n" +
"Reserved " + Converter.byteArrToHexString(upperReserved) + "\n" +
"Flags " + Converter.intToBinaryString(flags) + "\n" +
" |- 0. .text Compress " + isTextCompressFlag() + "\n" +
" |- 1. .rodata Compress " + isRoCompressFlag() + "\n" +
" |- 2. .data Compress " + isDataCompressFlag() + "\n" +
" |- 3. .text Hash " + isTextHashFlag() + "\n" +
" |- 4. .rodata Hash " + isRoHashFlag() + "\n" +
" |- 5. .data Hash " + isDataHashFlag() + "\n" +
" +++\n"+
"SegmentHeader for .text\n" +
" |- File Offset - - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSegmentOffset()) + "\n" +
" |- Memory Offset - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getMemoryOffset()) + "\n" +
" |- Size As Decompressed - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSizeAsDecompressed()) + "\n" +
"ModuleNameOffset (calculated by sizeof(header)) " + RainbowDump.formatDecHexString(moduleNameOffset) + "\n" +
" +++\n"+
"SegmentHeader for .rodata\n" +
" |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSegmentOffset()) + "\n" +
" |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getMemoryOffset()) + "\n" +
" |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSizeAsDecompressed()) + "\n" +
"ModuleNameSize " + RainbowDump.formatDecHexString(moduleNameSize) + "\n" +
" +++\n"+
"SegmentHeader for .data\n" +
" |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSegmentOffset()) + "\n" +
" |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getMemoryOffset()) + "\n" +
" |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSizeAsDecompressed()) + "\n" +
" .bss Size " + RainbowDump.formatDecHexString(bssSize) + "\n" + // Block Started by Symbol
"Module ID (aka Build ID) " + Converter.byteArrToHexString(moduleId) + "\n" +
" .text Size (compressed) " + RainbowDump.formatDecHexString(textCompressedSize) + "\n" +
" .rodata Size (compressed) " + RainbowDump.formatDecHexString(rodataCompressedSize) + "\n" +
" .data Size (compressed) " + RainbowDump.formatDecHexString(dataCompressedSize) + "\n" +
"Reserved " + Converter.byteArrToHexString(bottomReserved) + "\n" +
" xxx\n"+
"SegmentHeaderRelative for .api_info\n" +
" |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getOffset()) + "\n" +
" |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getSize()) + "\n" +
" xxx\n"+
"SegmentHeaderRelative for .dynstr\n" +
" |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getOffset()) + "\n" +
" |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getSize()) + "\n" +
" xxx\n"+
"SegmentHeaderRelative for .dynsym\n" +
" |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getOffset()) + "\n" +
" |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getSize()) + "\n" +
" xxx\n"+
".text decompressed' SHA-256 hash " + Converter.byteArrToHexString(textHash) + "\n" +
".rodata decompressed' SHA-256 hash " + Converter.byteArrToHexString(rodataHash) + "\n" +
".data decompressed' SHA-256 hash " + Converter.byteArrToHexString(dataHash) + "\n" +
" ============================================================= "
);
header.printDebug();
}
}

View file

@ -0,0 +1,47 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of libKonogonka.
libKonogonka is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
libKonogonka is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with libKonogonka. If not, see <https://www.gnu.org/licenses/>.
*/
package libKonogonka.Tools.NSO;
public class NSO0Raw {
private NSO0Header headerObject;
private final byte[] header;
private final byte[] _textDecompressedSection;
private final byte[] _rodataDecompressedSection;
private final byte[] _dataDecompressedSection;
NSO0Raw(byte[] header,
byte[] _textDecompressedSection,
byte[] _rodataDecompressedSection,
byte[] _dataDecompressedSection){
this.header = header;
this._textDecompressedSection = _textDecompressedSection;
this. _rodataDecompressedSection = _rodataDecompressedSection;
this._dataDecompressedSection = _dataDecompressedSection;
try {
this.headerObject = new NSO0Header(header);
}
catch (Exception e){ e.printStackTrace(); } //never happens
}
public NSO0Header getHeader() { return headerObject; }
public byte[] getHeaderRaw() {return header;}
public byte[] getTextRaw() {return _textDecompressedSection;}
public byte[] getRodataRaw() {return _rodataDecompressedSection;}
public byte[] getDataRaw() {return _dataDecompressedSection;}
}

View file

@ -29,15 +29,14 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class NSO0Unpacker {
class NSO0Unpacker {
private static final String DECOMPRESSED_FILE_NAME = "main_decompressed";
private final MessageDigest digest = MessageDigest.getInstance("SHA-256");
private NSO0Provider provider;
private InFileStreamProducer producer;
private final NSO0Header nso0Header;
private final InFileStreamProducer producer;
private byte[] _textDecompressedSection;
private byte[] _rodataDecompressedSection;
@ -47,19 +46,29 @@ public class NSO0Unpacker {
private int rodataFileOffsetNew;
private int dataFileOffsetNew;
private NSO0Unpacker() throws NoSuchAlgorithmException { }
private NSO0Unpacker(NSO0Header nso0Header, InFileStreamProducer producer) throws Exception {
this.nso0Header = nso0Header;
this.producer = producer;
public static void unpack(NSO0Provider provider, InFileStreamProducer producer, String saveToLocation) throws Exception{
if (! provider.isTextCompressFlag() && ! provider.isRoCompressFlag() && ! provider.isDataCompressFlag())
decompressSections();
validateHashes();
makeHeader();
}
static NSO0Raw getNSO0Raw(NSO0Header nso0Header, InFileStreamProducer producer) throws Exception{
NSO0Unpacker instance = new NSO0Unpacker(nso0Header, producer);
return new NSO0Raw(instance.header,
instance._textDecompressedSection,
instance._rodataDecompressedSection,
instance._dataDecompressedSection);
}
static void unpack(NSO0Header nso0Header, InFileStreamProducer producer, String saveToLocation) throws Exception{
if (! nso0Header.isTextCompressFlag() && ! nso0Header.isRoCompressFlag() && ! nso0Header.isDataCompressFlag())
throw new Exception("This file is not compressed");
NSO0Unpacker instance = new NSO0Unpacker(nso0Header, producer);
NSO0Unpacker instance = new NSO0Unpacker();
instance.provider = provider;
instance.producer = producer;
instance.decompressSections();
instance.validateHashes();
instance.makeHeader();
instance.writeFile(saveToLocation);
}
@ -69,22 +78,22 @@ public class NSO0Unpacker {
decompressDataSection();
}
private void decompressTextSection() throws Exception{
if (provider.isTextCompressFlag())
_textDecompressedSection = decompressSection(provider.getTextSegmentHeader(), provider.getTextCompressedSize());
if (nso0Header.isTextCompressFlag())
_textDecompressedSection = decompressSection(nso0Header.getTextSegmentHeader(), nso0Header.getTextCompressedSize());
else
_textDecompressedSection = duplicateSection(provider.getTextSegmentHeader());
_textDecompressedSection = duplicateSection(nso0Header.getTextSegmentHeader());
}
private void decompressRodataSection() throws Exception{
if (provider.isRoCompressFlag())
_rodataDecompressedSection = decompressSection(provider.getRodataSegmentHeader(), provider.getRodataCompressedSize());
if (nso0Header.isRoCompressFlag())
_rodataDecompressedSection = decompressSection(nso0Header.getRodataSegmentHeader(), nso0Header.getRodataCompressedSize());
else
_rodataDecompressedSection = duplicateSection(provider.getRodataSegmentHeader());
_rodataDecompressedSection = duplicateSection(nso0Header.getRodataSegmentHeader());
}
private void decompressDataSection() throws Exception{
if (provider.isDataCompressFlag())
_dataDecompressedSection = decompressSection(provider.getDataSegmentHeader(), provider.getDataCompressedSize());
if (nso0Header.isDataCompressFlag())
_dataDecompressedSection = decompressSection(nso0Header.getDataSegmentHeader(), nso0Header.getDataCompressedSize());
else
_dataDecompressedSection = duplicateSection(provider.getDataSegmentHeader());
_dataDecompressedSection = duplicateSection(nso0Header.getDataSegmentHeader());
}
private byte[] decompressSection(SegmentHeader segmentHeader, int compressedSectionSize) throws Exception{
@ -126,13 +135,13 @@ public class NSO0Unpacker {
}
private void validateHashes() throws Exception{
if ( ! Arrays.equals(provider.getTextHash(), digest.digest(_textDecompressedSection)) ) {
if ( ! Arrays.equals(nso0Header.getTextHash(), digest.digest(_textDecompressedSection)) ) {
throw new Exception(".text hash mismatch for .text section");
}
if ( ! Arrays.equals(provider.getRodataHash(), digest.digest(_rodataDecompressedSection)) ) {
if ( ! Arrays.equals(nso0Header.getRodataHash(), digest.digest(_rodataDecompressedSection)) ) {
throw new Exception(".rodata hash mismatch for .text section");
}
if ( ! Arrays.equals(provider.getDataHash(), digest.digest(_dataDecompressedSection)) ) {
if ( ! Arrays.equals(nso0Header.getDataHash(), digest.digest(_dataDecompressedSection)) ) {
throw new Exception(".data hash mismatch for .text section");
}
}
@ -163,41 +172,41 @@ public class NSO0Unpacker {
header = resultingHeader.array();
*/
textFileOffsetNew = provider.getTextSegmentHeader().getMemoryOffset()+0x100;
rodataFileOffsetNew = provider.getRodataSegmentHeader().getMemoryOffset()+0x100;
dataFileOffsetNew = provider.getDataSegmentHeader().getMemoryOffset()+0x100;
textFileOffsetNew = nso0Header.getTextSegmentHeader().getMemoryOffset()+0x100;
rodataFileOffsetNew = nso0Header.getRodataSegmentHeader().getMemoryOffset()+0x100;
dataFileOffsetNew = nso0Header.getDataSegmentHeader().getMemoryOffset()+0x100;
ByteBuffer resultingHeader = ByteBuffer.allocate(0x100).order(ByteOrder.LITTLE_ENDIAN);
resultingHeader.put("NSO0".getBytes(StandardCharsets.US_ASCII))
.putInt(provider.getVersion())
.put(provider.getUpperReserved())
.putInt(provider.getFlags() & 0b111000)
.putInt(nso0Header.getVersion())
.put(nso0Header.getUpperReserved())
.putInt(nso0Header.getFlags() & 0b111000)
.putInt(textFileOffsetNew)
.putInt(provider.getTextSegmentHeader().getMemoryOffset())
.putInt(provider.getTextSegmentHeader().getSizeAsDecompressed())
.putInt(nso0Header.getTextSegmentHeader().getMemoryOffset())
.putInt(nso0Header.getTextSegmentHeader().getSizeAsDecompressed())
.putInt(0x100)
.putInt(rodataFileOffsetNew)
.putInt(provider.getRodataSegmentHeader().getMemoryOffset())
.putInt(provider.getRodataSegmentHeader().getSizeAsDecompressed())
.putInt(nso0Header.getRodataSegmentHeader().getMemoryOffset())
.putInt(nso0Header.getRodataSegmentHeader().getSizeAsDecompressed())
.putInt(0)
.putInt(dataFileOffsetNew)
.putInt(provider.getDataSegmentHeader().getMemoryOffset())
.putInt(provider.getDataSegmentHeader().getSizeAsDecompressed())
.putInt(provider.getBssSize())
.put(provider.getModuleId())
.putInt(provider.getTextSegmentHeader().getSizeAsDecompressed())
.putInt(provider.getRodataSegmentHeader().getSizeAsDecompressed())
.putInt(provider.getDataSegmentHeader().getSizeAsDecompressed())
.put(provider.getBottomReserved())
.putInt(provider.get_api_infoRelative().getOffset())
.putInt(provider.get_api_infoRelative().getSize())
.putInt(provider.get_dynstrRelative().getOffset())
.putInt(provider.get_dynstrRelative().getSize())
.putInt(provider.get_dynsymRelative().getOffset())
.putInt(provider.get_dynsymRelative().getSize())
.put(provider.getTextHash())
.put(provider.getRodataHash())
.put(provider.getDataHash());
.putInt(nso0Header.getDataSegmentHeader().getMemoryOffset())
.putInt(nso0Header.getDataSegmentHeader().getSizeAsDecompressed())
.putInt(nso0Header.getBssSize())
.put(nso0Header.getModuleId())
.putInt(nso0Header.getTextSegmentHeader().getSizeAsDecompressed())
.putInt(nso0Header.getRodataSegmentHeader().getSizeAsDecompressed())
.putInt(nso0Header.getDataSegmentHeader().getSizeAsDecompressed())
.put(nso0Header.getBottomReserved())
.putInt(nso0Header.get_api_infoRelative().getOffset())
.putInt(nso0Header.get_api_infoRelative().getSize())
.putInt(nso0Header.get_dynstrRelative().getOffset())
.putInt(nso0Header.get_dynstrRelative().getSize())
.putInt(nso0Header.get_dynsymRelative().getOffset())
.putInt(nso0Header.get_dynsymRelative().getSize())
.put(nso0Header.getTextHash())
.put(nso0Header.getRodataHash())
.put(nso0Header.getDataHash());
header = resultingHeader.array();
}

View file

@ -184,7 +184,7 @@ public class FileSystemEntry {
nextHashTableBucketFileOffset = Converter.getLEint(filesMetadataTable, i);
/*
if (nextHashTableBucketFileOffset < 0) {
System.out.println("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
log.debug("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
}
//*/
i += 4;

View file

@ -19,6 +19,8 @@
package libKonogonka.Tools.XCI;
import libKonogonka.Tools.ISuperProvider;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.nio.charset.StandardCharsets;
@ -31,6 +33,8 @@ import static libKonogonka.Converter.*;
* HFS0
* */
public class HFS0Provider implements ISuperProvider {
private final static Logger log = LogManager.getLogger(HFS0Provider.class);
private final String magic;
private final int filesCount;
private final byte[] padding;
@ -136,7 +140,7 @@ public class HFS0Provider implements ISuperProvider {
PipedInputStream streamIn = new PipedInputStream(streamOut);
workerThread = new Thread(() -> {
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Executing thread");
log.trace("HFS0Provider -> getHfs0FilePipedInpStream(): Executing thread");
try{
long subFileRealPosition = rawFileDataStart + hfs0Files[subFileNumber].getOffset();
BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
@ -164,10 +168,10 @@ public class HFS0Provider implements ISuperProvider {
streamOut.close();
}
catch (Exception ioe){
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to provide stream");
log.error("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to provide stream");
ioe.printStackTrace();
}
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Thread died");
log.trace("HFS0Provider -> getHfs0FilePipedInpStream(): Thread died");
});
workerThread.start();
return streamIn;

View file

@ -18,20 +18,26 @@
*/
package libKonogonka.Tools.XCI;
import libKonogonka.Converter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Arrays;
/**
* Gamecard Cert
* */
public class XCIGamecardCert {
private byte[] rsa2048PKCS1sig;
private byte[] magicCert;
private byte[] unknown1;
private byte kekIndex;
private byte[] unknown2;
private byte[] deviceID;
private byte[] unknown3;
private byte[] encryptedData;
private final static Logger log = LogManager.getLogger(XCIGamecardCert.class);
private final byte[] rsa2048PKCS1sig;
private final byte[] magicCert;
private final byte[] unknown1;
private final byte kekIndex;
private final byte[] unknown2;
private final byte[] deviceID;
private final byte[] unknown3;
private final byte[] encryptedData;
XCIGamecardCert(byte[] certBytes) throws Exception{
if (certBytes.length != 512)
@ -44,16 +50,6 @@ public class XCIGamecardCert {
deviceID = Arrays.copyOfRange(certBytes, 272, 288);
unknown3 = Arrays.copyOfRange(certBytes, 288, 298);
encryptedData = Arrays.copyOfRange(certBytes, 298, 512);
/*
RainbowHexDump.hexDumpUTF8(rsa2048PKCS1sig);
RainbowHexDump.hexDumpUTF8(magicCert);
RainbowHexDump.hexDumpUTF8(unknown1);
System.out.println(kekIndex);
RainbowHexDump.hexDumpUTF8(unknown2);
RainbowHexDump.hexDumpUTF8(deviceID);
RainbowHexDump.hexDumpUTF8(unknown3);
RainbowHexDump.hexDumpUTF8(encryptedData);
*/
}
public byte[] getRsa2048PKCS1sig() { return rsa2048PKCS1sig; }
public byte[] getMagicCert() { return magicCert; }
@ -64,4 +60,17 @@ public class XCIGamecardCert {
public byte[] getDeviceID() { return deviceID; }
public byte[] getUnknown3() { return unknown3; }
public byte[] getEncryptedData() { return encryptedData; }
public void printDebug(){
log.debug("== XCIGamecardCert ==\n" +
"rsa2048PKCS1sig " + Converter.byteArrToHexString(rsa2048PKCS1sig) + "\n" +
"magicCert " + Converter.byteArrToHexString(magicCert) + "\n" +
"unknown1 " + Converter.byteArrToHexString(unknown1) + "\n" +
"kekIndex " + kekIndex + "\n" +
"unknown2 " + Converter.byteArrToHexString(unknown2) + "\n" +
"deviceID " + Converter.byteArrToHexString(deviceID) + "\n" +
"unknown3 " + Converter.byteArrToHexString(unknown3) + "\n" +
"encryptedData " + Converter.byteArrToHexString(encryptedData) + "\n"
);
}
}

View file

@ -30,6 +30,7 @@ import static libKonogonka.Converter.getLElong;
* Gamecard Info
* */
public class XCIGamecardInfo{
//private final static Logger log = LogManager.getLogger(XCIGamecardInfo.class);
private long fwVersion;
private byte[] accessCtrlFlags; // 0x00A10011 for 25MHz access or 0x00A10010 for 50MHz access
@ -73,12 +74,12 @@ public class XCIGamecardInfo{
cupID = Arrays.copyOfRange(decrypted, 48, 56);
emptyPadding2 = Arrays.copyOfRange(decrypted, 56, 112);
/*
System.out.println(fwVersion);
log.debug(fwVersion);
RainbowHexDump.hexDumpUTF8(accessCtrlFlags);
System.out.println(readWaitTime1);
System.out.println(readWaitTime2);
System.out.println(writeWaitTime1);
System.out.println(writeWaitTime2);
log.debug(readWaitTime1);
log.debug(readWaitTime2);
log.debug(writeWaitTime1);
log.debug(writeWaitTime2);
RainbowHexDump.hexDumpUTF8(fwMode);
RainbowHexDump.hexDumpUTF8(cupVersion);
RainbowHexDump.hexDumpUTF8(emptyPadding1);

View file

@ -88,7 +88,7 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
//1
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesFromFirstBlock);
//2
System.out.println("\n"+bytesFromFirstBlock+"\n"+ middleBlocksCount+" = "+(middleBlocksCount*0x200)+" bytes\n"+ bytesFromEnd+"\n");
//log.debug("\n"+bytesFromFirstBlock+"\n"+ middleBlocksCount+" = "+(middleBlocksCount*0x200)+" bytes\n"+ bytesFromEnd+"\n");
for (int i = 0; i < middleBlocksCount; i++) {
fillDecryptedCache();
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+i*0x200, 0x200);

View file

@ -30,7 +30,6 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.nio.file.Files;
public class NSOTest {
private static final String keysFileLocation = "./FilesForTests/prod.keys";
@ -116,6 +115,7 @@ public class NSOTest {
NSO0Provider nso0Provider = new NSO0Provider(pfs0Provider.getStreamProducer(0));
nso0Provider.printDebug();
nso0Provider.exportAsDecompressedNSO0("./tmp");
// NPDMProvider npdmProvider = new NPDMProvider(pfs0Provider.getProviderSubFilePipedInpStream(1));