|
@@ -2,9 +2,9 @@ package de.nplusc.izc.senabitwiggler;
|
|
|
|
|
|
import com.google.common.base.Charsets;
|
|
import com.google.common.base.Charsets;
|
|
import com.google.common.base.Strings;
|
|
import com.google.common.base.Strings;
|
|
|
|
+import com.google.common.primitives.Ints;
|
|
import com.google.common.primitives.Longs;
|
|
import com.google.common.primitives.Longs;
|
|
-import org.apache.logging.log4j.LogManager;
|
|
|
|
-import org.apache.logging.log4j.Logger;
|
|
|
|
|
|
+import com.google.common.primitives.Shorts;
|
|
import org.yaml.snakeyaml.Yaml;
|
|
import org.yaml.snakeyaml.Yaml;
|
|
|
|
|
|
import java.io.*;
|
|
import java.io.*;
|
|
@@ -17,7 +17,6 @@ import java.util.Arrays;
|
|
|
|
|
|
public class EntryPoint
|
|
public class EntryPoint
|
|
{
|
|
{
|
|
- private static Logger l = LogManager.getLogger();
|
|
|
|
public static void main(String[] args)
|
|
public static void main(String[] args)
|
|
{
|
|
{
|
|
if(args.length!=4)
|
|
if(args.length!=4)
|
|
@@ -28,7 +27,21 @@ public class EntryPoint
|
|
boolean extract = args[0].equalsIgnoreCase("extract");
|
|
boolean extract = args[0].equalsIgnoreCase("extract");
|
|
boolean immport = args[0].equalsIgnoreCase("import");
|
|
boolean immport = args[0].equalsIgnoreCase("import");
|
|
|
|
|
|
- if(!(extract||immport))
|
|
|
|
|
|
+ boolean regularfuckery = extract||immport;
|
|
|
|
+
|
|
|
|
+ boolean vmexport = args[0].equalsIgnoreCase("extractvm");
|
|
|
|
+ boolean importvm = args[0].equalsIgnoreCase("importvm");
|
|
|
|
+
|
|
|
|
+ boolean vmfuckery = vmexport||importvm;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ boolean incoming = immport|importvm;
|
|
|
|
+
|
|
|
|
+ boolean outgoing = extract||vmexport;
|
|
|
|
+
|
|
|
|
+ if(!(extract||immport||vmexport||importvm))
|
|
{
|
|
{
|
|
printUsage();
|
|
printUsage();
|
|
return;
|
|
return;
|
|
@@ -37,11 +50,16 @@ public class EntryPoint
|
|
boolean shorty = args[1].equalsIgnoreCase("short");
|
|
boolean shorty = args[1].equalsIgnoreCase("short");
|
|
boolean longy = args[1].equalsIgnoreCase("long");
|
|
boolean longy = args[1].equalsIgnoreCase("long");
|
|
|
|
|
|
- if(!(shorty||longy))
|
|
|
|
|
|
+ if(!(shorty||longy)&®ularfuckery)
|
|
{
|
|
{
|
|
printUsage();
|
|
printUsage();
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ else if(vmfuckery)
|
|
|
|
+ {
|
|
|
|
+ shorty = false;
|
|
|
|
+ longy = false;
|
|
|
|
+ }
|
|
|
|
|
|
if(shorty)
|
|
if(shorty)
|
|
{
|
|
{
|
|
@@ -50,16 +68,21 @@ public class EntryPoint
|
|
}
|
|
}
|
|
|
|
|
|
File input = new File(args[2]);
|
|
File input = new File(args[2]);
|
|
- if(immport&&input.exists())
|
|
|
|
|
|
+ if(incoming&&input.exists())
|
|
{
|
|
{
|
|
System.out.println("Refusing to overwrite a existing firmware archive. Use a fresh name instead");
|
|
System.out.println("Refusing to overwrite a existing firmware archive. Use a fresh name instead");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- if(extract&&!input.exists())
|
|
|
|
|
|
+ if(outgoing&&!input.exists())
|
|
{
|
|
{
|
|
System.out.println("Can't extract thin air. Give a file please");
|
|
System.out.println("Can't extract thin air. Give a file please");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(outgoing)
|
|
|
|
+ {
|
|
|
|
+ makeSureThatOutFolderIsCreated(args[3]);
|
|
|
|
+ }
|
|
|
|
+
|
|
if(extract)
|
|
if(extract)
|
|
{
|
|
{
|
|
if(longy)
|
|
if(longy)
|
|
@@ -72,16 +95,17 @@ public class EntryPoint
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ else if(immport)
|
|
{
|
|
{
|
|
- if(immport)
|
|
|
|
|
|
+ if(longy)
|
|
{
|
|
{
|
|
- if(longy)
|
|
|
|
- {
|
|
|
|
- assembleFirmware(input,args[3]);
|
|
|
|
- }
|
|
|
|
|
|
+ assembleFirmware(input,args[3]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ else if(vmexport)
|
|
|
|
+ {
|
|
|
|
+ extractVmImage(input,args[3]);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
private static void assembleFirmware(File output, String inputfolder)
|
|
private static void assembleFirmware(File output, String inputfolder)
|
|
@@ -174,26 +198,9 @@ public class EntryPoint
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
- private static byte[] LongToRawBytes(long l)
|
|
|
|
- {
|
|
|
|
- byte[] tmp = Longs.toByteArray(l);
|
|
|
|
- return new byte[]{tmp[7],tmp[6],tmp[5],tmp[4]};
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
private static void extractFirmwareLong(File input, String output) throws InputInvalidException {
|
|
private static void extractFirmwareLong(File input, String output) throws InputInvalidException {
|
|
byte filler = 0x00;
|
|
byte filler = 0x00;
|
|
- File od = (new File(output));
|
|
|
|
- if(!(od.exists()&&od.isDirectory()))
|
|
|
|
- {
|
|
|
|
- if(!od.mkdirs())
|
|
|
|
- {
|
|
|
|
- System.err.println("WTF! somethint ate shit");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
try (RandomAccessFile f = new RandomAccessFile(input,"r")) {
|
|
try (RandomAccessFile f = new RandomAccessFile(input,"r")) {
|
|
@@ -324,20 +331,124 @@ public class EntryPoint
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private static void extractVmImage(File input, String output)
|
|
|
|
+ {
|
|
|
|
+ byte filler = 0x00;
|
|
|
|
+ try (RandomAccessFile f = new RandomAccessFile(input,"r")) {
|
|
|
|
+ VMImageHeader h = new VMImageHeader();
|
|
|
|
+
|
|
|
|
+ long len = f.length()/2;
|
|
|
|
+ if(len>Integer.MAX_VALUE)
|
|
|
|
+ {
|
|
|
|
+ System.out.println("Ugggh, File too big");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ short[] checksumarray = new short[(int)len];
|
|
|
|
+
|
|
|
|
+ for(int i=0;i<len;i++)
|
|
|
|
+ {
|
|
|
|
+ checksumarray[i]=f.readShort();
|
|
|
|
+ }
|
|
|
|
+ if(xorsum(checksumarray)!=0)
|
|
|
|
+ {
|
|
|
|
+ System.out.println("Smells like Dead Beef, the data seems to be corrupt");
|
|
|
|
+ }
|
|
|
|
+ f.seek(0);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ byte[] magic = new byte[8];
|
|
|
|
+ f.read(magic);
|
|
|
|
+
|
|
|
|
+ h.setHeader(magic);
|
|
|
|
+
|
|
|
|
+ byte[] shortPants = new byte[2];
|
|
|
|
+ byte[] integer = new byte[4];
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setUnknownMagic(Ints.fromBytes(filler,filler,shortPants[0],shortPants[1]));
|
|
|
|
+
|
|
|
|
+ f.read(integer);
|
|
|
|
+ h.setSizeCodeInWords(Longs.fromBytes(filler,filler,filler,filler,integer[0],integer[1],integer[2],integer[3]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setSzConstantsInWords(Ints.fromBytes(filler,filler,shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setSzGlobalsInWords(Ints.fromBytes(filler,filler,shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setSzStack(Ints.fromBytes(filler,filler,shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setAddressMain(Ints.fromBytes(filler,filler,shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setUnknownFlag(Shorts.fromBytes(shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setSyscallCompatId(Ints.fromBytes(filler,filler,shortPants[0],shortPants[1]));
|
|
|
|
+ byte[] trapsets = new byte[8];
|
|
|
|
+ f.read(trapsets);
|
|
|
|
+ h.setTrapSet(trapsets);
|
|
|
|
+ h.setTrapSetStringlied(bytesToHex(trapsets));
|
|
|
|
+ f.read(integer);
|
|
|
|
+ h.setSizeFileInWords(Longs.fromBytes(filler,filler,filler,filler,integer[0],integer[1],integer[2],integer[3]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setChksum(Shorts.fromBytes(shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setUnknown_parameter_b(Shorts.fromBytes(shortPants[0],shortPants[1]));
|
|
|
|
+ f.read(integer);
|
|
|
|
+ h.setEtcetcaddress(Longs.fromBytes(filler,filler,filler,filler,integer[0],integer[1],integer[2],integer[3]));
|
|
|
|
+
|
|
|
|
+ f.read(shortPants);
|
|
|
|
+ h.setUnknown_twiddled_bits(Shorts.fromBytes(shortPants[0],shortPants[1]));
|
|
|
|
+
|
|
|
|
+ Yaml y = new Yaml();
|
|
|
|
+
|
|
|
|
+ y.dump(h, new FileWriter(new File(output+File.separator+"header.yml")));
|
|
|
|
+
|
|
|
|
+ f.seek(0);
|
|
|
|
+
|
|
|
|
+ RandomAccessFile hdrRaw = new RandomAccessFile(output+File.separator+"header.bin","rw");
|
|
|
|
+ byte[] header = new byte[0x30];
|
|
|
|
+ f.read(header);
|
|
|
|
+ hdrRaw.write(header);
|
|
|
|
+ byte[] code = new byte[(int)h.getSizeCodeInWords()*2];
|
|
|
|
+ f.read(code);
|
|
|
|
+ RandomAccessFile codeRaw = new RandomAccessFile(output+File.separator+"code.bin","rw");
|
|
|
|
+ codeRaw.write(code);
|
|
|
|
+
|
|
|
|
+ byte[] constants = new byte[h.getSzConstantsInWords()*2];
|
|
|
|
+ f.read(constants);
|
|
|
|
+ RandomAccessFile dataRaw = new RandomAccessFile(output+File.separator+"data.bin","rw");
|
|
|
|
+ dataRaw.write(constants);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ } catch (FileNotFoundException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
private static void printUsage()
|
|
private static void printUsage()
|
|
{
|
|
{
|
|
System.out.println("Usage:");
|
|
System.out.println("Usage:");
|
|
- System.out.println("program DIRECTION VARIANT FILE FOLDER");
|
|
|
|
- System.out.println("DIRECTION: extract OR import");
|
|
|
|
|
|
+ System.out.println("program MODE VARIANT FILE FOLDER");
|
|
|
|
+ System.out.println("DIRECTION: extract, import, extractVM, importVM");
|
|
|
|
+ System.out.println("extract: Extracts a Sena Firmware image");
|
|
|
|
+ System.out.println("Import: Imports a Sena Firmware Image");
|
|
|
|
+ System.out.println("extractvm Extracts a BlueCore exe-file");
|
|
|
|
+ System.out.println("importvm Reglues a BlueCore exe-file");
|
|
System.out.println("Variant: short OR long");
|
|
System.out.println("Variant: short OR long");
|
|
System.out.println("only long supported so far. short header needs more information");
|
|
System.out.println("only long supported so far. short header needs more information");
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
+ private static byte[] LongToRawBytes(long l)
|
|
|
|
+ {
|
|
|
|
+ byte[] tmp = Longs.toByteArray(l);
|
|
|
|
+ return new byte[]{tmp[7],tmp[6],tmp[5],tmp[4]};
|
|
|
|
+ }
|
|
|
|
|
|
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
|
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
|
public static String bytesToHex(byte[] bytes) {
|
|
public static String bytesToHex(byte[] bytes) {
|
|
@@ -349,6 +460,30 @@ public class EntryPoint
|
|
}
|
|
}
|
|
return new String(hexChars);
|
|
return new String(hexChars);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ private static void makeSureThatOutFolderIsCreated(String output)
|
|
|
|
+ {
|
|
|
|
+ File od = (new File(output));
|
|
|
|
+ if(!(od.exists()&&od.isDirectory()))
|
|
|
|
+ {
|
|
|
|
+ if(!od.mkdirs())
|
|
|
|
+ {
|
|
|
|
+ System.err.println("WTF! somethint ate shit");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static short xorsum(short[] filewords)
|
|
|
|
+ {
|
|
|
|
+ short xorsum = 0;
|
|
|
|
+ for(int i=0;i<filewords.length;i++)
|
|
|
|
+ {
|
|
|
|
+ xorsum ^= filewords[i];
|
|
|
|
+ }
|
|
|
|
+ return xorsum;
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|