Skip to content

Commit 7355143

Browse files
committed
Added agent for redirecting the auth server url
1 parent 5d2840e commit 7355143

File tree

8 files changed

+209
-32
lines changed

8 files changed

+209
-32
lines changed

.github/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ updates:
44
directory: "/"
55
schedule:
66
interval: "daily"
7+
- package-ecosystem: "gradle"
8+
directory: "/Agent/"
9+
schedule:
10+
interval: "daily"
711
- package-ecosystem: "github-actions"
812
directory: "/"
913
schedule:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ hs_err_pid*
1515
/build/
1616
/out/
1717
/run/
18+
/Agent/build/

Agent/build.gradle

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
dependencies {
2+
include "org.ow2.asm:asm:9.7.1"
3+
include "org.ow2.asm:asm-tree:9.7.1"
4+
}
5+
6+
jar {
7+
manifest {
8+
attributes(
9+
"Multi-Release": "true",
10+
"Premain-Class": "net.lenni0451.authhook.Agent",
11+
"PreMain-Class": "net.lenni0451.authhook.Agent",
12+
"Can-Redefine-Classes": "true",
13+
"Can-Retransform-Classes": "true"
14+
)
15+
}
16+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.lenni0451.authhook;
2+
3+
import java.lang.instrument.Instrumentation;
4+
import java.util.Map;
5+
6+
public class Agent {
7+
8+
public static void agentmain(final String args, final Instrumentation instrumentation) {
9+
hook(instrumentation);
10+
}
11+
12+
public static void premain(final String args, final Instrumentation instrumentation) {
13+
hook(instrumentation);
14+
}
15+
16+
private static void hook(final Instrumentation instrumentation) {
17+
try {
18+
Map<String, String> config = Config.load();
19+
instrumentation.addTransformer(new URLRedirector(config), true);
20+
} catch (Throwable t) {
21+
System.err.println("An error occurred while starting AuthHook");
22+
t.printStackTrace();
23+
System.exit(-1);
24+
}
25+
}
26+
27+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package net.lenni0451.authhook;
2+
3+
import java.io.File;
4+
import java.io.FileWriter;
5+
import java.io.IOException;
6+
import java.util.LinkedHashMap;
7+
import java.util.Map;
8+
import java.util.Scanner;
9+
10+
public class Config {
11+
12+
private static final File PATH = new File("auth_hook.properties");
13+
public static final String TARGET_ADDRESS = "target_address";
14+
public static final String SECRET_KEY = "secret_key";
15+
16+
private static Map<String, String> getDefaults() {
17+
Map<String, String> def = new LinkedHashMap<>();
18+
def.put(TARGET_ADDRESS, "http://localhost");
19+
def.put(SECRET_KEY, "paste secret key from ViaProxy here");
20+
return def;
21+
}
22+
23+
public static Map<String, String> load() throws IOException {
24+
Map<String, String> config = getDefaults();
25+
if (PATH.exists()) {
26+
try (Scanner scanner = new Scanner(PATH)) {
27+
while (scanner.hasNextLine()) {
28+
String line = scanner.nextLine();
29+
if (line.startsWith("#")) continue;
30+
if (line.contains("=")) {
31+
String[] split = line.split("=", 2);
32+
config.put(split[0], split[1]);
33+
}
34+
}
35+
}
36+
} else {
37+
save(config);
38+
}
39+
return config;
40+
}
41+
42+
public static void save(final Map<String, String> config) throws IOException {
43+
try (FileWriter writer = new FileWriter(PATH)) {
44+
writer.write("# AuthHook Configuration File\n\n");
45+
for (Map.Entry<String, String> entry : config.entrySet()) {
46+
writer.write(entry.getKey() + "=" + entry.getValue() + "\n");
47+
}
48+
}
49+
}
50+
51+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package net.lenni0451.authhook;
2+
3+
import org.objectweb.asm.ClassReader;
4+
import org.objectweb.asm.ClassWriter;
5+
import org.objectweb.asm.tree.AbstractInsnNode;
6+
import org.objectweb.asm.tree.ClassNode;
7+
import org.objectweb.asm.tree.LdcInsnNode;
8+
import org.objectweb.asm.tree.MethodNode;
9+
10+
import java.lang.instrument.ClassFileTransformer;
11+
import java.security.ProtectionDomain;
12+
import java.util.Map;
13+
14+
public class URLRedirector implements ClassFileTransformer {
15+
16+
private static final String URL = "https://sessionserver.mojang.com";
17+
18+
private final String targetAddress;
19+
private final String secretKey;
20+
21+
public URLRedirector(final Map<String, String> config) {
22+
this.targetAddress = this.formatURL(config.get(Config.TARGET_ADDRESS));
23+
this.secretKey = config.get(Config.SECRET_KEY);
24+
}
25+
26+
private String formatURL(String url) {
27+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
28+
throw new IllegalArgumentException("Invalid URL (missing protocol): " + url);
29+
}
30+
while (url.endsWith("/")) url = url.substring(0, url.length() - 1);
31+
return url;
32+
}
33+
34+
@Override
35+
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
36+
try {
37+
ClassNode node = this.read(classfileBuffer);
38+
boolean modified = false;
39+
for (MethodNode method : node.methods) {
40+
for (AbstractInsnNode insn : method.instructions) {
41+
if (insn instanceof LdcInsnNode ldc && ldc.cst instanceof String str) {
42+
if (str.startsWith(URL)) {
43+
str = str.substring(URL.length());
44+
str = this.targetAddress + "/" + this.secretKey + str;
45+
ldc.cst = str;
46+
47+
modified = true;
48+
System.out.println("Redirected Auth URL in class '" + node.name + "' method '" + method.name + "'");
49+
}
50+
}
51+
}
52+
}
53+
return modified ? this.write(node) : null;
54+
} catch (Throwable ignored) {
55+
}
56+
return null;
57+
}
58+
59+
private ClassNode read(final byte[] bytes) {
60+
ClassNode node = new ClassNode();
61+
ClassReader reader = new ClassReader(bytes);
62+
reader.accept(node, ClassReader.EXPAND_FRAMES);
63+
return node;
64+
}
65+
66+
private byte[] write(final ClassNode node) {
67+
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
68+
node.accept(writer);
69+
return writer.toByteArray();
70+
}
71+
72+
}

build.gradle

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,46 @@
1-
plugins {
2-
id "java-library"
3-
id "idea"
4-
}
1+
allprojects {
2+
apply plugin: "java"
53

6-
base {
7-
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
8-
compileJava.options.encoding = compileTestJava.options.encoding = javadoc.options.encoding = "UTF-8"
4+
base {
5+
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
6+
compileJava.options.encoding = compileTestJava.options.encoding = javadoc.options.encoding = "UTF-8"
97

10-
group = project.maven_group ?: rootProject.maven_group
11-
archivesName = project.maven_name ?: rootProject.maven_name
12-
version = project.maven_version ?: rootProject.maven_version
13-
}
8+
group = project.maven_group ?: rootProject.maven_group
9+
archivesName = project.maven_name ?: rootProject.maven_name
10+
version = project.maven_version ?: rootProject.maven_version
11+
}
12+
13+
repositories {
14+
mavenCentral()
15+
}
1416

15-
configurations {
16-
include
17+
configurations {
18+
include
19+
20+
implementation.extendsFrom include
21+
api.extendsFrom include
22+
}
23+
24+
jar {
25+
dependsOn configurations.include
26+
from {
27+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
28+
configurations.include.collect {
29+
zipTree(it)
30+
}
31+
} {
32+
exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
33+
}
1734

18-
implementation.extendsFrom include
19-
api.extendsFrom include
35+
from("LICENSE") {
36+
rename { "${it}_${project.name ?: rootProject.name}" }
37+
}
38+
}
2039
}
2140

41+
apply plugin: "idea"
42+
2243
repositories {
23-
mavenCentral()
2444
maven {
2545
name = "ViaVersion"
2646
url = "https://repo.viaversion.com"
@@ -39,22 +59,6 @@ processResources {
3959
}
4060
}
4161

42-
jar {
43-
dependsOn configurations.include
44-
from {
45-
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
46-
configurations.include.collect {
47-
zipTree(it)
48-
}
49-
} {
50-
exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
51-
}
52-
53-
from("LICENSE") {
54-
rename { "${it}_${project.name ?: rootProject.name}" }
55-
}
56-
}
57-
5862
idea {
5963
module {
6064
["run"].each {

settings.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ plugins {
1010
}
1111

1212
rootProject.name = "ViaProxyAuthHook"
13+
14+
include(":Agent")

0 commit comments

Comments
 (0)