From 4d7bc7ff62aafbed8f7797ba920dfeb187d35e73 Mon Sep 17 00:00:00 2001 From: sirjonasxx <36828922+sirjonasxx@users.noreply.github.com> Date: Fri, 8 May 2020 00:25:51 +0200 Subject: [PATCH] reimplement expression prediction + fixes --- ...tStructure.java => PacketStringUtils.java} | 14 +- .../prediction/StructurePredictor.java | 111 +++++++ .../prediction/checkers/BooleanChecker.java | 36 +++ .../prediction/checkers/ByteChecker.java | 32 ++ .../prediction/checkers/IntegerChecker.java | 103 +++++++ .../prediction/checkers/StringChecker.java | 84 ++++++ .../prediction/checkers/TypeChecker.java | 33 ++ .../checkers/TypeCheckerProducer.java | 19 ++ .../main/java/gearth/protocol/HPacket.java | 283 +----------------- .../ui/injection/InjectionController.java | 27 +- 10 files changed, 457 insertions(+), 285 deletions(-) rename G-Earth/src/main/java/gearth/misc/packetrepresentation/{PacketStructure.java => PacketStringUtils.java} (92%) create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/StructurePredictor.java create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/BooleanChecker.java create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/ByteChecker.java create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/IntegerChecker.java create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/StringChecker.java create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeChecker.java create mode 100644 G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeCheckerProducer.java diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/PacketStructure.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/PacketStringUtils.java similarity index 92% rename from G-Earth/src/main/java/gearth/misc/packetrepresentation/PacketStructure.java rename to G-Earth/src/main/java/gearth/misc/packetrepresentation/PacketStringUtils.java index 4ebe5ad..ab22bca 100644 --- a/G-Earth/src/main/java/gearth/misc/packetrepresentation/PacketStructure.java +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/PacketStringUtils.java @@ -1,5 +1,6 @@ package gearth.misc.packetrepresentation; +import gearth.misc.packetrepresentation.prediction.StructurePredictor; import gearth.protocol.HPacket; import java.nio.ByteBuffer; @@ -9,15 +10,18 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; // for all the logistics behind bytes-string conversion -public class PacketStructure { +public class PacketStringUtils { private static String replaceAll(String templateText, String regex, Function replacer) { - Pattern pattern = Pattern.compile(regex); + Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); Matcher matcher = pattern.matcher(templateText); StringBuffer result = new StringBuffer(); while (matcher.find()) { - matcher.appendReplacement(result, replacer.apply(matcher)); + matcher.appendReplacement( + result, + Matcher.quoteReplacement(replacer.apply(matcher)) + ); } matcher.appendTail(result); return result.toString(); @@ -129,6 +133,10 @@ public class PacketStructure { else return; } } + public static String predictedExpression(HPacket packet) { + StructurePredictor structurePredictor = new StructurePredictor(packet); + return structurePredictor.getExpression(); + } public static boolean structureEquals(HPacket packet, String struct) { if (packet.isCorrupted()) return false; diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/StructurePredictor.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/StructurePredictor.java new file mode 100644 index 0000000..807512a --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/StructurePredictor.java @@ -0,0 +1,111 @@ +package gearth.misc.packetrepresentation.prediction; + +import gearth.misc.packetrepresentation.PacketStringUtils; +import gearth.misc.packetrepresentation.prediction.checkers.TypeChecker; +import gearth.misc.packetrepresentation.prediction.checkers.TypeCheckerProducer; +import gearth.protocol.HPacket; + +import java.util.List; + +public class StructurePredictor { + + HPacket packet; + String structure; // null if not found/ didnt try to find + + public StructurePredictor(HPacket packet) { + this.packet = packet; + if (packet.isCorrupted()) { + structure = null; + } + else { + predictStructure(); + } + } + + private static class SubStructure { + int previous; + String type; + double logScore; + + public SubStructure(int previous, String type, double logScore) { + this.previous = previous; + this.type = type; + this.logScore = logScore; + } + } + + private void predictStructure() { + List typeCheckers = TypeCheckerProducer.getValidators(packet); + + SubStructure[] dynamic = new SubStructure[packet.getBytesLength() - 6 + 1]; + dynamic[0] = new SubStructure(-1, "", 0.0); + + int index = 6; + while (index < packet.getBytesLength()) { + double currentLogScore = dynamic[index - 6].logScore; + for (TypeChecker typeChecker : typeCheckers) { + if (typeChecker.canRead(index)) { + double score = typeChecker.score(index); + double newScore = currentLogScore + Math.log(score); + int nextIndex = typeChecker.nextIndex(index) - 6; + if (dynamic[nextIndex] == null || newScore > dynamic[nextIndex].logScore) { + dynamic[nextIndex] = new SubStructure( + index - 6, + typeChecker.getStructCode(), + newScore + ); + } + } + } + index++; + } + + StringBuilder stringBuilder = new StringBuilder(); + SubStructure current = dynamic[dynamic.length - 1]; + while (current.previous != -1) { + stringBuilder.append(current.type); + current = dynamic[current.previous]; + } + + structure = stringBuilder.reverse().toString(); + } + + public String getExpression() { + if (structure == null) { + return ""; + } + return PacketStringUtils.toExpressionFromGivenStructure(packet, structure); + } + + public String getStructure() { + return structure; + } + + public static void main(String[] args) { + HPacket[] packets = new HPacket[] { + new HPacket("{l}{u:500}{i:20}"), + new HPacket(4002, "test"), + new HPacket(4002, "test", 0, true), + new HPacket(4002, "test", "testtsd", 54452, true, false), + new HPacket(4002, "test", 46564554, "testtsd", 54452, true, false), + new HPacket(4002, "test", 0, 46564554, "testtsd", 54452, true, false), + new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, true, false), + new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, false, true, ""), + new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, false, true, ""), + new HPacket(4002, -1, "test", 0, 46564554, "testtsd", -1, 54452, false, true, 0), + new HPacket(4002, -1, (byte) 5, "test", 0, 46564554, "testtsd", -1, 54452, false, true, 0), + new HPacket(4002, "", 20, 0), + new HPacket(4002, 1), + new HPacket(4002, 0, 0), + new HPacket(4002, 0, 0, 42, false), + new HPacket(4002, 0, "") + + }; + + for (HPacket packet : packets) { + StructurePredictor structurePredictor = new StructurePredictor(packet); + System.out.println(structurePredictor.getStructure()); + System.out.println(structurePredictor.getExpression()); + } + } +} diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/BooleanChecker.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/BooleanChecker.java new file mode 100644 index 0000000..9536316 --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/BooleanChecker.java @@ -0,0 +1,36 @@ +package gearth.misc.packetrepresentation.prediction.checkers; + +import gearth.protocol.HPacket; + +public class BooleanChecker extends TypeChecker { + + BooleanChecker(HPacket hPacket) { + super("B", hPacket); + } + + @Override + public boolean canRead(int index) { + return index >= 6 && index < hPacket.getBytesLength() && + (hPacket.toBytes()[index] == 1 || hPacket.toBytes()[index] == 0); + } + + @Override + public double score(int index) { + // A [0] byte is not very likely to be a boolean + // A [1] byte is not very likely to be a boolean, but a little bit more + + // 0.6 may seem pretty high but 4 bytes in a row would get score 0.6*0.6*0.6*0.6, which is low + return get(index) ? 0.6 : 0.5; + } + + @Override + public Boolean get(int index) { + return hPacket.readBoolean(index); + } + + @Override + int nextIndexSafe(int index) { + return index + 1; + } + +} diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/ByteChecker.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/ByteChecker.java new file mode 100644 index 0000000..f3e957d --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/ByteChecker.java @@ -0,0 +1,32 @@ +package gearth.misc.packetrepresentation.prediction.checkers; + +import gearth.protocol.HPacket; + +public class ByteChecker extends TypeChecker { + + ByteChecker(HPacket hPacket) { + super("b", hPacket); + } + + @Override + public boolean canRead(int index) { + return index >= 6 && index < hPacket.getBytesLength(); + } + + @Override + public double score(int index) { + // A byte is never likely to be parsed as a literal byte, only rarely + + return 0.4; + } + + @Override + public Byte get(int index) { + return hPacket.readByte(index); + } + + @Override + int nextIndexSafe(int index) { + return index + 1; + } +} diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/IntegerChecker.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/IntegerChecker.java new file mode 100644 index 0000000..76656df --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/IntegerChecker.java @@ -0,0 +1,103 @@ +package gearth.misc.packetrepresentation.prediction.checkers; + +import gearth.protocol.HPacket; + +import java.nio.charset.StandardCharsets; + +public class IntegerChecker extends TypeChecker { + + IntegerChecker(HPacket hPacket) { + super("i", hPacket); + } + + @Override + public boolean canRead(int index) { + return index >= 6 && !(index + 4 > hPacket.getBytesLength()); + } + + @Override + public double score(int index) { + int value = get(index); + + + int ushortTest = hPacket.readUshort(index); + int ushortTest2 = hPacket.readUshort(index + 2); + // if 4 bytes reads like xy[0][0] or xy[0][1], it is very unlikely to be an actual integer + if (ushortTest != 0 && (ushortTest2 == 0 || ushortTest2 == 256 || ushortTest2 == 1 || ushortTest2 == 257)) { + return 0.05; + } + + // 4 bytes that read [0][0][1][0] are also unlikely to be an integer + if (value == 256) { + return 0.04; + } + + // 4 bytes that read [0][2]xy could be a string + if (ushortTest >= 2 && ushortTest <= 6 && StringChecker.canReadString(hPacket, index)) { + return (1 - StringChecker.scoreString(hPacket.readString(index))); + } + + // if 4 bytes read "abcd", it will most likely be part of a string + // so check if bytes are common + byte[] asBytes = hPacket.readBytes(4, index); + char[] asChars = new String(asBytes, StandardCharsets.ISO_8859_1).toCharArray(); + int count = 0; + for (int i = 0; i < 4; i++) { + if (StringChecker.isCommon(asChars[i], asBytes[i]) == 2) { + count++; + } + } + if (count == 4) { + return 0.2; + } + + // also this + if (StringChecker.canReadString(hPacket, index - 1)) { + String s = hPacket.readString(index - 1); + if (s.length() > 2 && s.length() < 10) { + if (StringChecker.scoreString(s) > 0.5) { + return 1 - StringChecker.scoreString(s); + } + } + } + + // when ordering, it often appears that integers are placed before strings/booleans/etc + // in the case of empty strings or false booleans, it is as good as always the integer that comes first + // so we'll try to respect that here with a small score adjust, which doesnt affect anything else than ordering + double offset = ((double)index) / 1000000000; + + // since -1 has a byte arrangement barely used by other packets, we can assign full score + if (value == -1) { + return 1 - offset; + } + + if (value == 0) { + return 0.99 - offset; + } + + // if the value is not 0, but the last byte is 0/1, we assign a little less score + // to keep the possibility open for a boolean + if (value % 256 == 0) { + return 0.87 - offset; + } + if (value != 1 && value % 256 == 1) { + return 0.88 - offset; + } + + if (value >= -1) { + return 0.92 - offset; + } + + return 0.8 - offset; + } + + @Override + public Integer get(int index) { + return hPacket.readInteger(index); + } + + @Override + int nextIndexSafe(int index) { + return index + 4; + } +} diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/StringChecker.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/StringChecker.java new file mode 100644 index 0000000..b0d38df --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/StringChecker.java @@ -0,0 +1,84 @@ +package gearth.misc.packetrepresentation.prediction.checkers; + +import gearth.protocol.HPacket; + +import java.nio.charset.StandardCharsets; + +public class StringChecker extends TypeChecker { + + StringChecker(HPacket hPacket) { + super("s", hPacket); + } + + @Override + public boolean canRead(int index) { + return canReadString(hPacket, index); + } + + @Override + public double score(int index) { + return scoreString(get(index)); + } + + @Override + public String get(int index) { + return hPacket.readString(index); + } + + @Override + int nextIndexSafe(int index) { + return index + get(index).length() + 2; + } + + // 2 = very common + // 1 = a bit common + // 0 = rare + public static int isCommon(char c, byte b) { + if (c == '\n' || c == '\r' ||c == '\t') { + return 1; + } + + int uByte = (((int)b) + 256) % 256; + + if (uByte >= 32 && uByte <= 126) { + return 2; + } + return 0; + } + + public static double scoreString(String s) { + byte[] asBytes = s.getBytes(StandardCharsets.ISO_8859_1); + char[] asChars = s.toCharArray(); + + if (s.equals("")) { + return 0.8; + } + + int len = s.length(); + double score = 1; + + double[] penalties = new double[]{ + (-1.0/(len*0.3+2) + 0.5), + (-1.0/(len+2)) + 1, + s.length() == 1 ? 0.9 : (s.length() == 2 ? 0.98 : 1.0) + }; + + for (int i = 0; i < s.length(); i++) { + score *= penalties[isCommon( + asChars[i], + asBytes[i] + )]; + + if (score < 0.001) { + return 0; + } + } + + return score; + } + + public static boolean canReadString(HPacket packet, int index) { + int l = packet.getBytesLength(); + return index >= 6 && !(index + 2 > l || packet.readUshort(index) + 2 + index > l); + } +} diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeChecker.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeChecker.java new file mode 100644 index 0000000..f467bfb --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeChecker.java @@ -0,0 +1,33 @@ +package gearth.misc.packetrepresentation.prediction.checkers; + +import gearth.protocol.HPacket; + +public abstract class TypeChecker { + + protected String structCode; + protected HPacket hPacket; + + protected TypeChecker(String structCode, HPacket hPacket) { + this.structCode = structCode; + this.hPacket = hPacket; + } + + public abstract boolean canRead(int index); + + public abstract double score(int index); + + abstract T get(int index); + + // -1 if cant read + public int nextIndex(int index) { + if (!canRead(index)) return -1; + return nextIndexSafe(index); + } + + abstract int nextIndexSafe(int index); + + public String getStructCode() { + return structCode; + } + +} diff --git a/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeCheckerProducer.java b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeCheckerProducer.java new file mode 100644 index 0000000..675699c --- /dev/null +++ b/G-Earth/src/main/java/gearth/misc/packetrepresentation/prediction/checkers/TypeCheckerProducer.java @@ -0,0 +1,19 @@ +package gearth.misc.packetrepresentation.prediction.checkers; + +import gearth.protocol.HPacket; + +import java.util.Arrays; +import java.util.List; + +public class TypeCheckerProducer { + + public static List getValidators(HPacket packet) { + return Arrays.asList( + new BooleanChecker(packet), + new ByteChecker(packet), + new IntegerChecker(packet), + new StringChecker(packet) + ); + } + +} diff --git a/G-Earth/src/main/java/gearth/protocol/HPacket.java b/G-Earth/src/main/java/gearth/protocol/HPacket.java index 05770bd..924f04a 100644 --- a/G-Earth/src/main/java/gearth/protocol/HPacket.java +++ b/G-Earth/src/main/java/gearth/protocol/HPacket.java @@ -4,7 +4,7 @@ import gearth.misc.StringifyAble; import gearth.misc.harble_api.HarbleAPI; import gearth.misc.harble_api.HarbleAPIFetcher; import gearth.misc.packetrepresentation.InvalidPacketException; -import gearth.misc.packetrepresentation.PacketStructure; +import gearth.misc.packetrepresentation.PacketStringUtils; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; @@ -27,11 +27,11 @@ public class HPacket implements StringifyAble { } public HPacket(String packet) { try { - packetInBytes = PacketStructure.fromString(packet).packetInBytes; + packetInBytes = PacketStringUtils.fromString(packet).packetInBytes; } catch (InvalidPacketException e) { packetInBytes = new byte[0]; // will be corrupted - e.printStackTrace(); + // e.printStackTrace(); } } public HPacket(int header) { @@ -75,11 +75,11 @@ public class HPacket implements StringifyAble { } public String toString() { - return PacketStructure.toString(packetInBytes); + return PacketStringUtils.toString(packetInBytes); } public boolean structureEquals(String structure) { - return PacketStructure.structureEquals(this, structure); + return PacketStringUtils.structureEquals(this, structure); } public int isEOF() { @@ -269,11 +269,6 @@ public class HPacket implements StringifyAble { replaceByte(index + i, bytes[i]); i++; } -// -// if (i < bytes.length) { -// appendBytes(Arrays.copyOfRange(bytes, i, bytes.length)); -// fixLength(); -// } return this; } public HPacket replaceUShort(int index, int ushort) { @@ -515,7 +510,7 @@ public class HPacket implements StringifyAble { if (HarbleAPIFetcher.HARBLEAPI != null && ((msg = HarbleAPIFetcher.HARBLEAPI.getHarbleMessageFromHeaderId(direction, headerId())) != null)) { if (msg.getStructure() != null) { - return PacketStructure.toExpressionFromGivenStructure(this, msg.getStructure()); + return PacketStringUtils.toExpressionFromGivenStructure(this, msg.getStructure()); } } return toExpression(); @@ -527,269 +522,7 @@ public class HPacket implements StringifyAble { */ public String toExpression() { if (isCorrupted()) return ""; - - boolean[] mask = new boolean[packetInBytes.length]; - String[] resultTest = new String[packetInBytes.length]; - - for (int i = 0; i < 6; i++) { - mask[i] = true; - } - - resultTest[0] = "{l}"; - resultTest[4] = "{u:"+headerId()+"}"; - - outerloop: - for (int i = 6; i < packetInBytes.length - 1; i++) { - int potentialstringlength = readUshort(i); - if ((potentialstringlength >= 0 && potentialstringlength < 3) || potentialstringlength > packetInBytes.length - i - 2) continue; - - for (int j = i; j < potentialstringlength+i+2; j++) { - if (mask[j]) continue outerloop; - } - - for (int j = i+2; j < potentialstringlength+i+2; j++) { - if (readByte(j) >= 0 && readByte(j) < 6) continue outerloop; - } - - if (i + 2 + potentialstringlength >= packetInBytes.length - 3 || - (packetInBytes[i+2+potentialstringlength] >= 0 && - packetInBytes[i+2+potentialstringlength] < 6 )) { - - for (int j = i; j < potentialstringlength+i+2; j++) { - mask[j] = true; - } - resultTest[i] = "{s:\""+readString(i).replace("\"", "\\\"")+"\"}"; - i += (1 + potentialstringlength); - } - } - - //TODO add special case for seperated 5, 6 and 7 bytes here - // long live the shitty code. - - //5 - out: - for (int i = 6; i < packetInBytes.length - 4; i++) { - for (int j = i; j < i+5; j++) { - if (mask[j]) { - i = j; - continue out; - } - } - if (!mask[i-1] || (i+5 < packetInBytes.length && !mask[i+5])) continue; - - if ((readByte(i) == 0 || readByte(i) == 1) && (readInteger(i+1) > 1 || readInteger(i+1) < 0)) { - //decide the first byte to be the a boolean - resultTest[i] = "{b:"+(readBoolean(i) ? "true" : "false")+"}"; - resultTest[i+1] = "{i:"+readInteger(i+1)+"}"; - for (int j = i; j < i+5; j++) { - mask[j] = true; - } - } - - } - -// //6 -// out: -// for (int i = 6; i < packetInBytes.length - 5; i++) { -// for (int j = i; j < i+6; j++) { -// if (mask[j]) { -// i = j; -// continue out; -// } -// } -// if (i+6 < packetInBytes.length && !mask[i+6]) continue; -// -// -// -// } -// -// //7 -// out: -// for (int i = 6; i < packetInBytes.length - 6; i++) { -// for (int j = i; j < i+7; j++) { -// if (mask[j]) { -// i = j; -// continue out; -// } -// } -// if (i+7 < packetInBytes.length && !mask[i+7]) continue; -// -// -// -// } - - lp22: - for (int i = 6; i < packetInBytes.length - 3; i++) { - for (int j = i; j < i + 4; j++) { - if (mask[j]) { - continue lp22; - } - } - - int num = readInteger(i); - if (num == -1 || (num >= 0 && num < 256)) { - for (int j = i; j < i+4; j++) { - mask[j] = true; - } - resultTest[i] = "{i:"+num+"}"; - i += 3; - } - } - - - boolean changed = true; - boolean isfirst = true; - - while (changed) { - changed = false; - // filtering strings - outerloop: - for (int i = 6; i < packetInBytes.length - 1; i++) { - int potentialstringlength = readUshort(i); - if ((potentialstringlength >= 0 && potentialstringlength < 3) || potentialstringlength > packetInBytes.length - i - 2) continue; - - for (int j = i; j < potentialstringlength+i+2; j++) { - if (mask[j]) continue outerloop; - } - - for (int j = i+2; j < potentialstringlength+i+2; j++) { - if (readByte(j) >= 0 && readByte(j) < 6) continue outerloop; - } - - if (i + 2 + potentialstringlength >= packetInBytes.length - 3 || - (packetInBytes[i+2+potentialstringlength] >= 0 && - packetInBytes[i+2+potentialstringlength] < 6 )) { - - for (int j = i; j < potentialstringlength+i+2; j++) { - mask[j] = true; - } - changed = true; - resultTest[i] = "{s:\""+readString(i).replace("\"", "\\\"")+"\"}"; - i += (1 + potentialstringlength); - } - } - - if (isfirst) { - int count = 0; - for (int i = 6; i < packetInBytes.length; i++) { - if (!mask[i]) count++; - } - if (count > 300) return ""; - } - isfirst = false; - - // filtering integers - boolean hasfoundsomtin = true; - while (hasfoundsomtin) { - hasfoundsomtin = false; - outerloop2: - for (int i = 6; i < packetInBytes.length - 3; i++) { - for (int j = i; j < i + 4; j++) { - if (mask[j]) { - continue outerloop2; - } - } - - if (i + 4 == packetInBytes.length || mask[i+4] || mask[i-1]) { - if (packetInBytes[i+1] == 2) { //could be an unfiltered string; don't filter yet - if (((packetInBytes[i+2] >= '0' && packetInBytes[i+2] <= '9') || - (packetInBytes[i+2] >= 'a' && packetInBytes[i+2] <= 'z') || - (packetInBytes[i+2] >= 'A' && packetInBytes[i+2] <= 'Z')) && - ((packetInBytes[i+3] >= '0' && packetInBytes[i+3] <= '9') || - (packetInBytes[i+3] >= 'a' && packetInBytes[i+3] <= 'z') || - (packetInBytes[i+3] >= 'A' && packetInBytes[i+3] <= 'Z'))) { - changed = true; - for (int j = i; j < i + 4; j++) { - mask[j] = true; - } - hasfoundsomtin = true; - resultTest[i] = "{i:"+readInteger(i)+"}"; - continue; - } - continue ; - } - else { - for (int j = i; j < i + 4; j++) { - mask[j] = true; - } - hasfoundsomtin = true; - changed = true; - resultTest[i] = "{i:"+readInteger(i)+"}"; - continue; - } - } - if (readInteger(i) < 65536) { - for (int j = i; j < i + 4; j++) { - mask[j] = true; - } - hasfoundsomtin = true; - resultTest[i] = "{i:"+readInteger(i)+"}"; - changed = true; - continue; - } - - } - } - - - // filtering strings - - outerloop3: - for (int i = 6; i < packetInBytes.length - 1; i++) { - int potentialstringlength = readUshort(i); - if (potentialstringlength > packetInBytes.length - i - 2) continue; - - for (int j = i; j < potentialstringlength+i+2; j++) { - if (mask[j]) continue outerloop3; - } - - for (int j = i+2; j < potentialstringlength+i+2; j++) { - if (readByte(j) >= 0 && readByte(j) < 6) continue outerloop3; - } - - for (int j = i; j < potentialstringlength+i+2; j++) { - mask[j] = true; - } - resultTest[i] = "{s:\""+readString(i).replace("\"", "\\\"")+"\"}"; - i += (1 + potentialstringlength); - changed = true; - } - } - - int opeenvolging = 0; - for (int i = 6; i < packetInBytes.length; i++) { - if (!mask[i]) { - opeenvolging++; - if (opeenvolging == 4) return ""; - if (i+1 == packetInBytes.length || mask[i+1]) { - for (int j = i - opeenvolging + 1; j <= i; j++) { - mask[j] = true; - if (packetInBytes[j] == 1 || packetInBytes[j] == 0) { - resultTest[j] = "{b:"+(packetInBytes[j] == 1 ? "true" : "false")+"}"; - } - else { - resultTest[j] = "{b:"+((((int)packetInBytes[j])+256)%256)+"}"; - } - } - opeenvolging = 0; - - - } - } - } - - - // if all values in mask are true, go further - for (boolean bool : mask) { - if (!bool) return ""; - } - - StringBuilder expression = new StringBuilder(); - for (int i = 0; i < resultTest.length; i++) { - if (resultTest[i] != null) expression.append(resultTest[i]); - } - - return expression.toString().replace("{i:0}{b:false}{b:true}", "{s:\"\"}{i:1}"); + return PacketStringUtils.predictedExpression(this); } @Override @@ -816,7 +549,7 @@ public class HPacket implements StringifyAble { public static void main(String[] args) { HPacket packet = new HPacket("{l}{u:4564}{i:3}{i:0}{s:\"hi\"}{i:0}{i:1}{s:\"how\"}{i:3}{b:1}{b:2}{b:3}{i:2}{s:\"r u\"}{i:1}{b:120}{i:2}{b:true}{d:1.4}"); - String str = PacketStructure.toExpressionFromGivenStructure(packet, "i(isi(b))iBd"); + String str = PacketStringUtils.toExpressionFromGivenStructure(packet, "i(isi(b))iBd"); HPacket packetverify = new HPacket(str); diff --git a/G-Earth/src/main/java/gearth/ui/injection/InjectionController.java b/G-Earth/src/main/java/gearth/ui/injection/InjectionController.java index 323adf4..82a0d29 100644 --- a/G-Earth/src/main/java/gearth/ui/injection/InjectionController.java +++ b/G-Earth/src/main/java/gearth/ui/injection/InjectionController.java @@ -28,14 +28,27 @@ public class InjectionController extends SubForm { } private boolean isPacketIncomplete(String line) { - int unmatchedBraces = 0; - for (int i = 0; i < line.length(); i++) - if (line.charAt(i) == '{') - unmatchedBraces++; - else if (line.charAt(i) == '}') - unmatchedBraces--; + boolean unmatchedBrace = false; - return unmatchedBraces != 0; + boolean ignoreBrace = false; + + for (int i = 0; i < line.length(); i++) { + if (unmatchedBrace && line.charAt(i) == '"' && line.charAt(i - 1) != '\\') { + ignoreBrace = !ignoreBrace; + } + + if (!ignoreBrace) { + if (line.charAt(i) == '{'){ + + unmatchedBrace = true; + } + else if (line.charAt(i) == '}') { + unmatchedBrace = false; + } + } + } + + return unmatchedBrace; } private HPacket[] parsePackets(String fullText) {