Created
April 16, 2020 01:01
-
-
Save rbrick/6ef78f6be9e054ac5285820f0f896fe9 to your computer and use it in GitHub Desktop.
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
@Command | |
public void patch(@Flag("patch") File file, @Flag("server") String server) throws IOException { | |
if (file.exists()) { | |
System.out.println("Found server jar...patching..."); | |
JarFile bungeecordJar = new JarFile(file); | |
byte[] newClassFile = null; | |
Enumeration<JarEntry> entries = bungeecordJar.entries(); | |
while (entries.hasMoreElements()) { | |
JarEntry jarEntry = entries.nextElement(); | |
if (jarEntry.getName().equalsIgnoreCase("net/md_5/bungee/api/ServerPing.class")) { | |
try { | |
ClassReader reader = new ClassReader(bungeecordJar.getInputStream(jarEntry)); | |
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); | |
ClassNode node = new ClassNode(); | |
{ | |
reader.accept(node, 0); | |
} | |
for (int i = 0; i < node.fields.size(); i++) { | |
if (node.fields.get(i).name.equals("lcServer")) { | |
node.fields.remove(node.fields.get(i--)); | |
} | |
} | |
node.fields.add(new FieldNode(ACC_PRIVATE, "lcServer", "Ljava/lang/String;", null, null)); | |
for (MethodNode mn : node.methods) { | |
if (mn.name.equalsIgnoreCase("<init>")) { | |
InsnList insnList = new InsnList(); | |
{ | |
// this.lcServer = "Server Name"; | |
insnList.add(new VarInsnNode(ALOAD, 0)); | |
insnList.add(new LdcInsnNode(server)); | |
insnList.add(new FieldInsnNode(PUTFIELD, "net/md_5/bungee/api/ServerPing", "lcServer", "Ljava/lang/String;")); | |
} | |
for (int i = 0; i < mn.instructions.size(); i++) { | |
// insert at the very end | |
if (mn.instructions.get(i).getOpcode() == INVOKESPECIAL) { | |
if (mn.instructions.get(i) instanceof MethodInsnNode) { | |
if (!((MethodInsnNode) mn.instructions.get(i)).desc.equalsIgnoreCase("()V")) { | |
// likely an constructor similar to this(x, y, z); | |
// we want to skip these. | |
break; | |
} | |
} | |
} | |
if (mn.instructions.get(i).getOpcode() == PUTFIELD) { | |
if (((FieldInsnNode) mn.instructions.get(i)).name.equalsIgnoreCase("lcServer")) { | |
for (int j = 0; j < 3; j++) { | |
mn.instructions.remove(mn.instructions.get(i--)); | |
} | |
} | |
} | |
// Inject right before the RETURN statement | |
// We don't need to worry about anything like IRETURN. This is a void function | |
if (mn.instructions.get(i).getOpcode() == RETURN) { | |
mn.instructions.insertBefore(mn.instructions.get(i), insnList); | |
break; | |
} | |
} | |
} | |
} | |
node.accept(classWriter); | |
newClassFile = classWriter.toByteArray(); | |
} catch (IOException ex) { | |
ex.printStackTrace(); | |
} | |
} | |
} | |
bungeecordJar.close(); | |
if (newClassFile != null) { | |
try { | |
File parent = new File("net/md_5/bungee/api"); | |
parent.mkdirs(); | |
File f = new File(parent, "ServerPing.class"); | |
f.deleteOnExit(); | |
try (FileOutputStream fos = new FileOutputStream(f)) { | |
fos.write(newClassFile); | |
} | |
Process process = new ProcessBuilder("jar", "uvf", file.getPath(), f.getPath()).inheritIO().start(); | |
process.waitFor(); | |
process.destroy(); | |
success.set(true); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
} else { | |
System.out.println("File not found. Is there a typo?"); | |
System.out.println(file.getPath()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment