mirror of
https://github.com/developersu/ns-usbloader.git
synced 2025-05-18 17:25:21 -04:00
Correct readme, update few icons, add freedesktop entry and svg icon. Could be useful for packagers.
This commit is contained in:
parent
8b23b8967b
commit
55df39923f
32 changed files with 2433 additions and 205 deletions
|
@ -88,6 +88,8 @@ public class AppPreferences {
|
|||
public String getHostIp(){ return preferences.get("HOSTIP", "0.0.0.0").replaceAll("(\\s)|(\t)", "");} // who the hell said 'paranoid'?
|
||||
public void setHostIp(String ip){preferences.put("HOSTIP", ip);}
|
||||
|
||||
public void give(){preferences.putBoolean("man", true);}
|
||||
public boolean take(){return preferences.getBoolean("man", false);}
|
||||
public String getHostPort(){
|
||||
String value = preferences.get("HOSTPORT", "6042");
|
||||
if (!value.matches("^[0-9]{1,5}$"))
|
||||
|
@ -138,4 +140,10 @@ public class AppPreferences {
|
|||
|
||||
public String getLastOpenedTab(){ return preferences.get("recent_tab", ""); }
|
||||
public void setLastOpenedTab(String tabId){ preferences.put("recent_tab", tabId); }
|
||||
// Patches
|
||||
public String getKeysLocation(){ return preferences.get("keys", ""); }
|
||||
public void setKeysLocation(String path){ preferences.put("keys", path); }
|
||||
|
||||
public String getPatchesSaveToLocation(){ return FilesHelper.getRealFolder(preferences.get("patches_saveto", System.getProperty("user.home"))); }
|
||||
public void setPatchesSaveToLocation(String value){ preferences.put("patches_saveto", value); }
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public class NSLMainController implements Initializable {
|
|||
@FXML
|
||||
private TabPane mainTabPane;
|
||||
@FXML
|
||||
private Tab GamesTabHolder, RCMTabHolder, SMTabHolder;
|
||||
private Tab GamesTabHolder, RCMTabHolder, SMTabHolder, PatchesTabHolder;
|
||||
|
||||
@FXML
|
||||
private GamesController GamesTabController;
|
||||
|
@ -55,6 +55,8 @@ public class NSLMainController implements Initializable {
|
|||
private RcmController RcmTabController;
|
||||
@FXML
|
||||
private NxdtController NXDTabController;
|
||||
@FXML
|
||||
private PatchesController PatchesTabController;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
|
@ -71,7 +73,7 @@ public class NSLMainController implements Initializable {
|
|||
if (AppPreferences.getInstance().getAutoCheckUpdates()){
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
if (! AppPreferences.getInstance().take()) mainTabPane.getTabs().remove(3);
|
||||
openLastOpenedTab();
|
||||
}
|
||||
private void checkForUpdates(){
|
||||
|
@ -127,6 +129,8 @@ public class NSLMainController implements Initializable {
|
|||
public RcmController getRcmCtrlr(){ return RcmTabController; }
|
||||
|
||||
public NxdtController getNXDTabController(){ return NXDTabController; }
|
||||
|
||||
public PatchesController getPatchesTabController(){ return PatchesTabController; }
|
||||
/**
|
||||
* Save preferences before exit
|
||||
* */
|
||||
|
@ -136,7 +140,7 @@ public class NSLMainController implements Initializable {
|
|||
SplitMergeTabController.updatePreferencesOnExit(); // NOTE: This shit above should be re-written to similar pattern
|
||||
RcmTabController.updatePreferencesOnExit();
|
||||
NXDTabController.updatePreferencesOnExit();
|
||||
|
||||
PatchesTabController.updatePreferencesOnExit();
|
||||
saveLastOpenedTab();
|
||||
}
|
||||
|
||||
|
@ -152,6 +156,9 @@ public class NSLMainController implements Initializable {
|
|||
case "SMTabHolder":
|
||||
mainTabPane.getSelectionModel().select(SMTabHolder);
|
||||
break;
|
||||
case "PatchesTabHolder":
|
||||
mainTabPane.getSelectionModel().select(PatchesTabHolder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void saveLastOpenedTab(){
|
||||
|
|
225
src/main/java/nsusbloader/Controllers/PatchesController.java
Normal file
225
src/main/java/nsusbloader/Controllers/PatchesController.java
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Controllers;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import javafx.stage.FileChooser;
|
||||
import nsusbloader.AppPreferences;
|
||||
import nsusbloader.FilesHelper;
|
||||
import nsusbloader.MediatorControl;
|
||||
import nsusbloader.NSLDataTypes.EModule;
|
||||
import nsusbloader.ServiceWindow;
|
||||
import nsusbloader.Utilities.patches.es.EsPatchMaker;
|
||||
|
||||
// TODO: CLI SUPPORT
|
||||
public class PatchesController implements Initializable {
|
||||
@FXML
|
||||
private VBox patchesToolPane;
|
||||
@FXML
|
||||
private Button selFwFolderBtn, selProdKeysBtn, makeEsBtn;
|
||||
@FXML
|
||||
private Label shortNameFirmwareLbl, locationFirmwareLbl, saveToLbl, shortNameKeysLbl, locationKeysLbl, statusLbl;
|
||||
private Thread workThread;
|
||||
|
||||
private String previouslyOpenedPath;
|
||||
private ResourceBundle resourceBundle;
|
||||
private Region convertRegion;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.previouslyOpenedPath = System.getProperty("user.home");
|
||||
|
||||
String myRegexp;
|
||||
if (File.separator.equals("/"))
|
||||
myRegexp = "^.+/";
|
||||
else
|
||||
myRegexp = "^.+\\\\";
|
||||
locationFirmwareLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
||||
shortNameFirmwareLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
||||
|
||||
locationKeysLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
||||
shortNameKeysLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
||||
|
||||
convertRegion = new Region();
|
||||
convertRegion.getStyleClass().add("regionCake");
|
||||
makeEsBtn.setGraphic(convertRegion);
|
||||
|
||||
AppPreferences preferences = AppPreferences.getInstance();
|
||||
String keysLocation = preferences.getKeysLocation();
|
||||
File keysFile = new File(keysLocation);
|
||||
|
||||
if (keysFile.exists() && keysFile.isFile()) {
|
||||
locationKeysLbl.setText(keysLocation);
|
||||
}
|
||||
|
||||
saveToLbl.setText(preferences.getPatchesSaveToLocation());
|
||||
//makeEsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
|
||||
makeEsBtn.setOnAction(actionEvent -> makeEs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag-n-drop support (dragOver consumer)
|
||||
* */
|
||||
@FXML
|
||||
private void handleDragOver(DragEvent event){
|
||||
if (event.getDragboard().hasFiles())
|
||||
event.acceptTransferModes(TransferMode.ANY);
|
||||
event.consume();
|
||||
}
|
||||
/**
|
||||
* Drag-n-drop support (drop consumer)
|
||||
* */
|
||||
@FXML
|
||||
private void handleDrop(DragEvent event){
|
||||
List<File> filesDropped = event.getDragboard().getFiles();
|
||||
for (File file : filesDropped){
|
||||
if (file.isDirectory()) {
|
||||
locationFirmwareLbl.setText(file.getAbsolutePath());
|
||||
continue;
|
||||
}
|
||||
String fileName = file.getName().toLowerCase();
|
||||
if ((fileName.endsWith(".dat")) ||
|
||||
(fileName.endsWith(".keys") &&
|
||||
! fileName.equals("dev.keys") &&
|
||||
! fileName.equals("title.keys")))
|
||||
locationKeysLbl.setText(file.getAbsolutePath());
|
||||
}
|
||||
event.setDropCompleted(true);
|
||||
event.consume();
|
||||
}
|
||||
@FXML
|
||||
private void selectFirmware(){
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setTitle(resourceBundle.getString("tabPatches_Lbl_Firmware"));
|
||||
directoryChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
||||
File firmware = directoryChooser.showDialog(patchesToolPane.getScene().getWindow());
|
||||
if (firmware == null)
|
||||
return;
|
||||
locationFirmwareLbl.setText(firmware.getAbsolutePath());
|
||||
}
|
||||
@FXML
|
||||
private void selectSaveTo(){
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFolder"));
|
||||
directoryChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
||||
File saveToDir = directoryChooser.showDialog(patchesToolPane.getScene().getWindow());
|
||||
if (saveToDir == null)
|
||||
return;
|
||||
saveToLbl.setText(saveToDir.getAbsolutePath());
|
||||
}
|
||||
@FXML
|
||||
private void selectProdKeys(){
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle(resourceBundle.getString("tabPatches_Lbl_Keys"));
|
||||
fileChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("keys", "*.dat", "*.keys"));
|
||||
File keys = fileChooser.showOpenDialog(patchesToolPane.getScene().getWindow());
|
||||
|
||||
if (keys != null && keys.exists()) {
|
||||
locationKeysLbl.setText(keys.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
private void makeEs(){
|
||||
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||
resourceBundle.getString("tabPatches_ServiceWindowMessage"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (workThread != null && workThread.isAlive())
|
||||
return;
|
||||
statusLbl.setText("");
|
||||
|
||||
if (MediatorControl.getInstance().getTransferActive()) {
|
||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||
resourceBundle.getString("windowBodyPleaseStopOtherProcessFirst"));
|
||||
return;
|
||||
}
|
||||
|
||||
EsPatchMaker esPatchMaker = new EsPatchMaker(locationFirmwareLbl.getText(), locationKeysLbl.getText(),
|
||||
saveToLbl.getText());
|
||||
workThread = new Thread(esPatchMaker);
|
||||
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
private void interruptProcessOfPatchMaking(){
|
||||
if (workThread == null || ! workThread.isAlive())
|
||||
return;
|
||||
|
||||
workThread.interrupt();
|
||||
}
|
||||
|
||||
public void notifyThreadStarted(boolean isActive, EModule type) {
|
||||
if (! type.equals(EModule.PATCHES)) {
|
||||
patchesToolPane.setDisable(isActive);
|
||||
return;
|
||||
}
|
||||
|
||||
convertRegion.getStyleClass().clear();
|
||||
|
||||
if (isActive) {
|
||||
MediatorControl.getInstance().getContoller().logArea.clear();
|
||||
convertRegion.getStyleClass().add("regionStop");
|
||||
|
||||
makeEsBtn.setOnAction(e-> interruptProcessOfPatchMaking());
|
||||
makeEsBtn.setText(resourceBundle.getString("btn_Stop"));
|
||||
makeEsBtn.getStyleClass().remove("buttonUp");
|
||||
makeEsBtn.getStyleClass().add("buttonStop");
|
||||
}
|
||||
else {
|
||||
convertRegion.getStyleClass().add("regionCake");
|
||||
|
||||
makeEsBtn.setOnAction(actionEvent -> makeEs());
|
||||
makeEsBtn.setText(resourceBundle.getString("tabPatches_Btn_MakeEs"));
|
||||
makeEsBtn.getStyleClass().remove("buttonStop");
|
||||
makeEsBtn.getStyleClass().add("buttonUp");
|
||||
}
|
||||
}
|
||||
|
||||
public void setOneLineStatus(boolean statusSuccess){
|
||||
if (statusSuccess)
|
||||
statusLbl.setText(resourceBundle.getString("done_txt"));
|
||||
else
|
||||
statusLbl.setText(resourceBundle.getString("failure_txt"));
|
||||
}
|
||||
|
||||
void updatePreferencesOnExit(){
|
||||
AppPreferences.getInstance().setPatchesSaveToLocation(saveToLbl.getText());
|
||||
if (locationKeysLbl.getText().isEmpty())
|
||||
return;
|
||||
AppPreferences.getInstance().setKeysLocation(locationKeysLbl.getText());
|
||||
}
|
||||
|
||||
}
|
|
@ -40,11 +40,12 @@ public class MediatorControl {
|
|||
}
|
||||
|
||||
public NSLMainController getContoller(){ return mainController; }
|
||||
public GamesController getGamesController(){ return mainController.getGamesCtrlr(); };
|
||||
public SettingsController getSettingsController(){ return mainController.getSettingsCtrlr(); };
|
||||
public SplitMergeController getSplitMergeController(){ return mainController.getSmCtrlr(); };
|
||||
public RcmController getRcmController(){ return mainController.getRcmCtrlr(); };
|
||||
public NxdtController getNxdtController(){ return mainController.getNXDTabController(); };
|
||||
public GamesController getGamesController(){ return mainController.getGamesCtrlr(); }
|
||||
public SettingsController getSettingsController(){ return mainController.getSettingsCtrlr(); }
|
||||
public SplitMergeController getSplitMergeController(){ return mainController.getSmCtrlr(); }
|
||||
public RcmController getRcmController(){ return mainController.getRcmCtrlr(); }
|
||||
public NxdtController getNxdtController(){ return mainController.getNXDTabController(); }
|
||||
public PatchesController getPatchesController(){ return mainController.getPatchesTabController(); }
|
||||
|
||||
public ResourceBundle getResourceBundle(){
|
||||
return mainController.getResourceBundle();
|
||||
|
@ -56,6 +57,7 @@ public class MediatorControl {
|
|||
getSplitMergeController().notifyThreadStarted(isActive, appModuleType);
|
||||
getRcmController().notifyThreadStarted(isActive, appModuleType);
|
||||
getNxdtController().notifyThreadStarted(isActive, appModuleType);
|
||||
getPatchesController().notifyThreadStarted(isActive, appModuleType);
|
||||
}
|
||||
public synchronized boolean getTransferActive() { return this.isTransferActive.get(); }
|
||||
}
|
||||
|
|
|
@ -112,6 +112,8 @@ public class MessagesConsumer extends AnimationTimer {
|
|||
case SPLIT_MERGE_TOOL:
|
||||
MediatorControl.getInstance().getSplitMergeController().setOneLineStatus(oneLinerStatus.get());
|
||||
break;
|
||||
case PATCHES:
|
||||
MediatorControl.getInstance().getPatchesController().setOneLineStatus(oneLinerStatus.get());
|
||||
}
|
||||
this.stop();
|
||||
}
|
||||
|
|
|
@ -22,5 +22,6 @@ public enum EModule {
|
|||
USB_NET_TRANSFERS,
|
||||
SPLIT_MERGE_TOOL,
|
||||
RCM,
|
||||
NXDT
|
||||
NXDT,
|
||||
PATCHES
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import nsusbloader.Controllers.NSLMainController;
|
|||
import nsusbloader.cli.CommandLineInterface;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class NSLMain extends Application {
|
||||
|
@ -47,10 +48,10 @@ public class NSLMain extends Application {
|
|||
Parent root = loader.load();
|
||||
|
||||
primaryStage.getIcons().addAll(
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")),
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")),
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")),
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon128x128.png"))
|
||||
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon32x32.png"))),
|
||||
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon48x48.png"))),
|
||||
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon64x64.png"))),
|
||||
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon128x128.png")))
|
||||
);
|
||||
|
||||
primaryStage.setTitle("NS-USBloader "+appVersion);
|
||||
|
|
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import nsusbloader.Main;
|
||||
import nsusbloader.NSLMain;
|
||||
|
||||
public class BinToAsmPrinter {
|
||||
static {
|
||||
boolean notWindows = ! System.getProperty("os.name").toLowerCase().contains("windows");
|
||||
|
||||
if(notWindows && NSLMain.isCli){
|
||||
ANSI_RESET = "\u001B[0m";
|
||||
ANSI_GREEN = "\u001B[32m";
|
||||
ANSI_BLUE = "\u001B[34m";
|
||||
ANSI_YELLOW = "\u001B[33m";
|
||||
ANSI_PURPLE = "\u001B[35m";
|
||||
ANSI_CYAN = "\u001B[36m";
|
||||
ANSI_RED = "\u001B[31m";
|
||||
}
|
||||
else {
|
||||
ANSI_RESET = ANSI_RED = ANSI_GREEN = ANSI_BLUE = ANSI_YELLOW = ANSI_PURPLE = ANSI_CYAN = "";
|
||||
}
|
||||
}
|
||||
private static final String ANSI_RESET;
|
||||
private static final String ANSI_RED;
|
||||
private static final String ANSI_GREEN;
|
||||
private static final String ANSI_BLUE;
|
||||
private static final String ANSI_YELLOW;
|
||||
private static final String ANSI_PURPLE;
|
||||
private static final String ANSI_CYAN;
|
||||
|
||||
public static String print(int instructionExpression, int offset){
|
||||
if (instructionExpression == 0xd503201f)
|
||||
return printNOP(instructionExpression);
|
||||
|
||||
if ((instructionExpression & 0x7FE0FFE0) == 0x2A0003E0) {
|
||||
return printMOVRegister(instructionExpression);
|
||||
}
|
||||
|
||||
switch ((instructionExpression >> 23 & 0b011111111)){
|
||||
case 0xA5:
|
||||
return printMOV(instructionExpression);
|
||||
case 0x62:
|
||||
if (((instructionExpression & 0x1f) == 0x1f)){
|
||||
return printCMN(instructionExpression, offset);
|
||||
}
|
||||
}
|
||||
|
||||
switch (instructionExpression >> 24 & 0xff) {
|
||||
case 0x34:
|
||||
case 0xb4:
|
||||
return printCBZ(instructionExpression, offset);
|
||||
case 0xb5:
|
||||
case 0x35:
|
||||
return printCBNZ(instructionExpression, offset);
|
||||
case 0x36:
|
||||
case 0xb6:
|
||||
return printTBZ(instructionExpression, offset);
|
||||
case 0x54:
|
||||
return printBConditional(instructionExpression, offset);
|
||||
}
|
||||
switch ((instructionExpression >> 26 & 0b111111)) {
|
||||
case 0x5:
|
||||
return printB(instructionExpression, offset);
|
||||
case 0x25:
|
||||
return printBL(instructionExpression, offset);
|
||||
}
|
||||
|
||||
return printUnknown(instructionExpression);
|
||||
}
|
||||
public static String printSimplified(int instructionExpression, int offset){
|
||||
if (instructionExpression == 0xd503201f)
|
||||
return printNOPSimplified(instructionExpression, offset);
|
||||
|
||||
if ((instructionExpression & 0x7FE0FFE0) == 0x2A0003E0) {
|
||||
return printMOVRegisterSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
switch (instructionExpression >> 22 & 0b1011111111) {
|
||||
case 0x2e5:
|
||||
return printLRDImmUnsignSimplified(instructionExpression, offset);
|
||||
case 0xe5:
|
||||
return printLRDBImmUnsignSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
if ((instructionExpression >> 21 & 0x7FF) == 0x1C2)
|
||||
return printLDURBSimplified(instructionExpression, offset);
|
||||
|
||||
// same to (afterJumpExpression >> 23 & 0x1F9) != 0xA1
|
||||
switch (instructionExpression >> 22 & 0x1FF){
|
||||
case 0xA3: // 0b10100011
|
||||
case 0xA7: // 0b10100111
|
||||
case 0xA5: // 0b10100101
|
||||
return printLDPSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
switch ((instructionExpression >> 23 & 0xff)){
|
||||
case 0xA5:
|
||||
return printMOVSimplified(instructionExpression, offset);
|
||||
case 0x22:
|
||||
return printADDSimplified(instructionExpression, offset);
|
||||
case 0x62:
|
||||
if (((instructionExpression & 0x1f) == 0x1f)){
|
||||
return printCMNSimplified(instructionExpression, offset);
|
||||
}
|
||||
case 0xA2:
|
||||
return printSUBSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
switch (instructionExpression >> 24 & 0xff) {
|
||||
case 0x34:
|
||||
case 0xb4:
|
||||
return printCBZSimplified(instructionExpression, offset);
|
||||
case 0xb5:
|
||||
case 0x35:
|
||||
return printCBNZSimplified(instructionExpression, offset);
|
||||
case 0x36:
|
||||
case 0xb6:
|
||||
return printTBZSimplified(instructionExpression, offset);
|
||||
case 0x54:
|
||||
return printBConditionalSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
switch ((instructionExpression >> 26 & 0b111111)) {
|
||||
case 0x5:
|
||||
return printBSimplified(instructionExpression, offset);
|
||||
case 0x25:
|
||||
return printBLSimplified(instructionExpression, offset);
|
||||
}
|
||||
return printUnknownSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
private static String printCBZ(int instructionExpression, int offset){
|
||||
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(ANSI_YELLOW + "sf == 0 ? <Wt> else <Xt>\n" +
|
||||
"CBZ <?t>, <label> |.....CBZ signature......|\n" +
|
||||
ANSI_CYAN + " sf 0 1 1 0 1 0 0 |imm19..........................................................||Rd.............|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n\n"+
|
||||
ANSI_YELLOW + "CBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
|
||||
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
|
||||
}
|
||||
|
||||
|
||||
private static String printCBNZ(int instructionExpression, int offset){
|
||||
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(ANSI_YELLOW + "sf == 0 ? <Wt> else <Xt>\n" +
|
||||
"CBNZ <?t>, <label> |.....CBZ signature......|\n" +
|
||||
ANSI_CYAN + " sf 0 1 1 0 1 0 |imm19..........................................................||Rd.............|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n\n"+
|
||||
ANSI_YELLOW + "CBNZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
|
||||
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
|
||||
}
|
||||
|
||||
private static String printCMN(int instructionExpression, int offset){
|
||||
int Rn = instructionExpression >> 5 & 0x1F;
|
||||
int imm = instructionExpression >> 10 & 0xFFF;
|
||||
|
||||
return String.format(ANSI_YELLOW + "sf == 0 ? <Wt> else <Xt>\n" +
|
||||
"CMN <?n>, <label> |.....CMN signature...........| |..CMN signature.|\n" +
|
||||
ANSI_CYAN+" sf 0 1 1 0 0 0 1 0 |imm12......................................||Rn.............| 1 1 1 1 1" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n\n" +
|
||||
ANSI_YELLOW + "CMN " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
(instructionExpression >> 31 == 0) ? "w" : "x", Rn, imm);
|
||||
}
|
||||
|
||||
private static String printB(int instructionExpression, int offset){
|
||||
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(ANSI_YELLOW+"B <label> |....B signature...|\n" +
|
||||
" "+ANSI_CYAN+" 0 0 0 1 0 1 |imm26...................................................................................|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
((instructionExpression >> 26 & 0b111111) == 5)?"B":"Some weird stuff",
|
||||
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
|
||||
}
|
||||
|
||||
|
||||
private static String printBL(int instructionExpression, int offset){
|
||||
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(ANSI_YELLOW+"BL <label> |...BL signature...|\n" +
|
||||
" "+ANSI_CYAN+" 1 0 0 1 0 1 |imm26...................................................................................|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
((instructionExpression >> 26 & 0b111111) == 25)?"BL":"Some weird stuff",
|
||||
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
|
||||
}
|
||||
|
||||
|
||||
private static String printMOV(int instructionExpression){
|
||||
int imm16 = instructionExpression >> 5 & 0xFFFF;
|
||||
int sfHw = (instructionExpression >> 22 & 1);
|
||||
|
||||
return String.format(ANSI_YELLOW + "sf == 0 && hw == 0x ? <Wt> else <Xt>\n" +
|
||||
"MOV <?t>, <label> |.....MOV signature...........|\n" +
|
||||
ANSI_CYAN +" sf 1 0 1 0 0 1 0 1 |hw...|imm16.................................................||Rd.............|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "MOV " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
(sfHw == 0) ? "w" : "x", (instructionExpression & 0b11111), imm16);
|
||||
}
|
||||
|
||||
private static String printMOVRegister(int instructionExpression){
|
||||
String sfHw = (instructionExpression >> 31 & 1) == 0 ? "W" : "X";
|
||||
int Rm = instructionExpression >> 16 & 0xF;
|
||||
int Rd = instructionExpression & 0xF;
|
||||
|
||||
return String.format(ANSI_YELLOW + "sf == 0 && hw == 0x ? <Wt> else <Xt>\n" +
|
||||
"MOV (register) <?d>, <?m> |.....MOV (register) signature.......|\n" +
|
||||
ANSI_CYAN +" sf 0 1 0 1 0 1 0 0 0 0 |Rm..............| 0 0 0 0 0 0 1 1 1 1 1 |Rd.............|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "MOV(reg) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "%s%d" + ANSI_RESET + "\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
sfHw, Rm, sfHw, Rd);
|
||||
}
|
||||
|
||||
private static String printNOP(int instructionExpression){
|
||||
return String.format(
|
||||
ANSI_YELLOW+"NOP |.....NOP signature..........................................................................................|\n" +
|
||||
ANSI_CYAN +" 1 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 " + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n"+
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "%s" + ANSI_RESET + "\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
(instructionExpression == 0xd503201f)?"NOP":"Some weird stuff");
|
||||
}
|
||||
|
||||
private static String printTBZ(int instructionExpression, int offset){
|
||||
int xwSelector = (instructionExpression >> 31 & 1);
|
||||
int imm = instructionExpression >> 18 & 0b11111;
|
||||
int Rt = instructionExpression & 0b11111;
|
||||
int label = (offset + (instructionExpression >> 5 & 0x3fff) * 4) & 0xfffff;
|
||||
|
||||
//System.out.printf("\nInstruction: %x\n", instructionExpression);
|
||||
return String.format(ANSI_YELLOW + "sf == 0 && hw == 0x ? <Wt> else <Xt>\n" +
|
||||
"TBZ <?t>,#<imm>, <label> |.....TBZ signature.......|\n" +
|
||||
ANSI_CYAN+" b5 0 1 1 0 1 1 0 |b40.............|imm14.........................................||Rt.............|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "TBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ", " + ANSI_PURPLE + "%x" + ANSI_RESET + "\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
(xwSelector == 0) ? "w" : "x", Rt, imm, label);
|
||||
}
|
||||
|
||||
private static String printBConditional(int instructionExpression, int offset){
|
||||
int conditionalJumpLocation = ((instructionExpression >> 4 & 0b1111111111111111111) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(
|
||||
ANSI_YELLOW+"B.%s <label> |...B.cond signature.......|\n" +
|
||||
ANSI_CYAN+" 0 1 0 1 0 1 0 0 |imm19..........................................................| 0 |.condit...|" + ANSI_RESET + "\n" +
|
||||
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n" +
|
||||
ANSI_YELLOW + "B.%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
getBConditionalMarker(instructionExpression & 0xf),
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
|
||||
getBConditionalMarker(instructionExpression & 0xf),
|
||||
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
|
||||
}
|
||||
|
||||
private static String printUnknown(int instructionExpression){
|
||||
return String.format(ANSI_RED + " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
|
||||
"Instruction (BE) : %s | %s\n",
|
||||
intAsBinString(instructionExpression), intAsHexString(instructionExpression));
|
||||
}
|
||||
|
||||
private static String getBConditionalMarker(int cond){
|
||||
switch (cond){
|
||||
case 0b0000: return "EQ";
|
||||
case 0b0001: return "NE";
|
||||
case 0b0010: return "CS";
|
||||
case 0b0011: return "CC";
|
||||
case 0b0100: return "MI";
|
||||
case 0b0101: return "PL";
|
||||
case 0b0110: return "VS";
|
||||
case 0b0111: return "VC";
|
||||
case 0b1000: return "HI";
|
||||
case 0b1001: return "LS";
|
||||
case 0b1010: return "GE";
|
||||
case 0b1011: return "LT";
|
||||
case 0b1100: return "GT";
|
||||
case 0b1101: return "LE";
|
||||
case 0b1110: return "AL";
|
||||
default: return "??";
|
||||
}
|
||||
/*
|
||||
"__________________CheatSheet_____________________________________\n"+
|
||||
"0000 | EQ | Z set | equal\n"+
|
||||
"0001 | NE | Z clear | not equal\n"+
|
||||
"0010 | CS | C set | unsigned higher or same\n"+
|
||||
"0011 | CC | C clear | unsigned lower\n"+
|
||||
"0100 | MI | N set | negative\n"+
|
||||
"0101 | PL | N clear | positive or zero\n"+
|
||||
"0110 | VS | V set | overflow\n"+
|
||||
"0111 | VC | V clear | no overflow\n"+
|
||||
"1000 | HI | C set & V clear | unsigned higher\n"+
|
||||
"1001 | LS | C clear or Z set | unsigned lower or same\n"+
|
||||
"1010 | GE | N equals V | greater or equal\n"+
|
||||
"1011 | LT | N not equals V | less than\n"+
|
||||
"1100 | GT | Z clear AND (N equals V) | greater that\n"+
|
||||
"1101 | LE | Z set OR (N not equals V) | less than or equal\n"+
|
||||
"1110 | AL | (ignored) | always\n";
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
private static String printCBZSimplified(int instructionExpression, int offset){
|
||||
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (" + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
|
||||
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
|
||||
}
|
||||
|
||||
private static String printCBNZSimplified(int instructionExpression, int offset){
|
||||
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CBNZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (" + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
|
||||
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
|
||||
}
|
||||
|
||||
private static String printBSimplified(int instructionExpression, int offset){
|
||||
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " B " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
|
||||
}
|
||||
|
||||
|
||||
private static String printBLSimplified(int instructionExpression, int offset){
|
||||
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " BL " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String printMOVSimplified(int instructionExpression, int offset){
|
||||
int imm16 = instructionExpression >> 5 & 0xFFFF;
|
||||
int sfHw = (instructionExpression >> 22 & 1);
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " MOV " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
(sfHw == 0) ? "w" : "x", (instructionExpression & 0b11111), imm16);
|
||||
}
|
||||
|
||||
private static String printNOPSimplified(int instructionExpression, int offset){
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " NOP " + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
|
||||
}
|
||||
|
||||
private static String printTBZSimplified(int instructionExpression, int offset){
|
||||
int xwSelector = (instructionExpression >> 31 & 1);
|
||||
int imm = instructionExpression >> 18 & 0b11111;
|
||||
int Rt = instructionExpression & 0b11111;
|
||||
int label = (offset + (instructionExpression >> 5 & 0x3fff) * 4) & 0xfffff;
|
||||
|
||||
//System.out.printf("\nInstruction: %x\n", instructionExpression);
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " TBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ", " + ANSI_PURPLE + "%x" + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
(xwSelector == 0) ? "w" : "x", Rt, imm, label);
|
||||
}
|
||||
|
||||
private static String printBConditionalSimplified(int instructionExpression, int offset){
|
||||
int conditionalJumpLocation = ((instructionExpression >> 4 & 0b1111111111111111111) * 4 + offset) & 0xfffff;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " B.%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
getBConditionalMarker(instructionExpression & 0xf),
|
||||
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
|
||||
}
|
||||
|
||||
private static String printADDSimplified(int instructionExpression, int offset){ //ADD (immediate)
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " ADD . . . \n"+ ANSI_RESET,
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
|
||||
}
|
||||
private static String printLDPSimplified(int instructionExpression, int offset){
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDP . . . \n"+ ANSI_RESET,
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
|
||||
}
|
||||
private static String printLDURBSimplified(int instructionExpression, int offset){
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDURB . . . \n"+ ANSI_RESET,
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
|
||||
}
|
||||
private static String printSUBSimplified(int instructionExpression, int offset){
|
||||
String wx = (instructionExpression >> 31 == 0) ? "W" : "X";
|
||||
int Rt = instructionExpression & 0x1f;
|
||||
int Rn = instructionExpression >> 5 & 0x1F;
|
||||
int imm12 = instructionExpression >> 10 & 0xFFF; // unsigned only
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " SUB (imm) " + ANSI_GREEN + "%s%d, " + ANSI_BLUE + "%s%d, #0x%x" + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
wx, Rt, wx, Rn, imm12);
|
||||
}
|
||||
|
||||
|
||||
private static String printMOVRegisterSimplified(int instructionExpression, int offset){ //ADD (immediate)
|
||||
String sfHw = (instructionExpression >> 31 & 1) == 0 ? "W" : "X";
|
||||
int Rm = instructionExpression >> 16 & 0xF;
|
||||
int Rd = instructionExpression & 0xF;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " MOV (reg) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "%s%d" + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
sfHw, Rm, sfHw, Rd);
|
||||
}
|
||||
|
||||
private static String printCMNSimplified(int instructionExpression, int offset){
|
||||
int Rn = instructionExpression >> 5 & 0x1F;
|
||||
int imm = instructionExpression >> 10 & 0xFFF;
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CMN " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
(instructionExpression >> 31 == 0) ? "w" : "x", Rn, imm);
|
||||
}
|
||||
|
||||
private static String printLRDImmUnsignSimplified(int instructionExpression, int offset){
|
||||
String wx = (instructionExpression >> 31 == 0) ? "W" : "X";
|
||||
int Rt = instructionExpression & 0x1f;
|
||||
int Rn = instructionExpression >> 5 & 0xF;
|
||||
int imm12 = (instructionExpression >> 10 & 0xFFF) * 8; // unsigned only
|
||||
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDR(imm) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "[%s%d, #0x%x]" + ANSI_RESET + " (note: unsigned offset)\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
wx, Rt, wx, Rn, imm12);
|
||||
}
|
||||
private static String printLRDBImmUnsignSimplified(int instructionExpression, int offset){
|
||||
String wx = (instructionExpression >> 31 == 0) ? "W" : "X";
|
||||
int Rt = instructionExpression & 0x1f;
|
||||
int Rn = instructionExpression >> 5 & 0xF;
|
||||
int imm12 = (instructionExpression >> 10 & 0xFFF) * 8; // unsigned only
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDRB(imm) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "[%s%d, #0x%x]" + ANSI_RESET + " (note: unsigned offset)\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
wx, Rt, wx, Rn, imm12);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String printUnknownSimplified(int instructionExpression, int offset){
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " ??? 0b"+ANSI_RESET+ Converter.intToBinaryString(Integer.reverseBytes(instructionExpression)) +"\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
|
||||
}
|
||||
|
||||
private static String intAsBinString(int number) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(int i = 31; i >= 0 ; i--) {
|
||||
int mask = 1 << i;
|
||||
result.append((number & mask) != 0 ? "1" : "0");
|
||||
result.append(" ");
|
||||
if (i % 4 == 0)
|
||||
result.append(" ");
|
||||
}
|
||||
result.replace(result.length() - 1, result.length(), "");
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
private static String intAsHexString(int number) {
|
||||
number = Integer.reverseBytes(number);
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(int i = 0; i <= 3 ; i++) {
|
||||
int mask = 0xff << i*8;
|
||||
result.append(String.format("%02x", (byte)((number & mask) >> i*8)));
|
||||
result.append(" ");
|
||||
}
|
||||
result.replace(result.length() - 1, result.length(), "");
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import libKonogonka.Tools.NCA.NCAProvider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
class EsNcaSearchTask implements Callable<NCAProvider> {
|
||||
private final List<NCAProvider> ncaProviders;
|
||||
|
||||
EsNcaSearchTask(List<NCAProvider> ncaProviders){
|
||||
this.ncaProviders = ncaProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NCAProvider call() {
|
||||
try {
|
||||
for (NCAProvider ncaProvider : ncaProviders) {
|
||||
String titleId = Converter.byteArrToHexStringAsLE(ncaProvider.getTitleId());
|
||||
if (titleId.startsWith("0100000000000033") && ncaProvider.getContentType() == 0) {
|
||||
return ncaProvider;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
174
src/main/java/nsusbloader/Utilities/patches/es/EsPatch.java
Normal file
174
src/main/java/nsusbloader/Utilities/patches/es/EsPatch.java
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
---
|
||||
Based on ES-AutoIPS.py patch script made by GBATemp member MrDude.
|
||||
Taken from: https://gbatemp.net/threads/info-on-sha-256-hashes-on-fs-patches.581550/
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import libKonogonka.Tools.NCA.NCAProvider;
|
||||
import libKonogonka.Tools.NSO.NSO0Header;
|
||||
import libKonogonka.Tools.NSO.NSO0Provider;
|
||||
import nsusbloader.ModelControllers.ILogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.Utilities.patches.es.finders.HeuristicEsWizard;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EsPatch {
|
||||
private final NCAProvider ncaProvider;
|
||||
private final String saveToLocation;
|
||||
private final ILogPrinter logPrinter;
|
||||
|
||||
private Long fwVersion;
|
||||
private String buildId;
|
||||
private byte[] _textSection;
|
||||
|
||||
private HeuristicEsWizard wizard;
|
||||
|
||||
EsPatch(NCAProvider ncaProvider, String saveToLocation, ILogPrinter logPrinter) throws Exception{
|
||||
this.ncaProvider = ncaProvider;
|
||||
this.saveToLocation = saveToLocation + File.separator +
|
||||
"atmosphere" + File.separator + "exefs_patches" + File.separator + "es_patches";
|
||||
this.logPrinter = logPrinter;
|
||||
|
||||
getPlainFirmwareVersion();
|
||||
NSO0Provider nso0Provider = new NSO0Provider(ncaProvider.getNCAContentProvider(0).getPfs0().getStreamProducer(0));
|
||||
getBuildId(nso0Provider);
|
||||
getTextSection(nso0Provider);
|
||||
findAllOffsets();
|
||||
mkDirs();
|
||||
writeFile();
|
||||
logPrinter.print(" == Debug information ==\n"+wizard.getDebug(), EMsgType.NULL);
|
||||
}
|
||||
private void getPlainFirmwareVersion() throws Exception{
|
||||
fwVersion = Long.parseLong(""+ncaProvider.getSdkVersion()[3]+ncaProvider.getSdkVersion()[2]
|
||||
+ncaProvider.getSdkVersion()[1] +ncaProvider.getSdkVersion()[0]);
|
||||
logPrinter.print("Internal firmware version: "+ncaProvider.getSdkVersion()[3] +"."+ncaProvider.getSdkVersion()[2] +"."+ncaProvider.getSdkVersion()[1] +"."+ncaProvider.getSdkVersion()[0], EMsgType.INFO);
|
||||
}
|
||||
private void getBuildId(NSO0Provider nso0Provider) throws Exception{
|
||||
NSO0Header nso0DecompressedHeader = nso0Provider.getAsDecompressedNSO0().getHeader();
|
||||
byte[] buildIdBytes = nso0DecompressedHeader.getModuleId();
|
||||
buildId = Converter.byteArrToHexStringAsLE(buildIdBytes).substring(0, 40).toUpperCase();
|
||||
logPrinter.print("Build ID: "+buildId, EMsgType.INFO);
|
||||
}
|
||||
private void getTextSection(NSO0Provider nso0Provider) throws Exception{
|
||||
_textSection = nso0Provider.getAsDecompressedNSO0().getTextRaw();
|
||||
}
|
||||
private void findAllOffsets() throws Exception{
|
||||
this.wizard = new HeuristicEsWizard(fwVersion, _textSection);
|
||||
String errorsAndNotes = wizard.getErrorsAndNotes();
|
||||
if (errorsAndNotes.length() > 0)
|
||||
logPrinter.print(errorsAndNotes, EMsgType.WARNING);
|
||||
}
|
||||
private void mkDirs(){
|
||||
File parentFolder = new File(saveToLocation);
|
||||
parentFolder.mkdirs();
|
||||
}
|
||||
|
||||
private void writeFile() throws Exception{
|
||||
String patchFileLocation = saveToLocation + File.separator + buildId + ".ips";
|
||||
int offset1 = wizard.getOffset1();
|
||||
int offset2 = wizard.getOffset2();
|
||||
int offset3 = wizard.getOffset3();
|
||||
|
||||
ByteBuffer handyEsPatch = ByteBuffer.allocate(0x23).order(ByteOrder.LITTLE_ENDIAN);
|
||||
handyEsPatch.put(getHeader());
|
||||
if (offset1 > 0) {
|
||||
logPrinter.print("Patch component 1 will be used", EMsgType.PASS);
|
||||
handyEsPatch.put(getPatch1(offset1));
|
||||
}
|
||||
if (offset2 > 0) {
|
||||
logPrinter.print("Patch component 2 will be used", EMsgType.PASS);
|
||||
handyEsPatch.put(getPatch2(offset2));
|
||||
}
|
||||
if (offset3 > 0) {
|
||||
logPrinter.print("Patch component 3 will be used", EMsgType.PASS);
|
||||
handyEsPatch.put(getPatch3(offset3));
|
||||
}
|
||||
handyEsPatch.put(getFooter());
|
||||
|
||||
try (BufferedOutputStream stream = new BufferedOutputStream(
|
||||
Files.newOutputStream(new File(patchFileLocation).toPath()))){
|
||||
stream.write(handyEsPatch.array());
|
||||
}
|
||||
logPrinter.print("Patch created at "+patchFileLocation, EMsgType.PASS);
|
||||
}
|
||||
private byte[] getHeader(){
|
||||
return "PATCH".getBytes(StandardCharsets.US_ASCII);
|
||||
}
|
||||
private byte[] getFooter(){
|
||||
return "EOF".getBytes(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
// WE EXPECT TO SEE CBZ (for patch 1) INSTRUCTION RIGHT BEFORE FOUND SEQUENCE (requiredInstructionOffsetInternal)
|
||||
// IN RESULTING FILE InstructionOffset SHOULD BE INCREMENTED by 0x100 to get real offset
|
||||
// (because header for decompressed NSO0 size = 0x100; it's fixed alignment produced by libKonogonka)
|
||||
private byte[] getPatch1(int offset) throws Exception{
|
||||
int requiredInstructionOffsetInternal = offset - 4;
|
||||
int requiredInstructionOffsetReal = requiredInstructionOffsetInternal + 0x100;
|
||||
int instructionExpression = Converter.getLEint(_textSection, requiredInstructionOffsetInternal);
|
||||
int patch = ((0x14 << 24) | (instructionExpression >> 5) & 0x7FFFF);
|
||||
|
||||
logPrinter.print(BinToAsmPrinter.printSimplified(patch, requiredInstructionOffsetInternal), EMsgType.NULL);
|
||||
|
||||
// Somehow IPS patches uses offsets written as big_endian (0.o) and bytes dat should be patched as LE.
|
||||
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
|
||||
.putInt(requiredInstructionOffsetReal)
|
||||
.putShort((short) 4)
|
||||
.putInt(Integer.reverseBytes(patch));
|
||||
|
||||
return Arrays.copyOfRange(prePatch.array(), 1, 10);
|
||||
}
|
||||
private byte[] getPatch2(int offset) throws Exception{
|
||||
final int NopExpression = 0x1F2003D5; // reversed
|
||||
int offsetReal = offset - 4 + 0x100;
|
||||
|
||||
logPrinter.print(BinToAsmPrinter.printSimplified(Integer.reverseBytes(NopExpression), offset - 4), EMsgType.NULL);
|
||||
|
||||
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
|
||||
.putInt(offsetReal)
|
||||
.putShort((short) 4)
|
||||
.putInt(NopExpression);
|
||||
|
||||
return Arrays.copyOfRange(prePatch.array(), 1, 10);
|
||||
}
|
||||
private byte[] getPatch3(int offset) throws Exception{
|
||||
int requiredInstructionOffsetInternal = offset - 4;
|
||||
int requiredInstructionOffsetReal = requiredInstructionOffsetInternal + 0x100;
|
||||
|
||||
int instructionExpression = Converter.getLEint(_textSection, requiredInstructionOffsetInternal);
|
||||
int patch = ((0x14 << 24) | (instructionExpression >> 5) & 0x7FFFF);
|
||||
|
||||
logPrinter.print(BinToAsmPrinter.printSimplified(patch, requiredInstructionOffsetInternal), EMsgType.NULL);
|
||||
|
||||
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
|
||||
.putInt(requiredInstructionOffsetReal)
|
||||
.putShort((short) 4)
|
||||
.putInt(Integer.reverseBytes(patch));
|
||||
|
||||
return Arrays.copyOfRange(prePatch.array(), 1, 10);
|
||||
}
|
||||
}
|
187
src/main/java/nsusbloader/Utilities/patches/es/EsPatchMaker.java
Normal file
187
src/main/java/nsusbloader/Utilities/patches/es/EsPatchMaker.java
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es;
|
||||
|
||||
import libKonogonka.KeyChainHolder;
|
||||
import libKonogonka.Tools.NCA.NCAProvider;
|
||||
import nsusbloader.ModelControllers.CancellableRunnable;
|
||||
import nsusbloader.ModelControllers.ILogPrinter;
|
||||
import nsusbloader.ModelControllers.Log;
|
||||
import nsusbloader.NSLDataTypes.EModule;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class EsPatchMaker extends CancellableRunnable {
|
||||
private int THREADS_POOL_SIZE = 4;
|
||||
private final ILogPrinter logPrinter;
|
||||
private final String pathToFirmware;
|
||||
private final String pathToKeysFile;
|
||||
private final String saveTo;
|
||||
|
||||
private File firmware;
|
||||
private KeyChainHolder keyChainHolder;
|
||||
private ExecutorService executorService;
|
||||
private List<String> ncaFilesList; // inside the folder
|
||||
|
||||
private boolean oneLinerStatus = false;
|
||||
|
||||
public EsPatchMaker(String pathToFirmware, String pathToKeysFile, String saveTo){
|
||||
this.logPrinter = Log.getPrinter(EModule.PATCHES); //TODO: UNCOMMENT
|
||||
/*
|
||||
this.logPrinter = new ILogPrinter() {
|
||||
@Override
|
||||
public void print(String message, EMsgType type) throws InterruptedException {}
|
||||
@Override
|
||||
public void updateProgress(Double value) throws InterruptedException {}
|
||||
@Override
|
||||
public void update(HashMap<String, File> nspMap, EFileStatus status) {}
|
||||
@Override
|
||||
public void update(File file, EFileStatus status) {}
|
||||
@Override
|
||||
public void updateOneLinerStatus(boolean status) {}
|
||||
@Override
|
||||
public void close() {}
|
||||
};
|
||||
*/
|
||||
this.pathToFirmware = pathToFirmware;
|
||||
this.pathToKeysFile = pathToKeysFile;
|
||||
this.saveTo = saveTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logPrinter.print("..:: Make ES Patches ::..", EMsgType.INFO);
|
||||
receiveFirmware();
|
||||
buildKeyChainHolder();
|
||||
receiveNcaFileNamesList();
|
||||
adjustThreadsPoolSize();
|
||||
createPool();
|
||||
executePool();
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
try{
|
||||
logPrinter.print(e.getMessage(), EMsgType.FAIL);
|
||||
} catch (Exception ignore){}
|
||||
}
|
||||
finally {
|
||||
logPrinter.updateOneLinerStatus(oneLinerStatus);
|
||||
logPrinter.close();
|
||||
}
|
||||
}
|
||||
private void receiveFirmware() throws Exception{
|
||||
logPrinter.print("Looking at firmware", EMsgType.INFO);
|
||||
this.firmware = new File(pathToFirmware);
|
||||
}
|
||||
private void buildKeyChainHolder() throws Exception{
|
||||
logPrinter.print("Reading keys", EMsgType.INFO);
|
||||
this.keyChainHolder = new KeyChainHolder(pathToKeysFile, null);
|
||||
}
|
||||
private void receiveNcaFileNamesList() throws Exception{
|
||||
logPrinter.print("Collecting NCA files", EMsgType.INFO);
|
||||
String[] fileNamesArray = firmware.list((File directory, String file) -> ( ! file.endsWith(".cnmt.nca") && file.endsWith(".nca")));
|
||||
ncaFilesList = Arrays.asList(Objects.requireNonNull(fileNamesArray));
|
||||
if (ncaFilesList.size() == 0)
|
||||
throw new Exception("No NCA files found in firmware folder");
|
||||
}
|
||||
private void adjustThreadsPoolSize(){
|
||||
if (ncaFilesList.size() < 4)
|
||||
THREADS_POOL_SIZE = ncaFilesList.size();
|
||||
}
|
||||
|
||||
private void createPool() throws Exception{
|
||||
logPrinter.print("Creating sub-tasks pool", EMsgType.INFO);
|
||||
this.executorService = Executors.newFixedThreadPool(
|
||||
THREADS_POOL_SIZE,
|
||||
runnable -> {
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
}
|
||||
|
||||
private void executePool() throws Exception{ //TODO: FIX. Exceptions thrown only by logPrinter
|
||||
try {
|
||||
logPrinter.print("Executing sub-tasks pool", EMsgType.INFO);
|
||||
List<Future<NCAProvider>> futuresResults = executorService.invokeAll(getSubTasksCollection());
|
||||
for (Future<NCAProvider> future : futuresResults){
|
||||
NCAProvider ncaProvider = future.get();
|
||||
if (ncaProvider != null) {
|
||||
makePatches(ncaProvider);
|
||||
break;
|
||||
}
|
||||
}
|
||||
executorService.shutdown();
|
||||
}
|
||||
catch (InterruptedException ie){
|
||||
executorService.shutdownNow();
|
||||
boolean interruptedSuccessfully = false;
|
||||
try {
|
||||
interruptedSuccessfully = executorService.awaitTermination(20, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException awaitInterrupt){
|
||||
logPrinter.print("Force interrupting task...", EMsgType.WARNING);
|
||||
}
|
||||
logPrinter.print("Task interrupted "+(interruptedSuccessfully?"successfully":"with some issues"), EMsgType.WARNING);
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
logPrinter.print("Task failed: "+e.getMessage(), EMsgType.FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
private void makePatches(NCAProvider ncaProvider) throws Exception{
|
||||
logPrinter.print(String.format("File found: .."+File.separator+"%s"+File.separator+"%s",
|
||||
ncaProvider.getFile().getParentFile().getName(), ncaProvider.getFile().getName())
|
||||
, EMsgType.INFO);
|
||||
new EsPatch(ncaProvider, saveTo, logPrinter);
|
||||
oneLinerStatus = true;
|
||||
}
|
||||
private List<Callable<NCAProvider>> getSubTasksCollection() throws Exception{
|
||||
logPrinter.print("Forming sub-tasks collection", EMsgType.INFO);
|
||||
List<Callable<NCAProvider>> subTasks = new ArrayList<>();
|
||||
|
||||
int ncaPerThreadAmount = ncaFilesList.size() / THREADS_POOL_SIZE;
|
||||
Iterator<String> iterator = ncaFilesList.listIterator();
|
||||
|
||||
for (int i = 1; i < THREADS_POOL_SIZE; i++){
|
||||
Callable<NCAProvider> task = new EsNcaSearchTask(getNextSet(iterator, ncaPerThreadAmount));
|
||||
subTasks.add(task);
|
||||
}
|
||||
|
||||
Callable<NCAProvider> task = new EsNcaSearchTask(getNextSet(iterator,
|
||||
ncaFilesList.size() % THREADS_POOL_SIZE == 0 ? ncaPerThreadAmount : ncaPerThreadAmount+1));
|
||||
subTasks.add(task);
|
||||
return subTasks;
|
||||
}
|
||||
private List<NCAProvider> getNextSet(Iterator<String> iterator, int amount) throws Exception{
|
||||
List<NCAProvider> ncas = new ArrayList<>();
|
||||
for (int j = 0; j < amount; j++){
|
||||
String ncaFileName = iterator.next();
|
||||
File nca = new File(firmware.getAbsolutePath()+File.separator+ncaFileName);
|
||||
NCAProvider provider = new NCAProvider(nca, keyChainHolder.getRawKeySet());
|
||||
ncas.add(provider);
|
||||
}
|
||||
return ncas;
|
||||
}
|
||||
}
|
161
src/main/java/nsusbloader/Utilities/patches/es/SimplyFind.java
Normal file
161
src/main/java/nsusbloader/Utilities/patches/es/SimplyFind.java
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SimplyFind {
|
||||
private String what;
|
||||
private final byte[] where;
|
||||
|
||||
private Matcher matcherHex;
|
||||
private Matcher matcherDot;
|
||||
|
||||
private final List<Integer> findings = new ArrayList<>();
|
||||
private final int statementLength;
|
||||
private final List<SearchBlock> searchBlocks = new ArrayList<>();
|
||||
/**
|
||||
* Abstraction layer for searching patterns like "..CAFE..BE" in bytes array.
|
||||
* It's 'String' combination of hex values and '.' which stands for unknown value.
|
||||
* Returns offset of the first symbol.
|
||||
* */
|
||||
public SimplyFind(String what, byte[] where){
|
||||
this.where = where;
|
||||
if (! what.contains(".")){
|
||||
doKMPSearch(Converter.hexStringToByteArray(what), 0);
|
||||
this.statementLength = what.length()/2;
|
||||
return;
|
||||
}
|
||||
this.what = what.replaceAll("\\.", "\\.\\.");
|
||||
this.statementLength = this.what.length()/2;
|
||||
|
||||
buildSearchingSequence();
|
||||
complexSearch();
|
||||
}
|
||||
private void buildSearchingSequence(){
|
||||
Pattern patternHex = Pattern.compile("[0-9]|[A-F]|[a-f]");
|
||||
Pattern patternDot = Pattern.compile("\\.");
|
||||
this.matcherHex = patternHex.matcher(what);
|
||||
this.matcherDot = patternDot.matcher(what);
|
||||
|
||||
int nextDotPos = 0;
|
||||
int nextHexPos;
|
||||
|
||||
while(true){
|
||||
nextHexPos = getNextNumberPosition(nextDotPos);
|
||||
if (nextHexPos == -1)
|
||||
break;
|
||||
|
||||
nextDotPos = getNextDotPosition(nextHexPos);
|
||||
if (nextDotPos == -1) {
|
||||
searchBlocks.add(new SearchBlock(what.substring(nextHexPos), nextHexPos));
|
||||
break;
|
||||
}
|
||||
String searchStatement = what.substring(nextHexPos, nextDotPos);
|
||||
searchBlocks.add(new SearchBlock(searchStatement, nextHexPos));
|
||||
}
|
||||
}
|
||||
private int getNextNumberPosition(int since){
|
||||
if (matcherHex.find(since))
|
||||
return matcherHex.start();
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int getNextDotPosition(int since){
|
||||
if (matcherDot.find(since))
|
||||
return matcherDot.start();
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void complexSearch(){
|
||||
SearchBlock block = searchBlocks.get(0);
|
||||
doKMPSearch(block.statement, block.offsetInStatement);
|
||||
findings.removeIf(this::searchForward);
|
||||
}
|
||||
private boolean searchForward(int offset){
|
||||
for (int i = 1; i < searchBlocks.size(); i++) {
|
||||
SearchBlock block = searchBlocks.get(i);
|
||||
if (! doDumbSearch(block.statement, offset+block.offsetInStatement)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void doKMPSearch(byte[] subject, int skip){
|
||||
int whereSize = where.length;
|
||||
int subjectSize = subject.length;
|
||||
|
||||
int[] pf = new int[subjectSize];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 1; i < subjectSize; i++ ) {
|
||||
while ((j > 0) && (subject[j] != subject[i]))
|
||||
j = pf[j-1];
|
||||
if (subject[j] == subject[i])
|
||||
j++;
|
||||
pf[i] = j;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (int i = 0; i < whereSize; i++){
|
||||
while ((j > 0) && (subject[j] != where[i]))
|
||||
j = pf[j - 1];
|
||||
if (subject[j] == where[i])
|
||||
j++;
|
||||
if (j == subjectSize) {
|
||||
findings.add(i-j+1-skip);
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doDumbSearch(byte[] subject, int since){
|
||||
for (int i = 0; i < subject.length; i++) {
|
||||
if (where[since + i] != subject[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getStatementLength() {
|
||||
return statementLength;
|
||||
}
|
||||
|
||||
public List<Integer> getResults(){
|
||||
return findings;
|
||||
}
|
||||
|
||||
private static class SearchBlock{
|
||||
byte[] statement;
|
||||
int offsetInStatement;
|
||||
|
||||
SearchBlock(String statement, int offset){
|
||||
if (statement != null) {
|
||||
this.statement = Converter.hexStringToByteArray(statement);
|
||||
}
|
||||
this.offsetInStatement = offset/2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es.finders;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import nsusbloader.Utilities.patches.es.BinToAsmPrinter;
|
||||
import nsusbloader.Utilities.patches.es.SimplyFind;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class HeuristicEs1 implements IHeuristicEs {
|
||||
private static final String PATTERN = "1F90013128.8052";
|
||||
|
||||
private final List<Integer> findings;
|
||||
private final byte[] where;
|
||||
|
||||
HeuristicEs1(byte[] where){
|
||||
this.where = where;
|
||||
SimplyFind simplyfind = new SimplyFind(PATTERN, where);
|
||||
this.findings = simplyfind.getResults();
|
||||
|
||||
this.findings.removeIf(this::dropStep1);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep2);
|
||||
}
|
||||
|
||||
// Check ranges
|
||||
private boolean dropStep1(int offsetOfPatternFound){
|
||||
return ((offsetOfPatternFound < 0x10000 || offsetOfPatternFound > 0xffffc));
|
||||
}
|
||||
// Remove non-CBZ
|
||||
private boolean dropStep2(int offsetOfPatternFound){
|
||||
return ((where[offsetOfPatternFound - 1] & (byte) 0b01111111) != 0x34);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFound(){
|
||||
return findings.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantLessEntropy(){
|
||||
return findings.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() throws Exception{
|
||||
if(findings.isEmpty())
|
||||
throw new Exception("Nothing found");
|
||||
if (findings.size() > 1)
|
||||
throw new Exception("Too many offsets");
|
||||
return findings.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setOffsetsNearby(int offsetNearby) {
|
||||
findings.removeIf(offset -> {
|
||||
if (offset > offsetNearby)
|
||||
return ! (offset < offsetNearby - 0xffff);
|
||||
return ! (offset > offsetNearby - 0xffff);
|
||||
});
|
||||
return isFound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetails(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int cbzOffsetInternal = findings.get(0) - 4;
|
||||
int instructionExpression = Converter.getLEint(where, cbzOffsetInternal);
|
||||
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + cbzOffsetInternal) & 0xfffff;
|
||||
|
||||
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
|
||||
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
|
||||
|
||||
builder.append(BinToAsmPrinter.printSimplified(instructionExpression, cbzOffsetInternal));
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+4),
|
||||
cbzOffsetInternal+4));
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+8),
|
||||
cbzOffsetInternal+8));
|
||||
builder.append("...\n");
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation+4));
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es.finders;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import nsusbloader.Utilities.patches.es.BinToAsmPrinter;
|
||||
import nsusbloader.Utilities.patches.es.SimplyFind;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class HeuristicEs2 implements IHeuristicEs {
|
||||
private static final String PATTERN = ".D2.52";
|
||||
|
||||
private List<Integer> findings;
|
||||
private final byte[] where;
|
||||
|
||||
HeuristicEs2(byte[] where){
|
||||
this.where = where;
|
||||
find();
|
||||
|
||||
this.findings.removeIf(this::dropStep1);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep2);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep3);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep4);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep5);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep6);
|
||||
}
|
||||
private void find(){
|
||||
SimplyFind simplyfind = new SimplyFind(PATTERN, where);
|
||||
findings = new ArrayList<>();
|
||||
// This approach a bit different. We're looking for pattern we want to patch, not the next one.
|
||||
// So easier way is just to shift every value and pretend that nothing happened.
|
||||
for (int offset : simplyfind.getResults())
|
||||
findings.add(offset+4);
|
||||
}
|
||||
|
||||
// Limit range
|
||||
private boolean dropStep1(int offsetOfPatternFound){
|
||||
return ((offsetOfPatternFound < 0x10000 || offsetOfPatternFound > 0xffffc));
|
||||
}
|
||||
// Is CBNZ next?
|
||||
private boolean dropStep2(int offsetOfPatternFound){
|
||||
return ! isCBNZ(Converter.getLEint(where, offsetOfPatternFound));
|
||||
}
|
||||
// Check what's above
|
||||
private boolean dropStep3(int offsetOfPatternFound){
|
||||
return ! isMOV(Converter.getLEint(where, offsetOfPatternFound-4));
|
||||
}
|
||||
// Check what's beyond or after jump
|
||||
private boolean dropStep4(int offsetOfPatternFound) {
|
||||
int nextExpression = Converter.getLEint(where, offsetOfPatternFound + 4);
|
||||
return ! isLDRB_LDURB(nextExpression); // Drop if not LDRB OR LDURB
|
||||
}
|
||||
|
||||
// Check second after jump if LDR-TBZ
|
||||
private boolean dropStep5(int offsetOfPatternFound) {
|
||||
int expression = Converter.getLEint(where, offsetOfPatternFound);
|
||||
int afterJumpPosition = ((expression >> 5 & 0x7FFFF) * 4 + offsetOfPatternFound) & 0xfffff;
|
||||
int secondAfterJumpExpression = Converter.getLEint(where, afterJumpPosition+4);
|
||||
return ! isBL(secondAfterJumpExpression); //Second after jump = BL? No -> Drop
|
||||
}
|
||||
|
||||
// Check second after jump if LDR-TBZ
|
||||
private boolean dropStep6(int offsetOfPatternFound) {
|
||||
int expression = Converter.getLEint(where, offsetOfPatternFound);
|
||||
int afterJumpPosition = ((expression >> 5 & 0x7FFFF) * 4 + offsetOfPatternFound) & 0xfffff;
|
||||
int forthAfterJumpExpression = Converter.getLEint(where, afterJumpPosition+12);
|
||||
return ! isBL(forthAfterJumpExpression); //Forth after jump = BL? No -> Drop
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFound(){
|
||||
return findings.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantLessEntropy(){
|
||||
return findings.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() throws Exception{
|
||||
if(findings.isEmpty())
|
||||
throw new Exception("Nothing found");
|
||||
if (findings.size() > 1)
|
||||
throw new Exception("Too many offsets");
|
||||
return findings.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setOffsetsNearby(int offsetNearby) {
|
||||
findings.removeIf(offset -> {
|
||||
if (offset > offsetNearby)
|
||||
return ! (offset < offsetNearby - 0xffff);
|
||||
return ! (offset > offsetNearby - 0xffff);
|
||||
});
|
||||
return isFound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetails(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int secondExpressionOffset = findings.get(0);
|
||||
|
||||
int firstExpression = Converter.getLEint(where, secondExpressionOffset-4);
|
||||
int secondExpression = Converter.getLEint(where, secondExpressionOffset);
|
||||
int conditionalJumpLocation = 0;
|
||||
if ((secondExpression >> 24 & 0x7f) == 0x35) {
|
||||
conditionalJumpLocation = ((secondExpression >> 5 & 0x7FFFF) * 4 + secondExpressionOffset) & 0xfffff;
|
||||
}
|
||||
else if ((firstExpression >> 24 & 0x7f) == 0x36) {
|
||||
conditionalJumpLocation = (secondExpressionOffset-4 + (firstExpression >> 5 & 0x3fff) * 4) & 0xfffff;
|
||||
}
|
||||
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
|
||||
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation + 4);
|
||||
int secondExpressionsPairElement3 = Converter.getLEint(where, conditionalJumpLocation + 8);
|
||||
int secondExpressionsPairElement4 = Converter.getLEint(where, conditionalJumpLocation + 12);
|
||||
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, secondExpressionOffset-4), secondExpressionOffset-4));
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpression, secondExpressionOffset));
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, secondExpressionOffset+4), secondExpressionOffset+4));
|
||||
builder.append("...\n");
|
||||
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4));
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement3, conditionalJumpLocation + 8));
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement4, conditionalJumpLocation + 12));
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es.finders;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import nsusbloader.Utilities.patches.es.BinToAsmPrinter;
|
||||
import nsusbloader.Utilities.patches.es.SimplyFind;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class HeuristicEs3 implements IHeuristicEs {
|
||||
private static final String PATTERN0 = "..FF97";
|
||||
private static final String PATTERN1 = "......FF97"; // aka "E0230091..FF97";
|
||||
|
||||
private final List<Integer> findings;
|
||||
private final byte[] where;
|
||||
|
||||
HeuristicEs3(long fwVersion, byte[] where){
|
||||
this.where = where;
|
||||
String pattern = getPattern(fwVersion);
|
||||
SimplyFind simplyfind = new SimplyFind(pattern, where);
|
||||
this.findings = simplyfind.getResults();
|
||||
|
||||
this.findings.removeIf(this::dropStep1);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep2);
|
||||
if(findings.size() < 2)
|
||||
return;
|
||||
|
||||
this.findings.removeIf(this::dropStep3);
|
||||
}
|
||||
private String getPattern(long fwVersion){
|
||||
if (fwVersion < 10400)
|
||||
return PATTERN0;
|
||||
return PATTERN1;
|
||||
}
|
||||
// Let's focus on CBZ-ONLY statements
|
||||
private boolean dropStep1(int offsetOfPatternFound){
|
||||
return ((where[offsetOfPatternFound - 1] & (byte) 0b01111111) != 0x34);
|
||||
}
|
||||
|
||||
private boolean dropStep2(int offsetOfPatternFound){
|
||||
int conditionalJumpLocation = getCBZConditionalJumpLocation(offsetOfPatternFound - 4);
|
||||
|
||||
int afterJumpSecondExpressions = Converter.getLEint(where, conditionalJumpLocation);
|
||||
int afterJumpThirdExpressions = Converter.getLEint(where, conditionalJumpLocation+4);
|
||||
// Check first is 'MOV'; second is 'B'
|
||||
return (! isMOV_REG(afterJumpSecondExpressions)) || ! isB(afterJumpThirdExpressions);
|
||||
}
|
||||
|
||||
private boolean dropStep3(int offsetOfPatternFound){
|
||||
int conditionalJumpLocation = getCBZConditionalJumpLocation(offsetOfPatternFound-4);
|
||||
int afterJumpSecondExpressions = Converter.getLEint(where, conditionalJumpLocation+4);
|
||||
int secondPairConditionalJumpLocation = ((afterJumpSecondExpressions & 0x3ffffff) * 4 + (conditionalJumpLocation+4)) & 0xfffff;
|
||||
|
||||
int thirdExpressionsPairElement1 = Converter.getLEint(where, secondPairConditionalJumpLocation);
|
||||
int thirdExpressionsPairElement2 = Converter.getLEint(where, secondPairConditionalJumpLocation+4);
|
||||
// Check first is 'ADD'; second is 'BL'
|
||||
return (! isADD(thirdExpressionsPairElement1)) || (! isBL(thirdExpressionsPairElement2));
|
||||
}
|
||||
|
||||
private int getCBZConditionalJumpLocation(int cbzOffsetInternal){
|
||||
int cbzExpression = Converter.getLEint(where, cbzOffsetInternal);
|
||||
return ((cbzExpression >> 5 & 0x7FFFF) * 4 + cbzOffsetInternal) & 0xfffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFound(){
|
||||
return findings.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantLessEntropy(){
|
||||
return findings.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() throws Exception{
|
||||
if(findings.isEmpty())
|
||||
throw new Exception("Nothing found");
|
||||
if (findings.size() > 1)
|
||||
throw new Exception("Too many offsets");
|
||||
return findings.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setOffsetsNearby(int offsetNearby) {
|
||||
findings.removeIf(offset -> {
|
||||
if (offset > offsetNearby)
|
||||
return ! (offset < offsetNearby - 0xffff);
|
||||
return ! (offset > offsetNearby - 0xffff);
|
||||
});
|
||||
return isFound();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDetails(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int cbzOffsetInternal = findings.get(0) - 4;
|
||||
int cbzExpression = Converter.getLEint(where, cbzOffsetInternal);
|
||||
int conditionalJumpLocation = ((cbzExpression >> 5 & 0x7FFFF) * 4 + cbzOffsetInternal) & 0xfffff;
|
||||
|
||||
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
|
||||
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
|
||||
|
||||
builder.append(BinToAsmPrinter.printSimplified(cbzExpression, cbzOffsetInternal));
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+4), cbzOffsetInternal+4));
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+8), cbzOffsetInternal+8));
|
||||
builder.append("...\n");
|
||||
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
|
||||
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation+4));
|
||||
|
||||
if (((secondExpressionsPairElement2 >> 26 & 0b111111) == 0x5)){
|
||||
builder.append("...\n");
|
||||
int conditionalJumpLocation2 = ((secondExpressionsPairElement2 & 0x3ffffff) * 4 + (conditionalJumpLocation+4)) & 0xfffff;
|
||||
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, conditionalJumpLocation2), conditionalJumpLocation2));
|
||||
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, conditionalJumpLocation2+4), conditionalJumpLocation2+4));
|
||||
|
||||
}
|
||||
else {
|
||||
builder.append("NO CONDITIONAL JUMP ON 2nd iteration (HeuristicEs3)");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
return 3;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es.finders;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HeuristicEsWizard {
|
||||
private final List<IHeuristicEs> all;
|
||||
private final List<IHeuristicEs> found;
|
||||
private final List<IHeuristicEs> wantLessEntropy;
|
||||
|
||||
private final StringBuilder errorsAndNotes;
|
||||
|
||||
private int offset1 = -1;
|
||||
private int offset2 = -1;
|
||||
private int offset3 = -1;
|
||||
|
||||
public HeuristicEsWizard(long fwVersion, byte[] where) throws Exception{
|
||||
this.errorsAndNotes = new StringBuilder();
|
||||
|
||||
this.all = Arrays.asList(
|
||||
new HeuristicEs1(where),
|
||||
new HeuristicEs2(where),
|
||||
new HeuristicEs3(fwVersion, where)
|
||||
);
|
||||
|
||||
this.found = all.stream()
|
||||
.filter(IHeuristicEs::isFound)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (found.isEmpty())
|
||||
throw new Exception("Nothing found!");
|
||||
|
||||
this.wantLessEntropy = all.stream()
|
||||
.filter(IHeuristicEs::wantLessEntropy)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
shareOffsetsWithEachOther();
|
||||
|
||||
assignOffset1();
|
||||
assignOffset2();
|
||||
assignOffset3();
|
||||
}
|
||||
|
||||
private void shareOffsetsWithEachOther(){
|
||||
for (IHeuristicEs es : wantLessEntropy) {
|
||||
if (shareWithNext(es))
|
||||
return;
|
||||
}
|
||||
}
|
||||
private boolean shareWithNext(IHeuristicEs es){
|
||||
try {
|
||||
for (IHeuristicEs foundEs : found) {
|
||||
if (es.setOffsetsNearby(foundEs.getOffset())) {
|
||||
found.add(es);
|
||||
wantLessEntropy.remove(es);
|
||||
shareOffsetsWithEachOther();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e){ e.printStackTrace(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
private void assignOffset1(){
|
||||
try {
|
||||
offset1 = all.get(0).getOffset();
|
||||
}
|
||||
catch (Exception e){ errorsAndNotes.append(e.getLocalizedMessage()).append("\n"); }
|
||||
}
|
||||
private void assignOffset2(){
|
||||
try {
|
||||
offset2 = all.get(1).getOffset();
|
||||
}
|
||||
catch (Exception e){ errorsAndNotes.append(e.getLocalizedMessage()).append("\n"); }
|
||||
}
|
||||
private void assignOffset3(){
|
||||
try {
|
||||
offset3 = all.get(2).getOffset();
|
||||
}
|
||||
catch (Exception e){ errorsAndNotes.append(e.getLocalizedMessage()).append("\n"); }
|
||||
}
|
||||
|
||||
public String getErrorsAndNotes(){
|
||||
return errorsAndNotes.toString();
|
||||
}
|
||||
|
||||
public String getDebug(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (all.get(0).isFound()){
|
||||
builder.append("\t\t-=== 1 ===-\n");
|
||||
builder.append(all.get(0).getDetails());
|
||||
}
|
||||
if (all.get(1).isFound()){
|
||||
builder.append("\t\t-=== 2 ===-\n");
|
||||
builder.append(all.get(1).getDetails());
|
||||
}
|
||||
if (all.get(2).isFound()){
|
||||
builder.append("\t\t-=== 3 ===-\n");
|
||||
builder.append(all.get(2).getDetails());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public int getOffset1() { return offset1; }
|
||||
public int getOffset2() { return offset2; }
|
||||
public int getOffset3() { return offset3; }
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader 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.
|
||||
|
||||
NS-USBloader 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 NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.es.finders;
|
||||
/**
|
||||
* Searches instructions (via known patterns) that follows 'specific instruction' we want to patch.
|
||||
* Returns offset of the pattern. Not offset of the 'specific instruction'.
|
||||
* */
|
||||
interface IHeuristicEs {
|
||||
default boolean isLDR(int expression){ return (expression >> 22 & 0x2FF) == 0x2e5; }// LDR ! Sounds like LDP, don't mess up
|
||||
default boolean isLDP(int expression){ return (expression >> 22 & 0x1F9) == 0xA1; }// LDP !
|
||||
default boolean isCBNZ(int expression){ return (expression >> 24 & 0x7f) == 0x35; }
|
||||
default boolean isMOV(int expression){ return (expression >> 23 & 0xff) == 0xA5; }
|
||||
default boolean isTBZ(int expression){ return (expression >> 24 & 0x7f) == 0x36; }
|
||||
default boolean isLDRB_LDURB(int expression){ return (expression >> 21 & 0x7f7) == 0x1c2; }
|
||||
default boolean isMOV_REG(int expression){ return (expression & 0x7FE0FFE0) == 0x2A0003E0; }
|
||||
default boolean isB(int expression) { return (expression >> 26 & 0x3f) == 0x5; }
|
||||
default boolean isBL(int expression){ return (expression >> 26 & 0x3f) == 0x25; }
|
||||
default boolean isADD(int expression){ return (expression >> 23 & 0xff) == 0x22; }
|
||||
boolean isFound();
|
||||
boolean wantLessEntropy();
|
||||
int getOffset() throws Exception;
|
||||
String getDetails();
|
||||
|
||||
/**
|
||||
* Should be used if wantLessEntropy() == true
|
||||
* @return isFound();
|
||||
* */
|
||||
boolean setOffsetsNearby(int offsetNearby);
|
||||
|
||||
int getId();
|
||||
}
|
|
@ -18,9 +18,12 @@
|
|||
*/
|
||||
package nsusbloader.cli;
|
||||
|
||||
import nsusbloader.AppPreferences;
|
||||
import nsusbloader.Main;
|
||||
import nsusbloader.NSLMain;
|
||||
import org.apache.commons.cli.*;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
public class CommandLineInterface {
|
||||
|
@ -32,10 +35,12 @@ public class CommandLineInterface {
|
|||
}
|
||||
|
||||
final Options cliOptions = createCliOptions();
|
||||
final Options cliOptionsToBeExact =
|
||||
createCliOptions().addOption(Option.builder().longOpt("gimmegimmegimme").hasArg(false).build());
|
||||
|
||||
CommandLineParser cliParser = new DefaultParser();
|
||||
try{
|
||||
CommandLine cli = cliParser.parse(cliOptions, args);
|
||||
CommandLine cli = cliParser.parse(cliOptionsToBeExact, args);
|
||||
if (cli.hasOption('v') || cli.hasOption("version")){
|
||||
handleVersion();
|
||||
return;
|
||||
|
@ -75,6 +80,16 @@ public class CommandLineInterface {
|
|||
return;
|
||||
}
|
||||
*/
|
||||
if (cli.hasOption("gimmegimmegimme")){
|
||||
if (LocalTime.now().isBefore(LocalTime.parse("09:00:00"))){
|
||||
AppPreferences.getInstance().give();
|
||||
AppPreferences.getInstance().setLastOpenedTab("PatchesTabHolder");
|
||||
System.out.println("=)");
|
||||
Main.main(new String[]{});
|
||||
return;
|
||||
}
|
||||
throw new ParseException("Unhandled LocalTime() exception;");
|
||||
}
|
||||
if (cli.hasOption("s") || cli.hasOption("split")){
|
||||
final String[] arguments = cli.getOptionValues("split");
|
||||
new SplitCli(arguments);
|
||||
|
|
|
@ -15,7 +15,7 @@ Steps to roll NXDT functionality back:
|
|||
* Set 'Visible' on NXDT Tab selector (SVGPath container)
|
||||
-->
|
||||
|
||||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NSLMainController">
|
||||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NSLMainController">
|
||||
<children>
|
||||
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
|
@ -47,6 +47,14 @@ Steps to roll NXDT functionality back:
|
|||
<SVGPath content="M 2.4003906 2 C 1.0683906 2 2.9605947e-16 3.1125 0 4.5 L 0 19.5 A 2.4 2.5 0 0 0 2.4003906 22 L 21.599609 22 A 2.4 2.5 0 0 0 24 19.5 L 24 7 C 24 5.6125 22.919609 4.5 21.599609 4.5 L 12 4.5 L 9.5996094 2 L 2.4003906 2 z M 9 5 L 13 8.5 L 9 12 L 9 10 L 6 10 L 6 7 L 9 7 L 9 5 z M 5 9 L 5 11 L 8 11 L 8 14 L 5 14 L 5 16 L 1 12.5 L 5 9 z M 13.193359 10.962891 C 14.113498 10.962891 14.814236 11.348741 15.296875 12.123047 C 15.779514 12.89388 16.021484 13.935113 16.021484 15.244141 C 16.021484 16.556641 15.779514 17.598741 15.296875 18.373047 C 14.814236 19.14388 14.113498 19.529297 13.193359 19.529297 C 12.276693 19.529297 11.575955 19.14388 11.089844 18.373047 C 10.607205 17.598741 10.365234 16.556641 10.365234 15.244141 C 10.365234 13.935113 10.607205 12.89388 11.089844 12.123047 C 11.575955 11.348741 12.276693 10.962891 13.193359 10.962891 z M 19.589844 10.962891 C 20.509983 10.962891 21.21072 11.348741 21.693359 12.123047 C 22.175998 12.89388 22.417969 13.935113 22.417969 15.244141 C 22.417969 16.556641 22.175998 17.598741 21.693359 18.373047 C 21.21072 19.14388 20.509983 19.529297 19.589844 19.529297 C 18.673177 19.529297 17.970486 19.14388 17.484375 18.373047 C 17.001736 17.598741 16.761719 16.556641 16.761719 15.244141 C 16.761719 13.935113 17.001736 12.89388 17.484375 12.123047 C 17.970486 11.348741 18.673177 10.962891 19.589844 10.962891 z M 13.193359 11.769531 C 12.613498 11.769531 12.173177 12.092448 11.871094 12.738281 C 11.56901 13.380642 11.417969 14.195964 11.417969 15.185547 C 11.417969 15.411241 11.423611 15.655599 11.4375 15.916016 C 11.451389 16.176432 11.511068 16.528212 11.615234 16.972656 L 14.412109 12.591797 C 14.235026 12.26888 14.042318 12.052517 13.833984 11.941406 C 13.629123 11.826823 13.415582 11.769531 13.193359 11.769531 z M 19.589844 11.769531 C 19.009983 11.769531 18.567708 12.092448 18.265625 12.738281 C 17.963542 13.380642 17.8125 14.195964 17.8125 15.185547 C 17.8125 15.411241 17.820095 15.655599 17.833984 15.916016 C 17.847873 16.176432 17.907552 16.528212 18.011719 16.972656 L 20.808594 12.591797 C 20.63151 12.26888 20.438802 12.052517 20.230469 11.941406 C 20.025608 11.826823 19.812066 11.769531 19.589844 11.769531 z M 14.761719 13.556641 L 11.984375 17.962891 C 12.133681 18.216363 12.305556 18.406684 12.5 18.535156 C 12.694444 18.660156 12.91276 18.722656 13.152344 18.722656 C 13.812066 18.722656 14.280816 18.355252 14.558594 17.619141 C 14.836372 16.879557 14.974609 16.059462 14.974609 15.160156 C 14.974609 14.604601 14.90408 14.07053 14.761719 13.556641 z M 21.15625 13.556641 L 18.380859 17.962891 C 18.530165 18.216363 18.70204 18.406684 18.896484 18.535156 C 19.090929 18.660156 19.307292 18.722656 19.546875 18.722656 C 20.206597 18.722656 20.675347 18.355252 20.953125 17.619141 C 21.230903 16.879557 21.371094 16.059462 21.371094 15.160156 C 21.371094 14.604601 21.298611 14.07053 21.15625 13.556641 z" />
|
||||
</graphic>
|
||||
</Tab>
|
||||
<Tab fx:id="PatchesTabHolder" closable="false">
|
||||
<content>
|
||||
<fx:include fx:id="PatchesTab" source="PatchesTab.fxml" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" VBox.vgrow="ALWAYS" />
|
||||
</content>
|
||||
<graphic>
|
||||
<SVGPath content="M 5.8828125 0.2109375 C 5.0191331 0.17810553 4.0925755 0.5807669 3.421875 1.3671875 L 0.88671875 4.3398438 C -0.18640328 5.598116 -0.18550892 7.3497981 0.890625 8.2675781 L 4.625 11.451172 L 0.76367188 14.517578 C -0.34380932 15.397272 -0.4055432 17.146472 0.62304688 18.441406 L 3.0527344 21.501953 C 4.0813235 22.796885 5.8007221 23.131646 6.9082031 22.251953 L 12.283203 17.982422 L 17.5 22.431641 C 18.57613 23.34942 20.305782 23.07468 21.378906 21.816406 L 23.914062 18.84375 C 24.987183 17.585475 24.986236 15.833793 23.910156 14.916016 L 20.164062 11.722656 L 24.001953 8.6738281 C 25.109433 7.7941344 25.171167 6.0449323 24.142578 4.75 L 21.712891 1.6914062 C 20.684303 0.39647305 18.964905 0.059759405 17.857422 0.93945312 L 12.505859 5.1914062 L 7.3007812 0.75195312 C 6.8972331 0.40778617 6.4010201 0.23063678 5.8828125 0.2109375 z M 10.304688 5.703125 C 10.467609 5.685648 10.663263 5.7499911 10.828125 5.890625 L 11.210938 6.21875 L 6.5957031 9.8847656 L 10.060547 5.8242188 C 10.120897 5.7534558 10.206934 5.7136111 10.304688 5.703125 z M 14.550781 5.7402344 C 14.6898 5.7328444 14.815451 5.7759495 14.892578 5.8730469 L 18.494141 10.408203 C 18.648395 10.602401 18.552761 10.932817 18.28125 11.148438 L 10.611328 17.238281 C 10.339882 17.453897 9.9980038 17.47154 9.84375 17.277344 L 6.2421875 12.744141 C 6.0879337 12.549944 6.1836297 12.221473 6.4550781 12.005859 L 14.123047 5.9140625 C 14.258772 5.806255 14.411762 5.7476235 14.550781 5.7402344 z M 13.505859 7.1542969 A 0.76761252 0.76761252 0 0 0 13.0625 7.3222656 A 0.76761252 0.76761252 0 0 0 12.943359 8.4023438 A 0.76761252 0.76761252 0 0 0 14.023438 8.5195312 A 0.76761252 0.76761252 0 0 0 14.140625 7.4414062 A 0.76761252 0.76761252 0 0 0 13.505859 7.1542969 z M 16.201172 10.509766 A 0.76742482 0.76742482 0 0 0 15.757812 10.677734 A 0.76742482 0.76742482 0 0 0 15.640625 11.757812 A 0.76742482 0.76742482 0 0 0 16.71875 11.875 A 0.76742482 0.76742482 0 0 0 16.837891 10.796875 A 0.76742482 0.76742482 0 0 0 16.201172 10.509766 z M 12.322266 10.855469 A 0.76742482 0.76742482 0 0 0 11.878906 11.023438 A 0.76742482 0.76742482 0 0 0 11.759766 12.101562 A 0.76742482 0.76742482 0 0 0 12.839844 12.220703 A 0.76742482 0.76742482 0 0 0 12.957031 11.140625 A 0.76742482 0.76742482 0 0 0 12.322266 10.855469 z M 8.4589844 11.199219 A 0.76742482 0.76742482 0 0 0 8.0136719 11.367188 A 0.76742482 0.76742482 0 0 0 7.8964844 12.447266 A 0.76742482 0.76742482 0 0 0 8.9746094 12.566406 A 0.76742482 0.76742482 0 0 0 9.09375 11.486328 A 0.76742482 0.76742482 0 0 0 8.4589844 11.199219 z M 18.248047 13.244141 L 14.707031 17.396484 C 14.546099 17.585183 14.205167 17.555044 13.941406 17.330078 L 13.537109 16.986328 L 18.248047 13.244141 z M 11.15625 14.570312 A 0.76742482 0.76742482 0 0 0 10.712891 14.738281 A 0.76742482 0.76742482 0 0 0 10.595703 15.816406 A 0.76742482 0.76742482 0 0 0 11.671875 15.935547 A 0.76742482 0.76742482 0 0 0 11.791016 14.855469 A 0.76742482 0.76742482 0 0 0 11.15625 14.570312 z" />
|
||||
</graphic>
|
||||
</Tab>
|
||||
<Tab closable="false">
|
||||
<content>
|
||||
<fx:include fx:id="SettingsTab" source="SettingsTab.fxml" VBox.vgrow="ALWAYS" />
|
||||
|
|
122
src/main/resources/PatchesTab.fxml
Normal file
122
src/main/resources/PatchesTab.fxml
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.SVGPath?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<ScrollPane fitToWidth="true" onDragDropped="#handleDrop" onDragOver="#handleDragOver" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.PatchesController">
|
||||
<VBox fx:id="patchesToolPane" spacing="15.0">
|
||||
<Pane minHeight="-Infinity" prefHeight="10.0" style="-fx-background-color: linear-gradient(from 41px 34px to 50px 50px, reflect, #2cd882 40%, transparent 45%);" />
|
||||
<HBox alignment="CENTER">
|
||||
<children>
|
||||
<Label text="%tabPatches_Lbl_Title">
|
||||
<font>
|
||||
<Font name="System Bold" size="15.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</HBox>
|
||||
<GridPane>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" percentWidth="90.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Separator prefWidth="200.0" styleClass="strangeSeparator" GridPane.columnIndex="1" />
|
||||
</children>
|
||||
</GridPane>
|
||||
<VBox spacing="8.0">
|
||||
<children>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||
<children>
|
||||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Firmware" wrapText="true" />
|
||||
<Label fx:id="shortNameFirmwareLbl" textOverrun="LEADING_WORD_ELLIPSIS" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="selFwFolderBtn" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectFirmware" styleClass="buttonSelect" text="%tabSplMrg_Btn_SelectFolder" wrapText="true">
|
||||
<graphic>
|
||||
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
<Label fx:id="locationFirmwareLbl" disable="true" textOverrun="LEADING_WORD_ELLIPSIS">
|
||||
<font>
|
||||
<Font name="System Italic" size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</VBox>
|
||||
<Separator prefWidth="200.0" />
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||
<children>
|
||||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Keys" wrapText="true" />
|
||||
<Label fx:id="shortNameKeysLbl" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="selProdKeysBtn" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectProdKeys" styleClass="buttonSelect" text="%btn_Select">
|
||||
<graphic>
|
||||
<SVGPath content="M22,18V22H18V19H15V16H12L9.74,13.74C9.19,13.91 8.61,14 8,14A6,6 0 0,1 2,8A6,6 0 0,1 8,2A6,6 0 0,1 14,8C14,8.61 13.91,9.19 13.74,9.74L22,18M7,5A2,2 0 0,0 5,7A2,2 0 0,0 7,9A2,2 0 0,0 9,7A2,2 0 0,0 7,5Z" fill="#289de8" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
<Label fx:id="locationKeysLbl" disable="true" textOverrun="LEADING_WORD_ELLIPSIS">
|
||||
<font>
|
||||
<Font name="System Italic" size="13.0" />
|
||||
</font></Label>
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||
<children>
|
||||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabSplMrg_Lbl_SaveToLocation" wrapText="true" />
|
||||
<Label fx:id="saveToLbl" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="selProdKeysBtn1" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectSaveTo" styleClass="buttonSelect" text="%btn_Select">
|
||||
<graphic>
|
||||
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<VBox.margin>
|
||||
<Insets left="15.0" right="15.0" />
|
||||
</VBox.margin>
|
||||
</VBox>
|
||||
<HBox alignment="CENTER">
|
||||
<children>
|
||||
<Label fx:id="statusLbl" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Pane VBox.vgrow="ALWAYS" />
|
||||
<HBox alignment="CENTER">
|
||||
<children>
|
||||
<Button fx:id="makeEsBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabPatches_Btn_MakeEs" />
|
||||
</children>
|
||||
</HBox>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
</ScrollPane>
|
|
@ -79,3 +79,14 @@ windowBodyFilesScanned=Files scanned: %d\nWould be added: %d
|
|||
tab2_Lbl_AwooBlockTitle=Awoo Installer and compatible
|
||||
tabRcm_Lbl_Payload=Payload:
|
||||
tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
|
||||
tabPatches_Lbl_Firmware=Firmware:
|
||||
tabPatches_Lbl_Atmo=Atmosphere:
|
||||
tabPatches_Btn_fromFolder=From folder
|
||||
tabPatches_Btn_asZipFile=as ZIP file
|
||||
tabPatches_Lbl_Title=Patches
|
||||
tabPatches_Lbl_Keys=Keys:
|
||||
tabPatches_Btn_MakeEs=Make ES
|
||||
tabPatches_Btn_MakeFs=Make FS
|
||||
tabPatches_Btn_MakeAtmo=Make Atmo
|
||||
tabPatches_Btn_MakeAll=Make all
|
||||
tabPatches_ServiceWindowMessage=Both firmware and keys should be set to generate patches. Otherwise, it's not clear what to patch.
|
||||
|
|
|
@ -77,5 +77,16 @@ windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u043E\u0432 \u043F\u0440\u043E\u
|
|||
tab2_Lbl_AwooBlockTitle=Awoo Installer \u0438 \u0441\u043E\u0432\u043C\u0435\u0441\u0442\u0438\u043C\u044B\u0435
|
||||
tabRcm_Lbl_Payload=Payload:
|
||||
tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
|
||||
tabPatches_Btn_asZipFile=\u0432 \u0432\u0438\u0434\u0435 ZIP
|
||||
tabPatches_Btn_fromFolder=\u0418\u0437 \u043F\u0430\u043F\u043A\u0438
|
||||
tabPatches_Btn_MakeAll=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0441\u0451
|
||||
tabPatches_Btn_MakeAtmo=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F Atmo
|
||||
tabPatches_Btn_MakeEs=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F ES
|
||||
tabPatches_Btn_MakeFs=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F FS
|
||||
tabPatches_Lbl_Atmo=Atmosphere:
|
||||
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
||||
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0438
|
||||
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
|
||||
tabPatches_ServiceWindowMessage=\u0414\u043B\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u0430\u0442\u0447\u0435\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043A\u0430\u043A \u043F\u0443\u0442\u044C \u043A \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0435, \u0442\u0430\u043A \u0438 \u043F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0435\u0439. \u0418\u043D\u0430\u0447\u0435 \u043D\u0435 \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u0447\u0442\u043E \u0436\u0435 \u043F\u0430\u0442\u0447\u0438\u0442\u044C.
|
||||
|
||||
|
||||
|
|
|
@ -77,4 +77,15 @@ windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u0456\u0432 \u043F\u0440\u043E\u
|
|||
tab2_Lbl_AwooBlockTitle=Awoo Installer \u0442\u0430 \u0441\u0443\u043C\u0456\u0441\u043D\u0456
|
||||
tabRcm_Lbl_Payload=Payload:
|
||||
tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
|
||||
tabPatches_Btn_asZipFile=\u044F\u043A ZIP
|
||||
tabPatches_Btn_fromFolder=\u0417 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0456\u0457
|
||||
tabPatches_Btn_MakeAll=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0432\u0441\u0456
|
||||
tabPatches_Btn_MakeAtmo=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F Atmo
|
||||
tabPatches_Btn_MakeEs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F ES
|
||||
tabPatches_Btn_MakeFs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F FS
|
||||
tabPatches_Lbl_Atmo=Atmosphere:
|
||||
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
||||
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0456
|
||||
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
|
||||
tabPatches_ServiceWindowMessage=\u0414\u043B\u044F \u0441\u0442\u0432\u043E\u0440\u0435\u043D\u043D\u044F \u043F\u0430\u0442\u0447\u0456\u0432 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u043E \u0432\u043A\u0430\u0437\u0430\u0442\u0438 \u044F\u043A \u0448\u043B\u044F\u0445 \u0434\u043E \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0438, \u0442\u0430\u043A \u0456 \u0434\u043E \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0456\u0432. \u0411\u043E \u0456\u043D\u0430\u043A\u0448\u0435 \u043D\u0435 \u0437\u0440\u043E\u0437\u0443\u043C\u0456\u043B\u043E \u0449\u043E \u0436 \u0442\u0440\u0435\u0431\u0430 \u043F\u0430\u0442\u0447\u0438\u0442\u0438.
|
||||
|
||||
|
|
|
@ -409,6 +409,13 @@
|
|||
-fx-min-height: 24;
|
||||
-fx-min-width: 36;
|
||||
}
|
||||
.regionCake{
|
||||
-fx-shape: "M12,1.5A2.5,2.5 0 0,1 14.5,4A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 9.5,4A2.5,2.5 0 0,1 12,1.5M15.87,5C18,5 20,7 20,9C22.7,9 22.7,13 20,13H4C1.3,13 1.3,9 4,9C4,7 6,5 8.13,5C8.57,6.73 10.14,8 12,8C13.86,8 15.43,6.73 15.87,5M5,15H8L9,22H7L5,15M10,15H14L13,22H11L10,15M16,15H19L17,22H15L16,15Z";
|
||||
-fx-background-color: #71e016;
|
||||
-size: 24;
|
||||
-fx-min-height: -size;
|
||||
-fx-min-width: -size;
|
||||
}
|
||||
.regionDump{
|
||||
-fx-shape: "M 4.0078125 0 C 1.5078125 0 0 1.4882812 0 3.984375 L 0 15.988281 C 0 18.417969 1.4927148 20 4.0078125 20 L 6.5 20 L 6.5 0 L 4.0078125 0 z M 23.5 0 L 23.5 20 C 24.504057 19.999294 25.159942 20 25.992188 20 C 28.414062 20 30 18.496094 30 15.996094 L 30 3.9765625 C 30 1.5195311 28.508726 0 26.003906 0 L 23.5 0 z M 11.990234 2.8886719 L 11.990234 9.9003906 L 6.9902344 9.9003906 L 14.990234 20 L 22.990234 9.9003906 L 17.990234 9.9003906 C 17.990234 8.2387016 17.9999 3.6538029 18 2.8886719 L 11.990234 2.8886719 z M 3.1015625 2.9570312 C 4.1485235 2.9562481 4.9977514 3.8046013 4.9980469 4.8515625 C 4.998831 5.8992865 4.1492865 6.7488309 3.1015625 6.7480469 C 2.0546013 6.7477509 1.2062483 5.8985235 1.2070312 4.8515625 C 1.2073268 3.8053642 2.0553642 2.9573267 3.1015625 2.9570312 z M 26.865234 11.148438 C 27.912958 11.147652 28.762503 11.997198 28.761719 13.044922 C 28.761423 14.091883 27.912195 14.940236 26.865234 14.939453 C 25.819036 14.939158 24.970999 14.09112 24.970703 13.044922 C 24.96992 11.997961 25.818273 11.148733 26.865234 11.148438 z ";
|
||||
-fx-background-color: #71e016;
|
||||
|
|
|
@ -327,6 +327,13 @@
|
|||
-fx-min-height: 24;
|
||||
-fx-min-width: 36;
|
||||
}
|
||||
.regionCake{
|
||||
-fx-shape: "M12,1.5A2.5,2.5 0 0,1 14.5,4A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 9.5,4A2.5,2.5 0 0,1 12,1.5M15.87,5C18,5 20,7 20,9C22.7,9 22.7,13 20,13H4C1.3,13 1.3,9 4,9C4,7 6,5 8.13,5C8.57,6.73 10.14,8 12,8C13.86,8 15.43,6.73 15.87,5M5,15H8L9,22H7L5,15M10,15H14L13,22H11L10,15M16,15H19L17,22H15L16,15Z";
|
||||
-fx-background-color: #71e016;
|
||||
-size: 24;
|
||||
-fx-min-height: -size;
|
||||
-fx-min-width: -size;
|
||||
}
|
||||
.regionDump{
|
||||
-fx-shape: "M 4.0078125 0 C 1.5078125 0 0 1.4882812 0 3.984375 L 0 15.988281 C 0 18.417969 1.4927148 20 4.0078125 20 L 6.5 20 L 6.5 0 L 4.0078125 0 z M 23.5 0 L 23.5 20 C 24.504057 19.999294 25.159942 20 25.992188 20 C 28.414062 20 30 18.496094 30 15.996094 L 30 3.9765625 C 30 1.5195311 28.508726 0 26.003906 0 L 23.5 0 z M 11.990234 2.8886719 L 11.990234 9.9003906 L 6.9902344 9.9003906 L 14.990234 20 L 22.990234 9.9003906 L 17.990234 9.9003906 C 17.990234 8.2387016 17.9999 3.6538029 18 2.8886719 L 11.990234 2.8886719 z M 3.1015625 2.9570312 C 4.1485235 2.9562481 4.9977514 3.8046013 4.9980469 4.8515625 C 4.998831 5.8992865 4.1492865 6.7488309 3.1015625 6.7480469 C 2.0546013 6.7477509 1.2062483 5.8985235 1.2070312 4.8515625 C 1.2073268 3.8053642 2.0553642 2.9573267 3.1015625 2.9570312 z M 26.865234 11.148438 C 27.912958 11.147652 28.762503 11.997198 28.761719 13.044922 C 28.761423 14.091883 27.912195 14.940236 26.865234 14.939453 C 25.819036 14.939158 24.970999 14.09112 24.970703 13.044922 C 24.96992 11.997961 25.818273 11.148733 26.865234 11.148438 z ";
|
||||
-fx-background-color: #71e016;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue