mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2025-01-18 16:26:26 +01:00
PING-message-independent now, changed alot, more efficiency & clean retro support
This commit is contained in:
parent
f2dd96249a
commit
ce2c38ecc7
@ -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(() -> {
|
||||
|
@ -184,6 +184,10 @@ public class RC4 {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean couldBeFresh() {
|
||||
return (x == 0 && y == 0);
|
||||
}
|
||||
|
||||
public void undoRc4(byte[] buf) {
|
||||
|
||||
byte tmp;
|
||||
|
@ -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<MemorySnippet> createMemorySnippetList () {
|
||||
refreshMemoryMaps();
|
||||
return createMemorySnippetList(maps);
|
||||
}
|
||||
private static List<MemorySnippet> createMemorySnippetList (List<long[]> maps) {
|
||||
List<MemorySnippet> result = new ArrayList<>();
|
||||
|
||||
@ -93,12 +89,12 @@ public class HabboClient {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void fetchMemory(List<MemorySnippet> snippets) {
|
||||
private void fetchMemory(List<MemorySnippet> 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<MemorySnippet> differentiate2(List<MemorySnippet> original, int minChangedBytes, int maxChangedBytes, int range) {
|
||||
List<MemorySnippet> upToDate = new ArrayList<>();
|
||||
for (MemorySnippet memorySnippet : original) {
|
||||
upToDate.add(new MemorySnippet(memorySnippet.getOffset(), new byte[memorySnippet.getData().length]));
|
||||
}
|
||||
fetchMemory(upToDate);
|
||||
List<MemorySnippet> result = new ArrayList<>();
|
||||
Queue<Integer> 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<byte[]> getRC4possibilities() {
|
||||
int offset = 4;
|
||||
|
||||
System.out.println( "---- MEMORY MAPS:");
|
||||
for (long[] map : maps) {
|
||||
long begin = map[0];
|
||||
long end = map[1];
|
||||
List<MemorySnippet> possibilities = createMemorySnippetListForRC4();
|
||||
fetchMemory(possibilities);
|
||||
|
||||
System.out.println(begin + " - " + end);
|
||||
List<byte[]> 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<MemorySnippet> createMemorySnippetListForRC4() {
|
||||
private List<MemorySnippet> 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;
|
||||
}
|
||||
|
@ -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<MemorySnippet> diff = null;
|
||||
|
||||
|
||||
// STEP ONE: filtering to obtain one area containing the rc4 data field
|
||||
int foundbuffersize = 0;
|
||||
while (foundbuffersize == 0) {
|
||||
List<byte[]> 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<Byte> 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<Byte> 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<MemorySnippet> searchForPossibleRC4Tables(List<MemorySnippet> snippets) {
|
||||
List<MemorySnippet> 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<MemorySnippet> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
Loading…
Reference in New Issue
Block a user