PING-message-independent now, changed alot, more efficiency & clean retro support

This commit is contained in:
sirjonasxx 2018-06-13 00:14:14 +02:00
parent f2dd96249a
commit ce2c38ecc7
5 changed files with 71 additions and 336 deletions

View File

@ -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(() -> {

View File

@ -184,6 +184,10 @@ public class RC4 {
return result;
}
public boolean couldBeFresh() {
return (x == 0 && y == 0);
}
public void undoRc4(byte[] buf) {
byte tmp;

View File

@ -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;
}

View File

@ -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();
}
}
}

View File

@ -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()) {