mirror of
https://github.com/Maschell/JWUDTool.git
synced 2024-11-16 21:19:19 +01:00
- Update to use the latest JNUSLIB version.
- Use jitpack.io instead of having a .jar - Building now via maven - Added support to handle kiosk disc. - Support for handling multiple GM partition, and support for the GM partition. - Added an option to decompress a .wux back to .wud - Fix serveral bugs
This commit is contained in:
parent
053eaac3bf
commit
0529ab5c5d
12
README.md
12
README.md
@ -1,4 +1,4 @@
|
|||||||
# JWUDTool 0.1
|
# JWUDTool 0.2
|
||||||
|
|
||||||
Here is just a simple program that uses the (http://gbatemp.net/threads/jnuslib-java-nus-library.452954/).
|
Here is just a simple program that uses the (http://gbatemp.net/threads/jnuslib-java-nus-library.452954/).
|
||||||
The usage should be pretty self explaining.
|
The usage should be pretty self explaining.
|
||||||
@ -8,8 +8,10 @@ The usage should be pretty self explaining.
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Compressing .wud and splitted wud files into .wux
|
* Compressing .wud and splitted wud files into .wux
|
||||||
|
* Decompressing a .wux back to .wud
|
||||||
|
* Extracting from the GI or GM partition
|
||||||
* Extracting .app/-h3/.tmd/.cert/.tik files from a .wud/.wux or splitted .wud
|
* Extracting .app/-h3/.tmd/.cert/.tik files from a .wud/.wux or splitted .wud
|
||||||
* Exctracting just the contents/hashes/ticket.
|
* Extracting just the contents/hashes/ticket.
|
||||||
* Decrypting the full game partition from a .wud/.wux or splitted .wud
|
* Decrypting the full game partition from a .wud/.wux or splitted .wud
|
||||||
* Decrypting specific files the game partition from a .wud/.wux or splitted .wud
|
* Decrypting specific files the game partition from a .wud/.wux or splitted .wud
|
||||||
* Verify a image / Compare two images (for example a .wud with .wux to make sure its legit)
|
* Verify a image / Compare two images (for example a .wud with .wux to make sure its legit)
|
||||||
@ -24,7 +26,9 @@ Optional:
|
|||||||
usage:
|
usage:
|
||||||
-commonkey <WiiU common key> Optional. HexString. Will be used if no "common.key" in the
|
-commonkey <WiiU common key> Optional. HexString. Will be used if no "common.key" in the
|
||||||
folder of this .jar is found
|
folder of this .jar is found
|
||||||
|
-dev Required when using discs without a titlekey.
|
||||||
-compress Compresses the input to a .wux file.
|
-compress Compresses the input to a .wux file.
|
||||||
|
-decompress Decompresses the input to a .wud file.
|
||||||
-decrypt Decrypts full the game partition of the given wud.
|
-decrypt Decrypts full the game partition of the given wud.
|
||||||
-decryptFile <regular expression> Decrypts files of the game partition that match the regular
|
-decryptFile <regular expression> Decrypts files of the game partition that match the regular
|
||||||
expression of the given wud.
|
expression of the given wud.
|
||||||
@ -32,7 +36,7 @@ usage:
|
|||||||
(Arguments optional)
|
(Arguments optional)
|
||||||
-help shows this text
|
-help shows this text
|
||||||
-in <input file> Input file. Can be a .wux, .wud or a game_part1.wud
|
-in <input file> Input file. Can be a .wux, .wud or a game_part1.wud
|
||||||
-noVerify Disables verification after compressing
|
-noVerify Disables verification after (de)compressing
|
||||||
-out <output path> The path where the result will be saved
|
-out <output path> The path where the result will be saved
|
||||||
-overwrite Optional. Overwrites existing files
|
-overwrite Optional. Overwrites existing files
|
||||||
-titlekey <WUD title key> Optional. HexString. Will be used if no "game.key" in the
|
-titlekey <WUD title key> Optional. HexString. Will be used if no "game.key" in the
|
||||||
@ -108,7 +112,7 @@ java -jar JWUDTool.jar -in "game_part1.wud" -decryptFile /content/Sound/.*
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
Add the "jnuslib.jar" into the library path and load the other dependicies through maven.
|
`clean assembly:single package`
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
Maschell
|
Maschell
|
||||||
|
BIN
libs/jnuslib.jar
BIN
libs/jnuslib.jar
Binary file not shown.
88
pom.xml
88
pom.xml
@ -1,27 +1,71 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
<modelVersion>4.0.0</modelVersion>
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<groupId>de.mas</groupId>
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<artifactId>jwudtool</artifactId>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<groupId>de.mas</groupId>
|
||||||
|
<artifactId>jwudtool</artifactId>
|
||||||
|
<version>0.2</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<build>
|
||||||
<dependency>
|
<plugins>
|
||||||
<groupId>org.projectlombok</groupId>
|
<plugin>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
<version>1.16.12</version>
|
<version>3.1.0</version>
|
||||||
<scope>provided</scope>
|
<configuration>
|
||||||
</dependency>
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>de.mas.jwudtool.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id> <!-- this is used for inheritance merges -->
|
||||||
|
<phase>package</phase> <!-- bind to the packaging phase -->
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id> <!-- JitPack allows github repo to be used as a maven repo -->
|
||||||
|
<url>https://jitpack.io</url> <!-- For documentation: http://jitpack.io/ -->
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<dependency>
|
<dependencies>
|
||||||
<groupId>commons-cli</groupId>
|
<dependency>
|
||||||
<artifactId>commons-cli</artifactId>
|
<groupId>com.github.Maschell</groupId>
|
||||||
<version>1.3.1</version>
|
<artifactId>JNUSLib</artifactId>
|
||||||
</dependency>
|
<version>8016b3e</version>
|
||||||
</dependencies>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.4</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-cli</groupId>
|
||||||
|
<artifactId>commons-cli</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -3,6 +3,7 @@ package de.mas.jwudtool;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
@ -13,19 +14,34 @@ import org.apache.commons.cli.Option;
|
|||||||
import org.apache.commons.cli.Options;
|
import org.apache.commons.cli.Options;
|
||||||
import org.apache.commons.cli.UnrecognizedOptionException;
|
import org.apache.commons.cli.UnrecognizedOptionException;
|
||||||
|
|
||||||
import de.mas.jnus.lib.DecryptionService;
|
import de.mas.wiiu.jnus.DecryptionService;
|
||||||
import de.mas.jnus.lib.ExtractionService;
|
import de.mas.wiiu.jnus.ExtractionService;
|
||||||
import de.mas.jnus.lib.NUSTitle;
|
import de.mas.wiiu.jnus.NUSTitle;
|
||||||
import de.mas.jnus.lib.NUSTitleLoaderWUD;
|
import de.mas.wiiu.jnus.NUSTitleLoaderWUD;
|
||||||
import de.mas.jnus.lib.Settings;
|
import de.mas.wiiu.jnus.Settings;
|
||||||
import de.mas.jnus.lib.WUDService;
|
import de.mas.wiiu.jnus.WUDService;
|
||||||
import de.mas.jnus.lib.implementations.wud.WUDImage;
|
import de.mas.wiiu.jnus.implementations.wud.WUDImage;
|
||||||
import de.mas.jnus.lib.utils.Utils;
|
import de.mas.wiiu.jnus.utils.Utils;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
private final static String OPTION_IN = "in";
|
||||||
|
private final static String OPTION_HELP = "help";
|
||||||
|
private static final String OPTION_OUT = "out";
|
||||||
|
private static final String OPTION_DECOMPRESS = "decompress";
|
||||||
|
private static final String OPTION_COMPRESS = "compress";
|
||||||
|
private static final String OPTION_COMMON_KEY = "commonkey";
|
||||||
|
private static final String OPTION_NO_VERIFY = "noVerify";
|
||||||
|
private static final String OPTION_VERIFY = "verify";
|
||||||
|
private static final String OPTION_OVERWRITE = "overwrite";
|
||||||
|
private static final String OPTION_DECRYPT = "decrypt";
|
||||||
|
private static final String OPTION_TITLEKEY = "titleKey";
|
||||||
|
private static final String OPTION_DECRYPT_FILE = "decryptFile";
|
||||||
|
private static final String OPTION_EXTRACT = "extract";
|
||||||
|
private static final String OPTION_DEVMODE = "dev";
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
System.out.println("JWUDTool 0.1b - Maschell");
|
System.out.println("JWUDTool 0.2 - Maschell");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
Options options = getOptions();
|
Options options = getOptions();
|
||||||
|
|
||||||
@ -36,12 +52,12 @@ public class Main {
|
|||||||
|
|
||||||
CommandLineParser parser = new DefaultParser();
|
CommandLineParser parser = new DefaultParser();
|
||||||
CommandLine cmd = null;
|
CommandLine cmd = null;
|
||||||
try{
|
try {
|
||||||
cmd = parser.parse(options, args);
|
cmd = parser.parse(options, args);
|
||||||
}catch(MissingArgumentException e){
|
} catch (MissingArgumentException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
return ;
|
return;
|
||||||
}catch(UnrecognizedOptionException e){
|
} catch (UnrecognizedOptionException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
showHelp(options);
|
showHelp(options);
|
||||||
return;
|
return;
|
||||||
@ -50,94 +66,107 @@ public class Main {
|
|||||||
String input = null;
|
String input = null;
|
||||||
String output = null;
|
String output = null;
|
||||||
boolean overwrite = false;
|
boolean overwrite = false;
|
||||||
|
boolean devMode = false;
|
||||||
byte[] titlekey = null;
|
byte[] titlekey = null;
|
||||||
|
|
||||||
readKey();
|
readKey();
|
||||||
|
|
||||||
if(cmd.hasOption("help")){
|
if (cmd.hasOption(OPTION_HELP)) {
|
||||||
showHelp(options);
|
showHelp(options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd.hasOption("in")){
|
if (cmd.hasOption(OPTION_IN)) {
|
||||||
input = cmd.getOptionValue("in");
|
input = cmd.getOptionValue(OPTION_IN);
|
||||||
}
|
}
|
||||||
if(cmd.hasOption("out")){
|
if (cmd.hasOption(OPTION_OUT)) {
|
||||||
output = cmd.getOptionValue("out");
|
output = cmd.getOptionValue(OPTION_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd.hasOption("commonkey")){
|
if (cmd.hasOption(OPTION_COMMON_KEY)) {
|
||||||
String commonKey = cmd.getOptionValue("commonkey");
|
String commonKey = cmd.getOptionValue(OPTION_COMMON_KEY);
|
||||||
byte[] key = Utils.StringToByteArray(commonKey);
|
byte[] key = Utils.StringToByteArray(commonKey);
|
||||||
if(key.length == 0x10){
|
if (key.length == 0x10) {
|
||||||
Settings.commonKey = key;
|
Settings.commonKey = key;
|
||||||
System.out.println("Commonkey was set to: " + Utils.ByteArrayToString(key));
|
System.out.println("Commonkey was set to: " + Utils.ByteArrayToString(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd.hasOption("titlekey")){
|
if (cmd.hasOption(OPTION_TITLEKEY)) {
|
||||||
String titlekey_string = cmd.getOptionValue("titlekey");
|
String titlekey_string = cmd.getOptionValue(OPTION_TITLEKEY);
|
||||||
titlekey = Utils.StringToByteArray(titlekey_string);
|
titlekey = Utils.StringToByteArray(titlekey_string);
|
||||||
if(titlekey.length != 0x10){
|
if (titlekey.length != 0x10) {
|
||||||
titlekey = null;
|
titlekey = null;
|
||||||
}else{
|
} else {
|
||||||
System.out.println("Titlekey was set to: " + Utils.ByteArrayToString(titlekey));
|
System.out.println("Titlekey was set to: " + Utils.ByteArrayToString(titlekey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd.hasOption("overwrite")){
|
if (cmd.hasOption(OPTION_OVERWRITE)) {
|
||||||
overwrite = true;
|
overwrite = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd.hasOption("compress")){
|
if (cmd.hasOption(OPTION_DEVMODE)) {
|
||||||
|
devMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.hasOption(OPTION_COMPRESS)) {
|
||||||
boolean verify = true;
|
boolean verify = true;
|
||||||
System.out.println("Compressing: " + input);
|
System.out.println("Compressing: " + input);
|
||||||
if(cmd.hasOption("noVerify")){
|
if (cmd.hasOption(OPTION_NO_VERIFY)) {
|
||||||
System.out.println("Verification disabled.");
|
System.out.println("Verification disabled.");
|
||||||
verify = false;
|
verify = false;
|
||||||
}
|
}
|
||||||
compressWUD(input,output,verify,overwrite);
|
compressDecompressWUD(input, output, verify, overwrite, false);
|
||||||
return;
|
return;
|
||||||
}else if(cmd.hasOption("verify")){
|
} else if (cmd.hasOption(OPTION_DECOMPRESS)) {
|
||||||
|
boolean verify = true;
|
||||||
|
System.out.println("Decompressing: " + input);
|
||||||
|
if (cmd.hasOption(OPTION_NO_VERIFY)) {
|
||||||
|
System.out.println("Verification disabled.");
|
||||||
|
verify = false;
|
||||||
|
}
|
||||||
|
compressDecompressWUD(input, output, verify, overwrite, true);
|
||||||
|
return;
|
||||||
|
} else if (cmd.hasOption(OPTION_VERIFY)) {
|
||||||
System.out.println("Comparing images.");
|
System.out.println("Comparing images.");
|
||||||
String[] verifyArgs = cmd.getOptionValues("verify");
|
String[] verifyArgs = cmd.getOptionValues(OPTION_VERIFY);
|
||||||
|
|
||||||
File input1 = new File(verifyArgs[0]);
|
File input1 = new File(verifyArgs[0]);
|
||||||
File input2 = new File(verifyArgs[1]);
|
File input2 = new File(verifyArgs[1]);
|
||||||
|
|
||||||
verifyImages(input1,input2);
|
verifyImages(input1, input2);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}else{
|
} else {
|
||||||
if(cmd.hasOption("decrypt")){
|
if (cmd.hasOption(OPTION_DECRYPT)) {
|
||||||
System.out.println("Decrypting full game partition.");
|
System.out.println("Decrypting full game partition.");
|
||||||
|
|
||||||
decrypt(input,output,overwrite,titlekey);
|
decrypt(input, output, devMode, overwrite, titlekey);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}else if(cmd.hasOption("decryptFile")){
|
} else if (cmd.hasOption(OPTION_DECRYPT_FILE)) {
|
||||||
String regex = cmd.getOptionValue("decryptFile");
|
String regex = cmd.getOptionValue(OPTION_DECRYPT_FILE);
|
||||||
System.out.println("Decrypting files matching \"" +regex + "\"");
|
System.out.println("Decrypting files matching \"" + regex + "\"");
|
||||||
|
|
||||||
decryptFile(input,output,regex,overwrite,titlekey);
|
decryptFile(input, output, regex, devMode, overwrite, titlekey);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}else if(cmd.hasOption("extract")){
|
} else if (cmd.hasOption(OPTION_EXTRACT)) {
|
||||||
System.out.println("Extracting WUD");
|
System.out.println("Extracting WUD");
|
||||||
String arg = cmd.getOptionValue("extract");
|
String arg = cmd.getOptionValue(OPTION_EXTRACT);
|
||||||
if(arg == null){
|
if (arg == null) {
|
||||||
arg = "all";
|
arg = "all";
|
||||||
}
|
}
|
||||||
extract(input,output,overwrite,titlekey,arg);
|
extract(input, output, devMode, overwrite, titlekey, arg);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void extract(String input, String output, boolean devMode, boolean overwrite, byte[] titlekey, String arg) throws Exception {
|
||||||
private static void extract(String input, String output, boolean overwrite, byte[] titlekey, String arg) throws Exception {
|
if (input == null) {
|
||||||
if(input == null){
|
|
||||||
System.out.println("You need to provide an input file");
|
System.out.println("You need to provide an input file");
|
||||||
}
|
}
|
||||||
boolean extractAll = false;
|
boolean extractAll = false;
|
||||||
@ -145,164 +174,192 @@ public class Main {
|
|||||||
boolean extractTicket = false;
|
boolean extractTicket = false;
|
||||||
boolean extractHashes = false;
|
boolean extractHashes = false;
|
||||||
|
|
||||||
switch(arg){
|
switch (arg) {
|
||||||
case "all":
|
case "all":
|
||||||
extractAll = true;
|
extractAll = true;
|
||||||
break;
|
break;
|
||||||
case "content":
|
case "content":
|
||||||
extractContent = true;
|
extractContent = true;
|
||||||
break;
|
break;
|
||||||
case "ticket":
|
case "ticket":
|
||||||
extractTicket = true;
|
extractTicket = true;
|
||||||
break;
|
break;
|
||||||
case "hashes":
|
case "hashes":
|
||||||
extractHashes = true;
|
extractHashes = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.out.println("Argument not found:" + arg);
|
System.out.println("Argument not found:" + arg);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
File inputFile = new File(input);
|
File inputFile = new File(input);
|
||||||
|
|
||||||
System.out.println("Extracting: " + inputFile.getAbsolutePath());
|
System.out.println("Extracting: " + inputFile.getAbsolutePath());
|
||||||
|
|
||||||
NUSTitle title = NUSTitleLoaderWUD.loadNUSTitle(inputFile.getAbsolutePath(),titlekey);
|
List<NUSTitle> titles = null;
|
||||||
if(title == null){
|
if (!devMode) {
|
||||||
|
titles = NUSTitleLoaderWUD.loadNUSTitle(inputFile.getAbsolutePath(), titlekey);
|
||||||
|
} else {
|
||||||
|
titles = NUSTitleLoaderWUD.loadNUSTitleDev(inputFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
if (titles == null || titles.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
System.out.println("Found " + titles.size() + " titles on the Disc.");
|
||||||
|
for (val title : titles) {
|
||||||
|
String newOutput = output;
|
||||||
|
System.out.println("Extract files of Title " + String.format("%016X", title.getTMD().getTitleID()));
|
||||||
|
if (newOutput == null) {
|
||||||
|
newOutput = String.format("%016X", title.getTMD().getTitleID());
|
||||||
|
} else {
|
||||||
|
newOutput += File.separator + String.format("%016X", title.getTMD().getTitleID());
|
||||||
|
}
|
||||||
|
|
||||||
if(output == null){
|
File outputFolder = new File(newOutput);
|
||||||
output = String.format("%016X", title.getTMD().getTitleID());
|
System.out.println("To the folder: " + outputFolder.getAbsolutePath());
|
||||||
}else{
|
|
||||||
output += File.separator + String.format("%016X", title.getTMD().getTitleID());
|
ExtractionService extractionService = ExtractionService.getInstance(title);
|
||||||
|
if (extractAll) {
|
||||||
|
extractionService.extractAll(outputFolder.getAbsolutePath());
|
||||||
|
} else if (extractTicket) {
|
||||||
|
extractionService.extractTicketTo(outputFolder.getAbsolutePath());
|
||||||
|
} else if (extractContent) {
|
||||||
|
extractionService.extractAllEncryptedContentFilesWithoutHashesTo(outputFolder.getAbsolutePath());
|
||||||
|
} else if (extractHashes) {
|
||||||
|
extractionService.extractAllEncrpytedContentFileHashes(outputFolder.getAbsolutePath());
|
||||||
|
}
|
||||||
|
System.out.println("Extraction done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
File outputFolder = new File(output);
|
|
||||||
System.out.println("To the folder: " + outputFolder.getAbsolutePath());
|
|
||||||
|
|
||||||
ExtractionService extractionService = ExtractionService.getInstance(title);
|
|
||||||
if(extractAll){
|
|
||||||
extractionService.extractAll(outputFolder.getAbsolutePath());
|
|
||||||
}else if(extractTicket){
|
|
||||||
extractionService.extractTicketTo(outputFolder.getAbsolutePath());
|
|
||||||
}else if(extractContent){
|
|
||||||
extractionService.extractAllEncryptedContentFilesWithoutHashesTo(outputFolder.getAbsolutePath());
|
|
||||||
}else if(extractHashes){
|
|
||||||
extractionService.extractAllEncrpytedContentFileHashes(outputFolder.getAbsolutePath());
|
|
||||||
}
|
|
||||||
System.out.println("Extraction done!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void decryptFile(String input, String output, String regex, boolean devMode, boolean overwrite, byte[] titlekey) throws Exception {
|
||||||
private static void decryptFile(String input, String output, String regex, boolean overwrite, byte[] titlekey) throws Exception {
|
if (input == null) {
|
||||||
if(input == null){
|
|
||||||
System.out.println("You need to provide an input file");
|
System.out.println("You need to provide an input file");
|
||||||
}
|
}
|
||||||
File inputFile = new File(input);
|
File inputFile = new File(input);
|
||||||
|
|
||||||
System.out.println("Decrypting: " + inputFile.getAbsolutePath());
|
System.out.println("Decrypting: " + inputFile.getAbsolutePath());
|
||||||
|
|
||||||
NUSTitle title = NUSTitleLoaderWUD.loadNUSTitle(inputFile.getAbsolutePath(),titlekey);
|
List<NUSTitle> titles = null;
|
||||||
if(title == null){
|
if (!devMode) {
|
||||||
|
titles = NUSTitleLoaderWUD.loadNUSTitle(inputFile.getAbsolutePath(), titlekey);
|
||||||
|
} else {
|
||||||
|
titles = NUSTitleLoaderWUD.loadNUSTitleDev(inputFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (titles == null || titles.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
System.out.println("Found " + titles.size() + " titles on the Disc.");
|
||||||
|
|
||||||
|
for (val title : titles) {
|
||||||
|
String newOutput = output;
|
||||||
|
System.out.println("Decrypting files in Title " + String.format("%016X", title.getTMD().getTitleID()));
|
||||||
|
if (newOutput == null) {
|
||||||
|
newOutput = String.format("%016X", title.getTMD().getTitleID());
|
||||||
|
} else {
|
||||||
|
newOutput += File.separator + String.format("%016X", title.getTMD().getTitleID());
|
||||||
|
}
|
||||||
|
|
||||||
if(output == null){
|
File outputFolder = new File(newOutput);
|
||||||
output = String.format("%016X", title.getTMD().getTitleID());
|
|
||||||
}else{
|
System.out.println("To the folder: " + outputFolder.getAbsolutePath());
|
||||||
output += File.separator + String.format("%016X", title.getTMD().getTitleID());
|
title.setSkipExistingFiles(!overwrite);
|
||||||
|
DecryptionService decryption = DecryptionService.getInstance(title);
|
||||||
|
|
||||||
|
decryption.decryptFSTEntriesTo(regex, outputFolder.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
File outputFolder = new File(output);
|
|
||||||
|
|
||||||
System.out.println("To the folder: " + outputFolder.getAbsolutePath());
|
|
||||||
title.setSkipExistingFiles(!overwrite);
|
|
||||||
DecryptionService decryption = DecryptionService.getInstance(title);
|
|
||||||
|
|
||||||
|
|
||||||
decryption.decryptFSTEntriesTo(regex,outputFolder.getAbsolutePath());
|
|
||||||
System.out.println("Decryption done");
|
System.out.println("Decryption done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void decrypt(String input, String output, boolean devMode, boolean overwrite, byte[] titlekey) throws Exception {
|
||||||
private static void decrypt(String input,String output, boolean overwrite,byte[] titlekey) throws Exception {
|
decryptFile(input, output, ".*", devMode, overwrite, titlekey);
|
||||||
decryptFile(input,output,".*",overwrite,titlekey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void verifyImages(File input1, File input2) throws IOException {
|
private static void verifyImages(File input1, File input2) throws IOException {
|
||||||
System.out.println("Input 1: " +input1.getAbsolutePath());
|
System.out.println("Input 1: " + input1.getAbsolutePath());
|
||||||
WUDImage image1 = new WUDImage(input1);
|
WUDImage image1 = new WUDImage(input1);
|
||||||
|
|
||||||
System.out.println("Input 2: " +input2.getAbsolutePath());
|
System.out.println("Input 2: " + input2.getAbsolutePath());
|
||||||
WUDImage image2 = new WUDImage(input2);
|
WUDImage image2 = new WUDImage(input2);
|
||||||
if(WUDService.compareWUDImage(image1, image2)){
|
if (WUDService.compareWUDImage(image1, image2)) {
|
||||||
System.out.println("Both images have the same data");
|
System.out.println("Both images have the same data");
|
||||||
}else{
|
} else {
|
||||||
System.out.println("The images are different!");
|
System.out.println("The images are different!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void compressDecompressWUD(String input, String output, boolean verify, boolean overwrite, boolean decompress) throws IOException {
|
||||||
private static void compressWUD(String input,String output, boolean verify, boolean overwrite) throws IOException {
|
if (input == null) {
|
||||||
if(input == null){
|
System.out.println("-" + OPTION_IN + " was null");
|
||||||
System.out.println("-in null");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File inputImage = new File(input);
|
File inputImage = new File(input);
|
||||||
if(inputImage.isDirectory() || !inputImage.exists()){
|
if (inputImage.isDirectory() || !inputImage.exists()) {
|
||||||
System.out.println(inputImage.getAbsolutePath() + " is no file or does not exist");
|
System.out.println(inputImage.getAbsolutePath() + " is no file or does not exist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
System.out.println("Parsing WUD image.");
|
System.out.println("Parsing WUD image.");
|
||||||
WUDImage image = new WUDImage(inputImage);
|
WUDImage image = new WUDImage(inputImage);
|
||||||
File compressedImage = WUDService.compressWUDToWUX(image, output,overwrite);
|
File outputFile = null;
|
||||||
if(compressedImage != null){
|
if (!decompress) {
|
||||||
System.out.println("Compression successful!");
|
outputFile = WUDService.compressWUDToWUX(image, output, overwrite);
|
||||||
|
if (outputFile != null) {
|
||||||
|
System.out.println("Compression successful!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outputFile = WUDService.decompressWUX(image, output, overwrite);
|
||||||
|
if (outputFile != null) {
|
||||||
|
System.out.println("Decompression successful!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(verify){
|
|
||||||
if(compressedImage != null){
|
if (verify) {
|
||||||
WUDImage image2 = new WUDImage(compressedImage);
|
if (outputFile != null) {
|
||||||
if(WUDService.compareWUDImage(image, image2)){
|
WUDImage image2 = new WUDImage(outputFile);
|
||||||
|
if (WUDService.compareWUDImage(image, image2)) {
|
||||||
System.out.println("Compressed files is valid.");
|
System.out.println("Compressed files is valid.");
|
||||||
}else{
|
} else {
|
||||||
System.out.println("Warning! Compressed file in INVALID!");
|
System.out.println("Warning! (De)Compressed file is INVALID!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
System.out.println("Verfication skipped");
|
System.out.println("Verfication skipped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void readKey() throws IOException {
|
private static void readKey() throws IOException {
|
||||||
File file = new File("common.key");
|
File file = new File("common.key");
|
||||||
if(file.isFile()){
|
if (file.isFile()) {
|
||||||
byte[] key = Files.readAllBytes(file.toPath());
|
byte[] key = Files.readAllBytes(file.toPath());
|
||||||
Settings.commonKey = key;
|
Settings.commonKey = key;
|
||||||
System.out.println("Commonkey was set to: " + Utils.ByteArrayToString(key));
|
System.out.println("Commonkey was set to: " + Utils.ByteArrayToString(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Options getOptions() {
|
||||||
private static Options getOptions() { // TODO: schöner machen?
|
|
||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
options.addOption(Option.builder("in").argName("input file").hasArg().desc("Input file. Can be a .wux, .wud or a game_part1.wud").build());
|
options.addOption(Option.builder(OPTION_IN).argName("input file").hasArg().desc("Input file. Can be a .wux, .wud or a game_part1.wud").build());
|
||||||
options.addOption(Option.builder("out").argName("output path").hasArg().desc("The path where the result will be saved").build());
|
options.addOption(Option.builder(OPTION_OUT).argName("output path").hasArg().desc("The path where the result will be saved").build());
|
||||||
options.addOption(Option.builder("compress").desc("Compresses the input to a .wux file.").build());
|
options.addOption(Option.builder(OPTION_DEVMODE).argName("dev mode").desc("Allows you to handle Kiosk Discs").build());
|
||||||
options.addOption(Option.builder("noVerify").desc("Disables verification after compressing").build());
|
options.addOption(Option.builder(OPTION_COMPRESS).desc("Compresses the input to a .wux file.").build());
|
||||||
options.addOption(Option.builder("verify").argName("wudimage1|wudimage2").hasArg().numberOfArgs(2).desc("Compares two WUD images to find differences").build());
|
options.addOption(Option.builder(OPTION_DECOMPRESS).desc("Decompresses the input back to a .wud file.").build());
|
||||||
options.addOption(Option.builder("overwrite").desc("Optional. Overwrites existing files").build());
|
options.addOption(Option.builder(OPTION_NO_VERIFY).desc("Disables verification after compressing").build());
|
||||||
options.addOption(Option.builder("commonkey").argName("WiiU common key").hasArg().desc("Optional. HexString. Will be used if no \"common.key\" in the folder of this .jar is found").build());
|
options.addOption(Option.builder(OPTION_VERIFY).argName("wudimage1|wudimage2").hasArg().numberOfArgs(2)
|
||||||
options.addOption(Option.builder("decrypt").desc("Decrypts full the game partition of the given wud.").build());
|
.desc("Compares two WUD images to find differences").build());
|
||||||
options.addOption(Option.builder("titlekey").argName("WUD title key").hasArg().desc("Optional. HexString. Will be used if no \"game.key\" in the folder of the wud image is found").build());
|
options.addOption(Option.builder(OPTION_OVERWRITE).desc("Optional. Overwrites existing files").build());
|
||||||
options.addOption(Option.builder("decryptFile").argName("regular expression").hasArg().desc("Decrypts full the game partition of the given wud.").build());
|
options.addOption(Option.builder(OPTION_COMMON_KEY).argName("WiiU common key").hasArg()
|
||||||
options.addOption(Option.builder("extract").argName("all|content|ticket|hashes").hasArg().optionalArg(true).desc("Extracts files from the game partition of the given wud (Arguments optional)").build());
|
.desc("Optional. HexString. Will be used if no \"common.key\" in the folder of this .jar is found").build());
|
||||||
|
options.addOption(Option.builder(OPTION_DECRYPT).desc("Decrypts full the game partition of the given wud.").build());
|
||||||
|
options.addOption(Option.builder(OPTION_TITLEKEY).argName("WUD title key").hasArg()
|
||||||
|
.desc("Optional. HexString. Will be used if no \"game.key\" in the folder of the wud image is found").build());
|
||||||
|
options.addOption(
|
||||||
|
Option.builder(OPTION_DECRYPT_FILE).argName("regular expression").hasArg().desc("Decrypts full the game partition of the given wud.").build());
|
||||||
|
options.addOption(Option.builder(OPTION_EXTRACT).argName("all|content|ticket|hashes").hasArg().optionalArg(true)
|
||||||
|
.desc("Extracts files from the game partition of the given wud (Arguments optional)").build());
|
||||||
|
|
||||||
options.addOption("help", false, "shows this text");
|
options.addOption(OPTION_HELP, false, "shows this text");
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user