Corrections at front and back end
continuous-integration/drone/push Build is passing Details

master
Dmitry Isaenko 2023-02-04 15:25:34 +03:00
parent f8b60af41b
commit 6c51b8e1b6
20 changed files with 531 additions and 887 deletions

View File

@ -18,6 +18,7 @@
*/
package nsusbloader.Controllers;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.input.DragEvent;
@ -74,7 +75,10 @@ public class PatchesController implements Initializable {
convertRegionEs = new Region();
convertRegionEs.getStyleClass().add("regionCake");
makeEsBtn.setGraphic(convertRegionEs);
//makeFsBtn.setGraphic(convertRegionEs);
Region cakeRegionFs = new Region();
cakeRegionFs.getStyleClass().add("regionCake");
makeFsBtn.setGraphic(cakeRegionFs);
AppPreferences preferences = AppPreferences.getInstance();
String keysLocation = preferences.getKeysLocation();
@ -85,8 +89,10 @@ public class PatchesController implements Initializable {
}
saveToLbl.setText(preferences.getPatchesSaveToLocation());
//makeEsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
makeEsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
makeEsBtn.setOnAction(actionEvent -> makeEs());
makeFsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
makeFsBtn.setOnAction(actionEvent -> makeFs());
}
@ -215,6 +221,7 @@ public class PatchesController implements Initializable {
}
convertRegionEs.getStyleClass().clear();
makeFsBtn.setVisible(! isActive);
if (isActive) {
MediatorControl.getInstance().getContoller().logArea.clear();

View File

@ -59,7 +59,7 @@ public class BinToAsmPrinter {
return printMOV(instructionExpression);
case 0x62:
if (((instructionExpression & 0x1f) == 0x1f)){
return printCMN(instructionExpression, offset);
return printCMN(instructionExpression);
}
}
@ -123,10 +123,10 @@ public class BinToAsmPrinter {
case 0xA2:
return printSUBSimplified(instructionExpression, offset);
case 0xE2:
case 0x1e2:
//case 0x1e2:
return printCMPSimplified(instructionExpression, offset);
case 0x24:
case 0x124:
//case 0x124:
return printANDSimplified(instructionExpression, offset);
}
@ -144,13 +144,15 @@ public class BinToAsmPrinter {
return printBConditionalSimplified(instructionExpression, offset);
}
switch ((instructionExpression >> 26 & 0b111111)) {
switch (instructionExpression >> 26 & 0b111111) {
case 0x5:
return printBSimplified(instructionExpression, offset);
case 0x25:
return printBLSimplified(instructionExpression, offset);
}
System.out.printf("0x%x\n", (instructionExpression >> 23 & 0xff));
if ((instructionExpression >> 10 & 0x3FFFFF) == 0x3597c0 && ((instructionExpression & 0x1F) == 0))
return printRetSimplified(instructionExpression, offset);
return printUnknownSimplified(instructionExpression, offset);
}
@ -183,7 +185,7 @@ public class BinToAsmPrinter {
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printCMN(int instructionExpression, int offset){
private static String printCMN(int instructionExpression){
int Rn = instructionExpression >> 5 & 0x1F;
int imm = instructionExpression >> 10 & 0xFFF;
@ -271,7 +273,6 @@ public class BinToAsmPrinter {
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" +
@ -382,8 +383,6 @@ public class BinToAsmPrinter {
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
}
private static String printMOVSimplified(int instructionExpression, int offset){
int imm16 = instructionExpression >> 5 & 0xFFFF;
int sfHw = (instructionExpression >> 22 & 1);
@ -404,9 +403,8 @@ public class BinToAsmPrinter {
int xwSelector = (instructionExpression >> 31 & 1);
int imm = instructionExpression >> 18 & 0b11111;
int Rt = instructionExpression & 0b11111;
int label = (offset + (instructionExpression >> 5 & 0x3fff) * 4) & 0xfffff;
int label = offset + (instructionExpression >> 5 & 0x3fff) * 4;
//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,
@ -440,7 +438,6 @@ public class BinToAsmPrinter {
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 & 0x1F;
@ -517,6 +514,14 @@ public class BinToAsmPrinter {
offset, Integer.reverseBytes(instructionExpression), instructionExpression, Rn, Rd, Converter.intToBinaryString(imm));
}
private static String printRetSimplified(int instructionExpression, int offset){
int Xn = (instructionExpression >> 5) & 0x1F;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " RET " + ANSI_GREEN + " X%d" + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression, Xn == 0 ? 30 : Xn);
}
private static String printUnknownSimplified(int instructionExpression, int offset){
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " ??? 0b"+ANSI_RESET+ Converter.intToBinaryString(instructionExpression) +"\n",

View File

@ -0,0 +1,26 @@
/*
Copyright 2019-2023 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;
public class MalformedIniFileException extends Exception{
public MalformedIniFileException(){}
public MalformedIniFileException(String message){
super(message);
}
}

View File

@ -40,6 +40,9 @@ import java.nio.file.Paths;
import java.util.Arrays;
public class EsPatch {
private static final byte[] HEADER = "PATCH".getBytes(StandardCharsets.US_ASCII);
private static final byte[] FOOTER = "EOF".getBytes(StandardCharsets.US_ASCII);
private final NCAProvider ncaProvider;
private final String saveToLocation;
private final ILogPrinter logPrinter;
@ -66,10 +69,10 @@ public class EsPatch {
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);
if (fwVersion < 9300)
final byte[] byteSdkVersion = ncaProvider.getSdkVersion();
fwVersion = Long.parseLong(""+byteSdkVersion[3]+byteSdkVersion[2]+byteSdkVersion[1]+byteSdkVersion[0]);
logPrinter.print("Internal firmware version: "+byteSdkVersion[3] +"."+byteSdkVersion[2] +"."+byteSdkVersion[1] +"."+byteSdkVersion[0], EMsgType.INFO);
if (byteSdkVersion[3] < 9 || fwVersion < 9300)
logPrinter.print("WARNING! FIRMWARES VERSIONS BEFORE 9.0.0 ARE NOT SUPPORTED! USING PRODUCED ES PATCHES (IF ANY) COULD BREAK SOMETHING! IT'S NEVER BEEN TESTED!", EMsgType.WARNING);
}
private void getBuildId(NSO0Provider nso0Provider) throws Exception{
@ -99,7 +102,7 @@ public class EsPatch {
int offset3 = wizard.getOffset3();
ByteBuffer handyEsPatch = ByteBuffer.allocate(0x23).order(ByteOrder.LITTLE_ENDIAN);
handyEsPatch.put(getHeader());
handyEsPatch.put(HEADER);
if (offset1 > 0) {
logPrinter.print("Patch component 1 will be used", EMsgType.PASS);
handyEsPatch.put(getPatch1(offset1));
@ -112,7 +115,7 @@ public class EsPatch {
logPrinter.print("Patch component 3 will be used", EMsgType.PASS);
handyEsPatch.put(getPatch3(offset3));
}
handyEsPatch.put(getFooter());
handyEsPatch.put(FOOTER);
try (BufferedOutputStream stream = new BufferedOutputStream(
Files.newOutputStream(Paths.get(patchFileLocation)))){
@ -120,12 +123,6 @@ public class EsPatch {
}
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
@ -147,15 +144,15 @@ public class EsPatch {
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}
private byte[] getPatch2(int offset) throws Exception{
final int NopExpression = 0x1F2003D5; // reversed
final int NopInstruction = 0x1F2003D5; // reversed
int offsetReal = offset - 4 + 0x100;
logPrinter.print(BinToAsmPrinter.printSimplified(Integer.reverseBytes(NopExpression), offset - 4), EMsgType.NULL);
logPrinter.print(BinToAsmPrinter.printSimplified(Integer.reverseBytes(NopInstruction), offset - 4), EMsgType.NULL);
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
.putInt(offsetReal)
.putShort((short) 4)
.putInt(NopExpression);
.putInt(NopInstruction);
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}

View File

@ -31,7 +31,7 @@ import java.util.*;
import java.util.concurrent.*;
public class EsPatchMaker extends CancellableRunnable {
private int THREADS_POOL_SIZE = 4;
private int THREADS_POOL_SIZE;
private final ILogPrinter logPrinter;
private final String pathToFirmware;
private final String pathToKeysFile;
@ -45,20 +45,14 @@ public class EsPatchMaker extends CancellableRunnable {
private boolean oneLinerStatus = false;
public EsPatchMaker(String pathToFirmware, String pathToKeysFile, String saveTo){
this.logPrinter = Log.getPrinter(EModule.PATCHES); //TODO: UNCOMMENT
this.logPrinter = Log.getPrinter(EModule.PATCHES);
/*
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() {}
};
*/
@ -74,7 +68,7 @@ public class EsPatchMaker extends CancellableRunnable {
receiveFirmware();
buildKeyChainHolder();
receiveNcaFileNamesList();
adjustThreadsPoolSize();
specifyThreadsPoolSize();
createPool();
executePool();
}
@ -106,9 +100,9 @@ public class EsPatchMaker extends CancellableRunnable {
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 specifyThreadsPoolSize(){
THREADS_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()+1, 4);
THREADS_POOL_SIZE = Math.min(THREADS_POOL_SIZE, ncaFilesList.size());
}
private void createPool() throws Exception{
@ -170,9 +164,8 @@ public class EsPatchMaker extends CancellableRunnable {
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));
int leftovers = ncaFilesList.size() % THREADS_POOL_SIZE;
Callable<NCAProvider> task = new EsNcaSearchTask(getNextSet(iterator, ncaPerThreadAmount+leftovers));
subTasks.add(task);
return subTasks;
}

View File

@ -83,7 +83,6 @@ class HeuristicEs1 extends AHeuristic {
@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;
@ -91,15 +90,13 @@ class HeuristicEs1 extends AHeuristic {
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();
return BinToAsmPrinter.printSimplified(instructionExpression, cbzOffsetInternal) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal + 4),
cbzOffsetInternal + 4) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal + 8),
cbzOffsetInternal + 8) +
"...\n" +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4);
}
}

View File

@ -132,7 +132,6 @@ class HeuristicEs2 extends AHeuristic {
@Override
public String getDetails(){
StringBuilder builder = new StringBuilder();
int secondExpressionOffset = findings.get(0);
int firstExpression = Converter.getLEint(where, secondExpressionOffset-4);
@ -149,16 +148,13 @@ class HeuristicEs2 extends AHeuristic {
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();
return BinToAsmPrinter.printSimplified(Converter.getLEint(where, secondExpressionOffset - 4), secondExpressionOffset - 4) +
BinToAsmPrinter.printSimplified(secondExpression, secondExpressionOffset) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, secondExpressionOffset + 4), secondExpressionOffset + 4) +
"...\n" +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement3, conditionalJumpLocation + 8) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement4, conditionalJumpLocation + 12);
}
}

View File

@ -112,17 +112,15 @@ class HeuristicEs3 extends AHeuristic {
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);
StringBuilder builder = new StringBuilder();
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));
@ -137,7 +135,6 @@ class HeuristicEs3 extends AHeuristic {
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)");

View File

@ -21,10 +21,11 @@ package nsusbloader.Utilities.patches.fs;
import libKonogonka.Converter;
import libKonogonka.fs.NCA.NCAProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
class FsNcaSearchTask implements Callable<NCAProvider> {
class FsNcaSearchTask implements Callable<List<NCAProvider>> {
private final List<NCAProvider> ncaProviders;
FsNcaSearchTask(List<NCAProvider> ncaProviders){
@ -32,19 +33,18 @@ class FsNcaSearchTask implements Callable<NCAProvider> {
}
@Override
public NCAProvider call() {
public List<NCAProvider> call() {
List<NCAProvider> result = new ArrayList<>();
try {
for (NCAProvider ncaProvider : ncaProviders) {
String titleId = Converter.byteArrToHexStringAsLE(ncaProvider.getTitleId());
if (titleId.equals("0100000000000819") || titleId.equals("010000000000081b")) { // eq. FAT || exFAT
return ncaProvider;
}
if (titleId.equals("0100000000000819") || titleId.equals("010000000000081b")) // eq. FAT32 || exFAT
result.add(ncaProvider);
}
return null;
}
catch (Exception e){
e.printStackTrace();
return null;
}
return result;
}
}

View File

@ -16,16 +16,13 @@
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 FS-AutoIPS.py patch script made by GBATemp member MrDude.
Taken from: https://gbatemp.net/threads/info-on-sha-256-hashes-on-fs-patches.581550/
Based on https://github.com/mrdude2478/IPS_Patch_Creator patch script made by GBATemp member MrDude.
*/
package nsusbloader.Utilities.patches.fs;
import libKonogonka.Converter;
import libKonogonka.KeyChainHolder;
import libKonogonka.RainbowDump;
import libKonogonka.fs.NCA.NCAProvider;
import libKonogonka.fs.NSO.NSO0Provider;
import libKonogonka.fs.RomFs.FileSystemEntry;
import libKonogonka.fs.RomFs.RomFsProvider;
import libKonogonka.fs.other.System2.System2Provider;
@ -37,9 +34,7 @@ import nsusbloader.NSLDataTypes.EMsgType;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.fs.finders.HeuristicFsWizard;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
@ -50,22 +45,26 @@ import java.util.Arrays;
import java.util.stream.Collectors;
public class FsPatch {
private static final byte[] HEADER = "PATCH".getBytes(StandardCharsets.US_ASCII);
private static final byte[] FOOTER = "EOF".getBytes(StandardCharsets.US_ASCII);
private final NCAProvider ncaProvider;
private final String saveToLocation;
private final KeyChainHolder keyChainHolder;
private final ILogPrinter logPrinter;
private long fwVersion;
private String patchName;
private byte[] _textSection;
private boolean filesystemTypeFat32;
private HeuristicFsWizard wizard;
FsPatch(NCAProvider ncaProvider, String saveToLocation, KeyChainHolder keyChainHolder, ILogPrinter logPrinter) throws Exception{
// Called twice: once for FAT32, once for ExFAT
FsPatch(NCAProvider ncaProvider,
String saveToLocation,
KeyChainHolder keyChainHolder,
ILogPrinter logPrinter) throws Exception{
this.ncaProvider = ncaProvider;
this.saveToLocation = saveToLocation + File.separator +
"atmosphere" + File.separator + "kip_patches" + File.separator + "fs_patches";
this.saveToLocation = saveToLocation;
this.keyChainHolder = keyChainHolder;
this.logPrinter = logPrinter;
@ -75,15 +74,22 @@ public class FsPatch {
checkFirmwareVersion();
getFilesystemType();
findAllOffsets();
//mkDirs();
//writeFile();
//updatePatchesIni();
//logPrinter.print(" == Debug information ==\n"+wizard.getDebug(), EMsgType.NULL);
mkDirs();
writeFile();
new IniMaker(logPrinter,
saveToLocation,
_textSection,
wizard.getOffset1(),
wizard.getOffset2(),
ncaProvider.getSdkVersion(),
patchName,
filesystemTypeFat32);
logPrinter.print(" == Debug information ==\n"+wizard.getDebug(), EMsgType.NULL);
}
private KIP1Provider getKIP1Provider() throws Exception{
RomFsProvider romFsProvider = ncaProvider.getNCAContentProvider(0).getRomfs();
FileSystemEntry package2FSEntry = romFsProvider.getRootEntry().getContent()
FileSystemEntry package2FsEntry = romFsProvider.getRootEntry().getContent()
.stream()
.filter(e -> e.getName().equals("nx"))
.collect(Collectors.toList())
@ -93,7 +99,7 @@ public class FsPatch {
.filter(e -> e.getName().equals("package2"))
.collect(Collectors.toList())
.get(0);
InFileStreamProducer producer = romFsProvider.getStreamProducer(package2FSEntry);
InFileStreamProducer producer = romFsProvider.getStreamProducer(package2FsEntry);
System2Provider system2Provider = new System2Provider(producer, keyChainHolder);
Ini1Provider ini1Provider = system2Provider.getIni1Provider();
@ -104,6 +110,7 @@ public class FsPatch {
if (kip1Provider == null)
throw new Exception("No FS KIP1");
return kip1Provider;
}
private void getPatchName(KIP1Provider kip1Provider) throws Exception{
@ -123,85 +130,87 @@ public class FsPatch {
}
private void checkFirmwareVersion() throws Exception{
final byte[] byteSdkVersion = ncaProvider.getSdkVersion();
fwVersion = Long.parseLong(""+byteSdkVersion[3] + byteSdkVersion[2] + byteSdkVersion[1] + byteSdkVersion[0]);
logPrinter.print("Internal firmware version: " +
byteSdkVersion[3] +"."+byteSdkVersion[2] +"."+byteSdkVersion[1] +"."+byteSdkVersion[0], EMsgType.INFO);
System.out.println("FW "+byteSdkVersion[3] +"."+byteSdkVersion[2] +"."+byteSdkVersion[1] +"."+byteSdkVersion[0]); // TODO:REMOVE!
if (fwVersion < 9300)
long fwVersion = Long.parseLong(""+byteSdkVersion[3]+byteSdkVersion[2]+byteSdkVersion[1]+byteSdkVersion[0]);
logPrinter.print("Internal firmware version: " + byteSdkVersion[3] +"."+ byteSdkVersion[2] +"."+ byteSdkVersion[1] +"."+ byteSdkVersion[0], EMsgType.INFO);
if (byteSdkVersion[3] < 9 || fwVersion < 9300)
logPrinter.print("WARNING! FIRMWARES VERSIONS BEFORE 9.0.0 ARE NOT SUPPORTED! " +
"USING PRODUCED ES PATCHES (IF ANY) COULD BREAK SOMETHING! IT'S NEVER BEEN TESTED!", EMsgType.WARNING);
}
private void getFilesystemType(){
private void getFilesystemType() throws Exception{
String titleId = Converter.byteArrToHexStringAsLE(ncaProvider.getTitleId());
filesystemTypeFat32 = titleId.equals("0100000000000819");
if (filesystemTypeFat32)
logPrinter.print("\n\t\t-- [ FAT32 ] --\n", EMsgType.INFO);
else
logPrinter.print("\n\t\t-- [ ExFAT ] --\n", EMsgType.INFO);
}
private void findAllOffsets() throws Exception{
// TODO: FIX, IMPLEMENT, DEPLOY
this.wizard = new HeuristicFsWizard(fwVersion, _textSection, filesystemTypeFat32);
this.wizard = new HeuristicFsWizard(_textSection);
String errorsAndNotes = wizard.getErrorsAndNotes();
if (errorsAndNotes.length() > 0)
logPrinter.print(errorsAndNotes, EMsgType.WARNING);
}
private void mkDirs(){
File parentFolder = new File(saveToLocation);
File parentFolder = new File(saveToLocation + File.separator +
"atmosphere" + File.separator + "kip_patches" + File.separator + "fs_patches");
parentFolder.mkdirs();
}
private void writeFile() throws Exception{
String patchFileLocation = saveToLocation + File.separator + patchName; // THIS IS GOOD
String patchFileLocation = saveToLocation + File.separator +
"atmosphere" + File.separator + "kip_patches" + File.separator + "fs_patches" + File.separator + patchName;
int offset1 = wizard.getOffset1();
int offset2 = wizard.getOffset2();
ByteBuffer handyFsPatch = ByteBuffer.allocate(0x23).order(ByteOrder.LITTLE_ENDIAN);
handyFsPatch.put(getHeader());
// TODO: FIX, UPDATE
ByteBuffer handyFsPatch = ByteBuffer.allocate(0x100).order(ByteOrder.LITTLE_ENDIAN);
handyFsPatch.put(HEADER);
if (offset1 > 0) {
logPrinter.print("Patch component 1 will be used", EMsgType.PASS);
handyFsPatch.put(getPatch1(offset1));
}
handyFsPatch.put(getFooter());
if (offset2 > 0) {
logPrinter.print("Patch component 2 will be used", EMsgType.PASS);
handyFsPatch.put(getPatch2(offset2));
}
handyFsPatch.put(FOOTER);
byte[] fsPatch = new byte[handyFsPatch.position()];
handyFsPatch.rewind();
handyFsPatch.get(fsPatch);
try (BufferedOutputStream stream = new BufferedOutputStream(
Files.newOutputStream(Paths.get(patchFileLocation)))){
stream.write(handyFsPatch.array());
stream.write(fsPatch);
}
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);
}
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);
final int patch = 0x1F2003D5; // NOP
logPrinter.print(BinToAsmPrinter.printSimplified(patch, requiredInstructionOffsetInternal), EMsgType.NULL);
logPrinter.print(BinToAsmPrinter.printSimplified(Integer.reverseBytes(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));
.putInt(patch);
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}
private byte[] getPatch2(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);
final int patch = 0xE0031F2A; // mov w0, wzr
logPrinter.print(BinToAsmPrinter.printSimplified(Integer.reverseBytes(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));
.putInt(patch);
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}

View File

@ -22,15 +22,16 @@ import libKonogonka.KeyChainHolder;
import libKonogonka.fs.NCA.NCAProvider;
import nsusbloader.ModelControllers.CancellableRunnable;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.ModelControllers.Log;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
import nsusbloader.NSLDataTypes.EFileStatus;
import java.io.File;
import java.util.*;
import java.util.concurrent.*;
public class FsPatchMaker extends CancellableRunnable {
private int THREADS_POOL_SIZE = 4;
private int THREADS_POOL_SIZE;
private final ILogPrinter logPrinter;
private final String pathToFirmware;
private final String pathToKeysFile;
@ -44,23 +45,17 @@ public class FsPatchMaker extends CancellableRunnable {
private boolean oneLinerStatus = false;
public FsPatchMaker(String pathToFirmware, String pathToKeysFile, String saveTo){
//this.logPrinter = Log.getPrinter(EModule.PATCHES); //TODO: UNCOMMENT
this.logPrinter = Log.getPrinter(EModule.PATCHES);
/*
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;
@ -73,7 +68,7 @@ public class FsPatchMaker extends CancellableRunnable {
receiveFirmware();
buildKeyChainHolder();
receiveNcaFileNamesList();
adjustThreadsPoolSize();
specifyThreadsPoolSize();
createPool();
executePool();
}
@ -106,9 +101,9 @@ public class FsPatchMaker extends CancellableRunnable {
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 specifyThreadsPoolSize(){
THREADS_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()+1, 4);
THREADS_POOL_SIZE = Math.min(THREADS_POOL_SIZE, ncaFilesList.size());
}
private void createPool() throws Exception{
@ -125,11 +120,11 @@ public class FsPatchMaker extends CancellableRunnable {
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());
List<Future<List<NCAProvider>>> futuresResults = executorService.invokeAll(getSubTasksCollection());
int counter = 0;
for (Future<NCAProvider> future : futuresResults){
NCAProvider ncaProvider = future.get();
if (ncaProvider != null) {
for (Future<List<NCAProvider>> future : futuresResults){
List<NCAProvider> ncaProviders = future.get();
for (NCAProvider ncaProvider : ncaProviders) {
makePatches(ncaProvider);
if (++counter > 1)
break;
@ -155,27 +150,25 @@ public class FsPatchMaker extends CancellableRunnable {
}
private void makePatches(NCAProvider ncaProvider) throws Exception{
final File foundFile = ncaProvider.getFile();
logPrinter.print(String.format("File found: .."+File.separator+"%s"+File.separator+"%s",
ncaProvider.getFile().getParentFile().getName(), ncaProvider.getFile().getName())
, EMsgType.INFO);
//TODO : FIX; IMPLEMENT; DEPLOY ;)
foundFile.getParentFile().getName(), foundFile.getName()), EMsgType.INFO);
new FsPatch(ncaProvider, saveTo, keyChainHolder, logPrinter);
oneLinerStatus = true;
}
private List<Callable<NCAProvider>> getSubTasksCollection() throws Exception{
private List<Callable<List<NCAProvider>>> getSubTasksCollection() throws Exception{
logPrinter.print("Forming sub-tasks collection", EMsgType.INFO);
List<Callable<NCAProvider>> subTasks = new ArrayList<>();
List<Callable<List<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 FsNcaSearchTask(getNextSet(iterator, ncaPerThreadAmount));
Callable<List<NCAProvider>> task = new FsNcaSearchTask(getNextSet(iterator, ncaPerThreadAmount));
subTasks.add(task);
}
Callable<NCAProvider> task = new FsNcaSearchTask(getNextSet(iterator,
ncaFilesList.size() % THREADS_POOL_SIZE == 0 ? ncaPerThreadAmount : ncaPerThreadAmount+1));
int leftovers = ncaFilesList.size() % THREADS_POOL_SIZE;
Callable<List<NCAProvider>> task = new FsNcaSearchTask(getNextSet(iterator, ncaPerThreadAmount+leftovers));
subTasks.add(task);
return subTasks;
}

View File

@ -0,0 +1,163 @@
/*
Copyright 2019-2023 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.fs;
import libKonogonka.Converter;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import nsusbloader.Utilities.patches.MalformedIniFileException;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
public class IniMaker {
private static final String FILE_HEADER_TEXT = "# UTF-8\n" +
"# A KIP section is [kip1_name:sha256_hex_8bytes]\n" +
"# A patchset is .patch_name=kip_section_dec:offset_hex_0x:length_hex_0x:src_data_hex,dst_data_hex\n" +
"# _dec: 1 char decimal | _hex_0x: max u32 prefixed with 0x | _hex: hex array.\n" +
"# Kip1 section decimals: TEXT: 0, RODATA: 1, DATA: 2.\n"; // Sending good vibes to Mr. ITotalJustice
private final ILogPrinter logPrinter;
private final String saveToLocation;
private final int offset1;
private final int offset2;
private String firmwareVersionInformationNotice;
private String sectionDeclaration;
private String patchSet1;
private String patchSet2;
IniMaker(ILogPrinter logPrinter,
String saveToLocation,
byte[] _textSection,
int wizardOffset1,
int wizardOffset2,
byte[] sdkVersion,
String patchName,
boolean filesystemTypeFat32) throws Exception{
this.logPrinter = logPrinter;
this.saveToLocation = saveToLocation;
this.offset1 = wizardOffset1 - 4;
this.offset2 = wizardOffset2 - 4;
mkDirs();
makeFwVersionInformationNotice(filesystemTypeFat32, sdkVersion);
makeSectionDeclaration(patchName);
makePatchSet1(_textSection);
makePatchSet2(_textSection);
writeFile();
}
private void mkDirs(){
File parentFolder = new File(saveToLocation + File.separator + "bootloader");
parentFolder.mkdirs();
}
private void makeFwVersionInformationNotice(boolean isFat32, byte[] fwVersion){
String fwVersionFormatted = fwVersion[3]+"."+fwVersion[2]+"."+fwVersion[1]+"."+fwVersion[0];
if (isFat32)
firmwareVersionInformationNotice = "\n#FS "+fwVersionFormatted+"\n";
else
firmwareVersionInformationNotice = "\n#FS "+fwVersionFormatted+"-ExFAT\n";
}
private void makeSectionDeclaration(String patchName){
sectionDeclaration = "[FS:"+patchName.substring(0, 16)+"]";
}
private void makePatchSet1(byte[] _textSection){
if (offset1 > 0) {
byte[] originalInstruction = Arrays.copyOfRange(_textSection, offset1, offset1 + 4);
patchSet1 = String.format(".nosigchk=0:0x%02X:0x4:%s,1F2003D5",
offset1, Converter.byteArrToHexStringAsLE(originalInstruction, true));
}
}
private void makePatchSet2(byte[] _textSection){
if (offset2 > 0) {
byte[] originalInstruction = Arrays.copyOfRange(_textSection, offset2, offset2 + 4);
patchSet2 = String.format(".nosigchk=0:0x%02X:0x4:%s,E0031F2A",
offset2, Converter.byteArrToHexStringAsLE(originalInstruction, true));
}
}
private void writeFile() throws Exception{
final String iniLocation = saveToLocation + File.separator + "bootloader" + File.separator + "patches.ini";
final Path iniLocationPath = Paths.get(iniLocation);
boolean iniNotExists = Files.notExists(iniLocationPath);
try (RandomAccessFile ini = new RandomAccessFile(iniLocation, "rw")){
if (iniNotExists)
ini.writeBytes(FILE_HEADER_TEXT);
else {
String line;
while ((line = ini.readLine()) != null){
if (! line.startsWith(sectionDeclaration))
continue;
if (offset1 > 0) {
String expression1 = ini.readLine();
if (expression1 == null || ! expression1.startsWith(patchSet1))
throw new MalformedIniFileException("Somewhere near "+ini.getFilePointer());
}
String expression2 = ini.readLine();
if (offset2 > 0) {
if (expression2 == null || ! expression2.startsWith(patchSet2))
throw new MalformedIniFileException("Somewhere near "+ini.getFilePointer());
}
else {
if (expression2 == null || ! expression2.startsWith(".nosigchk"))
return;
throw new MalformedIniFileException("Somewhere near "+ini.getFilePointer());
}
return; // Ini file already contains correct information regarding patch file we made.
}
}
ini.writeBytes(firmwareVersionInformationNotice);
ini.writeBytes(sectionDeclaration);
ini.writeBytes("\n");
if (offset1 > 0) {
ini.writeBytes(patchSet1);
ini.writeBytes("\n");
}
if (offset2 > 0) {
ini.writeBytes(patchSet2);
ini.writeBytes("\n");
}
}
catch (MalformedIniFileException e){
e.printStackTrace();
logPrinter.print(
"Existing patches.ini file is malformed or contains incorrect (outdated) information regarding current patch.\n" +
"It's now saved at "+iniLocation+".OLD\n" +
"New patches.ini file created instead.", EMsgType.WARNING);
Files.move(iniLocationPath, Paths.get(iniLocation+".OLD"),
StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
writeFile();
}
}
}

View File

@ -0,0 +1,89 @@
/*
Copyright 2018-2023 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.fs.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.AHeuristic;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.SimplyFind;
import java.util.ArrayList;
import java.util.List;
class HeuristicFs1 extends AHeuristic {
private static final String PATTERN = "..0036....1F..71..0054..4839"; // TBZ
private final byte[] where;
private final List<Integer> findings;
HeuristicFs1(byte[] where) {
this.where = where;
this.findings = new ArrayList<>();
SimplyFind simplyfind = new SimplyFind(PATTERN, where);
simplyfind.getResults().forEach(var -> findings.add(var + 4));
}
@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() {
int offsetInternal = findings.get(0) - 4;
int firstExpression = Converter.getLEint(where, offsetInternal);
int conditionalJumpLocation = offsetInternal + (firstExpression >> 5 & 0x3fff) * 4;
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation + 4);
return BinToAsmPrinter.printSimplified(firstExpression, offsetInternal) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 4), offsetInternal + 4) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 8), offsetInternal + 8) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 12), offsetInternal + 12) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 16), offsetInternal + 16) +
"...\n" +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4);
}
}

View File

@ -0,0 +1,96 @@
/*
Copyright 2018-2023 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.fs.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.AHeuristic;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.SimplyFind;
import java.util.ArrayList;
import java.util.List;
class HeuristicFs2 extends AHeuristic {
private static final String PATTERN = "...94081c00121f050071..0054"; // "...94"->BL "081c0012"->AND "1f050071"->CMP "..0054"->B.cond (only '54' is signature!)
private final byte[] where;
private final List<Integer> findings;
HeuristicFs2(byte[] where){
this.where = where;
this.findings = new ArrayList<>();
SimplyFind simplyfind = new SimplyFind(PATTERN, where);
simplyfind.getResults().forEach(var -> findings.add(var + 4));
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep1);
}
// All matches are somewhere in 0x6xxxx-0x7xxxx, then let's just limit search field by 0x80000
private boolean dropStep1(int offsetOfPatternFound){
return (offsetOfPatternFound > 0x80000);
}
@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(){
int offsetInternal = findings.get(0) - 4;
int firstExpression = Converter.getLEint(where, offsetInternal);
int conditionalJumpLocation = ((firstExpression & 0x3ffffff) * 4 + offsetInternal) & 0xfffff;
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
return BinToAsmPrinter.printSimplified(firstExpression, offsetInternal) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 4), offsetInternal + 4) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 8), offsetInternal + 8) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, offsetInternal + 12), offsetInternal + 12) +
"...\n" +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4);
}
}

View File

@ -1,179 +0,0 @@
/*
Copyright 2018-2023 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.fs.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.AHeuristic;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.SimplyFind;
import java.util.List;
class HeuristicFsExFAT1 extends AHeuristic {
private static final String PATTERN0 = ".1e42b91fc14271";
private static final String PATTERN1 = "9408...1F05.....54";
private final List<Integer> findings;
private final byte[] where;
HeuristicFsExFAT1(long fwVersion, byte[] where){
this.where = where;
String pattern = getPattern(fwVersion);
SimplyFind simplyfind = new SimplyFind(pattern, where);
this.findings = simplyfind.getResults();
for (Integer find : findings)
System.out.println(getDetails(find));
/* FIXME
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 < 15300) // & fwVersion >= 9300
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();
}
public String getDetails(Integer value){
StringBuilder builder = new StringBuilder();
int cbzOffsetInternal = value - 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 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();
}
}

View File

@ -1,182 +0,0 @@
/*
Copyright 2018-2023 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.fs.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.AHeuristic;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.SimplyFind;
import java.util.List;
class HeuristicFsExFAT2 extends AHeuristic {
private static final String PATTERN0 = ".94081C00121F05007181000054";
private static final String PATTERN1 = "003688...1F";
private final List<Integer> findings;
private final byte[] where;
HeuristicFsExFAT2(long fwVersion, byte[] where){
this.where = where;
String pattern = getPattern(fwVersion);
SimplyFind simplyfind = new SimplyFind(pattern, where);
this.findings = simplyfind.getResults();
for (Integer find : findings)
System.out.println(getDetails(find));
/* FIXME
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 < 15300) // & fwVersion >= 9300
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();
}
public String getDetails(Integer value){
StringBuilder builder = new StringBuilder();
int cbzOffsetInternal = value - 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 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();
}
}

View File

@ -1,176 +0,0 @@
/*
Copyright 2018-2023 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.fs.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.AHeuristic;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.SimplyFind;
import java.util.ArrayList;
import java.util.List;
class HeuristicFsFAT1 extends AHeuristic {
private static final String PATTERN0 = ".1e42b91fc14271";
private static final String PATTERN1 = "...9408...1F05.....54"; // ...94 081C0012 1F050071 4101
/*
710006eba0 c0 02 40 f9 ldr x0 , [ x22 ]
710006eba4 5c c9 02 94 bl FUN_7100121114 undefined FUN_7100121114()
710006eba8 08 1c 00 12 and w8 , w0 , # 0xff
*/
private final List<Integer> findings;
private final byte[] where;
HeuristicFsFAT1(long fwVersion, byte[] where){
this.where = where;
String pattern = getPattern(fwVersion);
SimplyFind simplyfind = new SimplyFind(pattern, where);
List<Integer> temporary = simplyfind.getResults();
if (fwVersion >= 15300){
this.findings = new ArrayList<>();
temporary.forEach(var -> findings.add(var + 4));
}
else
findings = temporary;
System.out.println("\t\tFAT32 # 1 +++++++++++++++++++++++++++++++");
for (Integer find : findings) {
System.out.println(getDetails(find));
System.out.println("------------------------------------------------------------------");
}
/* FIXME
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 < 15300) // & fwVersion >= 9300
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();
}
public String getDetails(Integer value){
int firstOffsetInternal = value - 4;
int firstExpression = Converter.getLEint(where, firstOffsetInternal);
int conditionalJumpLocation = ((firstExpression >> 5 & 0x7FFFF) * 4 + firstOffsetInternal) & 0xfffff;
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
StringBuilder builder = new StringBuilder();
//builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal-4*11), firstOffsetInternal-4*11));
//builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal-4*10), firstOffsetInternal-4*10));
//builder.append("^ ^ ^ ...\n");
builder.append(BinToAsmPrinter.printSimplified(firstExpression, firstOffsetInternal));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal+4), firstOffsetInternal+4));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal+8), firstOffsetInternal+8));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal+12), firstOffsetInternal+12));
builder.append("...\n");
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation+4));
return builder.toString();
}
@Override
public String getDetails(){
int firstOffsetInternal = findings.get(0) - 4;
int firstExpression = Converter.getLEint(where, firstOffsetInternal);
int conditionalJumpLocation = ((firstExpression >> 5 & 0x7FFFF) * 4 + firstOffsetInternal) & 0xfffff;
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
return BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal - 4 * 11), firstOffsetInternal - 4 * 11) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal - 4 * 10), firstOffsetInternal - 4 * 10) +
"^ ^ ^ ...\n" +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal - 4 * 2), firstOffsetInternal - 4 * 2) +
"^ ^ ^ ...\n" +
BinToAsmPrinter.printSimplified(firstExpression, firstOffsetInternal) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal + 4), firstOffsetInternal + 4) +
BinToAsmPrinter.printSimplified(Converter.getLEint(where, firstOffsetInternal + 8), firstOffsetInternal + 8) +
"...\n" +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation) +
BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4);
}
}

View File

@ -1,163 +0,0 @@
/*
Copyright 2018-2023 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.fs.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.AHeuristic;
import nsusbloader.Utilities.patches.BinToAsmPrinter;
import nsusbloader.Utilities.patches.SimplyFind;
import java.util.List;
class HeuristicFsFAT2 extends AHeuristic {
private static final String PATTERN0 = "...94081C00121F05007181000054";
private static final String PATTERN1 = "..003688...1F";
private final List<Integer> findings;
private final byte[] where;
HeuristicFsFAT2(long fwVersion, byte[] where){
this.where = where;
String pattern = getPattern(fwVersion);
SimplyFind simplyfind = new SimplyFind(pattern, where);
this.findings = simplyfind.getResults();
/*
System.out.println("\t\tFAT32 # 2 +++++++++++++++++++++++++++++++");
for (Integer find : findings) {
System.out.println(getDetails(find));
System.out.println("------------------------------------------------------------------");
}
/* FIXME
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 < 15300) // & fwVersion >= 9300
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();
}
public String getDetails(Integer value){
StringBuilder builder = new StringBuilder();
int cbzOffsetInternal = value - 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));
return builder.toString();
}
@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));
return builder.toString();
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2018-2022 Dmitry Isaenko
Copyright 2018-2023 Dmitry Isaenko
This file is part of NS-USBloader.
@ -25,42 +25,23 @@ import java.util.List;
import java.util.stream.Collectors;
public class HeuristicFsWizard {
/*
private final List<AHeuristic> all;
private final List<AHeuristic> found;
private final List<AHeuristic> wantLessEntropy;
*/
private final boolean isFat;
private List<AHeuristic> all;
private List<AHeuristic> found;
private List<AHeuristic> wantLessEntropy;
private final StringBuilder errorsAndNotes;
private int offset1 = -1;
private int offset2 = -1;
public HeuristicFsWizard(long fwVersion, byte[] where, boolean isFat) throws Exception{
this.isFat = isFat;
public HeuristicFsWizard(byte[] where) throws Exception{
this.errorsAndNotes = new StringBuilder();
if (isFat){
this.all = Arrays.asList(
new HeuristicFsFAT1(fwVersion, where),
new HeuristicFsFAT2(fwVersion, where)
);
}
else {
System.out.println("TODO: IMPLEMENT FOR EXFAT");
return;
/*
this.all = Arrays.asList(
new HeuristicFsExFAT1(fwVersion, where),
new HeuristicFsExFAT2(fwVersion, where)
);
*/
}
/*
this.all = Arrays.asList(
new HeuristicFs1(where),
new HeuristicFs2(where)
);
this.found = all.stream()
.filter(AHeuristic::isFound)
.collect(Collectors.toList());
@ -71,12 +52,11 @@ public class HeuristicFsWizard {
this.wantLessEntropy = all.stream()
.filter(AHeuristic::wantLessEntropy)
.collect(Collectors.toList());
/* FIXME
shareOffsetsWithEachOther();
assignOffset1();
assignOffset2();
*/
}
private void shareOffsetsWithEachOther(){
@ -119,10 +99,6 @@ public class HeuristicFsWizard {
public String getDebug(){
StringBuilder builder = new StringBuilder();
if (isFat)
builder.append("\t\t--[ FAT32 ]--\n");
else
builder.append("\t\t--[ ExFAT ]--\n");
if (all.get(0).isFound()){
builder.append("\t\t-=== 1 ===-\n");
builder.append(all.get(0).getDetails());

View File

@ -14,7 +14,7 @@
<?import javafx.scene.shape.SVGPath?>
<?import javafx.scene.text.Font?>
<ScrollPane fitToWidth="true" onDragDropped="#handleDrop" onDragOver="#handleDragOver" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.PatchesController">
<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">