diff --git a/G-Earth/pom.xml b/G-Earth/pom.xml index ef8d76c..207afac 100644 --- a/G-Earth/pom.xml +++ b/G-Earth/pom.xml @@ -12,6 +12,7 @@ 1.8 + 9.2.14.v20151106 @@ -123,6 +124,7 @@ + @@ -172,6 +174,24 @@ + + javax.websocket + javax.websocket-api + 1.1 + + + + org.eclipse.jetty + jetty-server + ${jettyVersion} + + + org.eclipse.jetty.websocket + javax-websocket-server-impl + ${jettyVersion} + + + diff --git a/G-Earth/src/main/java/gearth/protocol/HConnection.java b/G-Earth/src/main/java/gearth/protocol/HConnection.java index 041e3dc..97ed7d4 100644 --- a/G-Earth/src/main/java/gearth/protocol/HConnection.java +++ b/G-Earth/src/main/java/gearth/protocol/HConnection.java @@ -7,6 +7,7 @@ import gearth.protocol.connection.proxy.ProxyProvider; import gearth.protocol.connection.proxy.flash.FlashProxyProvider; import gearth.protocol.connection.proxy.ProxyProviderFactory; 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) { diff --git a/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java b/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java index b49fd5e..67f7b71 100644 --- a/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java +++ b/G-Earth/src/main/java/gearth/protocol/connection/HProxy.java @@ -1,7 +1,8 @@ package gearth.protocol.connection; -import gearth.protocol.packethandler.IncomingPacketHandler; -import gearth.protocol.packethandler.OutgoingPacketHandler; +import gearth.protocol.packethandler.PacketHandler; +import gearth.protocol.packethandler.flash.IncomingFlashPacketHandler; +import gearth.protocol.packethandler.flash.OutgoingFlashPacketHandler; import java.net.ServerSocket; @@ -15,8 +16,8 @@ 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; @@ -33,7 +34,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 +65,11 @@ public class HProxy { return intercept_host; } - public IncomingPacketHandler getInHandler() { + public PacketHandler getInHandler() { return inHandler; } - public OutgoingPacketHandler getOutHandler() { + public PacketHandler getOutHandler() { return outHandler; } diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java index 0c69c33..5e61dd8 100644 --- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java +++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java @@ -7,9 +7,9 @@ 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.IncomingPacketHandler; -import gearth.protocol.packethandler.OutgoingPacketHandler; -import gearth.protocol.packethandler.PacketHandler; +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; @@ -45,9 +45,9 @@ public abstract class FlashProxyProvider implements ProxyProvider { 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); + 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); @@ -78,7 +78,7 @@ public abstract class FlashProxyProvider implements ProxyProvider { } } - private void handleInputStream(Socket socket, PacketHandler packetHandler, Semaphore abort) { + private void handleInputStream(Socket socket, FlashPacketHandler flashPacketHandler, Semaphore abort) { new Thread(() -> { try { int readLength; @@ -86,7 +86,7 @@ public abstract class FlashProxyProvider implements ProxyProvider { 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)); + flashPacketHandler.act(Arrays.copyOf(buffer, readLength)); } } catch (IOException ignore) { diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/ProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/ProxyProvider.java deleted file mode 100644 index 9f3daed..0000000 --- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/ProxyProvider.java +++ /dev/null @@ -1,4 +0,0 @@ -package gearth.protocol.connection.proxy.unity; - -public class ProxyProvider { -} diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityCommunicator.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityCommunicator.java new file mode 100644 index 0000000..3d158e1 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityCommunicator.java @@ -0,0 +1,86 @@ +package gearth.protocol.connection.proxy.unity; + +import gearth.protocol.HConnection; +import gearth.protocol.HMessage; +import gearth.protocol.HPacket; +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.packethandler.unity.UnityPacketHandler; + +import javax.websocket.*; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.nio.ByteBuffer; +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; + + HProxy hProxy = 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 { + + } + + @OnMessage + public void onMessage(byte[] b, Session session) throws IOException { +// session.getBasicRemote().sendText(message.toUpperCase()); +// session.getBasicRemote().sendBinary(ByteBuffer.wrap(b)); +// System.out.println("received " + new HPacket(b).toString()); + + 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) { + String hotelVersion = maybe.readString(); + hProxy = new HProxy("", "", -1, -1, ""); + hProxy.verifyProxy( + new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOCLIENT), + new UnityPacketHandler(hConnection.getExtensionHandler(), hConnection.getTrafficObservables(), session, HMessage.Direction.TOSERVER), + hotelVersion + ); + 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(); + } +} diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityCommunicatorConfig.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityCommunicatorConfig.java new file mode 100644 index 0000000..f007fe6 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityCommunicatorConfig.java @@ -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 getEndpointInstance(Class clazz) throws InstantiationException { + return (T)new UnityCommunicator(proxySetter, stateSetter, hConnection, proxyProvider); + } +} \ No newline at end of file diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java new file mode 100644 index 0000000..b87d8b3 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java @@ -0,0 +1,81 @@ +package gearth.protocol.connection.proxy.unity; + +import gearth.protocol.HConnection; +import gearth.protocol.connection.HProxySetter; +import gearth.protocol.connection.HState; +import gearth.protocol.connection.HStateSetter; +import gearth.protocol.connection.proxy.ProxyProvider; +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.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; + +import javax.websocket.server.ServerContainer; +import javax.websocket.server.ServerEndpointConfig; +import java.io.IOException; + +public class UnityProxyProvider implements ProxyProvider { + + private final HProxySetter proxySetter; + private final HStateSetter stateSetter; + private final HConnection hConnection; + + private Server server; + + 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/ + server = new Server(8025); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/ws"); + + HandlerList handlers = new HandlerList(); + handlers.setHandlers(new Handler[] { context }); + server.setHandler(handlers); + + ServerContainer wscontainer = null; + try { + wscontainer = WebSocketServerContainerInitializer.configureContext(context); + + wscontainer.addEndpoint(ServerEndpointConfig.Builder + .create(UnityCommunicator.class, "/packethandler") // the endpoint url + .configurator(new UnityCommunicatorConfig(proxySetter, stateSetter, hConnection, this)) + .build()); + + server.start(); + stateSetter.setState(HState.WAITING_FOR_CLIENT); + } catch (Exception e) { + stateSetter.setState(HState.NOT_CONNECTED); + e.printStackTrace(); + } + } + + @Override + public synchronized void abort() { + if (server == null) { + return; + } + + final Server abortThis = server; + stateSetter.setState(HState.ABORTING); + new Thread(() -> { + try { + abortThis.stop(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + stateSetter.setState(HState.NOT_CONNECTED); + } + }).start(); + server = null; + } +} diff --git a/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java b/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java index d8fa9f1..69f8c3a 100644 --- a/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java +++ b/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java @@ -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 packetHandlers; + private List 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 potentialRC4tables) { + private boolean onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler, List 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; } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/ByteArrayUtils.java b/G-Earth/src/main/java/gearth/protocol/packethandler/ByteArrayUtils.java new file mode 100644 index 0000000..22ea13b --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/ByteArrayUtils.java @@ -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; + } + +} diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java index 6151c3b..01c5552 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/PacketHandler.java @@ -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 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) 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 getEncryptedBuffer() { - return tempEncryptedBuffer; - } - - protected abstract void printForDebugging(byte[] bytes); - - private Observable bufferChangeObservable = new Observable<>(BufferChangeListener::act); - public Observable getBufferChangeObservable() { - return bufferChangeObservable; - } - - public int getCurrentIndex() { - return currentIndex; - } } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/PayloadBuffer.java b/G-Earth/src/main/java/gearth/protocol/packethandler/PayloadBuffer.java index ceb1d92..36c7045 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/PayloadBuffer.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/PayloadBuffer.java @@ -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; } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/BufferChangeListener.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java similarity index 57% rename from G-Earth/src/main/java/gearth/protocol/packethandler/BufferChangeListener.java rename to G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java index d004cb8..e39d6e7 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/BufferChangeListener.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java @@ -1,4 +1,4 @@ -package gearth.protocol.packethandler; +package gearth.protocol.packethandler.flash; public interface BufferChangeListener { diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java new file mode 100644 index 0000000..b894343 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java @@ -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 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 getEncryptedBuffer() { + return tempEncryptedBuffer; + } + + protected abstract void printForDebugging(byte[] bytes); + + private Observable bufferChangeObservable = new Observable<>(BufferChangeListener::act); + public Observable getBufferChangeObservable() { + return bufferChangeObservable; + } + + public int getCurrentIndex() { + return currentIndex; + } +} diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/IncomingPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java similarity index 84% rename from G-Earth/src/main/java/gearth/protocol/packethandler/IncomingPacketHandler.java rename to G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java index f968241..a7819aa 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/IncomingPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/IncomingFlashPacketHandler.java @@ -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() { diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/OnDatastreamConfirmedListener.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OnDatastreamConfirmedListener.java similarity index 67% rename from G-Earth/src/main/java/gearth/protocol/packethandler/OnDatastreamConfirmedListener.java rename to G-Earth/src/main/java/gearth/protocol/packethandler/flash/OnDatastreamConfirmedListener.java index fd6dabc..4b09343 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/OnDatastreamConfirmedListener.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OnDatastreamConfirmedListener.java @@ -1,4 +1,4 @@ -package gearth.protocol.packethandler; +package gearth.protocol.packethandler.flash; public interface OnDatastreamConfirmedListener { diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/OutgoingPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java similarity index 81% rename from G-Earth/src/main/java/gearth/protocol/packethandler/OutgoingPacketHandler.java rename to G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java index 156eec6..26467f6 100644 --- a/G-Earth/src/main/java/gearth/protocol/packethandler/OutgoingPacketHandler.java +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/OutgoingFlashPacketHandler.java @@ -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); } diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java new file mode 100644 index 0000000..2555e21 --- /dev/null +++ b/G-Earth/src/main/java/gearth/protocol/packethandler/unity/UnityPacketHandler.java @@ -0,0 +1,59 @@ +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) { + synchronized (sendLock) { + try { + byte[] prefix = new byte[]{(direction == HMessage.Direction.TOCLIENT ? ((byte)0) : ((byte)1))}; + byte[] combined = ByteArrayUtils.combineByteArrays(prefix, buffer); + + session.getBasicRemote().sendBinary(ByteBuffer.wrap(combined)); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public void act(byte[] buffer) throws IOException { + HPacket[] packets = payloadBuffer.pushAndReceive(buffer); + + for (HPacket hPacket : packets) { + HMessage hMessage = new HMessage(hPacket, direction, currentIndex); + + OnHMessageHandled afterExtensionIntercept = hMessage1 -> { + notifyListeners(2, hMessage1); + sendToStream(hMessage1.getPacket().toBytes()); + }; + + notifyListeners(0, hMessage); + notifyListeners(1, hMessage); + extensionHandler.handle(hMessage, afterExtensionIntercept); + + currentIndex++; + } + } +} diff --git a/G-Earth/src/main/java/gearth/services/g_chrome_tools/UnityFileServer.java b/G-Earth/src/main/java/gearth/services/g_chrome_tools/UnityFileServer.java new file mode 100644 index 0000000..932ed89 --- /dev/null +++ b/G-Earth/src/main/java/gearth/services/g_chrome_tools/UnityFileServer.java @@ -0,0 +1,4 @@ +package gearth.services.g_chrome_tools; + +public class UnityFileServer { +} diff --git a/G-Earth/src/main/java/gearth/services/g_chrome_tools/UnitywebModifyer.java b/G-Earth/src/main/java/gearth/services/g_chrome_tools/UnitywebModifyer.java new file mode 100644 index 0000000..20ef3e8 --- /dev/null +++ b/G-Earth/src/main/java/gearth/services/g_chrome_tools/UnitywebModifyer.java @@ -0,0 +1,4 @@ +package gearth.services.g_chrome_tools; + +public class UnitywebModifyer { +} diff --git a/G-Earth/src/main/java/gearth/ui/connection/ConnectionController.java b/G-Earth/src/main/java/gearth/ui/connection/ConnectionController.java index 98fa961..2f9eae2 100644 --- a/G-Earth/src/main/java/gearth/ui/connection/ConnectionController.java +++ b/G-Earth/src/main/java/gearth/ui/connection/ConnectionController.java @@ -168,12 +168,19 @@ public class ConnectionController extends SubForm { btnConnect.setDisable(true); new Thread(() -> { - if (cbx_autodetect.isSelected()) { - getHConnection().start(); + if (useFlash()) { + if (cbx_autodetect.isSelected()) { + getHConnection().start(); + } + else { + getHConnection().start(inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText())); + } } else { - getHConnection().start(inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText())); + getHConnection().startUnity(); } + + if (HConnection.DEBUG) System.out.println("connecting"); }).start();