From ce2c38ecc77c4e20c4cb7b805f3ff2d0b1b63130 Mon Sep 17 00:00:00 2001 From: sirjonasxx <36828922+sirjonasxx@users.noreply.github.com> Date: Wed, 13 Jun 2018 00:14:14 +0200 Subject: [PATCH] PING-message-independent now, changed alot, more efficiency & clean retro support --- src/main/protocol/HConnection.java | 1 - src/main/protocol/crypto/RC4.java | 4 + src/main/protocol/memory/HabboClient.java | 124 ++------- src/main/protocol/memory/Rc4Obtainer.java | 263 +++--------------- .../packethandler/OutgoingHandler.java | 15 +- 5 files changed, 71 insertions(+), 336 deletions(-) diff --git a/src/main/protocol/HConnection.java b/src/main/protocol/HConnection.java index acabdc8..a3ef48a 100644 --- a/src/main/protocol/HConnection.java +++ b/src/main/protocol/HConnection.java @@ -174,7 +174,6 @@ public class HConnection { final boolean[] aborted = new boolean[1]; Rc4Obtainer rc4Obtainer = new Rc4Obtainer(); - rc4Obtainer.setHConnection(this); // wachten op data van client new Thread(() -> { diff --git a/src/main/protocol/crypto/RC4.java b/src/main/protocol/crypto/RC4.java index e062291..392894a 100644 --- a/src/main/protocol/crypto/RC4.java +++ b/src/main/protocol/crypto/RC4.java @@ -184,6 +184,10 @@ public class RC4 { return result; } + public boolean couldBeFresh() { + return (x == 0 && y == 0); + } + public void undoRc4(byte[] buf) { byte tmp; diff --git a/src/main/protocol/memory/HabboClient.java b/src/main/protocol/memory/HabboClient.java index 55d2b5c..277ee66 100644 --- a/src/main/protocol/memory/HabboClient.java +++ b/src/main/protocol/memory/HabboClient.java @@ -14,7 +14,7 @@ public class HabboClient { private static final boolean DEBUG = false; - public static HabboClient create() { + static HabboClient create() { File folder = new File("/proc"); HabboClient client = null; @@ -43,7 +43,7 @@ public class HabboClient { if (DEBUG) System.out.println("* Found flashclient process: " + client.PID); return client; } - public void refreshMemoryMaps() { + private void refreshMemoryMaps() { String filename = "/proc/"+this.PID+"/maps"; BufferedReader reader; maps = new ArrayList<>(); @@ -76,10 +76,6 @@ public class HabboClient { if (DEBUG) System.out.println("* Found memory maps (amount: " + maps.size() + ")"); } - public List createMemorySnippetList () { - refreshMemoryMaps(); - return createMemorySnippetList(maps); - } private static List createMemorySnippetList (List maps) { List result = new ArrayList<>(); @@ -93,12 +89,12 @@ public class HabboClient { return result; } - public void fetchMemory(List snippets) { + private void fetchMemory(List snippets) { for (MemorySnippet snippet : snippets) { fetchMemory(snippet); } } - public void fetchMemory(MemorySnippet snippet) { + private void fetchMemory(MemorySnippet snippet) { String memoryPath = "/proc/" + PID + "/mem"; long begin = snippet.offset; try { @@ -111,82 +107,6 @@ public class HabboClient { e.printStackTrace(); } } - public List differentiate2(List original, int minChangedBytes, int maxChangedBytes, int range) { - List upToDate = new ArrayList<>(); - for (MemorySnippet memorySnippet : original) { - upToDate.add(new MemorySnippet(memorySnippet.getOffset(), new byte[memorySnippet.getData().length])); - } - fetchMemory(upToDate); - List result = new ArrayList<>(); - Queue wachter = new LinkedList<>(); - for (int i = 0; i < original.size(); i++) { - wachter.clear(); - int wachtersize = 0; - - MemorySnippet org = original.get(i); - byte[] orgdata = org.getData(); - MemorySnippet upd = upToDate.get(i); - byte[] upddata = upd.getData(); - - int curstartoffset = -1; - int lastendbuffer = -1; - - for (int p = 0; p < org.getData().length; p++) { - if (wachtersize > 0 && p == wachter.peek()) { - wachter.poll(); - wachtersize--; - } - if (orgdata[p] != upddata[p]) { - wachter.add(p + range); - wachtersize++; - } - - if (p >= range - 1 && wachtersize >= minChangedBytes && wachtersize <= maxChangedBytes) { - if (curstartoffset == -1) { - curstartoffset = p - range + 1; - } - else if (lastendbuffer < p - range) { - MemorySnippet snippet = new MemorySnippet(curstartoffset + org.getOffset(), new byte[lastendbuffer - curstartoffset + 1]); - result.add(snippet); - curstartoffset = p - range + 1; - } - lastendbuffer = p; - } - } - if (curstartoffset != -1) { - MemorySnippet snippet = new MemorySnippet(curstartoffset + org.getOffset(), new byte[lastendbuffer - curstartoffset + 1]); - result.add(snippet); - } - } - fetchMemory(result); - return result; - } - - @SuppressWarnings("Duplicates") - public void pauseProcess() { - String[] args = new String[] {"kill", "-STOP", PID+""}; - Process proc; - try { - proc = new ProcessBuilder(args).start(); - proc.waitFor(); - proc.destroy(); - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - } - - @SuppressWarnings("Duplicates") - public void resumeProcess() { - String[] args = new String[] {"kill", "-CONT", PID+""}; - Process proc; - try { - proc = new ProcessBuilder(args).start(); - proc.waitFor(); - proc.destroy(); - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - } static boolean stringIsNumeric(String str) { @@ -209,19 +129,31 @@ public class HabboClient { } - public void printmemmaps() { - refreshMemoryMaps(); + List getRC4possibilities() { + int offset = 4; - System.out.println( "---- MEMORY MAPS:"); - for (long[] map : maps) { - long begin = map[0]; - long end = map[1]; + List possibilities = createMemorySnippetListForRC4(); + fetchMemory(possibilities); - System.out.println(begin + " - " + end); + List resultSet = new ArrayList<>(); + + for (MemorySnippet snippet : possibilities) { + if (snippet.getData().length >= 1024 && snippet.getData().length <= 1024+2*offset) { + for (int i = 0; i < (snippet.getData().length - ((256 - 1) * offset)); i+=offset) { + byte[] wannabeRC4data = Arrays.copyOfRange(snippet.getData(), i, 1025 + i); + byte[] data = new byte[256]; // dis is the friggin key + for (int j = 0; j < 256; j++) data[j] = wannabeRC4data[j*4]; + resultSet.add(data); + } + } } + return resultSet; } - public List createMemorySnippetListForRC4() { + private List createMemorySnippetListForRC4() { + + int offset = 4; + refreshMemoryMaps(); String memoryPath = "/proc/" + PID + "/mem"; @@ -254,7 +186,7 @@ public class HabboClient { int matchStart = -1; int matchEnd = -1; - for (int i = 0; i < data.length; i+=4) { + for (int i = 0; i < data.length; i+=offset) { int b = (((int)data[i]) + 128) % 256; int indInMap = (i/4) % 256; @@ -278,13 +210,13 @@ public class HabboClient { if (maskCount == 256) { if (matchStart == -1) { - matchStart = i - 1020; + matchStart = i - ((256 - 1) * offset); matchEnd = i; } - if (matchEnd < i - 1020) { + if (matchEnd < i - ((256 - 1) * offset)) { result.add(new MemorySnippet(start + matchStart, new byte[matchEnd - matchStart + 4])); - matchStart = i - 1020; + matchStart = i - ((256 - 1) * offset); } matchEnd = i; } diff --git a/src/main/protocol/memory/Rc4Obtainer.java b/src/main/protocol/memory/Rc4Obtainer.java index f5d7a8c..bf6d571 100644 --- a/src/main/protocol/memory/Rc4Obtainer.java +++ b/src/main/protocol/memory/Rc4Obtainer.java @@ -7,9 +7,12 @@ import main.protocol.HPacket; import main.protocol.crypto.RC4; import main.protocol.packethandler.IncomingHandler; import main.protocol.packethandler.OutgoingHandler; +import main.protocol.packethandler.PayloadBuffer; +import java.util.Arrays; import java.util.List; import java.util.Random; +import java.util.function.Consumer; public class Rc4Obtainer { @@ -19,9 +22,6 @@ public class Rc4Obtainer { OutgoingHandler outgoingHandler = null; IncomingHandler incomingHandler = null; - String habboVersion = ""; - int pingHeader = -1; - public Rc4Obtainer() { client = HabboClient.create(); } @@ -30,7 +30,6 @@ public class Rc4Obtainer { public void setOutgoingHandler(OutgoingHandler handler) { outgoingHandler = handler; handler.addBufferListener((int addedbytes) -> { - if (handler.getCurrentIndex() >= 3) this.addedBytes += addedbytes; if (!hashappened1 && handler.getCurrentIndex() == 3) { hashappened1 = true; onSendFirstEncryptedMessage(); @@ -41,244 +40,58 @@ public class Rc4Obtainer { incomingHandler = handler; } - public void setHConnection(HConnection hConnection) { - hConnection.addTrafficListener(0, message -> { - if (message.getIndex() == 0 && message.getDestination() == HMessage.Side.TOSERVER) { - habboVersion = message.getPacket().readString(6); - if (Cacher.exists(habboVersion +"-pingHeader")) { - pingHeader = Integer.parseInt(Cacher.get(habboVersion +"-pingHeader")); - } - } - if (pingHeader == -1 && message.getDestination() == HMessage.Side.TOCLIENT && message.getPacket().length() == 2) { - pingHeader = message.getPacket().headerId(); - Cacher.add(habboVersion +"-pingHeader", pingHeader+""); - } - }); - } - - private volatile int addedBytes = 0; private void onSendFirstEncryptedMessage() { outgoingHandler.block(); + incomingHandler.block(); new Thread(() -> { - if (DEBUG) System.out.println("[+] send encrypted"); - sleep(20); - - int count = 0; - while (pingHeader == -1 && count < 500) { - sleep(50); - count++; - } - if (count == 500) { - System.out.println("are you connected to a retro? trying other things (might take a while).."); - } - incomingHandler.block(); - - List diff = null; - // STEP ONE: filtering to obtain one area containing the rc4 data field - int foundbuffersize = 0; - while (foundbuffersize == 0) { + List results = client.getRC4possibilities(); + for (byte[] possible : results) { - client.pauseProcess(); -// diff = client.createMemorySnippetList(); - diff = client.createMemorySnippetListForRC4(); - client.fetchMemory(diff); - client.resumeProcess(); - this.addedBytes = 0; - - Random rand = new Random(); - - if (DEBUG) System.out.println("size: " + getTotalBytesLengthOfDiff(diff)); - int i = 0; - while (getTotalBytesLengthOfDiff(diff) > 2000) { - if (pingHeader != -1) { - int am = 0; - if (i == 0 || i > 1) { - am = rand.nextInt(25) + 5; - for (int j = 0; j < am; j++) { - incomingHandler.sendToStream(new HPacket(pingHeader).toBytes()); - outgoingHandler.fakePongAlert(); - sleep(20); - } - } - sleep(50); - } - else { - while (addedBytes == 0) { - sleep(50); - } - System.out.println("making progress.."); - } - - diff = searchForPossibleRC4Tables(diff); - i++; + byte[] encBuffer = new byte[outgoingHandler.getEncryptedBuffer().size()]; + for (int i = 0; i < encBuffer.length; i++) { + encBuffer[i] = outgoingHandler.getEncryptedBuffer().get(i); } - foundbuffersize = (int)getTotalBytesLengthOfDiff(diff); - } - - - - - - //diff should only have one element now - // STEP TWO: obtain the exactly the 256 needed bytes - //research shows that this equals the first occurence of a number followed by 3 zeros is the start - //if that number accidentally is zero it won't work so fuck that - cry - - MemorySnippet snippet = diff.get(0); - byte[] wannabeRC4data = snippet.getData(); - int result_start_index = -1; - for (int i = 0; i < snippet.getData().length - 3; i++) { - if (wannabeRC4data[i] != 0 && wannabeRC4data[i+1] == 0 && wannabeRC4data[i+2] == 0 && wannabeRC4data[i+3] == 0) { - result_start_index = i; - if (DEBUG) System.out.println(result_start_index); - break; - } - } - - if (DEBUG) System.out.println("OFFSET RC4 TABLE: " + (snippet.getOffset() + result_start_index)); - -// client.printmemmaps(); - - byte[] data = new byte[256]; // dis is the friggin key - for (int i = 0; i < 256; i++) data[i] = wannabeRC4data[i*4 + result_start_index]; - - if (DEBUG) printByteArray(data); - - - - - - // STEP 3: find the i & j values (in our RC4 class called x & y) - // this goes together with the verification of this actually being the right RC4 table - - MemorySnippet snippet1 = new MemorySnippet(snippet.getOffset(), new byte[snippet.getData().length]); - client.fetchMemory(snippet1); - if (pingHeader != -1) { - incomingHandler.sendToStream(new HPacket(pingHeader).toBytes()); - outgoingHandler.fakePongAlert(); - } - - sleep(70); - - byte[] lastOutgoingPacket; - if (pingHeader != -1) { - lastOutgoingPacket = new byte[6]; - } - else { - int size = outgoingHandler.getEncryptedBuffer().size(); - int copy = size; - while (copy == size) { - sleep(1); - copy = outgoingHandler.getEncryptedBuffer().size(); - } - lastOutgoingPacket = new byte[copy - size]; - System.out.println("size: " + lastOutgoingPacket.length); - } - - for (int i = 0; i < lastOutgoingPacket.length; i++) { - List encodedbytelistraw = outgoingHandler.getEncryptedBuffer(); - lastOutgoingPacket[i] = encodedbytelistraw.get(encodedbytelistraw.size() - lastOutgoingPacket.length + i); - } - - - int counter = 0; - RC4 result = null; - - while (result == null && counter < 4 && result_start_index >= 0) { - - byte[] data1 = new byte[256]; - for (int i = 0; i < 256; i++) data1[i] = snippet1.getData()[i*4 + result_start_index]; - - //dont panic this runs extremely fast xo outerloop: - for (int x = 0; x < 256; x++) { - for (int y = 0; y < 256; y++) { - byte[] copy = new byte[256]; - for (int i = 0; i < 256; i++) { - copy[i] = data1[i]; - } - RC4 rc4Tryout = new RC4(copy, x, y); + for (int i = 0; i < 256; i++) { +// System.out.println(i); + for (int j = 0; j < 256; j++) { + byte[] keycpy = Arrays.copyOf(possible, possible.length); + RC4 rc4Tryout = new RC4(keycpy, i, j); + + rc4Tryout.undoRc4(encBuffer); + if (rc4Tryout.couldBeFresh()) { + byte[] encDataCopy = Arrays.copyOf(encBuffer, encBuffer.length); + RC4 rc4TryCopy = rc4Tryout.deepCopy(); + + try { + PayloadBuffer payloadBuffer = new PayloadBuffer(); + HPacket[] checker = payloadBuffer.pushAndReceive(rc4TryCopy.rc4(encDataCopy)); + + if (payloadBuffer.peak().length == 0) { + outgoingHandler.setRc4(rc4Tryout); + break outerloop; + } + + } + catch (Exception e) { + + } - HPacket tryout = new HPacket(rc4Tryout.rc4(lastOutgoingPacket)); - if (!tryout.isCorrupted()) { - result = rc4Tryout; - break outerloop; } + } } - if (result == null) { - result_start_index -= 4; - } - counter++; + + } + - //if result = null ud better reload - - if (result == null) { - System.out.println("please try again."); - System.out.println("found RC4 table:"); - printByteArray(data); - return; - } - - - // STEP FOUR: undo all sent packets in the rc4 stream - List enbuf = outgoingHandler.getEncryptedBuffer(); - byte[] encrbuffer = new byte[enbuf.size()]; - for (int i = 0; i < enbuf.size(); i++) { - encrbuffer[i] = enbuf.get(i); - } - - result.undoRc4(encrbuffer); - - - // STEP FIVE: set the rc4 stream - - if (result != null) { - outgoingHandler.setRc4(result); - } - else { - System.err.println("Did not find RC4 stream"); - } - - if (DEBUG) System.out.println("[-] send encrypted"); - outgoingHandler.unblock(); incomingHandler.unblock(); + outgoingHandler.unblock(); }).start(); } - - private List searchForPossibleRC4Tables(List snippets) { - List result; - result = client.differentiate2(snippets, addedBytes, addedBytes * 2, 1024); - addedBytes = 0; - - return result; - } - - private void printByteArray(byte[] booleans) { - StringBuilder builder = new StringBuilder(); - for (byte bool : booleans) { - builder.append(bool); - builder.append(","); - } - System.out.println(builder); - } - private long getTotalBytesLengthOfDiff(List snippets) { - long tot = 0; - for (MemorySnippet snippet : snippets) { - tot += (snippet.getData().length); - } - return tot; - } - private void sleep(int ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } diff --git a/src/main/protocol/packethandler/OutgoingHandler.java b/src/main/protocol/packethandler/OutgoingHandler.java index a5938d0..a4824d9 100644 --- a/src/main/protocol/packethandler/OutgoingHandler.java +++ b/src/main/protocol/packethandler/OutgoingHandler.java @@ -27,7 +27,7 @@ public class OutgoingHandler extends Handler { private void dataStreamCheck(byte[] buffer) { if (!isDataStream) { HPacket hpacket = new HPacket(buffer); - isDataStream = (hpacket.getBytesLength() > 6 && hpacket.headerId() == 4000 && hpacket.headerId() == 4000); + isDataStream = (hpacket.getBytesLength() > 6 && hpacket.headerId() == 4000); } } @@ -94,24 +94,11 @@ public class OutgoingHandler extends Handler { return tempEncryptedBuffer; } - - //as pings & pongs are used in order to find the RC4 table, we really don't want it to be displayed - //or even be sent to the server, we can fix that by calling this method everytime we fakesend a ping - private int skipPongAmount = 0; - public void fakePongAlert() { - skipPongAmount ++; - } - @Override public void flush() throws IOException { synchronized (lock) { HPacket[] hpackets = payloadBuffer.receive(); for (HPacket hpacket : hpackets){ - if (skipPongAmount > 0 && hpacket.length() == 2) { - skipPongAmount --; - continue; - } - HMessage hMessage = new HMessage(hpacket, HMessage.Side.TOSERVER, currentIndex); notifyListeners(hMessage); if (!hMessage.isBlocked()) {