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
All checks were successful
continuous-integration/drone/push Build is passing
Clean 'System.out.print*'
This commit is contained in:
parent
91ab6fd74b
commit
53af386738
15 changed files with 462 additions and 284 deletions
12
README.md
12
README.md
|
@ -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
|
||||
|
@ -30,4 +30,8 @@ JRE/JDK 8u60 or higher.
|
|||
|
||||
### Build
|
||||
|
||||
See .drone.yml
|
||||
See .drone.yml
|
||||
|
||||
### Install on local host (local maven repo)
|
||||
|
||||
`# mvn instal`
|
|
@ -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
13
pom.xml
|
@ -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>
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
174
src/main/java/libKonogonka/Tools/NSO/NSO0Header.java
Normal file
174
src/main/java/libKonogonka/Tools/NSO/NSO0Header.java
Normal 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" +
|
||||
" ============================================================= "
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
47
src/main/java/libKonogonka/Tools/NSO/NSO0Raw.java
Normal file
47
src/main/java/libKonogonka/Tools/NSO/NSO0Raw.java
Normal 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;}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in a new issue