Merge branch 'webviewLogger' into anime-edition

This commit is contained in:
sirjonasxx 2021-01-03 02:45:55 +01:00 committed by GitHub
commit 3e1acde242
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 4132 additions and 709 deletions

View File

@ -13,7 +13,7 @@
<parent>
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<version>1.1</version>
<version>1.3</version>
<relativePath>../../</relativePath>
</parent>
@ -106,7 +106,7 @@
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Earth</artifactId>
<version>1.0</version>
<version>1.3</version>
<!--<scope>provided</scope>-->
</dependency>
</dependencies>

View File

@ -13,7 +13,7 @@
<parent>
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<version>1.1</version>
<version>1.3</version>
<relativePath>../../</relativePath>
</parent>
@ -106,7 +106,7 @@
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Earth</artifactId>
<version>1.0</version>
<version>1.3</version>
<!--<scope>provided</scope>-->
</dependency>
</dependencies>

View File

@ -8,22 +8,21 @@
<packaging>jar</packaging>
<version>1.1</version>
<version>1.3</version>
<properties>
<javafx.version>1.8</javafx.version>
<jettyVersion>9.4.35.v20201120</jettyVersion>
</properties>
<parent>
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<version>1.1</version>
<version>1.3</version>
</parent>
<build>
<plugins>
<!-- this builds a non-standalone JAR file -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -36,7 +35,7 @@
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>gearth.J11Main</mainClass>
<mainClass>gearth.Main</mainClass>
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
@ -58,7 +57,7 @@
<outputDirectory>${project.build.directory}/bin</outputDirectory>
<archive>
<manifest>
<mainClass>gearth.J11Main</mainClass>
<mainClass>gearth.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
@ -86,6 +85,11 @@
<copy file="target/bin/G-Earth.jar" todir="../Build/Windows_32bit/"/>
<copy file="target/bin/G-Earth.jar" todir="../Build/Windows_64bit/"/>
<copy file="src/main/resources/build/messages.json" todir="../Build/Mac/"/>
<copy file="src/main/resources/build/messages.json" todir="../Build/Linux/"/>
<copy file="src/main/resources/build/messages.json" todir="../Build/Windows_32bit/"/>
<copy file="src/main/resources/build/messages.json" todir="../Build/Windows_64bit/"/>
<copy todir="../Build/Mac/">
<fileset dir="src/main/resources/build/mac" includes="**/*" />
</copy>
@ -123,6 +127,7 @@
</plugins>
</build>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>org.openjfx</groupId>-->
@ -152,13 +157,51 @@
<dependency>
<groupId>com.github.tulskiy</groupId>
<artifactId>jkeymaster</artifactId>
<version>1.2</version>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>2.0.0-alpha0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.maven/maven-artifact -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Wasm</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<repositories>

View File

@ -1,7 +0,0 @@
package gearth;
public class J11Main {
public static void main(String[] args) {
Main.main(args);
}
}

View File

@ -1,54 +1,53 @@
package gearth;
import gearth.misc.AdminValidator;
import gearth.ui.GEarthController;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Region;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import gearth.ui.GEarthController;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
// run as root issue Invalid MIT-MAGIC-COOKIE-1 key fix: https://stackoverflow.com/questions/48139447/invalid-mit-magic-cookie-1-key
public class Main extends Application {
public static Application main;
public static String version = "1.1";
public static String version = "1.3";
private static String gitApi = "https://api.github.com/repos/sirjonasxx/G-Earth/releases/latest";
@Override
public void start(Stage primaryStage) throws Exception{
main = this;
FXMLLoader loader = new FXMLLoader(getClass().getResource("/gearth/ui/G-Earth.fxml"));
FXMLLoader loader = new FXMLLoader(getClass().getResource("ui/G-Earth.fxml"));
Parent root = loader.load();
GEarthController companion = loader.getController();
companion.setStage(primaryStage);
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("/gearth/G-EarthLogoSmaller.png")));
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("G-EarthLogoSmaller.png")));
// TODO fix
primaryStage.setResizable(false);
// primaryStage.setResizable(true);
// primaryStage.onShownProperty().addListener(e -> {
// Platform.runLater(() -> primaryStage.setResizable(false));
// });
//primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setTitle("G-Earth " + version);
primaryStage.setScene(new Scene(root, 650, 295));
primaryStage.show();
primaryStage.getScene().getStylesheets().add(getClass().getResource("/gearth/ui/bootstrap3.css").toExternalForm());
primaryStage.getScene().getStylesheets().add(getClass().getResource("ui/bootstrap3.css").toExternalForm());
primaryStage.setOnCloseRequest( event -> {
companion.exit();
@ -58,21 +57,17 @@ public class Main extends Application {
System.exit(0);
});
new Thread(() -> {
if (!AdminValidator.isAdmin()) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Earth needs admin privileges in order to work properly, please restart G-Earth with admin permissions unless you know what you're doing", ButtonType.OK);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.setResizable(false);
// alert.setResizable(true);
// alert.onShownProperty().addListener(e -> {
// Platform.runLater(() -> alert.setResizable(false));
// new Thread(() -> {
// if (!AdminValidator.isAdmin()) {
// Platform.runLater(() -> {
// Alert alert = new Alert(Alert.AlertType.ERROR, "G-Earth needs admin privileges in order to work properly, please restart G-Earth with admin permissions unless you know what you're doing", ButtonType.OK);
// alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
// alert.setResizable(false);
// alert.show();
// });
alert.show();
});
}
}).start();
//
// }
// }).start();
new Thread(() -> {
try {
@ -83,7 +78,7 @@ public class Main extends Application {
if (!gitv.equals(version)) {
Platform.runLater(() -> {
String body = (String)object.get("body");
boolean isForcedUpdate = body.contains("<F>");
boolean isForcedUpdate = body.contains("(!)");
Alert alert = new Alert(isForcedUpdate ? Alert.AlertType.ERROR : Alert.AlertType.INFORMATION, "G-Earth is outdated!", ButtonType.OK);
@ -103,11 +98,6 @@ public class Main extends Application {
webView.setPrefSize(500, 200);
alert.setResizable(false);
// alert.setResizable(true);
// alert.onShownProperty().addListener(e -> {
// Platform.runLater(() -> alert.setResizable(false));
// });
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.getDialogPane().setContent(fp);
if (isForcedUpdate) {

View File

@ -298,7 +298,13 @@ public abstract class Extension implements IExtension {
public boolean requestFlags(FlagsCheckListener flagRequestCallback) {
if (this.flagRequestCallback != null) return false;
this.flagRequestCallback = flagRequestCallback;
try {
writeToStream(new HPacket(NetworkExtensionInfo.INCOMING_MESSAGES_IDS.REQUESTFLAGS).toBytes());
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}

View File

@ -11,7 +11,7 @@ import gearth.protocol.HPacket;
public abstract class ExtensionForm implements IExtension {
volatile Extension extension;
volatile Stage primaryStage;
protected volatile Stage primaryStage;
protected static void runExtensionForm(String[] args, Class<? extends ExtensionForm> extension) {
ExtensionFormLauncher launcher = new ExtensionFormLauncher();

View File

@ -6,6 +6,7 @@ import gearth.misc.harble_api.HarbleAPI;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.io.File;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
@ -30,7 +31,7 @@ public class HashSupport {
extension.onConnect((host, port, hotelversion, cachePath) -> {
// synchronized (lock) {
harbleAPI = new HarbleAPI(hotelversion, cachePath);
harbleAPI = new HarbleAPI(new File(cachePath));
// }
});

View File

@ -4,14 +4,14 @@ import gearth.protocol.HPacket;
public class HEntityUpdate {
private int index;
private boolean isController;
private boolean isController = false;
private HPoint tile;
private HPoint movingTo;
private HPoint movingTo = null;
private HSign sign;
private HStance stance;
private HAction action;
private HSign sign = null;
private HStance stance = null;
private HAction action = null;
private HDirection headFacing;
private HDirection bodyFacing;

View File

@ -71,7 +71,6 @@ public class HarbleAPI {
private boolean success = false;
private String fullPath = null;
private String revision = null;
/**
* cache file must be generated first within G-Earth, inb4 20 extensions requesting it at the same time
@ -92,22 +91,18 @@ public class HarbleAPI {
if (Cacher.cacheFileExists(possibleCachedMessagesPath)) {
JSONObject object = Cacher.getCacheContents(possibleCachedMessagesPath);
success = true;
revision = hotelversion;
fullPath = Cacher.getCacheDir() + File.separator + possibleCachedMessagesPath;
parse(object);
}
}
public HarbleAPI(String hotelversion, String path_to_file) {
File f = new File(path_to_file);
public HarbleAPI(File f) {
if (f.exists() && !f.isDirectory()) {
try {
String contents = String.join("\n", Files.readAllLines(f.toPath()));
JSONObject object = new JSONObject(contents);
success = true;
revision = hotelversion;
fullPath = path_to_file;
fullPath = f.getAbsolutePath();
parse(object);
} catch (IOException e) {
@ -118,15 +113,16 @@ public class HarbleAPI {
private void addMessage(HMessage.Direction direction, JSONObject object) {
String name;
try {
name = object.getString("Name");
} catch (Exception e) {
name = null;
}
String hash = object.getString("Hash");
Integer headerId = object.getInt("Id");
String structure;
String hash;
try { name = object.getString("Name"); }
catch (Exception e) { name = null; }
try { hash = object.getString("Hash"); }
catch (Exception e) { hash = null; }
int headerId = object.getInt("Id");
String structure;
try {
structure = object.getString("Structure");
} catch (Exception e) {
@ -218,10 +214,6 @@ public class HarbleAPI {
return nameToMessage.get(name);
}
public String getRevision() {
return revision;
}
public String getPath() {
if (success) {
return fullPath;

View File

@ -1,11 +1,14 @@
package gearth.misc.harble_api;
import gearth.Main;
import gearth.misc.Cacher;
import gearth.protocol.HMessage;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
/**
* Created by Jonas on 10/11/2018.
@ -36,6 +39,20 @@ public class HarbleAPIFetcher {
public static HarbleAPI HARBLEAPI = null;
public synchronized static void fetch(String hotelversion) {
// if unity
if (!(hotelversion.toLowerCase().contains("production") || hotelversion.toLowerCase().contains("release"))) {
try {
HARBLEAPI = new HarbleAPI(
new File(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI())
.getParentFile(), "messages.json"
)
);
} catch (URISyntaxException e) {
HARBLEAPI = null;
}
return;
}
String cacheName = CACHE_PREFIX + hotelversion;
if (Cacher.cacheFileExists(cacheName)) {

View File

@ -39,12 +39,18 @@ public class PacketStringUtils {
packet = replaceAll(packet, "\\{i:(-?[0-9]+)}",
m -> toString(ByteBuffer.allocate(4).putInt(Integer.parseInt(m.group(1))).array()));
packet = replaceAll(packet, "\\{l:(-?[0-9]+)}",
m -> toString(ByteBuffer.allocate(8).putLong(Integer.parseInt(m.group(1))).array()));
packet = replaceAll(packet, "\\{d:(-?[0-9]*\\.[0-9]*)}",
m -> toString(ByteBuffer.allocate(8).putDouble(Double.parseDouble(m.group(1))).array()));
packet = replaceAll(packet, "\\{u:([0-9]+)}",
m -> "[" + (Integer.parseInt(m.group(1))/256) + "][" + (Integer.parseInt(m.group(1)) % 256) + "]");
packet = replaceAll(packet, "\\{h:([0-9]+)}",
m -> "[" + (Integer.parseInt(m.group(1))/256) + "][" + (Integer.parseInt(m.group(1)) % 256) + "]");
packet = replaceAll(packet, "\\{b:([Ff]alse|[Tt]rue)}",
m -> m.group(1).toLowerCase().equals("true") ? "[1]" : "[0]");
@ -174,7 +180,7 @@ public class PacketStringUtils {
packet.resetReadIndex();
StringBuilder builder = new StringBuilder();
builder.append("{l}{u:").append(packet.headerId()).append("}");
builder.append("{l}{h:").append(packet.headerId()).append("}");
buildExpressionFromGivenStructure(packet, struct, 0, builder);
packet.setReadIndex(oldReadIndex);
@ -196,7 +202,7 @@ public class PacketStringUtils {
}
else if (c == 'i') builder.append("{i:").append(prevInt = p.readInteger()).append('}');
else if (c == 's') builder.append("{s:\"").append(
new String(p.readString().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
p.readString(StandardCharsets.UTF_8)
.replace("\\", "\\\\") // \ -> \\
.replace("\"", "\\\"") // " -> \"
.replace("\r", "\\r") // CR -> \r
@ -204,6 +210,8 @@ public class PacketStringUtils {
else if (c == 'd') builder.append("{d:").append(p.readDouble()).append('}');
else if (c == 'b') builder.append("{b:").append(p.readByte()).append('}');
else if (c == 'B') builder.append("{b:").append(p.readBoolean()).append('}');
else if (c == 'l') builder.append("{l:").append(p.readLong()).append('}');
else if (c == 'u') builder.append("{u:").append(p.readShort()).append('}');
else return;
}
}
@ -232,16 +240,16 @@ public class PacketStringUtils {
}
public static void main(String[] args) throws InvalidPacketException {
HPacket p1 = fromString("{l}{u:1129}{s:\"\\\\\\\\\"}{i:0}{i:0}");
HPacket p1 = fromString("{l}{h:1129}{s:\"\\\\\\\\\"}{i:0}{i:0}");
System.out.println(p1.toExpression());
HPacket p1_2 = fromString(p1.toExpression());
System.out.println(p1_2.toExpression());
HPacket p2 = fromString("{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}");
HPacket p2 = fromString("{l}{h: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}");
System.out.println(p2);
System.out.println(structureEquals(
new HPacket("{l}{u:5}{s:\"asdas\"}"),
new HPacket("{l}{h:5}{s:\"asdas\"}"),
"s"
));
}

View File

@ -9,8 +9,8 @@ import java.util.List;
public class StructurePredictor {
HPacket packet;
String structure; // null if not found/ didnt try to find
private HPacket packet;
private String structure; // null if not found/ didnt try to find
public StructurePredictor(HPacket packet) {
this.packet = packet;
@ -44,17 +44,12 @@ public class StructurePredictor {
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);
if (!typeChecker.canRead(index)) continue;
double newScore = currentLogScore + Math.log(typeChecker.score(index));
int nextIndex = typeChecker.nextIndex(index) - 6;
if (dynamic[nextIndex] == null || newScore > dynamic[nextIndex].logScore) {
dynamic[nextIndex] = new SubStructure(
index - 6,
typeChecker.getStructCode(),
newScore
);
}
dynamic[nextIndex] = new SubStructure(index - 6, typeChecker.getStructCode(), newScore);
}
}
index++;
@ -80,39 +75,4 @@ public class StructurePredictor {
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, ""),
new HPacket("[0][0][0]F[0] [0][0][0] [0][0][0][5][0]\u0013ACH_FriendListSize5[0][0][0]U[0][0][0] [0][0][0][0][0][0][0][0][0][0][0]Z[0][0][6]social[0][0][0][0][0][13][0][0][0][2]"),
new HPacket("[0][0][0]?[0] [0][0][0][4][0][0][0][4][0][10]ACH_Login4[0][0][0]\u000F[0][0][0]\u001C[0][0][0][0][0][0][0][0][0][0][0][2][0][0][8]identity[0][0][0][0][0]\u0014[0][0][0][0]"),
new HPacket("[0][0][0][6]\u000Ew[0][0][0][0]"),
new HPacket("[0][0][0]'[3] [0][5]Login[0][6]socket[0]\u000Eclient.auth_ok[0][0][0][0][0][0]"),
new HPacket(4002, false, ""),
new HPacket("{l}{u:145}[0][0][0]ÿÿÿÿ[0]"),
// new HPacket("[0][0][1]p[13]1[0][0][0][12][0][10]MOUSE_ZOOM[0][0][1][0]\u0015HABBO_CLUB_OFFER_BETA[0][0][1][0]\u000EUSE_GUIDE_TOOL[0]&requirement.unfulfilled.helper_level_4[0][0]\u000FBUILDER_AT_WORK[0](requirement.unfulfilled.group_membership[0][0]\u000FCALL_ON_HELPERS[0][0][1][0]\u001FNAVIGATOR_ROOM_THUMBNAIL_CAMERA[0][0][1][0][7]CITIZEN[0][0][1][0]\u0012JUDGE_CHAT_REVIEWS[0]&requirement.unfulfilled.helper_level_6[0][0][5]TRADE[0][0][1][0][6]CAMERA[0][0][1][0]\u0014VOTE_IN_COMPETITIONS[0][0][1][0]\u0018NAVIGATOR_PHASE_TWO_2014[0][0][1]")
};
for (HPacket packet : packets) {
StructurePredictor structurePredictor = new StructurePredictor(packet);
System.out.println(structurePredictor.getStructure());
System.out.println(structurePredictor.getExpression());
}
}
}

View File

@ -1,6 +1,7 @@
package gearth.misc.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;
import gearth.services.Constants;
import java.nio.charset.StandardCharsets;
@ -33,7 +34,7 @@ public class IntegerChecker extends TypeChecker<Integer> {
}
// 4 bytes that read [0][2]xy could be a string
if (ushortTest >= 2 && ushortTest <= 6 && StringChecker.canReadString(hPacket, index)) {
if (ushortTest == 2 && StringChecker.canReadString(hPacket, index)) {
return (1 - StringChecker.scoreString(hPacket.readString(index)));
}

View File

@ -0,0 +1,45 @@
package gearth.misc.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;
public class LongChecker extends TypeChecker<Long> {
private IntegerChecker integerChecker;
protected LongChecker(HPacket hPacket) {
super("l", hPacket);
integerChecker = new IntegerChecker(hPacket);
}
@Override
public boolean canRead(int index) {
return index >= 6 && !(index + 8 > hPacket.getBytesLength());
}
@Override
public double score(int index) {
int split1 = hPacket.readInteger(index);
int split2 = hPacket.readInteger(index + 4);
int zeros = 0;
for (int i = index + 4; i < index + 8; i++) {
zeros += hPacket.readByte(i) == 0 ? 1 : 0;
}
if (split2 > 256 * 256 * 3 && split1 == 0 && zeros < 2) {
return integerChecker.score(index) * integerChecker.score(index + 4) + 0.0000000001;
}
return 0;
}
@Override
Long get(int index) {
return hPacket.readLong(index);
}
@Override
int nextIndexSafe(int index) {
return index + 8;
}
}

View File

@ -0,0 +1,56 @@
package gearth.misc.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;
public class ShortChecker extends TypeChecker {
private BooleanChecker booleanChecker;
private ByteChecker byteChecker;
protected ShortChecker(HPacket hPacket) {
super("u", hPacket);
booleanChecker = new BooleanChecker(hPacket);
byteChecker = new ByteChecker(hPacket);
}
@Override
public boolean canRead(int index) {
return index >= 6 && !(index + 2 > hPacket.getBytesLength());
}
@Override
public double score(int index) {
short val = hPacket.readShort(index);
if (index == 6 && val == 0 && hPacket.length() == nextIndexSafe(index)) {
return 1;
}
if (val <= 0) {
return 0;
}
if (val < 1000) {
return 0.5;
}
double leftMinScore;
double rightMinScore;
if (booleanChecker.canRead(index)) leftMinScore = booleanChecker.score(index);
else leftMinScore = byteChecker.score(index);
if (booleanChecker.canRead(index+1)) rightMinScore = booleanChecker.score(index+1);
else rightMinScore = byteChecker.score(index+1);
return leftMinScore * rightMinScore + 0.00000001;
}
@Override
Object get(int index) {
return hPacket.readShort();
}
@Override
int nextIndexSafe(int index) {
return index + 2;
}
}

View File

@ -2,18 +2,27 @@ package gearth.misc.packetrepresentation.prediction.checkers;
import gearth.protocol.HPacket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static gearth.services.Constants.UNITY_PACKETS;
public class TypeCheckerProducer {
public static List<TypeChecker> getValidators(HPacket packet) {
return Arrays.asList(
List<TypeChecker> typeCheckers = new ArrayList<>(Arrays.asList(
new BooleanChecker(packet),
new ByteChecker(packet),
new IntegerChecker(packet),
new StringChecker(packet)
);
new StringChecker(packet)));
if (UNITY_PACKETS) {
typeCheckers.add(new LongChecker(packet));
typeCheckers.add(new ShortChecker(packet));
}
return typeCheckers;
}
}

View File

@ -4,9 +4,10 @@ import gearth.misc.listenerpattern.Observable;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider;
import gearth.protocol.connection.proxy.windows.WindowsRawIpProxyProvider;
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
import gearth.protocol.connection.proxy.unity.UnityProxyProvider;
import gearth.services.extensionhandler.ExtensionHandler;
import java.io.IOException;
@ -60,6 +61,12 @@ public class HConnection {
startMITM();
}
public void startUnity() {
HConnection selff = this;
proxyProvider = new UnityProxyProvider(proxy -> selff.proxy = proxy, selff::setState, this);
startMITM();
}
private void startMITM() {
try {
if (proxyProvider != null) {
@ -166,7 +173,7 @@ public class HConnection {
}
public boolean isRawIpMode() {
return proxyProvider != null && proxyProvider instanceof LinuxRawIpProxyProvider;
return proxyProvider != null && proxyProvider instanceof LinuxRawIpFlashProxyProvider;
// WindowsRawIpProxyProvider extends LinuxRawIpProxyProvider
}

View File

@ -8,6 +8,7 @@ import gearth.misc.packetrepresentation.PacketStringUtils;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
import java.util.Arrays;
@ -36,7 +37,7 @@ public class HPacket implements StringifyAble {
}
public HPacket(int header) {
packetInBytes = new byte[]{0,0,0,2,0,0};
replaceUShort(4, header);
replaceShort(4, (short)header);
isEdited = false;
}
public HPacket(int header, byte[] bytes) {
@ -126,7 +127,7 @@ public class HPacket implements StringifyAble {
}
public int headerId() {
return readUshort(4);
return readShort(4);
}
public int readInteger(){
@ -180,34 +181,49 @@ public class HPacket implements StringifyAble {
return java.nio.ByteBuffer.wrap(btarray).getLong();
}
public String readString() {
String r = readString(readIndex);
readIndex += (2 + r.length());
public String readString(Charset charset) {
String r = readString(readIndex, charset);
readIndex += (2 + readUshort(readIndex));
return r;
}
public String readString(int index) {
public String readString(int index, Charset charset) {
int length = readUshort(index);
index+=2;
return readString(index, length);
return readString(index, length, charset);
}
private String readString(int index, int length) {
public String readString() {
return readString(StandardCharsets.ISO_8859_1);
}
public String readString(int index) {
return readString(index, StandardCharsets.ISO_8859_1);
}
private String readString(int index, int length, Charset charset) {
byte[] x = new byte[length];
for (int i = 0; i < x.length; i++) { x[i] = readByte(index); index++; }
return new String(x, StandardCharsets.ISO_8859_1);
return new String(x, charset);
}
public String readLongString() {
String r = readLongString(readIndex);
readIndex += (4 + r.length());
public String readLongString(Charset charset) {
String r = readLongString(readIndex, charset);
readIndex += (4 + readInteger(readIndex));
return r;
}
public String readLongString(int index) {
public String readLongString(int index, Charset charset) {
int length = readInteger(index);
index += 4;
return readString(index, length);
return readString(index, length, charset);
}
public String readLongString() {
return readLongString(StandardCharsets.ISO_8859_1);
}
public String readLongString(int index) {
return readLongString(index, StandardCharsets.ISO_8859_1);
}
public boolean readBoolean() {
@ -231,6 +247,14 @@ public class HPacket implements StringifyAble {
}
return this;
}
public HPacket replaceLong(int index, long l) {
isEdited = true;
ByteBuffer b = ByteBuffer.allocate(8).putLong(l);
for (int j = 0; j < 8; j++) {
packetInBytes[index + j] = b.array()[j];
}
return this;
}
public HPacket replaceDouble(int index, double d) {
isEdited = true;
ByteBuffer b = ByteBuffer.allocate(8).putDouble(d);
@ -267,10 +291,11 @@ public class HPacket implements StringifyAble {
packetInBytes[index + 1] = b.array()[1];
return this;
}
public HPacket replaceString(int index, String s) {
public HPacket replaceString(int index, String s, Charset charset) {
isEdited = true;
byte[] sbytes = s.getBytes(StandardCharsets.ISO_8859_1);
int mover = s.length() - readUshort(index);
byte[] sbytes = s.getBytes(charset);
int mover = sbytes.length - readUshort(index);
if (mover != 0) {
byte[] newPacket = Arrays.copyOf(packetInBytes, packetInBytes.length + mover);
@ -283,7 +308,7 @@ public class HPacket implements StringifyAble {
}
}
else {
int i = index + 2 + s.length();
int i = index + 2 + sbytes.length;
while (i < newPacket.length) {
newPacket[i] = packetInBytes[i - mover];
i++;
@ -294,13 +319,17 @@ public class HPacket implements StringifyAble {
fixLength();
}
replaceUShort(index, s.length());
for (int i = 0; i < s.length(); i++) {
replaceUShort(index, sbytes.length);
for (int i = 0; i < sbytes.length; i++) {
packetInBytes[index + 2 + i] = sbytes[i];
}
return this;
}
public HPacket replaceString(int index, String s) {
return replaceString(index, s, StandardCharsets.ISO_8859_1);
}
private boolean canReadString(int index) {
if (index < packetInBytes.length - 1) {
int l = readUshort(index);
@ -394,6 +423,16 @@ public class HPacket implements StringifyAble {
fixLength();
return this;
}
public HPacket appendLong(long l) {
isEdited = true;
packetInBytes = Arrays.copyOf(packetInBytes, packetInBytes.length + 8);
ByteBuffer byteBuffer = ByteBuffer.allocate(8).putLong(l);
for (int j = 0; j < 8; j++) {
packetInBytes[packetInBytes.length - 8 + j] = byteBuffer.array()[j];
}
fixLength();
return this;
}
public HPacket appendDouble(double d) {
isEdited = true;
packetInBytes = Arrays.copyOf(packetInBytes, packetInBytes.length + 8);
@ -445,18 +484,27 @@ public class HPacket implements StringifyAble {
fixLength();
return this;
}
public HPacket appendString(String s, Charset charset) {
isEdited = true;
appendUShort(s.getBytes(charset).length);
appendBytes(s.getBytes(charset));
return this;
}
public HPacket appendString(String s) {
return appendString(s, StandardCharsets.ISO_8859_1);
}
public HPacket appendLongString(String s, Charset charset) {
isEdited = true;
appendUShort(s.length());
appendBytes(s.getBytes(StandardCharsets.ISO_8859_1));
appendInt(s.getBytes(charset).length);
appendBytes(s.getBytes(charset));
return this;
}
public HPacket appendLongString(String s) {
isEdited = true;
appendInt(s.length());
appendBytes(s.getBytes(StandardCharsets.ISO_8859_1));
return this;
return appendLongString(s, StandardCharsets.ISO_8859_1);
}
public HPacket appendObject(Object o) throws InvalidParameterException {
isEdited = true;
@ -472,6 +520,9 @@ public class HPacket implements StringifyAble {
else if (o instanceof Boolean) {
appendBoolean((Boolean) o);
}
else if (o instanceof Long) {
appendLong((Long) o);
}
else {
throw new InvalidParameterException();
}
@ -479,20 +530,6 @@ public class HPacket implements StringifyAble {
return this;
}
public HPacket removeFrom(int index) {
return removeRange(index, packetInBytes.length - index);
}
public HPacket removeRange(int index, int length) {
isEdited = true;
for (int i = index; i < packetInBytes.length - length; i++) {
packetInBytes[i] = packetInBytes[i + length];
}
packetInBytes = Arrays.copyOf(packetInBytes, packetInBytes.length - length);
fixLength();
return this;
}
public boolean isReplaced() {
return isEdited;
}
@ -507,25 +544,44 @@ public class HPacket implements StringifyAble {
isEdited = edited;
}
public String toExpression(HMessage.Direction direction) {
if (isCorrupted()) return "";
private String getHarbleStructure(HMessage.Direction direction) {
HarbleAPI.HarbleMessage msg;
if (HarbleAPIFetcher.HARBLEAPI != null &&
((msg = HarbleAPIFetcher.HARBLEAPI.getHarbleMessageFromHeaderId(direction, headerId())) != null)) {
if (msg.getStructure() != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, msg.getStructure());
if (msg.getStructure() != null && structureEquals(msg.getStructure())) {
return msg.getStructure();
}
}
return toExpression();
return null;
}
public String toExpression(HMessage.Direction direction) {
if (isCorrupted()) return "";
String structure = getHarbleStructure(direction);
if (structure != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, structure);
}
return PacketStringUtils.predictedExpression(this);
}
/**
* returns "" if not found or not sure enough
* dont hate on the coding quality in this function, its pretty effective.
*/
public String toExpression() {
if (isCorrupted()) return "";
String structure1 = getHarbleStructure(HMessage.Direction.TOCLIENT);
String structure2 = getHarbleStructure(HMessage.Direction.TOSERVER);
if (structure1 != null && structure2 == null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, structure1);
}
else if (structure1 == null && structure2 != null) {
return PacketStringUtils.toExpressionFromGivenStructure(this, structure2);
}
return PacketStringUtils.predictedExpression(this);
}
@ -551,7 +607,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}");
HPacket packet = new HPacket("{l}{h: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 = PacketStringUtils.toExpressionFromGivenStructure(packet, "i(isi(b))iBd");

View File

@ -0,0 +1,6 @@
package gearth.protocol.connection;
public enum HClient {
UNITY,
FLASH
}

View File

@ -1,11 +1,13 @@
package gearth.protocol.connection;
import gearth.protocol.packethandler.IncomingPacketHandler;
import gearth.protocol.packethandler.OutgoingPacketHandler;
import gearth.protocol.packethandler.PacketHandler;
import java.net.ServerSocket;
public class HProxy {
private final HClient hClient;
private volatile String input_domain; //string representation of the domain to intercept
private volatile String actual_domain; //dns resolved domain (ignoring hosts file)
private volatile int actual_port; //port of the server
@ -15,13 +17,14 @@ public class HProxy {
private volatile ServerSocket proxy_server = null; //listener for the client
private volatile IncomingPacketHandler inHandler = null; //connection with client (only initialized when verified habbo connection)
private volatile OutgoingPacketHandler outHandler = null; //connection with server (only initialized when verified habbo connection)
private volatile PacketHandler inHandler = null; //connection with client (only initialized when verified habbo connection)
private volatile PacketHandler outHandler = null; //connection with server (only initialized when verified habbo connection)
private volatile String hotelVersion = "";
private volatile AsyncPacketSender asyncPacketSender = null;
public HProxy(String input_domain, String actual_domain, int actual_port, int intercept_port, String intercept_host) {
public HProxy(HClient hClient, String input_domain, String actual_domain, int actual_port, int intercept_port, String intercept_host) {
this.hClient = hClient;
this.input_domain = input_domain;
this.actual_domain = actual_domain;
this.actual_port = actual_port;
@ -33,7 +36,7 @@ public class HProxy {
this.proxy_server = socket;
}
public void verifyProxy(IncomingPacketHandler incomingHandler, OutgoingPacketHandler outgoingHandler, String hotelVersion) {
public void verifyProxy(PacketHandler incomingHandler, PacketHandler outgoingHandler, String hotelVersion) {
this.inHandler = incomingHandler;
this.outHandler = outgoingHandler;
this.hotelVersion = hotelVersion;
@ -64,11 +67,11 @@ public class HProxy {
return intercept_host;
}
public IncomingPacketHandler getInHandler() {
public PacketHandler getInHandler() {
return inHandler;
}
public OutgoingPacketHandler getOutHandler() {
public PacketHandler getOutHandler() {
return outHandler;
}
@ -79,4 +82,8 @@ public class HProxy {
public AsyncPacketSender getAsyncPacketSender() {
return asyncPacketSender;
}
public HClient gethClient() {
return hClient;
}
}

View File

@ -1,129 +1,10 @@
package gearth.protocol.connection.proxy;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.memory.Rc4Obtainer;
import gearth.protocol.packethandler.IncomingPacketHandler;
import gearth.protocol.packethandler.OutgoingPacketHandler;
import gearth.protocol.packethandler.PacketHandler;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Region;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
public abstract class ProxyProvider {
public interface ProxyProvider {
protected final HProxySetter proxySetter;
protected final HStateSetter stateSetter;
protected final HConnection hConnection;
private Semaphore abortSemaphore = null;
public ProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection){
this.proxySetter = proxySetter;
this.stateSetter = stateSetter;
this.hConnection = hConnection;
}
protected void startProxyThread(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
final boolean[] datastream = new boolean[1];
server.setTcpNoDelay(true);
client.setTcpNoDelay(true);
client.setSoTimeout(0);
server.setSoTimeout(0);
if (HConnection.DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(hConnection);
OutgoingPacketHandler outgoingHandler = new OutgoingPacketHandler(server.getOutputStream(), hConnection.getTrafficObservables(), hConnection.getExtensionHandler());
IncomingPacketHandler incomingHandler = new IncomingPacketHandler(client.getOutputStream(), hConnection.getTrafficObservables(), outgoingHandler, hConnection.getExtensionHandler());
rc4Obtainer.setPacketHandlers(outgoingHandler, incomingHandler);
Semaphore abort = new Semaphore(0);
outgoingHandler.addOnDatastreamConfirmedListener(hotelVersion -> {
incomingHandler.setAsDataStream();
proxy.verifyProxy(incomingHandler, outgoingHandler, hotelVersion);
proxySetter.setProxy(proxy);
datastream[0] = true;
abortSemaphore = abort;
onConnect();
});
handleInputStream(client, outgoingHandler, abort);
handleInputStream(server, incomingHandler, abort);
// abort can be acquired as soon as one of the sockets is closed
abort.acquire();
try {
if (!server.isClosed()) server.close();
if (!client.isClosed()) client.close();
if (HConnection.DEBUG) System.out.println("STOP");
if (datastream[0]) {
onConnectEnd();
};
}
catch (IOException e) {
e.printStackTrace();
}
}
private void handleInputStream(Socket socket, PacketHandler packetHandler, Semaphore abort) {
new Thread(() -> {
try {
int readLength;
byte[] buffer = new byte[10000];
while (!socket.isClosed() &&
(hConnection.getState() == HState.WAITING_FOR_CLIENT || hConnection.getState() == HState.CONNECTED) &&
(readLength = socket.getInputStream().read(buffer)) != -1) {
packetHandler.act(Arrays.copyOf(buffer, readLength));
}
}
catch (IOException ignore) {
// System.err.println(packetHandler instanceof IncomingPacketHandler ? "incoming" : "outgoing");
// ignore.printStackTrace();
} finally {
abort.release();
}
}).start();
}
public abstract void start() throws IOException;
public void abort() {
if (abortSemaphore != null) {
abortSemaphore.release();
}
else {
stateSetter.setState(HState.NOT_CONNECTED);
}
}
protected void onConnect() {
stateSetter.setState(HState.CONNECTED);
}
protected void onConnectEnd() {
proxySetter.setProxy(null);
abortSemaphore = null;
stateSetter.setState(HState.NOT_CONNECTED);
}
protected void showInvalidConnectionError() {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "You entered invalid connection information, G-Earth could not connect", ButtonType.OK);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.setResizable(false);
alert.show();
});
}
void start() throws IOException;
void abort();
}

View File

@ -5,8 +5,10 @@ import gearth.misc.OSValidator;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider;
import gearth.protocol.connection.proxy.windows.WindowsRawIpProxyProvider;
import gearth.protocol.connection.proxy.flash.NormalFlashProxyProvider;
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
import gearth.protocol.connection.proxy.flash.windows.WindowsRawIpFlashProxyProvider;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
@ -67,7 +69,7 @@ public class ProxyProviderFactory {
// checks if host is a raw IP instead of a domain
// TODO support ipv6 (not only here, also in IPmapper)
static boolean hostIsIpAddress(String host){
public static boolean hostIsIpAddress(String host){
for (char c : host.toCharArray()) {
if (c != '.' && (c < '0' || c > '9')) {
return false;
@ -79,7 +81,6 @@ public class ProxyProviderFactory {
public ProxyProvider provide() {
return provide(autoDetectHosts);
}
public ProxyProvider provide(String domain, int port) {
List<Object> additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY);
if (additionalCachedHotels == null) {
@ -92,12 +93,12 @@ public class ProxyProviderFactory {
if (hostIsIpAddress(domain)) {
if (OSValidator.isWindows()) {
if (WindowsRawIpProxyProvider.isNoneConnected(domain) &&
if (WindowsRawIpFlashProxyProvider.isNoneConnected(domain) &&
(!socksConfig.useSocks() || socksConfig.onlyUseIfNeeded()) ) {
return new WindowsRawIpProxyProvider(proxySetter, stateSetter, hConnection, domain, port, false);
return new WindowsRawIpFlashProxyProvider(proxySetter, stateSetter, hConnection, domain, port, false);
}
else if (socksConfig.useSocks()) {
return new WindowsRawIpProxyProvider(proxySetter, stateSetter, hConnection, domain, port, true);
return new WindowsRawIpFlashProxyProvider(proxySetter, stateSetter, hConnection, domain, port, true);
}
Platform.runLater(() -> {
@ -112,7 +113,7 @@ public class ProxyProviderFactory {
return null;
}
else if (OSValidator.isUnix() || OSValidator.isMac()) {
return new LinuxRawIpProxyProvider(proxySetter, stateSetter, hConnection, domain, port, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
return new LinuxRawIpFlashProxyProvider(proxySetter, stateSetter, hConnection, domain, port, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
}
return null;
@ -123,9 +124,8 @@ public class ProxyProviderFactory {
return provide(potentialHost);
}
}
private ProxyProvider provide(List<String> potentialHosts) {
return new NormalProxyProvider(proxySetter, stateSetter, hConnection, potentialHosts, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
return new NormalFlashProxyProvider(proxySetter, stateSetter, hConnection, potentialHosts, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
}
public static void setSocksConfig(SocksConfiguration configuration) {

View File

@ -0,0 +1,130 @@
package gearth.protocol.connection.proxy.flash;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.memory.Rc4Obtainer;
import gearth.protocol.packethandler.flash.IncomingFlashPacketHandler;
import gearth.protocol.packethandler.flash.OutgoingFlashPacketHandler;
import gearth.protocol.packethandler.flash.FlashPacketHandler;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Region;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
public abstract class FlashProxyProvider implements ProxyProvider {
protected final HProxySetter proxySetter;
protected final HStateSetter stateSetter;
protected final HConnection hConnection;
private Semaphore abortSemaphore = null;
public FlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection){
this.proxySetter = proxySetter;
this.stateSetter = stateSetter;
this.hConnection = hConnection;
}
protected void startProxyThread(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
final boolean[] datastream = new boolean[1];
server.setTcpNoDelay(true);
client.setTcpNoDelay(true);
client.setSoTimeout(0);
server.setSoTimeout(0);
if (HConnection.DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(hConnection);
OutgoingFlashPacketHandler outgoingHandler = new OutgoingFlashPacketHandler(server.getOutputStream(), hConnection.getTrafficObservables(), hConnection.getExtensionHandler());
IncomingFlashPacketHandler incomingHandler = new IncomingFlashPacketHandler(client.getOutputStream(), hConnection.getTrafficObservables(), outgoingHandler, hConnection.getExtensionHandler());
rc4Obtainer.setFlashPacketHandlers(outgoingHandler, incomingHandler);
Semaphore abort = new Semaphore(0);
outgoingHandler.addOnDatastreamConfirmedListener(hotelVersion -> {
incomingHandler.setAsDataStream();
proxy.verifyProxy(incomingHandler, outgoingHandler, hotelVersion);
proxySetter.setProxy(proxy);
datastream[0] = true;
abortSemaphore = abort;
onConnect();
});
handleInputStream(client, outgoingHandler, abort);
handleInputStream(server, incomingHandler, abort);
// abort can be acquired as soon as one of the sockets is closed
abort.acquire();
try {
if (!server.isClosed()) server.close();
if (!client.isClosed()) client.close();
if (HConnection.DEBUG) System.out.println("STOP");
if (datastream[0]) {
onConnectEnd();
};
}
catch (IOException e) {
e.printStackTrace();
}
}
private void handleInputStream(Socket socket, FlashPacketHandler flashPacketHandler, Semaphore abort) {
new Thread(() -> {
try {
int readLength;
byte[] buffer = new byte[10000];
while (!socket.isClosed() &&
(hConnection.getState() == HState.WAITING_FOR_CLIENT || hConnection.getState() == HState.CONNECTED) &&
(readLength = socket.getInputStream().read(buffer)) != -1) {
flashPacketHandler.act(Arrays.copyOf(buffer, readLength));
}
}
catch (IOException ignore) {
// System.err.println(packetHandler instanceof IncomingPacketHandler ? "incoming" : "outgoing");
// ignore.printStackTrace();
} finally {
abort.release();
}
}).start();
}
public abstract void start() throws IOException;
public void abort() {
if (abortSemaphore != null) {
abortSemaphore.release();
}
else {
stateSetter.setState(HState.NOT_CONNECTED);
}
}
protected void onConnect() {
stateSetter.setState(HState.CONNECTED);
}
protected void onConnectEnd() {
proxySetter.setProxy(null);
abortSemaphore = null;
stateSetter.setState(HState.NOT_CONNECTED);
}
protected void showInvalidConnectionError() {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "You entered invalid connection information, G-Earth could not connect", ButtonType.OK);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.setResizable(false);
alert.show();
});
}
}

View File

@ -1,21 +1,19 @@
package gearth.protocol.connection.proxy;
package gearth.protocol.connection.proxy.flash;
import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.*;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.protocol.hostreplacer.hostsfile.HostReplacer;
import gearth.protocol.hostreplacer.hostsfile.HostReplacerFactory;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class NormalProxyProvider extends ProxyProvider {
public class NormalFlashProxyProvider extends FlashProxyProvider {
private List<String> potentialHosts;
@ -29,7 +27,7 @@ public class NormalProxyProvider extends ProxyProvider {
private boolean useSocks;
public NormalProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, List<String> potentialHosts, boolean useSocks) {
public NormalFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, List<String> potentialHosts, boolean useSocks) {
super(proxySetter, stateSetter, hConnection);
this.potentialHosts = potentialHosts;
this.useSocks = useSocks;
@ -72,7 +70,7 @@ public class NormalProxyProvider extends ProxyProvider {
int intercept_port = port;
String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254);
potentialProxies.add(new HProxy(input_dom, actual_dom, port, intercept_port, intercept_host));
potentialProxies.add(new HProxy(HClient.FLASH, input_dom, actual_dom, port, intercept_port, intercept_host));
c++;
}
}

View File

@ -1,26 +1,19 @@
package gearth.protocol.connection.proxy.unix;
package gearth.protocol.connection.proxy.flash.unix;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.connection.*;
import gearth.protocol.connection.proxy.flash.FlashProxyProvider;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Region;
import java.io.IOException;
import java.net.*;
import java.util.LinkedList;
import java.util.Queue;
public class LinuxRawIpProxyProvider extends ProxyProvider {
public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
private volatile String input_host;
private volatile int input_port;
@ -30,7 +23,7 @@ public class LinuxRawIpProxyProvider extends ProxyProvider {
private boolean useSocks;
public LinuxRawIpProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
public LinuxRawIpFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
super(proxySetter, stateSetter, hConnection);
this.input_host = input_host;
this.input_port = input_port;
@ -50,7 +43,7 @@ public class LinuxRawIpProxyProvider extends ProxyProvider {
new Thread(() -> {
try {
stateSetter.setState(HState.PREPARING);
proxy = new HProxy(input_host, input_host, input_port, input_port, "0.0.0.0");
proxy = new HProxy(HClient.FLASH, input_host, input_host, input_port, input_port, "0.0.0.0");
maybeRemoveMapping();

View File

@ -1,35 +1,23 @@
package gearth.protocol.connection.proxy.windows;
package gearth.protocol.connection.proxy.flash.windows;
import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxy;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.connection.proxy.unix.LinuxRawIpProxyProvider;
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Region;
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
import org.json.JSONObject;
import java.io.IOException;
import java.math.BigInteger;
import java.net.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.UUID;
// windows raw ip proxy provider extends the Linux one with the exception that it does not want to close
// the IP redirect on connect
public class WindowsRawIpProxyProvider extends LinuxRawIpProxyProvider {
public class WindowsRawIpFlashProxyProvider extends LinuxRawIpFlashProxyProvider {
private boolean hasMapped = false;
public WindowsRawIpProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
public WindowsRawIpFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, String input_host, int input_port, boolean useSocks) {
super(proxySetter, stateSetter, hConnection, input_host, input_port, useSocks);
}

View File

@ -0,0 +1,26 @@
package gearth.protocol.connection.proxy.unity;
import javafx.beans.InvalidationListener;
import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdText;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
// tells which port the packethandler is running on
// server gets closed afterwards
@ServerEndpoint(value = "/portrequest")
public class PortRequester {
private final int packetHandlerPort;
public PortRequester(int port) {
this.packetHandlerPort = port;
}
@OnOpen
public void onOpen(Session session) throws IOException {
session.getBasicRemote().sendText("port " + packetHandlerPort);
}
}

View File

@ -0,0 +1,17 @@
package gearth.protocol.connection.proxy.unity;
import javax.websocket.server.ServerEndpointConfig;
public class PortRequesterConfig extends ServerEndpointConfig.Configurator {
private final int packetHandlerPort;
public PortRequesterConfig(int packetHandlerPort) {
this.packetHandlerPort = packetHandlerPort;
}
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
return (T)new PortRequester(packetHandlerPort);
}
}

View File

@ -0,0 +1,92 @@
package gearth.protocol.connection.proxy.unity;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.connection.*;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.packethandler.unity.UnityPacketHandler;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@ServerEndpoint(value = "/packethandler")
public class UnityCommunicator {
private final HProxySetter proxySetter;
private final HStateSetter stateSetter;
private final HConnection hConnection;
private final ProxyProvider proxyProvider;
private HProxy hProxy = null;
private String allowedSession = null;
private String revision = null;
public UnityCommunicator(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, ProxyProvider proxyProvider) {
this.proxySetter = proxySetter;
this.stateSetter = stateSetter;
this.hConnection = hConnection;
this.proxyProvider = proxyProvider;
}
@OnOpen
public void onOpen(Session session) throws IOException {
session.setMaxBinaryMessageBufferSize(1024 * 1024 * 10);
}
@OnMessage
public void onMessage(byte[] b, Session session) throws IOException {
if (allowedSession != null && !session.getId().equals(allowedSession)) {
return;
}
if (revision == null) {
revision = new String(b, StandardCharsets.ISO_8859_1);
allowedSession = session.getId();
return;
}
byte[] packet = Arrays.copyOfRange(b, 1, b.length);
if (hProxy == null && b[0] == 1) {
HPacket maybe = new HPacket(packet);
if (maybe.getBytesLength() > 6 && maybe.headerId() == 4000) {
hProxy = new HProxy(HClient.UNITY, "", "", -1, -1, "");
hProxy.verifyProxy(
new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOCLIENT),
new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOSERVER),
revision
);
proxySetter.setProxy(hProxy);
stateSetter.setState(HState.CONNECTED);
}
}
if (hProxy != null && b[0] == 0) {
hProxy.getInHandler().act(packet);
}
else if (hProxy != null && b[0] == 1) {
hProxy.getOutHandler().act(packet);
}
else {
proxyProvider.abort();
}
}
@OnClose
public void onClose(Session session) throws IOException {
proxyProvider.abort();
}
@OnError
public void onError(Session session, Throwable throwable) {
proxyProvider.abort();
}
}

View File

@ -0,0 +1,27 @@
package gearth.protocol.connection.proxy.unity;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import javax.websocket.server.ServerEndpointConfig;
public class UnityCommunicatorConfig extends ServerEndpointConfig.Configurator {
private final HProxySetter proxySetter;
private final HStateSetter stateSetter;
private final HConnection hConnection;
private final ProxyProvider proxyProvider;
public UnityCommunicatorConfig(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, ProxyProvider proxyProvider) {
this.proxySetter = proxySetter;
this.stateSetter = stateSetter;
this.hConnection = hConnection;
this.proxyProvider = proxyProvider;
}
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
return (T)new UnityCommunicator(proxySetter, stateSetter, hConnection, proxyProvider);
}
}

View File

@ -0,0 +1,168 @@
package gearth.protocol.connection.proxy.unity;
import gearth.protocol.HConnection;
import gearth.protocol.StateChangeListener;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.services.unity_tools.GUnityFileServer;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
import java.io.IOException;
import static gearth.services.unity_tools.GUnityFileServer.FILESERVER_PORT;
public class UnityProxyProvider implements ProxyProvider {
private final HProxySetter proxySetter;
private final HStateSetter stateSetter;
private final HConnection hConnection;
private Server packetHandlerServer = null;
public UnityProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection) {
this.proxySetter = proxySetter;
this.stateSetter = stateSetter;
this.hConnection = hConnection;
}
@Override
public void start() throws IOException {
// https://happyhyppo.ro/2016/03/21/minimal-websockets-communication-with-javajetty-and-angularjs/
try {
int port = 9040;
boolean fail = true;
while (fail && port < 9100) {
try {
packetHandlerServer = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/ws");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder
.create(UnityCommunicator.class, "/packethandler") // the endpoint url
.configurator(new UnityCommunicatorConfig(proxySetter, stateSetter, hConnection, this))
.build());
packetHandlerServer.setHandler(handlers);
packetHandlerServer.start();
fail = false;
}
catch (Exception e) {
port++;
}
}
if (fail) {
throw new Exception();
}
startPortRequestServer(port);
startUnityFileServer();
stateSetter.setState(HState.WAITING_FOR_CLIENT);
} catch (Exception e) {
stateSetter.setState(HState.NOT_CONNECTED);
try {
packetHandlerServer.stop();
} catch (Exception ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
@Override
public synchronized void abort() {
if (packetHandlerServer == null) {
return;
}
final Server abortThis = packetHandlerServer;
stateSetter.setState(HState.ABORTING);
new Thread(() -> {
try {
abortThis.stop();
} catch (Exception e) {
e.printStackTrace();
} finally {
stateSetter.setState(HState.NOT_CONNECTED);
}
}).start();
packetHandlerServer = null;
}
private void startUnityFileServer() throws Exception {
Server server = new Server(FILESERVER_PORT);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(new ServletHolder(new GUnityFileServer()), "/*");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
server.setHandler(handlers);
server.start();
StateChangeListener fileServerCloser = new StateChangeListener() {
@Override
public void stateChanged(HState oldState, HState newState) {
if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
hConnection.getStateObservable().removeListener(this);
try {
server.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
hConnection.getStateObservable().addListener(fileServerCloser);
}
private void startPortRequestServer(int packetHandlerPort) throws Exception {
Server portRequestServer = new Server(9039);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/ws");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
portRequestServer.setHandler(handlers);
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder
.create(PortRequester.class, "/portrequest") // the endpoint url
.configurator(new PortRequesterConfig(packetHandlerPort))
.build());
portRequestServer.start();
StateChangeListener portRequesterCloser = new StateChangeListener() {
@Override
public void stateChanged(HState oldState, HState newState) {
if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
hConnection.getStateObservable().removeListener(this);
try {
portRequestServer.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
hConnection.getStateObservable().addListener(portRequesterCloser);
}
}

View File

@ -7,7 +7,9 @@ import gearth.protocol.HPacket;
import gearth.protocol.crypto.RC4;
import gearth.protocol.memory.habboclient.HabboClient;
import gearth.protocol.memory.habboclient.HabboClientFactory;
import gearth.protocol.packethandler.*;
import gearth.protocol.packethandler.flash.BufferChangeListener;
import gearth.protocol.packethandler.flash.FlashPacketHandler;
import gearth.protocol.packethandler.PayloadBuffer;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
@ -25,17 +27,17 @@ public class Rc4Obtainer {
public static final boolean DEBUG = false;
private HabboClient client;
private List<PacketHandler> packetHandlers;
private List<FlashPacketHandler> flashPacketHandlers;
public Rc4Obtainer(HConnection hConnection) {
client = HabboClientFactory.get(hConnection);
}
public void setPacketHandlers(PacketHandler... packetHandlers) {
this.packetHandlers = Arrays.asList(packetHandlers);
public void setFlashPacketHandlers(FlashPacketHandler... flashPacketHandlers) {
this.flashPacketHandlers = Arrays.asList(flashPacketHandlers);
for (PacketHandler handler : packetHandlers) {
for (FlashPacketHandler handler : flashPacketHandlers) {
BufferChangeListener bufferChangeListener = new BufferChangeListener() {
@Override
public void act() {
@ -53,10 +55,10 @@ public class Rc4Obtainer {
private void onSendFirstEncryptedMessage(PacketHandler packetHandler) {
private void onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler) {
if (!HConnection.DECRYPTPACKETS) return;
packetHandlers.forEach(PacketHandler::block);
flashPacketHandlers.forEach(FlashPacketHandler::block);
new Thread(() -> {
@ -67,8 +69,8 @@ public class Rc4Obtainer {
int i = 0;
while (!worked && i < 4) {
worked = (i % 2 == 0) ?
onSendFirstEncryptedMessage(packetHandler, client.getRC4cached()) :
onSendFirstEncryptedMessage(packetHandler, client.getRC4possibilities());
onSendFirstEncryptedMessage(flashPacketHandler, client.getRC4cached()) :
onSendFirstEncryptedMessage(flashPacketHandler, client.getRC4possibilities());
i++;
}
@ -107,16 +109,16 @@ public class Rc4Obtainer {
System.out.println("Cracked RC4 in " + (endTime - startTime) + "ms");
}
packetHandlers.forEach(PacketHandler::unblock);
flashPacketHandlers.forEach(FlashPacketHandler::unblock);
}).start();
}
private boolean onSendFirstEncryptedMessage(PacketHandler packetHandler, List<byte[]> potentialRC4tables) {
private boolean onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler, List<byte[]> potentialRC4tables) {
for (byte[] possible : potentialRC4tables) {
byte[] encBuffer = new byte[packetHandler.getEncryptedBuffer().size()];
byte[] encBuffer = new byte[flashPacketHandler.getEncryptedBuffer().size()];
for (int i = 0; i < encBuffer.length; i++) {
encBuffer[i] = packetHandler.getEncryptedBuffer().get(i);
encBuffer[i] = flashPacketHandler.getEncryptedBuffer().get(i);
}
for (int i = 0; i < 256; i++) {
@ -124,7 +126,7 @@ public class Rc4Obtainer {
byte[] keycpy = Arrays.copyOf(possible, possible.length);
RC4 rc4Tryout = new RC4(keycpy, i, j);
if (packetHandler.getMessageSide() == HMessage.Direction.TOSERVER) rc4Tryout.undoRc4(encBuffer);
if (flashPacketHandler.getMessageSide() == HMessage.Direction.TOSERVER) rc4Tryout.undoRc4(encBuffer);
if (rc4Tryout.couldBeFresh()) {
byte[] encDataCopy = Arrays.copyOf(encBuffer, encBuffer.length);
RC4 rc4TryCopy = rc4Tryout.deepCopy();
@ -135,7 +137,7 @@ public class Rc4Obtainer {
HPacket[] checker = payloadBuffer.pushAndReceive(decoded);
if (payloadBuffer.peak().length == 0) {
packetHandler.setRc4(rc4Tryout);
flashPacketHandler.setRc4(rc4Tryout);
return true;
}

View File

@ -0,0 +1,12 @@
package gearth.protocol.packethandler;
public class ByteArrayUtils {
public static byte[] combineByteArrays(byte[] arr1, byte[] arr2) {
byte[] combined = new byte[arr1.length + arr2.length];
System.arraycopy(arr1,0,combined,0 ,arr1.length);
System.arraycopy(arr2,0,combined,arr1.length,arr2.length);
return combined;
}
}

View File

@ -1,125 +1,32 @@
package gearth.protocol.packethandler;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.TrafficListener;
import gearth.protocol.crypto.RC4;
import gearth.services.extensionhandler.ExtensionHandler;
import gearth.services.extensionhandler.OnHMessageHandled;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public abstract class PacketHandler {
protected static final boolean DEBUG = false;
protected final ExtensionHandler extensionHandler;
private final Object[] trafficObservables; //get notified on packet send
protected final PayloadBuffer payloadBuffer;
protected volatile int currentIndex = 0;
protected final Object sendLock = new Object();
private volatile PayloadBuffer payloadBuffer = new PayloadBuffer();
private volatile OutputStream out;
private volatile ExtensionHandler extensionHandler;
private volatile Object[] trafficObservables; //get notified on packet send
private volatile boolean isTempBlocked = false;
volatile boolean isDataStream = false;
private volatile int currentIndex = 0;
private final Object manipulationLock = new Object();
private final Object sendLock = new Object();
private RC4 decryptcipher = null;
private RC4 encryptcipher = null;
private volatile List<Byte> tempEncryptedBuffer = new ArrayList<>();
volatile boolean isEncryptedStream = false;
PacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
this.trafficObservables = trafficObservables;
protected PacketHandler(ExtensionHandler extensionHandler, Object[] trafficObservables) {
this.extensionHandler = extensionHandler;
out = outputStream;
}
public boolean isDataStream() {return isDataStream;}
public void setAsDataStream() {
isDataStream = true;
}
public boolean isEncryptedStream() {
return isEncryptedStream;
}
public void act(byte[] buffer) throws IOException {
if (!isDataStream) {
out.write(buffer);
return;
}
bufferChangeObservable.fireEvent();
if (!isEncryptedStream) {
payloadBuffer.push(buffer);
}
else if (!HConnection.DECRYPTPACKETS) {
synchronized (sendLock) {
out.write(buffer);
}
}
else if (decryptcipher == null) {
for (int i = 0; i < buffer.length; i++) {
tempEncryptedBuffer.add(buffer[i]);
}
}
else {
byte[] tm = decryptcipher.rc4(buffer);
if (DEBUG) {
printForDebugging(tm);
}
payloadBuffer.push(tm);
}
if (!isTempBlocked) {
flush();
}
this.trafficObservables = trafficObservables;
this.payloadBuffer = new PayloadBuffer();
}
public void setRc4(RC4 rc4) {
this.decryptcipher = rc4.deepCopy();
this.encryptcipher = rc4.deepCopy();
public abstract void sendToStream(byte[] buffer);
byte[] encrbuffer = new byte[tempEncryptedBuffer.size()];
for (int i = 0; i < tempEncryptedBuffer.size(); i++) {
encrbuffer[i] = tempEncryptedBuffer.get(i);
}
public abstract void act(byte[] buffer) throws IOException;
try {
act(encrbuffer);
} catch (IOException e) {
e.printStackTrace();
}
tempEncryptedBuffer = null;
}
public void block() {
isTempBlocked = true;
}
public void unblock() {
try {
flush();
} catch (IOException e) {
e.printStackTrace();
}
isTempBlocked = false;
}
/**
* LISTENERS CAN EDIT THE MESSAGE BEFORE BEING SENT
* @param message
*/
private void notifyListeners(int i, HMessage message) {
protected void notifyListeners(int i, HMessage message) {
((Observable<TrafficListener>) trafficObservables[i]).fireEvent(trafficListener -> {
message.getPacket().resetReadIndex();
trafficListener.onCapture(message);
@ -127,72 +34,4 @@ public abstract class PacketHandler {
message.getPacket().resetReadIndex();
}
public void sendToStream(byte[] buffer) {
synchronized (sendLock) {
try {
out.write(
(!isEncryptedStream)
? buffer
: encryptcipher.rc4(buffer)
);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void flush() throws IOException {
synchronized (manipulationLock) {
HPacket[] hpackets = payloadBuffer.receive();
for (HPacket hpacket : hpackets){
HMessage hMessage = new HMessage(hpacket, getMessageSide(), currentIndex);
boolean isencrypted = isEncryptedStream;
OnHMessageHandled afterExtensionIntercept = hMessage1 -> {
if (isDataStream) {
notifyListeners(2, hMessage1);
}
if (!hMessage1.isBlocked()) {
synchronized (sendLock) {
out.write(
(!isencrypted)
? hMessage1.getPacket().toBytes()
: encryptcipher.rc4(hMessage1.getPacket().toBytes())
);
}
}
};
if (isDataStream) {
notifyListeners(0, hMessage);
notifyListeners(1, hMessage);
extensionHandler.handle(hMessage, afterExtensionIntercept);
}
else {
afterExtensionIntercept.finished(hMessage);
}
currentIndex++;
}
}
}
public abstract HMessage.Direction getMessageSide();
public List<Byte> getEncryptedBuffer() {
return tempEncryptedBuffer;
}
protected abstract void printForDebugging(byte[] bytes);
private Observable<BufferChangeListener> bufferChangeObservable = new Observable<>(BufferChangeListener::act);
public Observable<BufferChangeListener> getBufferChangeObservable() {
return bufferChangeObservable;
}
public int getCurrentIndex() {
return currentIndex;
}
}

View File

@ -14,7 +14,7 @@ public class PayloadBuffer {
return receive();
}
public void push(byte[] tcpData) {
buffer = buffer.length == 0 ? tcpData.clone() : combineByteArrays(buffer, tcpData);
buffer = buffer.length == 0 ? tcpData.clone() : ByteArrayUtils.combineByteArrays(buffer, tcpData);
}
public HPacket[] receive() {
if (buffer.length < 6) return new HPacket[0];
@ -30,14 +30,6 @@ public class PayloadBuffer {
}
private byte[] combineByteArrays(byte[] arr1, byte[] arr2) {
byte[] combined = new byte[arr1.length + arr2.length];
System.arraycopy(arr1,0,combined,0 ,arr1.length);
System.arraycopy(arr2,0,combined,arr1.length,arr2.length);
return combined;
}
public byte[] peak() {
return buffer;
}

View File

@ -1,4 +1,4 @@
package gearth.protocol.packethandler;
package gearth.protocol.packethandler.flash;
public interface BufferChangeListener {

View File

@ -0,0 +1,182 @@
package gearth.protocol.packethandler.flash;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.TrafficListener;
import gearth.protocol.crypto.RC4;
import gearth.protocol.packethandler.PacketHandler;
import gearth.protocol.packethandler.PayloadBuffer;
import gearth.services.extensionhandler.ExtensionHandler;
import gearth.services.extensionhandler.OnHMessageHandled;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public abstract class FlashPacketHandler extends PacketHandler {
protected static final boolean DEBUG = false;
private volatile OutputStream out;
private volatile boolean isTempBlocked = false;
volatile boolean isDataStream = false;
private final Object manipulationLock = new Object();
private RC4 decryptcipher = null;
private RC4 encryptcipher = null;
private volatile List<Byte> tempEncryptedBuffer = new ArrayList<>();
volatile boolean isEncryptedStream = false;
FlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
super(extensionHandler, trafficObservables);
out = outputStream;
}
public boolean isDataStream() {return isDataStream;}
public void setAsDataStream() {
isDataStream = true;
}
public boolean isEncryptedStream() {
return isEncryptedStream;
}
public void act(byte[] buffer) throws IOException {
if (!isDataStream) {
out.write(buffer);
return;
}
bufferChangeObservable.fireEvent();
if (!isEncryptedStream) {
payloadBuffer.push(buffer);
}
else if (!HConnection.DECRYPTPACKETS) {
synchronized (sendLock) {
out.write(buffer);
}
}
else if (decryptcipher == null) {
for (int i = 0; i < buffer.length; i++) {
tempEncryptedBuffer.add(buffer[i]);
}
}
else {
byte[] tm = decryptcipher.rc4(buffer);
if (DEBUG) {
printForDebugging(tm);
}
payloadBuffer.push(tm);
}
if (!isTempBlocked) {
flush();
}
}
public void setRc4(RC4 rc4) {
this.decryptcipher = rc4.deepCopy();
this.encryptcipher = rc4.deepCopy();
byte[] encrbuffer = new byte[tempEncryptedBuffer.size()];
for (int i = 0; i < tempEncryptedBuffer.size(); i++) {
encrbuffer[i] = tempEncryptedBuffer.get(i);
}
try {
act(encrbuffer);
} catch (IOException e) {
e.printStackTrace();
}
tempEncryptedBuffer = null;
}
public void block() {
isTempBlocked = true;
}
public void unblock() {
try {
flush();
} catch (IOException e) {
e.printStackTrace();
}
isTempBlocked = false;
}
public void sendToStream(byte[] buffer) {
synchronized (sendLock) {
try {
out.write(
(!isEncryptedStream)
? buffer
: encryptcipher.rc4(buffer)
);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void flush() throws IOException {
synchronized (manipulationLock) {
HPacket[] hpackets = payloadBuffer.receive();
for (HPacket hpacket : hpackets){
HMessage hMessage = new HMessage(hpacket, getMessageSide(), currentIndex);
boolean isencrypted = isEncryptedStream;
OnHMessageHandled afterExtensionIntercept = hMessage1 -> {
if (isDataStream) {
notifyListeners(2, hMessage1);
}
if (!hMessage1.isBlocked()) {
synchronized (sendLock) {
out.write(
(!isencrypted)
? hMessage1.getPacket().toBytes()
: encryptcipher.rc4(hMessage1.getPacket().toBytes())
);
}
}
};
if (isDataStream) {
notifyListeners(0, hMessage);
notifyListeners(1, hMessage);
extensionHandler.handle(hMessage, afterExtensionIntercept);
}
else {
afterExtensionIntercept.finished(hMessage);
}
currentIndex++;
}
}
}
public abstract HMessage.Direction getMessageSide();
public List<Byte> getEncryptedBuffer() {
return tempEncryptedBuffer;
}
protected abstract void printForDebugging(byte[] bytes);
private Observable<BufferChangeListener> bufferChangeObservable = new Observable<>(BufferChangeListener::act);
public Observable<BufferChangeListener> getBufferChangeObservable() {
return bufferChangeObservable;
}
public int getCurrentIndex() {
return currentIndex;
}
}

View File

@ -1,4 +1,4 @@
package gearth.protocol.packethandler;
package gearth.protocol.packethandler.flash;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HMessage;
@ -6,13 +6,11 @@ import gearth.protocol.HPacket;
import gearth.protocol.TrafficListener;
import gearth.services.extensionhandler.ExtensionHandler;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class IncomingPacketHandler extends PacketHandler {
public class IncomingFlashPacketHandler extends FlashPacketHandler {
public IncomingPacketHandler(OutputStream outputStream, Object[] trafficObservables, OutgoingPacketHandler outgoingHandler, ExtensionHandler extensionHandler) {
public IncomingFlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, OutgoingFlashPacketHandler outgoingHandler, ExtensionHandler extensionHandler) {
super(outputStream, trafficObservables, extensionHandler);
TrafficListener listener = new TrafficListener() {

View File

@ -1,4 +1,4 @@
package gearth.protocol.packethandler;
package gearth.protocol.packethandler.flash;
public interface OnDatastreamConfirmedListener {

View File

@ -1,4 +1,4 @@
package gearth.protocol.packethandler;
package gearth.protocol.packethandler.flash;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HMessage;
@ -7,13 +7,10 @@ import gearth.services.extensionhandler.ExtensionHandler;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class OutgoingPacketHandler extends PacketHandler {
public class OutgoingFlashPacketHandler extends FlashPacketHandler {
public OutgoingPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
public OutgoingFlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
super(outputStream, trafficObservables, extensionHandler);
}

View File

@ -0,0 +1,52 @@
package gearth.protocol.packethandler.unity;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.packethandler.ByteArrayUtils;
import gearth.protocol.packethandler.PacketHandler;
import gearth.protocol.packethandler.PayloadBuffer;
import gearth.services.extensionhandler.ExtensionHandler;
import gearth.services.extensionhandler.OnHMessageHandled;
import javax.websocket.Session;
import java.io.IOException;
import java.nio.ByteBuffer;
public class UnityPacketHandler extends PacketHandler {
private final Session session;
private final HMessage.Direction direction;
public UnityPacketHandler(ExtensionHandler extensionHandler, Object[] trafficObservables, Session session, HMessage.Direction direction) {
super(extensionHandler, trafficObservables);
this.session = session;
this.direction = direction;
}
@Override
public void sendToStream(byte[] buffer) {
byte[] prefix = new byte[]{(direction == HMessage.Direction.TOCLIENT ? ((byte)0) : ((byte)1))};
byte[] combined = ByteArrayUtils.combineByteArrays(prefix, buffer);
session.getAsyncRemote().sendBinary(ByteBuffer.wrap(combined));
}
@Override
public void act(byte[] buffer) throws IOException {
HMessage hMessage = new HMessage(new HPacket(buffer), direction, currentIndex);
OnHMessageHandled afterExtensionIntercept = hMessage1 -> {
notifyListeners(2, hMessage1);
if (!hMessage1.isBlocked()) {
sendToStream(hMessage1.getPacket().toBytes());
}
};
notifyListeners(0, hMessage);
notifyListeners(1, hMessage);
extensionHandler.handle(hMessage, afterExtensionIntercept);
currentIndex++;
}
}

View File

@ -0,0 +1,7 @@
package gearth.services;
public class Constants {
public static volatile boolean UNITY_PACKETS = false;
}

View File

@ -212,6 +212,27 @@ public class ExtensionHandler {
protected void manipulatedPacket(HMessage hMessage) {
onExtensionRespond(extension, hMessage);
}
@Override
protected void packetToStringRequest(HPacket packet) {
String s = "";
String expression = "";
try {
s = packet.toString();
if (packet.length() < 3000) {
expression = packet.toExpression();
}
}
finally {
extension.packetToStringResponse(s, expression);
}
}
@Override
protected void stringToPacketRequest(String string) {
HPacket packet = new HPacket(string);
extension.stringToPacketResponse(packet);
}
};
extension.getExtensionObservable().addListener(listener);

View File

@ -12,4 +12,7 @@ public abstract class ExtensionListener {
protected void log(String text) {}
protected void hasClosed() {}
protected void packetToStringRequest(HPacket packet) {}
protected void stringToPacketRequest(String string) {}
}

View File

@ -8,6 +8,8 @@ import gearth.services.extensionhandler.extensions.listeners.OmRemoveClickListen
import gearth.services.extensionhandler.extensions.listeners.OnClickListener;
import gearth.services.extensionhandler.extensions.listeners.OnDeleteListener;
import java.util.function.Consumer;
public abstract class GEarthExtension {
@ -40,6 +42,8 @@ public abstract class GEarthExtension {
public abstract void connectionEnd();
public abstract void init();
public abstract void close();
public abstract void packetToStringResponse(String string, String expression);
public abstract void stringToPacketResponse(HPacket packet);
// ---------------------------------------------------------------
@ -78,6 +82,19 @@ public abstract class GEarthExtension {
protected void hasClosed() {
extensionObservable.fireEvent(ExtensionListener::hasClosed);
}
protected void packetToStringRequest(HPacket packet) {
int orgIndex = packet.getReadIndex();
extensionObservable.fireEvent(listener -> {
packet.setReadIndex(6);
listener.packetToStringRequest(packet);
});
packet.setReadIndex(orgIndex);
}
protected void stringToPacketRequest(String string) {
extensionObservable.fireEvent(l -> l.stringToPacketRequest(string));
}
// --------------------------------------------------------------------

View File

@ -8,6 +8,7 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* Created by Jonas on 21/06/18.
@ -88,6 +89,14 @@ public class NetworkExtension extends GEarthExtension {
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.EXTENSIONCONSOLELOG) {
log(message.readString());
}
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.PACKETTOSTRING_REQUEST) {
HPacket p = new HPacket(new byte[0]);
p.constructFromString(message.readLongString());
packetToStringRequest(p);
}
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.STRINGTOPACKET_REQUEST) {
stringToPacketRequest(message.readLongString(StandardCharsets.UTF_8));
}
}
@ -211,4 +220,19 @@ public class NetworkExtension extends GEarthExtension {
connection.close();
} catch (IOException ignored) { }
}
@Override
public void packetToStringResponse(String string, String expression) {
HPacket packet = new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.PACKETTOSTRING_RESPONSE);
packet.appendLongString(string);
packet.appendLongString(expression, StandardCharsets.UTF_8);
sendMessage(packet);
}
@Override
public void stringToPacketResponse(HPacket packetFromString) {
HPacket packet = new HPacket(NetworkExtensionInfo.OUTGOING_MESSAGES_IDS.STRINGTOPACKET_RESPONSE);
packet.appendLongString(packetFromString.stringify());
sendMessage(packet);
}
}

View File

@ -87,6 +87,9 @@ public class NetworkExtensionInfo {
public static final int CONNECTIONSTART = 5;
public static final int CONNECTIONEND = 6;
public static final int INIT = 7;
public static final int PACKETTOSTRING_RESPONSE = 20;
public static final int STRINGTOPACKET_RESPONSE = 21;
}
@ -95,6 +98,10 @@ public class NetworkExtensionInfo {
public static final int MANIPULATEDPACKET = 2;
public static final int REQUESTFLAGS = 3;
public static final int SENDMESSAGE = 4;
public static final int PACKETTOSTRING_REQUEST = 20;
public static final int STRINGTOPACKET_REQUEST = 21;
public static final int EXTENSIONCONSOLELOG = 98;
}

View File

@ -6,9 +6,7 @@ import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.*;
/**
* Created by Jonas on 16/10/18.
@ -16,15 +14,24 @@ import java.util.Random;
public class Authenticator {
private static Map<String, String> cookies = new HashMap<>();
private static Set<String> perma_cookies = new HashSet<>();
public static String generateCookieForExtension(String filename) {
String cookie = getRandomCookie();
cookies.put(filename, cookie);
return cookie;
}
public static String generatePermanentCookie() {
String cookie = getRandomCookie();
perma_cookies.add(cookie);
return cookie;
}
public static boolean evaluate(NetworkExtension extension) {
if (extension.getCookie() != null && perma_cookies.contains(extension.getCookie())) {
return true;
}
if (extension.isInstalledExtension()) {
return claimSession(extension.getFileName(), extension.getCookie());
}

View File

@ -1,6 +1,7 @@
package gearth.services.extensionhandler.extensions.implementations.simple;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.extensionhandler.extensions.GEarthExtension;
public class ExampleExtension extends GEarthExtension {
@ -105,4 +106,18 @@ public class ExampleExtension extends GEarthExtension {
// finish up and call "hasClosed()"
hasClosed();
}
// ignore these
@Override
public void packetToStringResponse(String string, String expression) {
}
@Override
public void stringToPacketResponse(HPacket packet) {
}
}

View File

@ -0,0 +1,205 @@
package gearth.services.gpython;
import gearth.Main;
import gearth.ui.extra.ExtraController;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Region;
import java.io.*;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class GPythonShell {
private final String extensionName;
private final int port;
private final String cookie;
public GPythonShell(String extensionName, int port, String cookie) {
this.extensionName = extensionName;
this.port = port;
this.cookie = cookie;
}
public void launch(OnQtConsoleLaunch onLaunch) {
new Thread(() -> {
try {
// launch the jupyter console
ProcessBuilder gConsoleBuilder = new ProcessBuilder("python", "-m", "jupyter", "console", "--simple-prompt");
Process gConsole = gConsoleBuilder.start();
InputStreamReader in = new InputStreamReader(gConsole.getInputStream());
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(gConsole.getOutputStream()));
readUntilExpectInput(in);
// obtain jupyter kernel name
List<String> sysargs = enterCommandAndAwait(out, in, "import sys; sys.argv");
String kernelName = extractKernelName(sysargs);
InputStream initScriptResource = getClass().getResourceAsStream("init_script.py");
List<String> initScript = new BufferedReader(new InputStreamReader(initScriptResource,
StandardCharsets.UTF_8)).lines().collect(Collectors.toList());
for (String line : initScript) {
line = line.replace("$G_PYTHON_SHELL_TITLE$", extensionName)
.replace("$G_EARTH_PORT$", "" + port)
.replace("$COOKIE$", cookie);
enterCommandAndAwait(out, in, line);
}
ProcessBuilder qtConsoleBuilder = new ProcessBuilder("python", "-m", "jupyter", "qtconsole",
"--ConsoleWidget.include_other_output", "True",
"--ConsoleWidget.gui_completion", "'droplist'",
// "--ConsoleWidget.other_output_prefix", "'[G-Earth]'",
// "--JupyterWidget.in_prompt", "'>>>: '",
// "--JupyterWidget.out_prompt", "''",
"--KernelManager.autorestart", "False",
"--JupyterConsoleApp.confirm_exit", "False",
"--JupyterConsoleApp.existing", kernelName);
Process qtConsole = qtConsoleBuilder.start();
new Thread(() -> {
try {
qtConsole.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
enterCommandAndAwait(out, in, "ext.stop()");
enterCommand(out, "exit()");
} catch (IOException e) {
e.printStackTrace();
}
}).start();
onLaunch.launched(false);
}
catch (Exception e) {
e.printStackTrace();
showError();
onLaunch.launched(true);
}
}).start();
}
private List<String> readUntilExpectInput(InputStreamReader in) throws IOException {
List<String> readings = new ArrayList<>();
StringBuilder builder = new StringBuilder();
int c;
while ((c = in.read()) != -1) {
char character = (char)c;
if (character == '\n') {
String reading = builder.toString();
if (reading.endsWith("\r")) {
reading = reading.substring(0, reading.length() - 1);
}
if (reading.matches("Out\\[[0-9+]]: .*")) {
reading = reading.replaceAll("^Out\\[[0-9+]]: ", "");
if (reading.equals("")) {
builder = new StringBuilder();
continue;
}
}
readings.add(reading);
builder = new StringBuilder();
}
else {
builder.append(character);
if (builder.toString().matches("In \\[[0-9]+]: ") && !in.ready()) {
return readings;
}
}
}
return null;
}
private void enterCommand(BufferedWriter out, String command) throws IOException {
out.write(command);
out.newLine();
out.flush();
}
private List<String> enterCommandAndAwait(BufferedWriter out, InputStreamReader in, String command) throws IOException {
enterCommand(out, command);
return readUntilExpectInput(in);
}
private String extractKernelName(List<String> inputArgs) {
// null if not found
String joined = String.join("", inputArgs);
String paramsFull = joined.replaceAll("^[^\\[]*\\[", "").replaceAll("][^]]*$", "");
List<String> params = new ArrayList<>();
boolean backslashed = false;
int beginParameterIndex = -1;
for (int i = 0; i < paramsFull.length(); i++) {
char c = paramsFull.charAt(i);
if (c == '\'' && !backslashed) {
if (beginParameterIndex == -1) {
beginParameterIndex = i + 1;
}
else {
params.add(paramsFull.substring(beginParameterIndex, i));
beginParameterIndex = -1;
}
}
backslashed = c == '\\' && !backslashed;
}
for (int i = 0; i < params.size() - 1; i++) {
if (params.get(i).equals("-f")) {
return "'" + params.get(i+1) + "'";
}
}
return null;
}
private void showError() {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Python error", ButtonType.OK);
alert.setTitle("G-Python error");
FlowPane fp = new FlowPane();
Label lbl = new Label("Something went wrong launching the G-Python shell," +
System.lineSeparator() + "are you sure you followed the installation guide correctly?" +
System.lineSeparator() + System.lineSeparator() + "More information here:");
Hyperlink link = new Hyperlink(ExtraController.INFO_URL_GPYTHON);
fp.getChildren().addAll(lbl, link);
link.setOnAction(event -> {
Main.main.getHostServices().showDocument(link.getText());
event.consume();
});
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.getDialogPane().setContent(fp);
alert.show();
});
}
public String getExtensionName() {
return extensionName;
}
public static void main(String[] args) {
GPythonShell shell = new GPythonShell("test", 9092, "cookie");
shell.launch((b) -> {
System.out.println("launched");
});
}
}

View File

@ -0,0 +1,96 @@
package gearth.services.gpython;
import org.apache.maven.artifact.versioning.ComparableVersion;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class GPythonVersionUtils {
private static final String MIN_GPYTHON_VERSION = "0.1";
private static final String MIN_PYTHON_VERSION = "3.2";
// returns null if python not installed
public static String pythonVersion() {
List<String> commandOutput = executeCommand("python", "--version");
if (commandOutput.size() == 0) {
return null;
}
String maybeVersion = commandOutput.get(0);
if (!maybeVersion.contains("Python")) {
return null;
}
return maybeVersion.split(" ")[1];
}
public static boolean validInstallation() {
// validates if user has all dependencies installed
String pythonVersion = pythonVersion();
if (pythonVersion == null) {
return false;
}
ComparableVersion version = new ComparableVersion(pythonVersion);
if (version.compareTo(new ComparableVersion(MIN_PYTHON_VERSION)) < 0) {
return false;
}
List<String> allPackages = executeCommand("python", "-m", "pip", "list");
allPackages = allPackages.subList(2, allPackages.size());
String qtconsole = getPackageVersion(allPackages, "qtconsole");
String pyqt5 = getPackageVersion(allPackages, "pyqt5");
String jupyterConsole = getPackageVersion(allPackages, "jupyter-console");
String gPython = getPackageVersion(allPackages, "g-python");
if (qtconsole == null || pyqt5 == null || jupyterConsole == null || gPython == null) {
return false;
}
ComparableVersion gVersion = new ComparableVersion(gPython);
return gVersion.compareTo(new ComparableVersion(MIN_GPYTHON_VERSION)) >= 0;
}
// null if not found
private static String getPackageVersion(List<String> allPackages, String pkg) {
pkg = pkg.toLowerCase();
for (String maybePkg : allPackages) {
String[] split = maybePkg.split(" +");
if (split[0].toLowerCase().equals(pkg)) {
return split[1];
}
}
return null;
}
private static List<String> executeCommand(String... command) {
List<String> output = new ArrayList<>();
try {
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.add(line);
}
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return output;
}
// public static void main(String[] args) {
// System.out.println(validInstallation());
// }
}

View File

@ -0,0 +1,7 @@
package gearth.services.gpython;
public interface OnQtConsoleLaunch {
void launched(boolean failed);
}

View File

@ -0,0 +1,150 @@
package gearth.services.unity_tools;
import gearth.Main;
import gearth.misc.Cacher;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;
public class GUnityFileServer extends HttpServlet
{
public final static int FILESERVER_PORT = 9089;
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
try {
response.addHeader("Access-Control-Allow-Origin", "*");
String path = request.getPathInfo();
if (path.equals("/ping")) {
response.setStatus(200);
return;
}
String url = request.getParameter("blabla");
if (url == null || url.isEmpty()) {
response.setStatus(404);
return;
}
response.addHeader("ETag", createETag());
String revision = url.split("/")[4];
if (path.equals("/prod")) getProd(revision, response);
else if (path.equals("/data")) getData(revision, response);
else if (path.equals("/wasm/code")) getWasmCode(revision, response);
else if (path.equals("/wasm/framework")) getWasmFramework(revision, response);
else if (path.equals("/unityloader")) getUnityLoader(revision, response);
else if (path.equals("/version")) getVersion(revision, response, url);
else if (path.equals("/logo")) getLogo(response);
else {
response.setStatus(404);
}
response.setStatus(200);
}
catch (Exception e) {
e.printStackTrace();
response.setStatus(500);
}
}
private static String getRandomHexString(int numchars){
Random r = new Random();
StringBuffer sb = new StringBuffer();
while(sb.length() < numchars){
sb.append(Integer.toHexString(r.nextInt()));
}
return sb.toString().substring(0, numchars);
}
private String createETag() {
return "W/\"" + getRandomHexString(6) + "-" + getRandomHexString(13) + "\"";
}
private String getDir(String revision) {
return Cacher.getCacheDir() + File.separator + "UNITY-" + revision + File.separator;
}
private void fileResponse(String file, HttpServletResponse response, String contentType) throws IOException {
ServletOutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(file);
// response.setContentType(contentType);
byte[] bytes = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(bytes)) != -1) {
out.write(bytes, 0, bytesRead);
}
in.close();
out.close();
}
private void getProd(String revision, HttpServletResponse response) throws IOException {
UnityWebModifyer unitywebModifyer = new UnityWebModifyer(revision, getDir(revision));
unitywebModifyer.modifyAllFiles();
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_PROD, response, "application/json");
}
private void getData(String revision, HttpServletResponse response) throws IOException {
// application/vnd.unity
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_DATA, response, "application/vnd.unity");
}
private void getWasmCode(String revision, HttpServletResponse response) throws IOException {
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_CODE, response, "application/vnd.unity");
}
private void getWasmFramework(String revision, HttpServletResponse response) throws IOException {
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_FRAMEWORK, response, "application/vnd.unity");
}
private void getUnityLoader(String revision, HttpServletResponse response) throws IOException {
UnityWebModifyer unitywebModifyer = new UnityWebModifyer(revision, getDir(revision));
unitywebModifyer.modifyAllFiles();
fileResponse(getDir(revision) + UnityWebModifyer.UNITY_LOADER, response, "text/javascript");
}
private void getVersion(String revision, HttpServletResponse response, String url) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()));
String version = in.readLine();
String realVersion = version.split(" ")[0];
response.getOutputStream().print(realVersion + " - G-Earth by sirjonasxx");
response.getOutputStream().close();
}
private void getLogo(HttpServletResponse response) throws IOException {
OutputStream out = response.getOutputStream();
InputStream in = Main.class.getResourceAsStream("G-EarthLogo.png");
byte[] bytes = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(bytes)) != -1) {
out.write(bytes, 0, bytesRead);
}
in.close();
out.close();
}
}

View File

@ -0,0 +1,176 @@
package gearth.services.unity_tools;
import wasm.disassembly.InvalidOpCodeException;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
public class UnityWebModifyer {
public final static String UNITY_PROD = "habbo2020-global-prod.json";
public final static String UNITY_DATA = "habbo2020-global-prod.data.unityweb";
public final static String UNITY_CODE = "habbo2020-global-prod.wasm.code.unityweb";
public final static String UNITY_FRAMEWORK = "habbo2020-global-prod.wasm.framework.unityweb";
public final static String UNITY_LOADER = "UnityLoader.js";
private final static String UNITYFILES_URL = "https://images.habbo.com/habbo-webgl-clients/{revision}/WebGL/habbo2020-global-prod/Build/";
private final String revision;
private final File saveFolder;
private final String currentUrl;
public UnityWebModifyer(String revision, String saveFolder) {
this.revision = revision;
this.currentUrl = UNITYFILES_URL.replace("{revision}", revision);
this.saveFolder = new File(saveFolder);
}
public boolean modifyAllFiles() {
if (saveFolder.exists()) {
return true;
}
saveFolder.mkdirs();
try {
modifyProdFile();
modifyDataFile();
modifyCodeFile();
modifyFrameworkFile();
modifyUnityLoader();
} catch (Exception e) {
e.printStackTrace();
saveFolder.delete();
return false;
}
return true;
}
// return urls for: data, code & framework file
private void modifyProdFile() throws IOException {
String prodUrl = currentUrl + UNITY_PROD;
URLConnection connection = new URL(prodUrl).openConnection();
InputStream is = connection.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
FileWriter fileWriter = new FileWriter(new File(saveFolder, UNITY_PROD));
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
String line;
while ((line = in.readLine()) != null) {
bufferedWriter.write(line);
bufferedWriter.newLine();
}
bufferedWriter.close();
in.close();
}
private void downloadToFile(URL url, File file) throws IOException {
BufferedInputStream in = new BufferedInputStream(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] dataBuffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
fileOutputStream.close();
in.close();
}
private void modifyDataFile() throws IOException {
File dataFile = new File(saveFolder, UNITY_DATA);
URL dataUrl = new URL(currentUrl + UNITY_DATA);
downloadToFile(dataUrl, dataFile);
}
private void modifyCodeFile() throws IOException, InvalidOpCodeException {
File codeFile = new File(saveFolder, UNITY_CODE);
URL codeUrl = new URL(currentUrl + UNITY_CODE);
downloadToFile(codeUrl, codeFile);
new WasmCodePatcher(codeFile.getAbsolutePath()).patch();
}
private String insertFrameworkCode(String fileContents, int index, String codeName) throws IOException {
BufferedReader code = new BufferedReader(new InputStreamReader(UnityWebModifyer.class.getResourceAsStream(codeName), StandardCharsets.UTF_8));
String firstPart = fileContents.substring(0, index);
String lastPart = fileContents.substring(index);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(firstPart);
stringBuilder.append("\n");
String line;
while ((line = code.readLine()) != null) {
stringBuilder.append(line);
stringBuilder.append("\n");
}
stringBuilder.append(lastPart);
return stringBuilder.toString();
}
private void modifyFrameworkFile() throws IOException {
File frameworkFile = new File(saveFolder, UNITY_FRAMEWORK);
URL frameworkUrl = new URL(currentUrl + UNITY_FRAMEWORK);
downloadToFile(frameworkUrl, frameworkFile);
byte[] encoded = Files.readAllBytes(Paths.get(frameworkFile.getAbsolutePath()));
String contents = new String(encoded, StandardCharsets.UTF_8);
contents = insertFrameworkCode(contents, 0, "js_code/unity_code.js");
String exportSearch = "Module.asmLibraryArg,buffer);Module[\"asm\"]=asm;";
int exportIndex = contents.indexOf(exportSearch) + exportSearch.length();
contents = insertFrameworkCode(contents, exportIndex, "js_code/unity_exports.js");
String importSearch = "if(!env[\"tableBase\"]){env[\"tableBase\"]=0}";
int importIndex = contents.indexOf(importSearch) + importSearch.length();
contents = insertFrameworkCode(contents, importIndex, "js_code/unity_imports.js");
contents = contents
.replace("var _free", "_free")
.replace("var _malloc", "_malloc")
.replace("{{RevisionName}}", revision);
BufferedWriter writer = new BufferedWriter(new FileWriter(frameworkFile));
writer.write(contents);
writer.close();
}
private void modifyUnityLoader() throws IOException {
File loaderFile = new File(saveFolder, UNITY_LOADER);
URL loaderUrl = new URL(currentUrl + UNITY_LOADER);
downloadToFile(loaderUrl, loaderFile);
byte[] encoded = Files.readAllBytes(Paths.get(loaderFile.getAbsolutePath()));
String contents = new String(encoded, StandardCharsets.UTF_8);
contents = contents.replace("o.result.responseHeaders[e]==a.getResponseHeader(e)", "false");
contents = contents.replace("i.responseHeaders[e]=o.getResponseHeader(e)",
"const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');\n" +
" if (e === \"ETag\") {\n" +
" i.responseHeaders[e] = \"W/\\\"\" + genRanHex(6) + \"-\" + genRanHex(13) + \"\\\"\"\n" +
" }\n" +
" else {\n" +
" i.responseHeaders[e] = o.getResponseHeader(e)\n" +
" }");
BufferedWriter writer = new BufferedWriter(new FileWriter(loaderFile));
writer.write(contents);
writer.close();
}
}

View File

@ -0,0 +1,30 @@
package gearth.services.unity_tools;
import gearth.services.unity_tools.codepatcher.IncomingPacketPatcher;
import gearth.services.unity_tools.codepatcher.OutgoingPacketPatcher;
import gearth.services.unity_tools.codepatcher.ReturnBytePatcher;
import gearth.services.unity_tools.codepatcher.SetKeyPatcher;
import wasm.disassembly.InvalidOpCodeException;
import wasm.disassembly.modules.Module;
import java.io.IOException;
import java.util.Arrays;
public class WasmCodePatcher {
private String file;
public WasmCodePatcher(String file) {
this.file = file;
}
public void patch() throws IOException, InvalidOpCodeException {
Module module = new Module(file, Arrays.asList(
new SetKeyPatcher(),
new ReturnBytePatcher(),
new OutgoingPacketPatcher(),
new IncomingPacketPatcher()
));
module.assembleToFile(file);
}
}

View File

@ -0,0 +1,225 @@
//package gearth.services.unity_tools;
//
//import wasm.disassembly.InvalidOpCodeException;
//import wasm.disassembly.instructions.Expression;
//import wasm.disassembly.instructions.Instr;
//import wasm.disassembly.instructions.InstrType;
//import wasm.disassembly.instructions.control.CallInstr;
//import wasm.disassembly.instructions.variable.LocalVariableInstr;
//import wasm.disassembly.modules.Module;
//import wasm.disassembly.modules.indices.FuncIdx;
//import wasm.disassembly.modules.indices.LocalIdx;
//import wasm.disassembly.modules.indices.TypeIdx;
//import wasm.disassembly.modules.sections.code.Func;
//import wasm.disassembly.modules.sections.export.Export;
//import wasm.disassembly.modules.sections.export.ExportDesc;
//import wasm.disassembly.modules.sections.imprt.Import;
//import wasm.disassembly.modules.sections.imprt.ImportDesc;
//import wasm.disassembly.types.FuncType;
//import wasm.disassembly.types.ResultType;
//import wasm.disassembly.types.ValType;
//import wasm.misc.Function;
//
//import java.io.*;
//import java.util.*;
//
//public class WasmCodePatcherOld {
//
// private String file;
//
// public WasmCodePatcherOld(String file) {
// this.file = file;
// }
//
// public void patch() throws IOException, InvalidOpCodeException {
// Module module = new Module(file);
//
// FuncIdx returnByteId = findReturnByteFunc(module);
// FuncIdx setkey = findSetKeyFunc(module);
// FuncIdx outgoingIdx = findOutFunc(module);
// FuncIdx incomingIdx = findInFunc(module);
//
// hook(module, setkey, "g_chacha_setkey");
// copyEmptyHook(module, returnByteId, "_gearth_returnbyte_copy", "g_chacha_returnbyte");
// copyEmptyHook(module, outgoingIdx, "_gearth_outgoing_copy", "g_outgoing_packet");
// copyEmptyHook(module, incomingIdx, "_gearth_incoming_copy", "g_incoming_packet");
//
// module.assembleToFile(file);
// }
//
//
// private FuncIdx findOutFunc(Module module) {
// TypeIdx expectedTypeIdx = module.getTypeSection().getTypeIdxForFuncType(new FuncType(
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
// new ResultType(Collections.emptyList())
// ));
//
// outerloop:
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
// FuncIdx currentIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
//
// Func func = module.getCodeSection().getByIdx(currentIdx);
// if (func.getLocalss().size() != 0) continue;
// if (!module.getFunctionSection().getByIdx(currentIdx).equals(expectedTypeIdx)) continue;
//
// List<Instr> expression = func.getExpression().getInstructions();
//
// if (expression.size() != 6) continue;
//
// if (expression.get(0).getInstrType() != InstrType.LOCAL_GET) continue;
// if (expression.get(1).getInstrType() != InstrType.LOCAL_GET) continue;
// if (expression.get(2).getInstrType() != InstrType.LOCAL_GET) continue;
// if (expression.get(3).getInstrType() != InstrType.I32_LOAD) continue;
// if (expression.get(4).getInstrType() != InstrType.I32_CONST) continue;
// if (expression.get(5).getInstrType() != InstrType.CALL) continue;
//
// return currentIdx;
// }
//
// return null;
// }
// private FuncIdx findSetKeyFunc(Module module) {
// FuncType expectedType = new FuncType(
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
// new ResultType(Collections.emptyList())
// );
//
// List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
// InstrType.I32_EQZ, InstrType.IF, InstrType.BLOCK, InstrType.LOCAL_GET, InstrType.I32_CONST,
// InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.I32_CONST, InstrType.I32_CONST, InstrType.I32_CONST,
// InstrType.CALL);
//
// outerloop:
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
// FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
//
// Function function = new Function(module, funcIdx);
// if (!function.getFuncType().equals(expectedType)) continue;
// if (!(function.getLocalsFloored().size() == 1 && function.getLocalsFloored().get(0) == ValType.I32)) continue;
// if (function.getCode().getInstructions().size() != expectedExpr.size()) continue;
//
// for (int j = 0; j < function.getCode().getInstructions().size(); j++) {
// Instr instr = function.getCode().getInstructions().get(j);
// if (instr.getInstrType() != expectedExpr.get(j)) continue outerloop;
// }
//
// return funcIdx;
// }
//
// return null;
// }
// private FuncIdx findReturnByteFunc(Module module) {
// FuncType expectedType = new FuncType(
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
// new ResultType(Collections.singletonList(ValType.I32))
// );
//
// outerloop:
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
// FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
//
// Function function = new Function(module, funcIdx);
// if (!function.getFuncType().equals(expectedType)) continue;
// if (function.getLocalsFloored().size() != 0) continue;
// if (function.getCode().getInstructions().size() != 30) continue;
//
// List<Instr> expr = function.getCode().getInstructions();
// if (expr.get(expr.size() - 1).getInstrType() != InstrType.I32_XOR) continue;
//
// return funcIdx;
// }
//
// return null;
// }
// private FuncIdx findInFunc(Module module) {
// FuncType expectedType = new FuncType(
// new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
// new ResultType(Collections.emptyList())
// );
//
// List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
// InstrType.I32_EQZ, InstrType.IF, InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.LOCAL_TEE,
// InstrType.IF);
//
// outerloop:
// for (int i = 0; i < module.getCodeSection().getCodesEntries().size(); i++) {
// FuncIdx funcIdx = new FuncIdx(i + module.getImportSection().getTotalFuncImports(), module);
//
// Function function = new Function(module, funcIdx);
// if (!function.getFuncType().equals(expectedType)) continue;
// if (!(function.getLocalsFloored().size() == 1 && function.getLocalsFloored().get(0) == ValType.I32)) continue;
// if (function.getCode().getInstructions().size() != expectedExpr.size()) continue;
//
// for (int j = 0; j < function.getCode().getInstructions().size(); j++) {
// Instr instr = function.getCode().getInstructions().get(j);
// if (instr.getInstrType() != expectedExpr.get(j)) continue outerloop;
// }
//
// return funcIdx;
// }
//
// return null;
// }
//
// private void copyEmptyHook(Module module, FuncIdx orgFuncIdx, String exportName, String hookname) throws InvalidOpCodeException, IOException {
// // copies the method, empties the first one
// // export the copy
// // hooks to the emptied one
//
// Func func = module.getCodeSection().getByIdx(orgFuncIdx);
// FuncType funcType = module.getTypeSection().getByFuncIdx(orgFuncIdx);
//
// // copy the function
// Function copy = new Function(funcType, func.getLocalss(), func.getExpression());
// FuncIdx copyIdx = copy.addToModule(module);
//
// module.getExportSection().getExports().add(new Export(exportName, new ExportDesc(copyIdx)));
//
//
// // clear & hook original function, let it return whatever JS returns
// Import imp = new Import(
// "env",
// hookname,
// new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType(
// funcType.getParameterType(),
// funcType.getResultType()
// )))
// );
// FuncIdx hookIdx = module.getImportSection().importFunction(imp);
//
// CallInstr call = new CallInstr(hookIdx);
// List<Instr> newInstrs = new ArrayList<>();
// for (int i = 0; i < funcType.getParameterType().typeList().size(); i++) {
// newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(i)));
// }
// newInstrs.add(call);
// func.setExpression(new Expression(newInstrs));
//
// }
//
// private void hook(Module module, FuncIdx funcIdx, String jsFunctionName) throws InvalidOpCodeException, IOException {
// FuncType funcType = module.getTypeSection().getByFuncIdx(funcIdx);
//
// Import imp = new Import(
// "env",
// jsFunctionName,
// new ImportDesc(module.getTypeSection().getTypeIdxForFuncType(new FuncType(
// funcType.getParameterType(),
// new ResultType(Collections.emptyList())
// )))
// );
// FuncIdx hookIdx = module.getImportSection().importFunction(imp);
//
// CallInstr call = new CallInstr(hookIdx);
//
// Func root = module.getCodeSection().getByIdx(funcIdx);
// List<Instr> newInstrs = new ArrayList<>();
// for (int i = 0; i < funcType.getParameterType().typeList().size(); i++) {
// newInstrs.add(new LocalVariableInstr(InstrType.LOCAL_GET, new LocalIdx(i)));
// }
// newInstrs.add(call);
// newInstrs.addAll(root.getExpression().getInstructions());
// root.getExpression().setInstructions(newInstrs);
// }
//
//}

View File

@ -0,0 +1,60 @@
package gearth.services.unity_tools.codepatcher;
import wasm.disassembly.instructions.Instr;
import wasm.disassembly.instructions.InstrType;
import wasm.disassembly.modules.sections.code.Func;
import wasm.disassembly.modules.sections.code.Locals;
import wasm.disassembly.types.FuncType;
import wasm.disassembly.types.ResultType;
import wasm.disassembly.types.ValType;
import wasm.misc.CodeCompare;
import wasm.misc.StreamReplacement;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class IncomingPacketPatcher implements StreamReplacement {
@Override
public FuncType getFuncType() {
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
new ResultType(Collections.emptyList())
);
}
@Override
public ReplacementType getReplacementType() {
return ReplacementType.HOOKCOPYEXPORT;
}
@Override
public String getImportName() {
return "g_incoming_packet";
}
@Override
public String getExportName() {
return "_gearth_incoming_copy";
}
@Override
public CodeCompare getCodeCompare() {
return code -> {
if (!(code.getLocalss().equals(Collections.singletonList(new Locals(1, ValType.I32)))))
return false;
List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
InstrType.I32_EQZ, InstrType.IF, InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.LOCAL_TEE,
InstrType.IF);
if (code.getExpression().getInstructions().size() != expectedExpr.size()) return false;
for (int j = 0; j < code.getExpression().getInstructions().size(); j++) {
Instr instr = code.getExpression().getInstructions().get(j);
if (instr.getInstrType() != expectedExpr.get(j)) return false;
}
return true;
};
}
}

View File

@ -0,0 +1,53 @@
package gearth.services.unity_tools.codepatcher;
import wasm.disassembly.instructions.Instr;
import wasm.disassembly.instructions.InstrType;
import wasm.disassembly.modules.sections.code.Func;
import wasm.disassembly.types.FuncType;
import wasm.disassembly.types.ResultType;
import wasm.disassembly.types.ValType;
import wasm.misc.CodeCompare;
import wasm.misc.StreamReplacement;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class OutgoingPacketPatcher implements StreamReplacement {
@Override
public FuncType getFuncType() {
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
new ResultType(Collections.emptyList()));
}
@Override
public ReplacementType getReplacementType() {
return ReplacementType.HOOKCOPYEXPORT;
}
@Override
public String getImportName() {
return "g_outgoing_packet";
}
@Override
public String getExportName() {
return "_gearth_outgoing_copy";
}
@Override
public CodeCompare getCodeCompare() {
return code -> {
if (code.getLocalss().size() != 0) return false;
List<Instr> expression = code.getExpression().getInstructions();
if (expression.get(0).getInstrType() != InstrType.LOCAL_GET) return false;
if (expression.get(1).getInstrType() != InstrType.LOCAL_GET) return false;
if (expression.get(2).getInstrType() != InstrType.LOCAL_GET) return false;
if (expression.get(3).getInstrType() != InstrType.I32_LOAD) return false;
if (expression.get(4).getInstrType() != InstrType.I32_CONST) return false;
if (expression.get(5).getInstrType() != InstrType.CALL) return false;
return true;
};
}
}

View File

@ -0,0 +1,48 @@
package gearth.services.unity_tools.codepatcher;
import wasm.disassembly.instructions.Instr;
import wasm.disassembly.instructions.InstrType;
import wasm.disassembly.modules.sections.code.Func;
import wasm.disassembly.types.FuncType;
import wasm.disassembly.types.ResultType;
import wasm.disassembly.types.ValType;
import wasm.misc.CodeCompare;
import wasm.misc.StreamReplacement;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ReturnBytePatcher implements StreamReplacement {
@Override
public FuncType getFuncType() {
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32)),
new ResultType(Collections.singletonList(ValType.I32)));
}
@Override
public ReplacementType getReplacementType() {
return ReplacementType.HOOKCOPYEXPORT;
}
@Override
public String getImportName() {
return "g_chacha_returnbyte";
}
@Override
public String getExportName() {
return "_gearth_returnbyte_copy";
}
@Override
public CodeCompare getCodeCompare() {
return code -> {
if (code.getLocalss().size() != 0) return false;
if (code.getExpression().getInstructions().size() != 30) return false;
List<Instr> expr = code.getExpression().getInstructions();
if (expr.get(expr.size() - 1).getInstrType() != InstrType.I32_XOR) return false;
return true;
};
}
}

View File

@ -0,0 +1,60 @@
package gearth.services.unity_tools.codepatcher;
import wasm.disassembly.instructions.Instr;
import wasm.disassembly.instructions.InstrType;
import wasm.disassembly.modules.sections.code.Func;
import wasm.disassembly.modules.sections.code.Locals;
import wasm.disassembly.types.FuncType;
import wasm.disassembly.types.ResultType;
import wasm.disassembly.types.ValType;
import wasm.misc.CodeCompare;
import wasm.misc.StreamReplacement;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SetKeyPatcher implements StreamReplacement {
@Override
public FuncType getFuncType() {
return new FuncType(new ResultType(Arrays.asList(ValType.I32, ValType.I32, ValType.I32, ValType.I32)),
new ResultType(Collections.emptyList()));
}
@Override
public ReplacementType getReplacementType() {
return ReplacementType.HOOK;
}
@Override
public String getImportName() {
return "g_chacha_setkey";
}
@Override
public String getExportName() {
return null;
}
@Override
public CodeCompare getCodeCompare() {
return code -> {
if (!(code.getLocalss().equals(Collections.singletonList(new Locals(1, ValType.I32)))))
return false;
List<InstrType> expectedExpr = Arrays.asList(InstrType.I32_CONST, InstrType.I32_LOAD8_S,
InstrType.I32_EQZ, InstrType.IF, InstrType.BLOCK, InstrType.LOCAL_GET, InstrType.I32_CONST,
InstrType.LOCAL_GET, InstrType.I32_LOAD, InstrType.I32_CONST, InstrType.I32_CONST, InstrType.I32_CONST,
InstrType.CALL);
if (code.getExpression().getInstructions().size() != expectedExpr.size()) return false;
for (int j = 0; j < code.getExpression().getInstructions().size(); j++) {
Instr instr = code.getExpression().getInstructions().get(j);
if (instr.getInstrType() != expectedExpr.get(j)) return false;
}
return true;
};
}
}

View File

@ -1,6 +1,8 @@
package gearth.ui;
import gearth.ui.logger.loggerdisplays.PacketLoggerFactory;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.Pane;
@ -44,52 +46,35 @@ public class GEarthController {
public void initialize() {
tabs = new ArrayList<>();
// must be ordered correctly
tabs.add(connectionController);
tabs.add(injectionController);
tabs.add(loggerController);
tabs.add(toolsController);
tabs.add(schedulerController);
tabs.add(extensionsController);
tabs.add(extraController);
tabs.add(infoController);
tabs.add(extensionsController);
synchronized (this) {
trySetController();
}
List<Tab> uiTabs = tabBar.getTabs();
for (int i = 0; i < uiTabs.size(); i++) {
Tab tab = uiTabs.get(i);
int[] ii = {i};
tab.setOnSelectionChanged(event -> {
if (tab.isSelected()) {
tabs.get(ii[0]).onTabOpened();
}
});
}
if (PacketLoggerFactory.usesUIlogger()) {
tabBar.getTabs().remove(tab_Logger);
}
//custom header bar
// final Point[] startpos = {null};
// final Double[] xx = {0.0};
// final Double[] yy = {0.0};
// final Boolean[] isMoving = {false};
//
// mover.addEventHandler(MouseEvent.MOUSE_PRESSED,
// event -> {
// startpos[0] = MouseInfo.getPointerInfo().getLocation();
// xx[0] = stage.getX();
// yy[0] = stage.getY();
// isMoving[0] = true;
// });
//
// mover.addEventHandler(MouseEvent.MOUSE_RELEASED,
// event -> {
// isMoving[0] = false;
// });
//
//
// mover.setOnMouseDragged(event -> {
// if (isMoving[0]) {
// Point now = MouseInfo.getPointerInfo().getLocation();
// double diffX = now.getX() - startpos[0].getX();
// double diffY = now.getY() - startpos[0].getY();
// stage.setX(xx[0] + diffX);
// stage.setY(yy[0] + diffY);
// }
// });
}
public void setStage(Stage stage) {
@ -122,5 +107,4 @@ public class GEarthController {
tabs.forEach(SubForm::exit);
hConnection.abort();
}
}

View File

@ -28,6 +28,10 @@ public class SubForm {
}
protected void onTabOpened() {
}
protected HConnection getHConnection() {
return parentController.getHConnection();
}

View File

@ -18,8 +18,8 @@ public class BoxButton extends StackPane {
//paths zijn relatief aan deze classpath
public BoxButton(String imageName, String imageOnHoverName) {
this.image = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/" + imageName));
this.imageOnHover = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/" + imageOnHoverName));
this.image = new Image(getClass().getResourceAsStream("files/" + imageName));
this.imageOnHover = new Image(getClass().getResourceAsStream("files/" + imageOnHoverName));
this.imageView = new ImageView();
setCursor(Cursor.DEFAULT);

View File

@ -33,10 +33,10 @@ public class PauseResumeButton extends StackPane{
public PauseResumeButton(boolean isPaused) {
this.isPaused[0] = isPaused;
this.imagePause = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonPause.png"));
this.imagePauseOnHover = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonPauseHover.png"));
this.imageResume = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonResume.png"));
this.imageResumeOnHover = new Image(getClass().getResourceAsStream("/gearth/ui/buttons/files/ButtonResumeHover.png"));
this.imagePause = new Image(getClass().getResourceAsStream("files/ButtonPause.png"));
this.imagePauseOnHover = new Image(getClass().getResourceAsStream("files/ButtonPauseHover.png"));
this.imageResume = new Image(getClass().getResourceAsStream("files/ButtonResume.png"));
this.imageResumeOnHover = new Image(getClass().getResourceAsStream("files/ButtonResumeHover.png"));
this.imageView = new ImageView();
setCursor(Cursor.DEFAULT);

View File

@ -98,7 +98,9 @@ public class ConnectionController extends SubForm {
txtfield_hotelversion.setText(getHConnection().getHotelVersion());
btnConnect.setDisable(getHConnection().getState() == HState.PREPARING || getHConnection().getState() == HState.ABORTING);
if (!cbx_autodetect.isSelected() && !btnConnect.isDisable()) {
if (!cbx_autodetect.isSelected() && !btnConnect.isDisable() && useFlash()) {
try {
int i = Integer.parseInt(inpPort.getEditor().getText());
btnConnect.setDisable(i < 0 || i >= 256 * 256);
@ -110,6 +112,13 @@ public class ConnectionController extends SubForm {
inpHost.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpPort.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
cbx_autodetect.setDisable(!useFlash());
outHost.setDisable(!useFlash());
outPort.setDisable(!useFlash());
inpHost.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpPort.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
}
public void onParentSet(){
@ -134,14 +143,15 @@ public class ConnectionController extends SubForm {
if (newState == HState.CONNECTED) {
lblState.setText("Connected");
outHost.setText(getHConnection().getDomain());
outPort.setText(getHConnection().getServerPort()+"");
}
if (newState == HState.WAITING_FOR_CLIENT) {
lblState.setText("Waiting for connection");
}
if (newState == HState.CONNECTED) {
if (newState == HState.CONNECTED && useFlash()) {
outHost.setText(getHConnection().getDomain());
outPort.setText(getHConnection().getServerPort()+"");
JSONObject connectionSettings = new JSONObject();
connectionSettings.put(AUTODETECT_CACHE, cbx_autodetect.isSelected());
connectionSettings.put(HOST_CACHE, inpHost.getEditor().getText());
@ -158,12 +168,19 @@ public class ConnectionController extends SubForm {
btnConnect.setDisable(true);
new Thread(() -> {
if (useFlash()) {
if (cbx_autodetect.isSelected()) {
getHConnection().start();
}
else {
getHConnection().start(inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText()));
}
}
else {
getHConnection().startUnity();
}
if (HConnection.DEBUG) System.out.println("connecting");
}).start();
@ -179,4 +196,11 @@ public class ConnectionController extends SubForm {
getHConnection().abort();
}
public void changeClientMode() {
updateInputUI();
}
private boolean useFlash() {
return parentController.extraController.rd_flash.isSelected();
}
}

View File

@ -1,25 +1,31 @@
package gearth.ui.extensions;
import gearth.Main;
import gearth.services.extensionhandler.ExtensionConnectedListener;
import gearth.services.extensionhandler.ExtensionHandler;
import gearth.services.extensionhandler.extensions.ExtensionListener;
import gearth.services.extensionhandler.extensions.GEarthExtension;
import gearth.services.extensionhandler.extensions.implementations.network.NetworkExtensionsProducer;
import gearth.services.extensionhandler.extensions.implementations.network.authentication.Authenticator;
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExecutionInfo;
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExtensionRunner;
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExtensionRunnerFactory;
import gearth.services.gpython.GPythonShell;
import gearth.services.gpython.OnQtConsoleLaunch;
import gearth.ui.SubForm;
import gearth.ui.extensions.logger.ExtensionLogger;
import gearth.ui.extra.ExtraController;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import java.io.File;
import java.io.IOException;
/**
* Created by Jonas on 06/04/18.
@ -29,12 +35,12 @@ public class ExtensionsController extends SubForm {
public Button btn_install;
public Button btn_remove;
public TextField ext_port;
public VBox extensioncontainer;
public GridPane header_ext;
public ScrollPane scroller;
public Button btn_viewExtensionConsole;
public Button btn_gpython;
private ExtensionRunner extensionRunner = null;
private ExtensionHandler extensionHandler;
@ -98,6 +104,33 @@ public class ExtensionsController extends SubForm {
else {
extensionLogger.hide();
}
}
@Override
protected void onTabOpened() {
updateGPythonStatus();
}
public void updateGPythonStatus() {
if (!pythonShellLaunching) {
btn_gpython.setDisable(!parentController.extraController.useGPython());
}
}
private volatile int gpytonShellCounter = 1;
private volatile boolean pythonShellLaunching = false;
public void gpythonBtnClicked(ActionEvent actionEvent) {
pythonShellLaunching = true;
Platform.runLater(() -> btn_gpython.setDisable(true));
GPythonShell shell = new GPythonShell(
"Scripting shell " + gpytonShellCounter++,
networkExtensionsProducer.getPort(),
Authenticator.generatePermanentCookie()
);
shell.launch((b) -> {
pythonShellLaunching = false;
Platform.runLater(this::updateGPythonStatus);
});
}
}

View File

@ -1,14 +1,22 @@
package gearth.ui.extra;
import gearth.Main;
import gearth.misc.Cacher;
import gearth.misc.packetrepresentation.prediction.checkers.TypeCheckerProducer;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.services.Constants;
import gearth.services.gpython.GPythonVersionUtils;
import gearth.ui.SubForm;
import gearth.ui.info.InfoController;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import org.json.JSONObject;
/**
@ -16,12 +24,17 @@ import org.json.JSONObject;
*/
public class ExtraController extends SubForm implements SocksConfiguration {
public static final String INFO_URL_GPYTHON = "https://github.com/sirjonasxx/G-Earth/wiki/G-Python-qtConsole";
public static final String NOTEPAD_CACHE_KEY = "notepad_text";
public static final String SOCKS_CACHE_KEY = "socks_config";
public static final String GPYTHON_CACHE_KEY = "use_gpython";
public static final String USE_UNITY_CLIENT_CACHE_KEY = "use_unity";
public static final String SOCKS_IP = "ip";
public static final String SOCKS_PORT = "port";
public static final String IGNORE_ONCE = "ignore_once";
// public static final String IGNORE_ONCE = "ignore_once";
public TextArea txtarea_notepad;
@ -29,20 +42,32 @@ public class ExtraController extends SubForm implements SocksConfiguration {
public CheckBox cbx_alwaysOnTop;
public Hyperlink url_troubleshooting;
//TODO add setup link to g-earth wiki
public CheckBox cbx_gpython;
public CheckBox cbx_advanced;
public GridPane grd_advanced;
public CheckBox cbx_disableDecryption;
public CheckBox cbx_debug;
public CheckBox cbx_useSocks;
public GridPane grd_socksInfo;
public TextField txt_socksPort;
public TextField txt_socksIp;
public CheckBox cbx_socksUseIfNeeded;
public ToggleGroup tgl_clientMode;
public RadioButton rd_unity;
public RadioButton rd_flash;
public GridPane grd_clientSelection;
public void initialize() {
Constants.UNITY_PACKETS = rd_unity.isSelected();
tgl_clientMode.selectedToggleProperty().addListener(observable -> {
if (parentController != null) parentController.connectionController.changeClientMode();
Constants.UNITY_PACKETS = rd_unity.isSelected();
});
url_troubleshooting.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting"));
InfoController.activateHyperlink(url_troubleshooting);
@ -56,7 +81,16 @@ public class ExtraController extends SubForm implements SocksConfiguration {
JSONObject socksInitValue = Cacher.getCacheContents().getJSONObject(SOCKS_CACHE_KEY);
txt_socksIp.setText(socksInitValue.getString(SOCKS_IP));
txt_socksPort.setText(socksInitValue.getString(SOCKS_PORT));
cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE));
// cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE));
}
if (Cacher.getCacheContents().has(GPYTHON_CACHE_KEY)) {
cbx_gpython.setSelected(Cacher.getCacheContents().getBoolean(GPYTHON_CACHE_KEY));
}
if (Cacher.getCacheContents().has(USE_UNITY_CLIENT_CACHE_KEY)) {
rd_unity.setSelected(Cacher.getCacheContents().getBoolean(USE_UNITY_CLIENT_CACHE_KEY));
rd_flash.setSelected(!Cacher.getCacheContents().getBoolean(USE_UNITY_CLIENT_CACHE_KEY));
}
cbx_debug.selectedProperty().addListener(observable -> HConnection.DEBUG = cbx_debug.isSelected());
@ -85,6 +119,8 @@ public class ExtraController extends SubForm implements SocksConfiguration {
@Override
protected void onExit() {
Cacher.put(NOTEPAD_CACHE_KEY, txtarea_notepad.getText());
Cacher.put(GPYTHON_CACHE_KEY, cbx_gpython.isSelected());
Cacher.put(USE_UNITY_CLIENT_CACHE_KEY, rd_unity.isSelected());
saveSocksConfig();
}
@ -92,11 +128,13 @@ public class ExtraController extends SubForm implements SocksConfiguration {
JSONObject jsonObject = new JSONObject();
jsonObject.put(SOCKS_IP, txt_socksIp.getText());
jsonObject.put(SOCKS_PORT, txt_socksPort.getText());
jsonObject.put(IGNORE_ONCE, cbx_socksUseIfNeeded.isSelected());
// jsonObject.put(IGNORE_ONCE, cbx_socksUseIfNeeded.isSelected());
Cacher.put(SOCKS_CACHE_KEY, jsonObject);
}
private void updateAdvancedUI() {
grd_clientSelection.setDisable(getHConnection().getState() != HState.NOT_CONNECTED);
if (!cbx_advanced.isSelected()) {
cbx_debug.setSelected(false);
cbx_useSocks.setSelected(false);
@ -127,6 +165,54 @@ public class ExtraController extends SubForm implements SocksConfiguration {
@Override
public boolean onlyUseIfNeeded() {
return cbx_socksUseIfNeeded.isSelected();
// return cbx_socksUseIfNeeded.isSelected();
return false;
}
public boolean useGPython() {
return cbx_gpython.isSelected();
}
public void gpythonCbxClick(ActionEvent actionEvent) {
if (cbx_gpython.isSelected()) {
new Thread(() -> {
Platform.runLater(() -> {
cbx_gpython.setSelected(false);
cbx_gpython.setDisable(true);
});
if (!GPythonVersionUtils.validInstallation()) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Python installation", ButtonType.OK);
alert.setTitle("G-Python installation");
FlowPane fp = new FlowPane();
Label lbl = new Label("Before using G-Python, install the right packages using pip!" +
System.lineSeparator() + System.lineSeparator() + "More information here:");
Hyperlink link = new Hyperlink(INFO_URL_GPYTHON);
fp.getChildren().addAll( lbl, link);
link.setOnAction(event -> {
Main.main.getHostServices().showDocument(link.getText());
event.consume();
});
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.getDialogPane().setContent(fp);
alert.show();
cbx_gpython.setDisable(false);
});
}
else {
Platform.runLater(() -> {
cbx_gpython.setSelected(true);
cbx_gpython.setDisable(false);
parentController.extensionsController.updateGPythonStatus();
});
}
}).start();
}
}
}

View File

@ -2,27 +2,27 @@ package gearth.ui.info;
import gearth.Main;
import javafx.event.ActionEvent;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.*;
import gearth.ui.SubForm;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Region;
import javafx.scene.web.WebView;
/**
* Created by Jonas on 06/04/18.
*/
public class InfoController extends SubForm {
public ImageView img_logo;
public Hyperlink link_sng;
public Hyperlink link_ase;
public Hyperlink link_darkbox;
public Hyperlink link_d_harble;
public Hyperlink link_g_gearth;
public Hyperlink link_g_tanji;
public Hyperlink link_d_bonnie;
public Label version;
public Hyperlink link_d_gearth;
// this is a TEMPORARY info tab
public Label version;
public static void activateHyperlink(Hyperlink link) {
link.setOnAction((ActionEvent event) -> {
@ -38,16 +38,36 @@ public class InfoController extends SubForm {
img_logo.setImage(new Image("/gearth/G-EarthLogo.png"));
link_sng.setTooltip(new Tooltip("https://www.sngforum.info"));
link_ase.setTooltip(new Tooltip("https://allseeingeye.to"));
link_darkbox.setTooltip(new Tooltip("https://darkbox.nl"));
link_d_harble.setTooltip(new Tooltip("https://discord.gg/CzRuHvW"));
link_d_gearth.setTooltip(new Tooltip("https://discord.gg/AVkcF8y"));
link_g_gearth.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth"));
link_g_tanji.setTooltip(new Tooltip("https://github.com/ArachisH/Tanji"));
link_d_harble.setTooltip(new Tooltip("https://discord.gg/CzRuHvW"));
activateHyperlink(link_ase);
activateHyperlink(link_darkbox);
activateHyperlink(link_d_harble);
activateHyperlink(link_d_gearth);
activateHyperlink(link_g_gearth);
activateHyperlink(link_g_tanji);
activateHyperlink(link_sng);
activateHyperlink(link_darkbox);
}
public void donate(ActionEvent actionEvent) {
String pubkey = "1GEarthEV9Ua3RcixsKTcuc1PPZd9hqri3";
Alert alert = new Alert(Alert.AlertType.INFORMATION, "Donate Bitcoins", ButtonType.OK);
alert.setHeaderText("Donate Bitcoins");
WebView webView = new WebView();
webView.getEngine().loadContent("<html>Bitcoin public address:<br><br>" +
"<textarea>" + pubkey +"</textarea>" +
"</html>");
webView.setPrefSize(200, 100);
alert.setResizable(false);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.getDialogPane().setContent(webView);
alert.show();
}
}

View File

@ -136,8 +136,8 @@ public class InjectionController extends SubForm {
public static void main(String[] args) {
HPacket[] packets = parsePackets("{l}{u:3}{i:967585}{i:9589}{s:\"furni_inscriptionfuckfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\"}{s:\"sirjonasxx-II\"}{s:\"\"}{i:188}{i:0}{i:0}{b:false}");
System.out.println(new HPacket("{l}{u:2550}{s:\"ClientPerf\"\"ormance\\\"}\"}{s:\"23\"}{s:\"fps\"}{s:\"Avatars: 1, Objects: 0\"}{i:76970180}").toExpression());
HPacket[] packets = parsePackets("{l}{h:3}{i:967585}{i:9589}{s:\"furni_inscriptionfuckfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionfurni_inscriptionsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\"}{s:\"sirjonasxx-II\"}{s:\"\"}{i:188}{i:0}{i:0}{b:false}");
System.out.println(new HPacket("{l}{h:2550}{s:\"ClientPerf\"\"ormance\\\"}\"}{s:\"23\"}{s:\"fps\"}{s:\"Avatars: 1, Objects: 0\"}{i:76970180}").toExpression());
System.out.println("hi");
}

View File

@ -95,7 +95,7 @@ public class UiLoggerController implements Initializable {
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER);
lblHarbleAPI.setText("HarbleAPI: " + (HarbleAPIFetcher.HARBLEAPI == null ? "False" : "True"));
lblHarbleAPI.setText("Messages: " + (HarbleAPIFetcher.HARBLEAPI == null ? "False" : "True"));
if ((viewMessageName || viewMessageHash) && HarbleAPIFetcher.HARBLEAPI != null) {
HarbleAPI api = HarbleAPIFetcher.HARBLEAPI;
HarbleAPI.HarbleMessage message = api.getHarbleMessageFromHeaderId(
@ -124,7 +124,7 @@ public class UiLoggerController implements Initializable {
.append(packet.headerId())
.append(spanWithClass("]", isIncoming ? "incoming" : "outgoing"))
.append(isIncoming ? " <- " : " -> ")
.append(skiphugepackets && packet.length() > 8000 ?
.append(skiphugepackets && packet.length() > 4000 ?
divWithClass("<packet skipped>", "skipped") :
divWithClass(packet.toString(), isIncoming ? "incoming" : "outgoing"));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
from time import sleep
from g_python.gextension import Extension
from g_python.hmessage import Direction, HMessage
from g_python.hpacket import HPacket
from g_python import hparsers
from g_python import htools
extension_info = {"title": "$G_PYTHON_SHELL_TITLE$", "description": "G-Python scripting console", "version": "1.0", "author": ""}
ext = Extension(extension_info, ["--port", "$G_EARTH_PORT$", "--auth-token", "$COOKIE$"], {"can_leave": False})
ext.start()
def is_closed(): return ext.is_closed()
def send_to_client(packet): return ext.send_to_client(packet)
def send_to_server(packet): return ext.send_to_server(packet)
def on_event(event_name: str, func): return ext.on_event(event_name, func)
def intercept(direction: Direction, callback, id=-1): return ext.intercept(direction, callback, id)
def start(): return ext.start()
def stop(): return ext.stop()
def write_to_console(text, color='black', mention_title=True): return ext.write_to_console(text, color, mention_title)
def request_flags(): return ext.request_flags()
HPacket.default_extension = ext

View File

@ -0,0 +1,214 @@
let gearth_isconnected = false;
let revision = "{{RevisionName}}";
let g_ws;
let chachas = [];
let chachaClass = -1;
let out_send_param1 = -1;
let out_send_param3 = -1;
let out_packet_objid = new Uint8Array(4);
let in_recv_param1 = -1;
let in_packet_prefix = new Uint8Array(16);
let _gearth_returnbyte_copy;
let _gearth_outgoing_copy;
let _gearth_incoming_copy;
let _malloc;
let _free;
var packetBuff = {"out": [], "in": []};
function readLittleEndian(arr) {
return arr[0] + arr[1] * 256 + arr[2] * 65536 + arr[3] * 16777216;
}
function readBigEndian(arr) {
return arr[3] + arr[2] * 256 + arr[1] * 65536 + arr[0] * 16777216;
}
function writeLittleEndian(n) {
let arr = new Uint8Array(4);
for (let i = 0; i < 4; i++) {
let rest = n % 256;
arr[i] = rest;
n -= rest;
n /= 256;
}
return arr;
}
function writeBigEndian(n) {
let arr = new Uint8Array(4);
for (let i = 0; i < 4; i++) {
let rest = n % 256;
arr[3 - i] = rest;
n -= rest;
n /= 256;
}
return arr;
}
function packetToString(packet) {
let chars = [];
let textDecode = new TextDecoder('latin1');
for (let i = 0; i < packet.length; i++) {
let byte = packet[i];
if (byte < 32 || (byte > 127 && byte < 160) || byte === 93 || byte === 91 || byte === 125 || byte === 127) {
chars.push("["+byte+"]");
}
else {
chars.push(textDecode.decode(packet.slice(i, i+1)));
}
}
return chars.join("");
}
function printPacket(type, packet) {
packet = new Uint8Array(packet);
if (packet.length > 2000) {
console.log("[" + type + " capture]" + " -> skipped");
}
else {
console.log("[" + type + " capture]" + " -> " + packetToString(packet));
}
}
let _g_packet_split = 600;
function inject_out(packet) {
if (chachas.length > 1) {
packet[5] = _gearth_returnbyte_copy(chachas[0], packet[5], chachaClass);
packet[4] = _gearth_returnbyte_copy(chachas[0], packet[4], chachaClass);
}
let i = 0;
while (i < packet.length) {
let inject_amount = Math.min(_g_packet_split, packet.length - i);
let packet_location = _malloc(inject_amount + 16);
unityInstance.Module.HEAPU8.set(out_packet_objid, packet_location);
unityInstance.Module.HEAPU8.fill(0, packet_location + 4, packet_location + 12);
unityInstance.Module.HEAPU8.set(writeLittleEndian(inject_amount), packet_location + 12);
unityInstance.Module.HEAPU8.set(packet.slice(i, i + inject_amount), packet_location + 16);
_gearth_outgoing_copy(out_send_param1, packet_location, out_send_param3);
_free(packet_location);
i += inject_amount;
}
}
function handle_out(packet) {
if (gearth_isconnected) {
let g_message = new Uint8Array(packet.length + 1);
g_message[0] = 1; // toserver
g_message.set(new Uint8Array(packet), 1);
g_ws.send(g_message);
}
else {
inject_out(packet);
}
}
function inject_in(packet) {
let i = 0;
while (i < packet.length) {
let inject_amount = Math.min(_g_packet_split, packet.length - i);
let packet_location = _malloc(inject_amount + 16);
unityInstance.Module.HEAPU8.set(in_packet_prefix, packet_location);
unityInstance.Module.HEAPU8.set(packet.slice(i, i + inject_amount), packet_location + 16);
_gearth_incoming_copy(in_recv_param1, packet_location, 0, inject_amount, 0);
_free(packet_location);
i += inject_amount;
}
}
function handle_in(packet) {
if (gearth_isconnected) {
let g_message = new Uint8Array(packet.length + 1);
g_message[0] = 0; // toclient
g_message.set(new Uint8Array(packet), 1);
g_ws.send(g_message);
}
else {
inject_in(packet);
}
}
function collect_packets(type) {
let finishedPackets = [];
while (packetBuff[type].length >= 6 && readBigEndian(packetBuff[type].slice(0, 4)) + 4 <= packetBuff[type].length) {
let packetLength = readBigEndian(packetBuff[type].slice(0, 4)) + 4;
let packet = packetBuff[type].slice(0, packetLength);
finishedPackets.push(packet);
packetBuff[type] = packetBuff[type].slice(packetLength);
}
return finishedPackets;
}
let onOpen = function() {
g_ws.send(new TextEncoder('latin1').encode(revision));
gearth_isconnected = true;
};
let onClose = function() {
gearth_isconnected = false;
};
let onMessage = function(message) {
let buffer = new Uint8Array(message.data);
if (buffer[0] === 0) {
inject_in([].slice.call(buffer.slice(1)));
}
else if (buffer[0] === 1) {
inject_out([].slice.call(buffer.slice(1)));
}
else {
gearth_isconnected = false;
g_ws.close();
}
};
let onError = function(event) {
gearth_isconnected = false;
};
let portRequester = new WebSocket("ws://localhost:9039/ws/portrequest");
portRequester.onmessage = function(message) {
let port = message.data.split(" ")[1];
let _g_packet_url = "ws://localhost:" + port + "/ws/packethandler";
g_ws = new WebSocket(_g_packet_url);
g_ws.binaryType = "arraybuffer";
g_ws.onopen = onOpen;
g_ws.onclose = onClose;
g_ws.onmessage = onMessage;
g_ws.onerror = onError;
portRequester.close();
};

View File

@ -0,0 +1,11 @@
_gearth_returnbyte_copy = Module["_gearth_returnbyte_copy"] = (function() {
return Module["asm"]["_gearth_returnbyte_copy"].apply(null, arguments)
});
_gearth_outgoing_copy = Module["_gearth_outgoing_copy"] = (function() {
return Module["asm"]["_gearth_outgoing_copy"].apply(null, arguments)
});
_gearth_incoming_copy = Module["_gearth_incoming_copy"] = (function() {
return Module["asm"]["_gearth_incoming_copy"].apply(null, arguments)
});

View File

@ -0,0 +1,49 @@
function g_outgoing_packet(param1, param2, param3) {
out_send_param1 = param1;
out_send_param3 = param3;
out_packet_objid = unityInstance.Module.HEAPU8.slice(param2, param2 + 4);
let length = readLittleEndian(unityInstance.Module.HEAPU8.subarray(param2 + 12, param2 + 12 + 4));
let array = [].slice.call(unityInstance.Module.HEAPU8.subarray(param2 + 12 + 4, param2 + 12 + 4 + length));
packetBuff["out"] = packetBuff["out"].concat(array);
for (let packet of collect_packets("out")) {
handle_out(packet);
}
}
function g_incoming_packet(param1, param2, param3, param4, param5) {
in_recv_param1 = param1;
in_packet_prefix = unityInstance.Module.HEAPU8.slice(param2, param2 + 16);
let buffer = unityInstance.Module.HEAPU8.slice(param2 + 16, param2 + 16 + param4);
packetBuff["in"] = packetBuff["in"].concat([].slice.call(buffer));
let packets = collect_packets("in");
for (let packet of packets) {
if (chachas.length > 1) {
packet[5] = _gearth_returnbyte_copy(chachas[1], packet[5], chachaClass);
packet[4] = _gearth_returnbyte_copy(chachas[1], packet[4], chachaClass);
}
handle_in(packet);
}
}
function g_chacha_setkey(param1, param2, param3, param4) {
if (chachas.length === 2) {
chachas = [];
}
chachas.push(param1);
}
function g_chacha_returnbyte(param1, param2, param3) {
chachaClass = param3;
return param2;
}
env["g_outgoing_packet"] = g_outgoing_packet;
env["g_incoming_packet"] = g_incoming_packet;
env["g_chacha_setkey"] = g_chacha_setkey;
env["g_chacha_returnbyte"] = g_chacha_returnbyte;

View File

@ -11,7 +11,7 @@
fx:controller="gearth.ui.GEarthController">
<Pane fx:id="mover" maxHeight="0.0" minHeight="0.0" prefWidth="200.0"/>
<TabPane fx:id="tabBar" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="295.0" prefWidth="565.0" tabClosingPolicy="UNAVAILABLE">
minWidth="-Infinity" prefHeight="295.0" prefWidth="650.0" tabClosingPolicy="UNAVAILABLE">
<Tab text="Connection">
<fx:include fx:id="connection" source="connection/Connection.fxml"/>
</Tab>

View File

@ -11,7 +11,7 @@
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.connection.ConnectionController">
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.connection.ConnectionController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.ExtensionsController">
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.ExtensionsController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="277.0" />
</columnConstraints>
@ -19,11 +19,11 @@
<VBox fx:id="extensioncontainer" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<GridPane fx:id="header_ext" gridLinesVisible="true">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="163.0" minWidth="10.0" percentWidth="22.0" prefWidth="57.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="190.0" minWidth="10.0" percentWidth="34.0" prefWidth="189.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="118.0" minWidth="10.0" percentWidth="18.0" prefWidth="66.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="100.0" minWidth="10.0" percentWidth="13.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="100.0" minWidth="10.0" percentWidth="11.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="22.0" prefWidth="132.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="34.0" prefWidth="204.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="18.0" prefWidth="108.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="13.0" prefWidth="78.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="11.0" prefWidth="66.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
@ -52,14 +52,16 @@
<GridPane hgap="7.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="49.0" minWidth="49.0" prefWidth="49.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="101.0" minWidth="101.0" prefWidth="101.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="90.0" minWidth="90.0" prefWidth="90.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="0.0" prefWidth="247.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="140.0" prefWidth="140.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="140.0" prefWidth="140.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="130.0" prefWidth="130.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<Button fx:id="btn_gpython" disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#gpythonBtnClicked" text="G-Python shell" GridPane.columnIndex="3" />
<TextField fx:id="ext_port" editable="false" prefHeight="26.0" prefWidth="157.0" GridPane.columnIndex="1">
<GridPane.margin>
<Insets left="-7.0" />
@ -70,8 +72,8 @@
<Insets left="3.0" />
</GridPane.margin>
</Label>
<Button fx:id="btn_install" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#installBtnClicked" text="Install" GridPane.columnIndex="4" />
<Button fx:id="btn_viewExtensionConsole" layoutX="401.0" layoutY="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#extConsoleBtnClicked" text="View logs" GridPane.columnIndex="3" />
<Button fx:id="btn_install" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#installBtnClicked" text="Install" GridPane.columnIndex="5" />
<Button fx:id="btn_viewExtensionConsole" layoutX="401.0" layoutY="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#extConsoleBtnClicked" text="View logs" GridPane.columnIndex="4" />
</GridPane>
</GridPane>
</GridPane>

View File

@ -3,7 +3,7 @@
<?import javafx.geometry.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" prefHeight="230.0" prefWidth="394.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.logger.ExtensionLoggerController">
<BorderPane fx:id="borderPane" prefHeight="230.0" prefWidth="394.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extensions.logger.ExtensionLoggerController">
<padding>
<Insets bottom="1.0" left="5.0" right="1.0" top="5.0" />
</padding>

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extra.ExtraController">
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.extra.ExtraController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="331.0" minWidth="10.0" prefWidth="318.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="10.0" prefWidth="247.0" />
@ -26,38 +26,39 @@
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="125.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="235.0" minHeight="10.0" prefHeight="232.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="7.0" minHeight="7.0" prefHeight="7.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="34.0" minHeight="34.0" prefHeight="34.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="10.0" prefHeight="232.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane fx:id="grd_advanced" disable="true" style="-fx-border-color: #888888; -fx-border-radius: 5px;" GridPane.rowIndex="1">
<GridPane fx:id="grd_advanced" disable="true" prefHeight="161.0" prefWidth="299.0" style="-fx-border-color: #888888; -fx-border-radius: 5px;" GridPane.rowIndex="4">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="119.0" minHeight="58.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="119.0" minHeight="6.0" prefHeight="15.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="28.0" minHeight="28.0" prefHeight="28.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane.margin>
<Insets bottom="12.0" left="10.0" right="10.0" />
<Insets bottom="5.0" left="10.0" right="10.0" top="6.0" />
</GridPane.margin>
<padding>
<Insets bottom="4.0" left="7.0" top="7.0" />
<Insets left="7.0" top="3.0" />
</padding>
<children>
<CheckBox fx:id="cbx_useSocks" mnemonicParsing="false" text="Use SOCKS proxy" />
<CheckBox fx:id="cbx_disableDecryption" mnemonicParsing="false" text="Disable decryption" GridPane.rowIndex="3" />
<CheckBox fx:id="cbx_debug" mnemonicParsing="false" text="Debug to stdout" GridPane.rowIndex="4" />
<CheckBox fx:id="cbx_disableDecryption" mnemonicParsing="false" text="Disable decryption" GridPane.rowIndex="2" />
<CheckBox fx:id="cbx_debug" mnemonicParsing="false" text="Debug to stdout" GridPane.rowIndex="3" />
<GridPane fx:id="grd_socksInfo" disable="true" prefHeight="54.0" prefWidth="81.0" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane.margin>
<Insets />
@ -66,7 +67,6 @@
<Insets left="5.0" />
</padding>
<children>
<CheckBox fx:id="cbx_socksUseIfNeeded" mnemonicParsing="false" selected="true" text="Only use if needed" GridPane.rowIndex="1" />
<GridPane prefHeight="119.0" prefWidth="259.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="159.0" minWidth="10.0" prefWidth="68.0" />
@ -104,12 +104,50 @@
</GridPane>
</children>
</GridPane>
<CheckBox fx:id="cbx_advanced" mnemonicParsing="false" text="Advanced" textFill="#000000ba">
<CheckBox fx:id="cbx_advanced" mnemonicParsing="false" text="Advanced" textFill="#000000ba" GridPane.rowIndex="3">
<GridPane.margin>
<Insets left="10.0" top="2.0" />
</GridPane.margin>
<padding>
<Insets top="2.0" />
</padding>
</CheckBox>
<CheckBox fx:id="cbx_gpython" mnemonicParsing="false" onAction="#gpythonCbxClick" text="Enable G-Python scripting" textFill="#000000ba" GridPane.rowIndex="2">
<GridPane.margin>
<Insets left="10.0" top="2.0" />
</GridPane.margin>
</CheckBox>
<GridPane fx:id="grd_clientSelection" prefHeight="26.0" prefWidth="286.0" style="-fx-border-color: #888888; -fx-border-radius: 5px;" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="149.0" minWidth="10.0" prefWidth="38.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="81.0" minWidth="69.0" prefWidth="75.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="83.0" minWidth="66.0" prefWidth="72.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="82.0" minWidth="61.0" prefWidth="65.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="242.0" minWidth="10.0" prefWidth="47.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="20.0" prefHeight="34.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<RadioButton fx:id="rd_unity" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" selected="true" text="Unity" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
<toggleGroup>
<ToggleGroup fx:id="tgl_clientMode" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="rd_flash" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Flash" toggleGroup="$tgl_clientMode" GridPane.columnIndex="2" />
<RadioButton disable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Anime" GridPane.columnIndex="3" />
</children>
<GridPane.margin>
<Insets left="10.0" right="10.0" />
</GridPane.margin>
<padding>
<Insets bottom="8.0" top="8.0" />
</padding>
</GridPane>
</children>
<GridPane.margin>
<Insets />
</GridPane.margin>
</GridPane>
</children>
</GridPane>

View File

@ -5,7 +5,7 @@
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="595.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.info.InfoController">
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.info.InfoController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="332.0" />
</columnConstraints>
@ -20,61 +20,63 @@
<Font size="18.0" />
</font>
</Label>
<Label layoutX="260.0" layoutY="50.0" text="Habbo packet manipulator for Linux, Windows &amp; Mac" textFill="#000000b2">
<Label layoutX="260.0" layoutY="57.0" text="Habbo packet manipulator for Linux, Windows &amp; Mac" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="260.0" layoutY="87.0" text="Made by:" textFill="#000000b2">
<Label layoutX="260.0" layoutY="94.0" text="Made by:" textFill="#000000b2">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
<Label layoutX="260.0" layoutY="107.0" text="sirjonasxx" textFill="#000000b2">
<Label layoutX="260.0" layoutY="114.0" text="sirjonasxx" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="87.0" text="Contributors:" textFill="#000000b2">
<Label layoutX="363.0" layoutY="94.0" text="Contributors:" textFill="#000000b2">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="107.0" text="XePeleato" textFill="#000000b2">
<Label layoutX="363.0" layoutY="114.0" text="XePeleato" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="127.0" text="Scott Stamp" textFill="#000000b2">
<Label layoutX="363.0" layoutY="134.0" text="Scott Stamp" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="147.0" text="LittleJ" textFill="#000000b2">
<Label layoutX="363.0" layoutY="154.0" text="LittleJ" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="167.0" text="ArachisH" textFill="#000000b2">
<Label layoutX="363.0" layoutY="174.0" text="ArachisH" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="363.0" layoutY="187.0" text="BurakDev" textFill="#000000b2">
<Label layoutX="363.0" layoutY="194.0" text="BurakDev" textFill="#000000b2">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="487.0" layoutY="87.0" text="Links:" textFill="#000000b2">
<Label layoutX="491.0" layoutY="94.0" text="Links:" textFill="#000000b2">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Label>
<Hyperlink fx:id="link_sng" layoutX="487.0" layoutY="107.0" text="SNG Forum" />
<Hyperlink fx:id="link_darkbox" layoutX="487.0" layoutY="127.0" text="Darkbox" />
<Hyperlink fx:id="link_d_harble" layoutX="487.0" layoutY="187.0" text="Discord - Harble" />
<Hyperlink fx:id="link_g_gearth" layoutX="487.0" layoutY="147.0" text="Github - G-Earth" />
<Hyperlink fx:id="link_g_tanji" layoutX="487.0" layoutY="167.0" text="Github - Tanji" />
<Hyperlink fx:id="link_ase" layoutX="487.0" layoutY="114.0" text="AllSeeingEye" />
<Hyperlink fx:id="link_darkbox" layoutX="487.0" layoutY="134.0" text="Darkbox" />
<Hyperlink fx:id="link_d_gearth" layoutX="487.0" layoutY="194.0" text="Discord - G-Earth" />
<Hyperlink fx:id="link_d_harble" layoutX="487.0" layoutY="214.0" text="Discord - Harble" />
<Hyperlink fx:id="link_g_gearth" layoutX="487.0" layoutY="154.0" text="Github - G-Earth" />
<Hyperlink fx:id="link_g_tanji" layoutX="487.0" layoutY="174.0" text="Github - Tanji" />
<Button layoutX="537.0" layoutY="14.0" mnemonicParsing="false" onAction="#donate" prefHeight="20.0" prefWidth="100.0" text="Donate BTC" />
<!--<Hyperlink fx:id="link_d_bonnie" layoutX="400.0" layoutY="221.0" text="Discord - BonnieScripting (pt/br)" />-->
</children>
</AnchorPane>

View File

@ -10,7 +10,7 @@
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0"
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="gearth.ui.injection.InjectionController">
<columnConstraints>

View File

@ -12,7 +12,7 @@
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.TextFlow?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0"
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="gearth.ui.logger.LoggerController">
<columnConstraints>

View File

@ -75,7 +75,7 @@
<Insets right="10.0" />
</FlowPane.margin>
</Label>
<Label fx:id="lblHarbleAPI" layoutX="283.0" layoutY="11.0" style="-fx-text-fill: black !important" text="HarbleAPI: False">
<Label fx:id="lblHarbleAPI" layoutX="283.0" layoutY="11.0" style="-fx-text-fill: black !important" text="Messages: False">
<FlowPane.margin>
<Insets right="10.0" />
</FlowPane.margin>

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="595.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.scheduler.SchedulerController">
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.scheduler.SchedulerController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="277.0" />
</columnConstraints>

View File

@ -10,7 +10,7 @@
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="262.0" prefWidth="565.0"
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="gearth.ui.tools.ToolsController">
<rowConstraints>

View File

@ -3,25 +3,25 @@ Habbo packet logger & manipulator for Windows, Linux and Mac.
- Requires Java 8
FOR TROUBLESHOOTING, GO TO https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting
[CLICK HERE FOR TROUBLESHOOTING](https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting)
Join the G-Earth Discord server: https://discord.gg/AVkcF8y
Join the G-Earth [Discord server](https://discord.gg/AVkcF8y)
# Windows execution
Double click G-Earth.exe, which will be delivered in the release. Note that executing G-Earth requires admin privileges.
# Linux execution
Execution command (temporary, verified in Ubuntu):
Execution command:
> $ sudo java -jar G-Earth.jar
Additionally, you can add the -t flag to log the packets in your terminal instead of opening a new window for it.
# Mac execution
https://github.com/sirjonasxx/G-Earth/wiki/macOs-Installation-guide
[MacOs Installation guide](https://github.com/sirjonasxx/G-Earth/wiki/macOs-Installation-guide)
# Features
* Log outgoing and incoming packets
* Injection, both sides
* Injection, both directions
* Blocking & replacing packets functionality
* Packet expressions
* Encoding/decoding
@ -29,10 +29,13 @@ https://github.com/sirjonasxx/G-Earth/wiki/macOs-Installation-guide
* Retro support - enter game host & port manually (only the first time)
* Advanced scheduler
* Advanced extension support
* Python scripting on the fly
* SOCKS proxy
* 2 included extensions on-release
Interested in creating an extension?
* If you're not experienced with Java but have written extensions before in C#, you could have a look at https://github.com/ArachisH/Geode
* If you are experienced with Java, read this wiki page carefully: https://github.com/sirjonasxx/G-Earth/wiki/Extensions
* If you're not experienced with Java but have written extensions before in C#, you could have a look at [Geode](https://github.com/ArachisH/Geode).
* If you are experienced with Java, read this [wiki page](https://github.com/sirjonasxx/G-Earth/wiki/Extensions) carefully.
* The easiest way to create extensions is using [G-Python](https://github.com/sirjonasxx/G-Python). (can also be done inside G-Earth with a [live scripting console](https://github.com/sirjonasxx/G-Earth/wiki/G-Python-qtConsole))
For the memorysearcher that extracts the RC4 table, go to https://github.com/sirjonasxx/G-Mem
For the memorysearcher that extracts the RC4 table, go to [G-Mem](https://github.com/sirjonasxx/G-Mem).

View File

@ -7,7 +7,7 @@
<groupId>G-Earth</groupId>
<artifactId>G-Earth-Parent</artifactId>
<packaging>pom</packaging>
<version>1.1</version>
<version>1.3</version>
<name>G-Earth-Parent</name>
<url>https://github.com/sirjonasxx/G-Earth</url>