aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPandaNinjas <admin@malwarefight.gq>2023-01-29 21:42:45 -0800
committerPandaNinjas <admin@malwarefight.gq>2023-01-29 21:42:45 -0800
commit4d5700844809d45ca27a7efe8500d9d4c828ea2f (patch)
treecdc6dfb82907a58694a8b44e139a12d98132dbe5
parent7a27e0345d434891d24fe3ec3b3e33d296c989ce (diff)
downloadNoSession-4d5700844809d45ca27a7efe8500d9d4c828ea2f.tar.gz
NoSession-4d5700844809d45ca27a7efe8500d9d4c828ea2f.tar.bz2
NoSession-4d5700844809d45ca27a7efe8500d9d4c828ea2f.zip
On today's edition of why you shouldn't use git after 12 AM
-rw-r--r--README.md1
-rw-r--r--SECURITY.md2
-rw-r--r--build.gradle13
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin0 -> 52928 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rwxr-xr-xgradlew2
-rw-r--r--src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java116
-rw-r--r--src/main/java/gq/malwarefight/nosession/mixin/BlankTweaker.java29
-rw-r--r--src/main/java/gq/malwarefight/nosession/mixin/InitialTweaker.java209
-rw-r--r--src/main/java/gq/malwarefight/nosession/mixin/L2Tweaker.java68
-rw-r--r--src/main/java/gq/malwarefight/nosession/mixin/Utils.java122
-rw-r--r--src/main/java/gq/malwarefight/nosession/mixin/asm/ReplacingMethodVisitor.java22
-rw-r--r--src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java5
-rw-r--r--src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java100
-rw-r--r--src/main/java/gq/malwarefight/nosession/tweaks/CleanupTweaker.java82
-rw-r--r--src/main/java/gq/malwarefight/nosession/tweaks/InitialTweaker.java104
-rw-r--r--src/main/java/gq/malwarefight/nosession/utils/Utils.java221
-rw-r--r--src/main/java/gq/malwarefight/tokenapp/Main.java2
-rw-r--r--src/main/java/gq/malwarefight/tokenapp/SocketThread.java2
19 files changed, 463 insertions, 639 deletions
diff --git a/README.md b/README.md
index 925d2a6..c3cab54 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@ This mod doesn't make you 100% safe, but it makes it much harder to steal your s
## Staying Safe
In order to work around an unpatchable security vulnerability, rename the NoSession jar to !.jar so it can load its protection before any other mods.<br>
-You should also use [MultiMC](https://github.com/MultiMC/Launcher/) or one of its derivates [PolyMC](https://github.com/PolyMC/PolyMC) or [PrismLauncher](https://github.com/PrismLauncher/PrismLauncher), because they use launch Minecraft in a way that improves security.<br>
This only protects you from other mods. There are fake verification sites that can steal your session ID through that method.<br>
Don't login with Microsoft OAuth to anything except maybe your Minecraft launcher. You may also want to verify the signature on any NoSession binary. It's signed with [pandaninjas' GPG key](https://raw.githubusercontent.com/pandaninjas/pandaninjas/main/pandaninjas-publickey.key).
diff --git a/SECURITY.md b/SECURITY.md
index c64722e..d9d5e6d 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -7,7 +7,7 @@ Currently all versions are supported.
| Version | Supported |
| ------- | ------------------ |
| 1.0.0 | ✔️ |
-| Any nightly branch | ❌ |
+
## Reporting a Vulnerability
A vulnerability is currently defined as being able to get the session ID with only a mod that gets loaded after NoSession loads its tweaker.<br>
diff --git a/build.gradle b/build.gradle
index 5ececca..e6d4434 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,10 +16,10 @@ plugins {
id "com.github.johnrengelman.shadow" version "2.0.4"
}
-apply plugin: 'net.minecraftforge.gradle.forge'
+apply plugin: 'net.minecraftforge.gradle.tweaker-client'
apply plugin: 'org.spongepowered.mixin'
-version = "1.1.0-dev"
+version = "1.0.0"
group = "gq.malwarefight.nosession"
archivesBaseName = "nosession"
@@ -27,10 +27,11 @@ compileJava.sourceCompatibility = compileJava.targetCompatibility = 1.8
compileJava.options.encoding = "UTF-8"
minecraft {
- version = "1.8.9-11.15.1.2318-1.8.9"
+ version = "1.8.9"
runDir = "run"
mappings = "stable_22" //mappings for 1.8.9
makeObfSourceJar = false //disable creation of sources jar
+ tweakClass = 'gq.malwarefight.nosession.mixin.InitialTweaker'
}
configurations {
@@ -52,8 +53,6 @@ dependencies {
exclude module: 'commons-io'
exclude module: 'log4j-core'
}
-
- compileOnly "net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9:universal"
}
processResources {
@@ -91,8 +90,8 @@ jar {
"TweakOrder": 0,
"ModSide": "CLIENT",
'FMLCorePluginContainsFMLMod': true,
- 'MixinConfigs': 'mixins.nosession.json',
- "FMLCorePlugin": "gq.malwarefight.nosession.NoSessionLoadingPlugin"
+ 'TweakClass': 'gq.malwarefight.nosession.mixin.InitialTweaker',
+ 'MixinConfigs': 'mixins.nosession.json'
}
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..6ffa237
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 357df5f..7b64320 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip \ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip
diff --git a/gradlew b/gradlew
index 1751d8f..9aa616c 100755
--- a/gradlew
+++ b/gradlew
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-set -x
+
##############################################################################
##
## Gradle start up script for UN*X
diff --git a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java
deleted file mode 100644
index 3ccbff2..0000000
--- a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package gq.malwarefight.nosession;
-
-import gq.malwarefight.nosession.tweaks.InitialTweaker;
-import gq.malwarefight.nosession.utils.Utils;
-import net.minecraft.launchwrapper.Launch;
-import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-@IFMLLoadingPlugin.MCVersion("1.8.9")
-@IFMLLoadingPlugin.Name("NoSession trolling")
-@IFMLLoadingPlugin.SortingIndex(0)
-public class NoSessionLoadingPlugin implements IFMLLoadingPlugin {
- @Override
- public String[] getASMTransformerClass() {
- return new String[0];
- }
-
- @Override
- public String getModContainerClass() {
- return null;
- }
-
- @Override
- public String getSetupClass() {
- return null;
- }
-
- @Override
- public void injectData(Map<String, Object> map) {
- try {
- map.put("coremodLocation", Utils.getLibraryPathAsFile(NoSessionLoadingPlugin.class));
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String getAccessTransformerClass() {
- return null;
- }
-
- public static void shutdown() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- Class<?> shutdown = Class.forName("java.lang.Shutdown");
- Method m = shutdown.getDeclaredMethod("exit", int.class);
- m.setAccessible(true);
- m.invoke(null, 0);
- }
-
- @SuppressWarnings("unchecked")
- public static void injectTweaker() {
- ArrayList<String> tweakClassList = (ArrayList<String>) Launch.blackboard.get("TweakClasses");
- tweakClassList.add(0, InitialTweaker.class.getName());
- }
-
- public static void addSelfToClassLoader() {
- Launch.classLoader.addURL(NoSessionLoadingPlugin.class.getProtectionDomain().getCodeSource().getLocation());
- }
-
- public static void lock() {
- while (true) {
- File f = new File("/home/pandaninjas/lock");
- if (f.exists()) {
- f.delete();
- break;
- }
- }
- }
-
- static {
- System.out.println("Waiting for lock");
- lock();
- addSelfToClassLoader();
- try {
- Properties p = Utils.getJavaProperties();
- Pattern mcJWT = Pattern.compile("--accessToken +(?<token>eyJhbGciOiJIUzI1NiJ9\\.[A-Za-z0-9-_]*\\.[A-Za-z0-9-_]*)");
- Matcher m = mcJWT.matcher(p.getProperty("sun.java.command"));
- if (m.find()) {
- Utils.setToken(m.group("token"));
- RuntimeMXBean rmb = ManagementFactory.getRuntimeMXBean();
- ArrayList<String> args = new ArrayList<>();
- args.add(Utils.getJavaExe(p));
- args.add("-cp");
- args.add(p.getProperty("java.class.path"));
- args.addAll(rmb.getInputArguments());
- String newArgs = m.replaceAll("--accessToken <noSessionAccessToken>");
- args.addAll(Arrays.asList(newArgs.split(" ")));
- ProcessBuilder processBuilder = new ProcessBuilder(
- args.toArray(new String[0])
- ).inheritIO();
- try {
- processBuilder.start();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- shutdown();
- }
- injectTweaker();
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/src/main/java/gq/malwarefight/nosession/mixin/BlankTweaker.java b/src/main/java/gq/malwarefight/nosession/mixin/BlankTweaker.java
new file mode 100644
index 0000000..2c9109b
--- /dev/null
+++ b/src/main/java/gq/malwarefight/nosession/mixin/BlankTweaker.java
@@ -0,0 +1,29 @@
+package gq.malwarefight.nosession.mixin;
+
+import net.minecraft.launchwrapper.ITweaker;
+import net.minecraft.launchwrapper.LaunchClassLoader;
+
+import java.io.File;
+import java.util.List;
+
+public class BlankTweaker implements ITweaker {
+ @Override
+ public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
+
+ }
+
+ @Override
+ public void injectIntoClassLoader(LaunchClassLoader classLoader) {
+
+ }
+
+ @Override
+ public String getLaunchTarget() {
+ return null;
+ }
+
+ @Override
+ public String[] getLaunchArguments() {
+ return new String[0];
+ }
+}
diff --git a/src/main/java/gq/malwarefight/nosession/mixin/InitialTweaker.java b/src/main/java/gq/malwarefight/nosession/mixin/InitialTweaker.java
new file mode 100644
index 0000000..51425fc
--- /dev/null
+++ b/src/main/java/gq/malwarefight/nosession/mixin/InitialTweaker.java
@@ -0,0 +1,209 @@
+package gq.malwarefight.nosession.mixin;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ForwardingMultimap;
+import com.google.gson.Gson;
+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
+import net.minecraft.launchwrapper.ITweaker;
+import net.minecraft.launchwrapper.Launch;
+import net.minecraft.launchwrapper.LaunchClassLoader;
+import net.minecraft.launchwrapper.LogWrapper;
+import org.apache.commons.io.ByteOrderMark;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.Validate;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.objectweb.asm.Opcodes;
+import org.spongepowered.asm.launch.MixinBootstrap;
+import org.spongepowered.asm.mixin.MixinEnvironment;
+import org.spongepowered.asm.mixin.Mixins;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+@SuppressWarnings({"unused", "unchecked"})
+public class InitialTweaker implements ITweaker {
+
+ // I'm creating my own allTweakers list
+ // with blackjack and hookers!
+ public final ArrayList<ITweaker> allTweakers = new ArrayList<>();
+
+ public InitialTweaker() {}
+
+ public String getLibraryPath(Class<?> c) throws URISyntaxException {
+ return new File(c.getProtectionDomain().getCodeSource().getLocation().toURI()).getAbsolutePath();
+ }
+
+ public String getClasspath() throws URISyntaxException {
+ return String.join(
+ System.getProperty("path.separator"),
+ getLibraryPath(InitialTweaker.class),
+ getLibraryPath(YggdrasilAuthenticationService.class),
+ getLibraryPath(Gson.class),
+ getLibraryPath(LogManager.class),
+ getLibraryPath(Validate.class),
+ getLibraryPath(ForwardingMultimap.class),
+ getLibraryPath(Beta.class),
+ getLibraryPath(CharEncoding.class),
+ getLibraryPath(ByteOrderMark.class),
+ getLibraryPath(Logger.class),
+ getLibraryPath(Opcodes.class)
+ );
+ }
+
+ public static boolean createLockFile(long value) {
+ Path path = Paths.get(System.getProperty("java.io.tmpdir"), "NoSessionLock" + value);
+ try {
+ Files.createFile(path);
+ } catch (FileAlreadyExistsException e) {
+ System.out.println("You won the lottery! Two NoSession instances used the same ID. The chance that a new NoSession instance uses the same ID as an old one is (NoSession instances) / 2^64");
+ return false;
+ } catch (IOException e) {
+ LogManager.getLogger().warn("Failed to create lockfile " + e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ public static long getID() {
+ Random r = new Random();
+ while (true) {
+ long value = r.nextLong();
+ if (createLockFile(value)) {
+ Runtime.getRuntime().addShutdownHook(
+ new Thread(() -> {
+ try {
+ Files.delete(Paths.get(System.getProperty("java.io.tmpdir"), "NoSessionLock" + value));
+ } catch (Exception ignored) {}
+ })
+ );
+ return value;
+ }
+ }
+ }
+
+ public void setToken(String token) throws IOException, URISyntaxException {
+ long value = getID();
+ Utils.ID = value;
+ File javaExecutable = Paths.get(System.getProperty("java.home"), "bin", "java").toFile();
+ ProcessBuilder processBuilder = new ProcessBuilder(
+ javaExecutable.getAbsolutePath(), "-cp", getClasspath(), "gq.malwarefight.tokenapp.Main", Long.toString(value)
+ );
+ processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT).redirectError(ProcessBuilder.Redirect.INHERIT);
+ Process c = processBuilder.start();
+ c.getOutputStream().write((token + "\n").getBytes(StandardCharsets.UTF_8));
+ c.getOutputStream().flush();
+ Runtime.getRuntime().addShutdownHook(
+ new Thread(() -> {
+ try {
+ Socket socket = Utils.getProperSocket();
+ socket.getOutputStream().write("fullquit\n".getBytes(StandardCharsets.UTF_8));
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ })
+ );
+ }
+
+ /**
+ * This handles the launch arguments passed towards minecraft
+ * @param args The launch arguments
+ * @param gameDir The game directory (ie: .minecraft)
+ * @param assetsDir The assets directory
+ * @param profile The game profile
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
+ ArrayList<String> argsCopy = new ArrayList<>(args);
+ for (int i = 0; i < argsCopy.size(); i++) {
+ if (argsCopy.get(i).equals("--accessToken")) {
+ try {
+ setToken(args.get(i + 1));
+ } catch (IOException | URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ argsCopy.set(i + 1, "<noSessionAccessToken>");
+ }
+ }
+ boolean any = false;
+ // in order to prevent other mods from seeing the true list of args with the token
+ // we will just call all the other tweakers from here
+ ArrayList<ITweaker> tweakers = (ArrayList<ITweaker>) Launch.blackboard.get("Tweaks");
+ for (final ITweaker tweaker : tweakers) {
+ if (tweaker == this)
+ continue;
+
+ LogWrapper.log(Level.INFO, "Calling tweak class %s", tweaker.getClass().getName());
+ tweaker.acceptOptions(argsCopy, gameDir, assetsDir, profile);
+ tweaker.injectIntoClassLoader(Launch.classLoader);
+ allTweakers.add(tweaker);
+ tweakers.set(tweakers.indexOf(tweaker), new BlankTweaker());
+ any = true;
+ }
+ if (any) {
+ ((ArrayList<String>) Launch.blackboard.get("TweakClasses")).add(0,
+ Utils.getUniqueClassName()
+ );
+ }
+ }
+
+ /**
+ * Inject into the MC class loader
+ * @param classLoader The class loader
+ */
+ @Override
+ public final void injectIntoClassLoader(LaunchClassLoader classLoader) {
+ MixinBootstrap.init();
+ MixinEnvironment environment = MixinEnvironment.getDefaultEnvironment();
+ Mixins.addConfiguration("mixins.nosession.json");
+ // Check if the obfuscation context is null
+ if (environment.getObfuscationContext() == null) {
+ environment.setObfuscationContext("notch");
+ }
+ // This is a client side, client :)
+ environment.setSide(MixinEnvironment.Side.CLIENT);
+ }
+
+ @Override
+ public String getLaunchTarget() {
+ return MixinBootstrap.getPlatform().getLaunchTarget();
+ }
+
+ @Override
+ public String[] getLaunchArguments() {
+
+ ArrayList<String> argsFromOurTweakers = new ArrayList<>();
+
+ for (ITweaker i: allTweakers) {
+ argsFromOurTweakers.addAll(Arrays.asList(i.getLaunchArguments()));
+ }
+
+ //noinspection unchecked
+ ArrayList<String> launchArgs = (ArrayList<String>) Launch.blackboard.get("ArgumentList");
+ for (int i = 0; i < launchArgs.size(); i++) {
+ if (launchArgs.get(i).equals("--accessToken")) {
+ launchArgs.set(i + 1, "<noSessionAccessToken>");
+ }
+ }
+ if (!launchArgs.contains("--accessToken")) {
+ argsFromOurTweakers.add("--accessToken");
+ argsFromOurTweakers.add("<noSessionAccessToken>");
+ }
+
+ return argsFromOurTweakers.toArray(new String[0]);
+ }
+}
diff --git a/src/main/java/gq/malwarefight/nosession/mixin/L2Tweaker.java b/src/main/java/gq/malwarefight/nosession/mixin/L2Tweaker.java
new file mode 100644
index 0000000..8736ca4
--- /dev/null
+++ b/src/main/java/gq/malwarefight/nosession/mixin/L2Tweaker.java
@@ -0,0 +1,68 @@
+package gq.malwarefight.nosession.mixin;
+
+import net.minecraft.launchwrapper.ITweaker;
+import net.minecraft.launchwrapper.Launch;
+import net.minecraft.launchwrapper.LaunchClassLoader;
+import net.minecraft.launchwrapper.LogWrapper;
+import org.apache.logging.log4j.Level;
+import org.spongepowered.asm.launch.MixinBootstrap;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SuppressWarnings("unused") // is used, but not mentioned directly
+public class L2Tweaker implements ITweaker {
+
+ public final ArrayList<ITweaker> allTweakers = new ArrayList<>();
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
+ ArrayList<String> argsCopy = new ArrayList<>(args);
+ for (int i = 0; i < argsCopy.size(); i++) {
+ if (argsCopy.get(i).equals("--accessToken")) {
+ argsCopy.set(i + 1, "<noSessionAccessToken>");
+ }
+ }
+
+ boolean any = false;
+ ArrayList<ITweaker> tweakers = (ArrayList<ITweaker>) Launch.blackboard.get("Tweaks");
+ // in order to prevent other mods from seeing the true list of args with the token
+ // we will just call all the other tweakers from here
+ for (final ITweaker tweaker : tweakers) {
+ if (tweaker == this)
+ continue;
+ LogWrapper.log(Level.INFO, "Calling tweak class %s", tweaker.getClass().getName());
+ tweaker.acceptOptions(argsCopy, gameDir, assetsDir, profile);
+ tweaker.injectIntoClassLoader(Launch.classLoader);
+ allTweakers.add(tweaker);
+ tweakers.set(tweakers.indexOf(tweaker), new BlankTweaker());
+ any = true;
+ }
+ if (any) {
+ ((ArrayList<String>) Launch.blackboard.get("TweakClasses")).add(0,
+ Utils.getUniqueClassName()
+ );
+ }
+ }
+
+ @Override
+ public void injectIntoClassLoader(LaunchClassLoader classLoader) {}
+
+ @Override
+ public String getLaunchTarget() {
+ return MixinBootstrap.getPlatform().getLaunchTarget();
+ }
+
+ @Override
+ public String[] getLaunchArguments() {
+ ArrayList<String> argsFromOurTweakers = new ArrayList<>();
+
+ for (ITweaker i: allTweakers) {
+ argsFromOurTweakers.addAll(Arrays.asList(i.getLaunchArguments()));
+ }
+ return argsFromOurTweakers.toArray(new String[0]);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/gq/malwarefight/nosession/mixin/Utils.java b/src/main/java/gq/malwarefight/nosession/mixin/Utils.java
new file mode 100644
index 0000000..2aaec37
--- /dev/null
+++ b/src/main/java/gq/malwarefight/nosession/mixin/Utils.java
@@ -0,0 +1,122 @@
+package gq.malwarefight.nosession.mixin;
+
+import gq.malwarefight.nosession.mixin.asm.ReplacingMethodVisitor;
+import net.minecraft.launchwrapper.Launch;
+import org.objectweb.asm.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+public class Utils {
+ static int num = 0;
+ static int PORT = -1;
+ static long ID = -1;
+ private static final int BASE_PORT = 47777;
+
+ public static byte[] read(InputStream i, Character delimiter) throws IOException {
+ byte[] buffer = new byte[512];
+ int index = 0;
+ while (true) {
+ int in = i.read();
+ if (in == -1 || (delimiter != null && delimiter == in)) {
+ return Arrays.copyOfRange(buffer, 0, index);
+ }
+ if (index == buffer.length) {
+ // grow the buffer
+ byte[] newBuffer = new byte[buffer.length * 2];
+ System.arraycopy(
+ buffer, 0, newBuffer, 0, buffer.length
+ );
+ buffer = newBuffer;
+ }
+ buffer[index] = (byte) in;
+ index++;
+ }
+ }
+
+ public static String readString(InputStream i, Character delimiter) throws IOException {
+ return new String(read(i, delimiter), StandardCharsets.UTF_8);
+ }
+
+ public static void createClass(byte[] classArray, String name) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ Method m = ClassLoader.class.getDeclaredMethod(
+ "defineClass", String.class, byte[].class, int.class, int.class);
+ m.setAccessible(true);
+ m.invoke(Launch.classLoader, name, classArray, 0, classArray.length);
+ }
+
+ public static String getUniqueClassName() {
+
+ String className = "gq.malwarefight.nosession.mixin.L2TweakerClone" + num;
+
+ byte[] L2TweakerBytes;
+ try {
+ //noinspection ConstantConditions
+ L2TweakerBytes = read(Utils.class.getResourceAsStream("/gq/malwarefight/nosession/mixin/L2Tweaker.class"), null);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ ClassReader cr = new ClassReader(L2TweakerBytes);
+ ClassWriter cw = new ClassWriter(cr, 0);
+ cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
+ @Override
+ public void visit(int version, int access, String name,
+ String signature, String superName, String[] interfaces) {
+ super.visit(version, access, className.replace(".", "/"), signature, superName, interfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ return new ReplacingMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions), L2Tweaker.class.getName().replace(".", "/"), className.replace(".", "/"));
+ }
+ }, 0);
+
+ byte[] code = cw.toByteArray();
+ try {
+ createClass(code, className);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ num++;
+ return className;
+ }
+
+ public static Socket getProperSocket() {
+ if (PORT == -1) {
+ Socket socket = null;
+ int port = 0;
+ for (int i = BASE_PORT; i < BASE_PORT + 10; i++) {
+ try {
+ socket = new Socket();
+ socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), i));
+ socket.getOutputStream().write("id\n".getBytes(StandardCharsets.UTF_8));
+ String value = readString(socket.getInputStream(), '\n');
+ if (value.equals(Long.toString(ID))) {
+ port = i;
+ break;
+ }
+ } catch (Exception ignored) {}
+ }
+ PORT = port;
+ return socket;
+ } else {
+ try {
+ Socket socket = new Socket();
+ socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), PORT));
+ return socket;
+ } catch (IOException e) {
+ PORT = -1;
+ return getProperSocket();
+ }
+ }
+ }
+}
diff --git a/src/main/java/gq/malwarefight/nosession/mixin/asm/ReplacingMethodVisitor.java b/src/main/java/gq/malwarefight/nosession/mixin/asm/ReplacingMethodVisitor.java
new file mode 100644
index 0000000..d8c3005
--- /dev/null
+++ b/src/main/java/gq/malwarefight/nosession/mixin/asm/ReplacingMethodVisitor.java
@@ -0,0 +1,22 @@
+package gq.malwarefight.nosession.mixin.asm;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class ReplacingMethodVisitor extends MethodVisitor implements Opcodes {
+
+ final String newName;
+ final String oldName;
+ public ReplacingMethodVisitor(MethodVisitor mv, String oldName, String newName) {
+ super(ASM5, mv);
+ this.oldName = oldName;
+ this.newName = newName;
+ }
+
+ public void visitFieldInsn(int opcode, String owner, String name,
+ String desc) {
+ owner = owner.replace(oldName, newName);
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+}
diff --git a/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java b/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java
index 5451c26..48327fe 100644
--- a/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java
+++ b/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java
@@ -1,10 +1,9 @@
package gq.malwarefight.nosession.mixin.client;
-import com.google.common.primitives.Booleans;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService;
-import gq.malwarefight.nosession.utils.Utils;
+import gq.malwarefight.nosession.mixin.Utils;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -47,4 +46,4 @@ public class YggdrasilSessionMixin {
} catch (IOException ignored) {}
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java b/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java
deleted file mode 100644
index 55e907c..0000000
--- a/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package gq.malwarefight.nosession.relaunch;
-
-import gq.malwarefight.nosession.tweaks.CleanupTweaker;
-import gq.malwarefight.nosession.utils.Utils;
-import net.minecraft.launchwrapper.Launch;
-import net.minecraftforge.fml.client.FMLClientHandler;
-import net.minecraftforge.fml.common.Loader;
-import net.minecraftforge.fml.common.ModAPIManager;
-import net.minecraftforge.fml.common.asm.ASMTransformerWrapper;
-import net.minecraftforge.fml.common.registry.ItemStackHolderInjector;
-import net.minecraftforge.fml.common.registry.ObjectHolderRegistry;
-import net.minecraftforge.fml.relauncher.FMLInjectionData;
-import net.minecraftforge.fml.relauncher.FMLLaunchHandler;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-
-public class Relaunch {
- public static void relaunch(ArrayList<String> args, File gameDir, File assetsDir, String version) throws Exception {
- resetSecurityManager();
- setToNull(FMLLaunchHandler.class, "INSTANCE");
- setToNull(Loader.class, "instance");
- setToNull(ModAPIManager.class, "INSTANCE");
- setToNull(ObjectHolderRegistry.class, "INSTANCE");
- setToNull(ItemStackHolderInjector.class, "INSTANCE");
- setToNull(FMLClientHandler.class, "INSTANCE");
- setToNull(Loader.class, "injectedContainers");
- Utils.setStaticValue(FMLInjectionData.class, "containers", new ArrayList<String>());
- resetClass(ASMTransformerWrapper.class);
- URLClassLoader originalClassLoader = (URLClassLoader) Launch.class.getClassLoader();
- URL[] newURLS = new URL[originalClassLoader.getURLs().length + 1];
- URLClassLoader lcl = new URLClassLoader(newURLS, originalClassLoader);
- //noinspection unchecked
- Class<Launch> innerLaunch = (Class<Launch>) Class.forName("net.minecraft.launchwrapper.Launch", false, lcl);